一、概念
1隘击、Flutterr_Boot
這是一個(gè)由咸魚技術(shù)出品,幫助你在已有原生應(yīng)用的情況下研铆,搭建flutter混合開發(fā)環(huán)境的工具埋同。 它提供了標(biāo)準(zhǔn)的混合工程結(jié)構(gòu),同時(shí)支持混合棧(一套原生和flutter之前頁面通信和過渡的方案)的快速接入棵红。
https://github.com/alibaba-flutter/flutter-boot
2凶赁、Flutter_Boost
官網(wǎng)介紹:新一代Flutter-Native混合解決方案。 FlutterBoost是一個(gè)Flutter插件,它可以輕松地為現(xiàn)有原生應(yīng)用程序提供Flutter混合集成方案虱肄。FlutterBoost的理念是將Flutter像Webview那樣來使用致板。在現(xiàn)有應(yīng)用程序中同時(shí)管理Native頁面和Flutter頁面并非易事。 FlutterBoost幫你處理頁面的映射和跳轉(zhuǎn)咏窿,你只需關(guān)心頁面的名字和參數(shù)即可(通痴寤颍可以是URL)。
https://github.com/alibaba/flutter_boost
二集嵌、準(zhǔn)備工作
npm安裝以及環(huán)境配置
flutter 的v1.9.1-hotfixes分支安裝以及環(huán)境配置萝挤,對(duì)應(yīng)flutter_boost版本是0.1.60---0.1.64
JDK,Android SDK 等環(huán)境配置正確
三根欧、開始混合項(xiàng)目搭建
項(xiàng)目地址:https://github.com/jingzhanwu/FlutterHybrid-FlutterBoot
1怜珍、安裝flutter_boot,命令行執(zhí)行:npm install flutter_boot
npm install flutter_boot
2咽块、初始化flutter_boot項(xiàng)目绘面,進(jìn)入要存放工程的目錄執(zhí)行:
flutter-boot init
接著會(huì)提示你輸入工程名稱
輸完工程名會(huì)一次提示你輸入flutter 倉庫地址、是否有android項(xiàng)目侈沪,是否有IOS項(xiàng)目揭璃、關(guān)聯(lián)本地項(xiàng)目等,根據(jù)自己項(xiàng)目需求選擇即可亭罪,如果你已經(jīng)有了android原生項(xiàng)目瘦馍,則最好在關(guān)聯(lián)android項(xiàng)目哪一步輸入本地native項(xiàng)目的路勁進(jìn)行關(guān)聯(lián),如果選擇不關(guān)聯(lián)也可以应役,后面后說道如果關(guān)聯(lián)情组,因?yàn)槲沂堑诙蝿?chuàng)建,所以就默認(rèn)執(zhí)行了之前選擇的箩祥。
上面都執(zhí)行完畢后在本地就會(huì)生成一個(gè)項(xiàng)目院崇,名稱就是剛輸入的flutter_lib
3、編譯flutter_lib項(xiàng)目袍祖,下載配置gradle底瓣,如果是android studio 直接打開項(xiàng)目也可以
依次執(zhí)行下面命令,第一個(gè)命令是進(jìn)入到項(xiàng)目根目錄
cd flutter_lib
flutter build apk
4蕉陋、如果初始化的時(shí)候沒有關(guān)聯(lián)native項(xiàng)目捐凭,則在原生項(xiàng)目根目錄下運(yùn)行下面命令進(jìn)行關(guān)聯(lián)、如果初始化時(shí)已經(jīng)關(guān)聯(lián)則跳過此步驟凳鬓。
進(jìn)入native項(xiàng)目根目錄執(zhí)行:flutter-boot link "flutter項(xiàng)目的本地目錄"茁肠,link后面為flutter項(xiàng)目本地目錄
重新關(guān)聯(lián):flutter-boot link -f "flutter項(xiàng)目的本地目錄"
這一步是將原生項(xiàng)目與flutter項(xiàng)目進(jìn)行軟關(guān)聯(lián),這一步執(zhí)行完畢已經(jīng)就可以進(jìn)行正常的混合開發(fā)了
5缩举、使用flutter_boost垦梆,添加混合棧
執(zhí)行:flutter-boot use
flutter-boot use
這一步執(zhí)行完畢匹颤,會(huì)在原生項(xiàng)目的app下build.gradle、settings.gradle和gradle.properties文件中生成一些配置信息奶赔,具體如下
gradle.properties文件
settings.gradle文件
app下build.gradle文件
除了以上增加的內(nèi)容外惋嚎,還會(huì)多出來兩個(gè)gradle文件,分別是flutter的build.gradle和flutter-boost的build.gradle文件站刑;他們分別對(duì)應(yīng)flutter_lib(flutter側(cè))和flutter_boost庫的gradle配置另伍,一般情況下不要去修改這兩個(gè)文件中的內(nèi)容,否則會(huì)引起一些編譯錯(cuò)誤绞旅。
6摆尝、初始化flutter-boost
執(zhí)行完flutter-boot use 命令后分別會(huì)在native側(cè)和flutter側(cè)的項(xiàng)目根目錄下生成一些初始化使用的事例代碼,可以參考因悲;native側(cè)的在 fb目錄下堕汞,flutter的在main.dart和my_flutter_boost_app.dart文件中。
Native側(cè)我把生成的事例代碼進(jìn)行了整理晃琳,首先是Application中的初始化部分:FlutterInitializer.init(this);
public class App extends Application {
@Override
public void onCreate() {
super.onCreate();
FlutterInitializer.init(this);
}
}
FlutterInitializer.java的部分
public class FlutterInitializer {
private final static String TAG = FlutterInitializer.class.getSimpleName();
public static void init(Application app) {
if (!(app instanceof FlutterApplication)) {
FlutterMain.startInitialization(app);
}
//路由,Flutter 啟動(dòng)Native頁面的時(shí)候回調(diào)這里
INativeRouter router = (context, url, urlParams, requestCode, exts) -> {
String assembleUrl = Utils.assembleUrl(url, urlParams);
PageRouter.openPageByUrl(context, assembleUrl, urlParams);
};
//插件注冊(cè)
FlutterBoost.BoostPluginsRegister pluginsRegister = mRegistry -> {
GeneratedPluginRegistrant.registerWith(mRegistry);
//注冊(cè)native的TextView插件讯检,插件名稱:TextPlatformViewPlugin
TextPlatformViewPlugin.register(mRegistry.registrarFor("TextPlatformViewPlugin"));
};
//配置
Platform platform = new FlutterBoost.ConfigBuilder(app, router)
.isDebug(true)
.whenEngineStart(FlutterBoost.ConfigBuilder.ANY_ACTIVITY_CREATED)
.renderMode(FlutterView.RenderMode.texture)
.pluginsRegister(pluginsRegister)
.build();
//初始化flutter_boost
FlutterBoost.instance().init(platform);
}
}
PageRouter.java:是一個(gè)自定義的路由控制輔助類,方便管理頁面跳轉(zhuǎn)
public class PageRouter {
public final static Map<String, String> pageName = new HashMap<String, String>() {{
put("first", "first");
put("second", "second");
put("tab", "tab");
put("sample://flutterPage", "flutterPage");
put("sample://demoFlutterPage", "flutterDemoPage");
}};
public static final String NATIVE_PAGE_URL = "sample://nativePage";
public static final String FLUTTER_DEMO_PAGE_URL = "sample://demoFlutterPage";
public static final String FLUTTER_PAGE_URL = "sample://flutterPage";
public static final String FLUTTER_FRAGMENT_PAGE_URL = "sample://flutterFragmentPage";
public static boolean openPageByUrl(Context context, String url, Map params) {
return openPageByUrl(context, url, params, 0);
}
public static boolean openPageByUrl(Context context, String url, Map params, int requestCode) {
String path = url.split("\\?")[0];
Log.i("openPageByUrl", path);
try {
if (pageName.containsKey(path)) {
//打開指定url的flutter頁面
Intent intent = BoostFlutterActivity.withNewEngine().url(pageName.get(path)).params(params)
.backgroundMode(BoostFlutterActivity.BackgroundMode.opaque).build(context);
if (context instanceof Activity) {
Activity activity = (Activity) context;
activity.startActivityForResult(intent, requestCode);
} else {
context.startActivity(intent);
}
return true;
} else if (url.startsWith(FLUTTER_FRAGMENT_PAGE_URL)) {
//打開flutter創(chuàng)建的fragment
context.startActivity(new Intent(context, FlutterFragmentPageActivity.class));
return true;
} else if (url.startsWith(NATIVE_PAGE_URL)) {
//打開原生Activity
context.startActivity(new Intent(context, NativePageActivity.class));
return true;
}
return false;
} catch (Throwable t) {
return false;
}
}
}
flutter側(cè)的代碼我整理到lib下了卫旱,具體如下
main.dart文件人灼,我自己在生成的事例代碼上添加了自己的一些邏輯
void main() => runApp(MyFlutterBoostApp({
'embeded': (pageName, params, String id) => EmbededFirstRouteWidget(),
'first': (pageName, params, String id) => FirstRouteWidget(),
'second': (pageName, params, String id) => SecondRouteWidget(),
'tab': (pageName, params, String id) => TabRouteWidget(),
'platformView': (pageName, params, String id) => PlatformRouteWidget(),
'flutterDemoPage': (String url, Map params, String id) =>
MyHomePage(title: '$url $id'),
'flutterPage': (String pageName, Map params, String id) =>
FlutterRouteWidget(params: params),
'flutterFragment': (String url, Map params, String id) =>
FragmentRouteWidget(params),
}));
my_flutter_boost_app.dart文件
class MyFlutterBoostApp extends StatefulWidget {
final Map<String, PageBuilder> builders;
MyFlutterBoostApp(this.builders);
@override
_MyFlutterBoostAppState createState() => _MyFlutterBoostAppState();
}
class _MyFlutterBoostAppState extends State<MyFlutterBoostApp> {
@override
void initState() {
super.initState();
FlutterBoost.singleton.registerPageBuilders(widget.builders);
}
@override
Widget build(BuildContext context) {
return MaterialApp(
builder: FlutterBoost.init(postPush: _onRoutePushed),
home: Container(),
);
}
void _onRoutePushed(
String pageName,
String uniqueId,
Map params,
Route route,
Future _,
) {
print("flutter端路由:pageName:$pageName\n params:$params\n route:$route");
}
}
核心代碼為: FlutterBoost.singleton.registerPageBuilders(widget.builders)這句,flutter-boost注冊(cè)一個(gè)flutter 的widget供native側(cè)通過url來調(diào)用顾翼。
7投放、manifest文件的配置
必須注冊(cè)這個(gè)activity,否則無法打開flutter頁面
<!-- 這個(gè)必須注冊(cè)适贸,不然無法打開flutter的頁面-->
<activity
android:name="com.idlefish.flutterboost.containers.BoostFlutterActivity"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density"
android:hardwareAccelerated="true"
android:screenOrientation="portrait"
android:theme="@style/Theme.AppCompat"
android:windowSoftInputMode="adjustResize">
<meta-data
android:name="io.flutter.embedding.android.SplashScreenDrawable"
android:resource="@drawable/page_loading" />
</activity>
在每個(gè)需要使用flutter頁面的activity中都要加入android:hardwareAccelerated="true"這個(gè)屬性的配置
8灸芳、如果native項(xiàng)目出現(xiàn)support庫重復(fù)的情況拜姿,可以在項(xiàng)目的build.gradle文件中加入以下代碼來排除重復(fù)包
def addRepos(RepositoryHandler handler) {
handler.google()
handler.jcenter()
handler.maven { url "https://jitpack.io" }
}
allprojects {
//循環(huán)所有依賴烙样,指定support的版本為28.0.0,解決重復(fù)包問題
//此方法在編譯的時(shí)候會(huì)循環(huán)依賴蕊肥,所以會(huì)增加編譯時(shí)間误阻。建議在
//依賴的時(shí)候使用exclude 方法排除可能重復(fù)的包
addRepos(repositories)
subprojects {
project.configurations.all {
resolutionStrategy.eachDependency { details ->
if (details.requested.group == 'com.android.support'
&& !details.requested.name.contains('multidex')) {
details.useVersion "28.0.0"
}
}
}
}
}
以上就是flutter-boot混合項(xiàng)目腳手架的使用以及flutter-boost的配置了,每一步都是本人自己通過動(dòng)手實(shí)踐驗(yàn)證過的晴埂,如過程中有錯(cuò)誤,首頁確認(rèn)以下flutter版本和使用的flutter-boost的版本寻定,版本對(duì)應(yīng)關(guān)系以flutter-boost官網(wǎng)介紹為準(zhǔn)https://github.com/alibaba/flutter_boost儒洛。
簡(jiǎn)易MVP,支持Jetpack:https://blog.csdn.net/qq_19979101/article/details/103691091
Flutter中Sqlite使用:https://blog.csdn.net/qq_19979101/article/details/93030803
Flutter的Stomp-websocket插件:https://blog.csdn.net/qq_19979101/article/details/93873731
原文作者:與猿同行
原文鏈接:https://blog.csdn.net/qq_19979101/article/details/103777979