本文首發於微信公眾號「Android開發之旅」,歡迎關注 ,獲取更多技術乾貨
混合開發應用場景
目前在國內開發純Flutter的應用還是比較少的,絕大部分使用Flutter來開發的公司也都是使用混合開發。那麼混合開發的主要使用場景有哪些呢?
- 作為獨立的頁面進行加入,可以從原生頁面跳轉到Flutter頁面,也可以從Flutter頁面跳轉到原生頁面。
- 作為頁面的一部分嵌入。
建立Flutter module
既然是做混合開發,那麼我們肯定是由Android原生專案的。假如native專案的路徑是這樣的:flutter/flutter_hybrid/native,那麼我們需要在native上一層目錄flutter_hybrid中建立Flutter module。
cd flutter/flutter_hybrid/
//建立支援AndroidX的flutter_module
flutter create --androidx -t module flutter_module
//建立不支援AndroidX的flutter_module
flutter create -t module flutter_module
複製程式碼
所以我們在建立模組的時候首先要確定native專案是不是已經支援AndroidX,如果支援就需要加上 --androidx 引數。
輸入後控制檯列印如下:
$ flutter create -t module flutter_module
Creating project flutter_module...
flutter_module/test/widget_test.dart (created)
flutter_module/flutter_module.iml (created)
flutter_module/.gitignore (created)
flutter_module/.metadata (created)
flutter_module/pubspec.yaml (created)
flutter_module/README.md (created)
flutter_module/lib/main.dart (created)
flutter_module/flutter_module_android.iml (created)
flutter_module/.idea/libraries/Flutter_for_Android.xml (created)
flutter_module/.idea/libraries/Dart_SDK.xml (created)
flutter_module/.idea/modules.xml (created)
flutter_module/.idea/workspace.xml (created)
Running "flutter pub get" in flutter_module... 1.2s
Wrote 12 files.
All done!
Your module code is in flutter_module/lib/main.dart.
複製程式碼
看到All done就表示我們專案建立好了。整個module目錄和原生Flutter基本一樣,主要就是Android、iOS的宿主工程和lib目錄以及pubspec.yaml檔案。
新增Flutter module依賴
module專案建立好後就需要新增到Android專案中了。我們開啟Android專案的setting.gradle檔案,新增如下程式碼:
setBinding(new Binding([gradle: this]))
evaluate(new File(
settingsDir.parentFile,
//flutter_module即為建立的模組名稱
'flutter_module/.android/include_flutter.groovy'
))
複製程式碼
setBinding與evaluate允許Flutter模組包括它自己在內的任何Flutter外掛,在settings.gradle中以類似 :flutter、package_info、:video_player的方式存在。
然後開啟app/build.gradle在dependencies標籤中新增依賴:
implementation project(':flutter')
複製程式碼
這樣兩步就完成了依賴的新增,這裡為什麼新增的叫“flutter” 而不是 “flutter_module”呢?因為專案編譯完成後會在Android專案的目錄下生成叫Flutter的目錄,這就是需要我們依賴的。還有個需要注意是gradle中的minSdkVersion必須要大於等於16,因為這個flutter支援的最低版本。同時新增使用java8來編譯。在app/build.gradle中的android標籤中新增:
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
複製程式碼
呼叫Flutter module
依賴完成後我們就可以呼叫flutter模組來建立UI了。Flutter為我們提供了兩種方式呼叫,一種是createView,以view的形式載入。另一種是createFragment,以Android中的fragment的形式載入。
createView方式:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// setContentView(R.layout.activity_main);
FlutterView flutterView = Flutter.createView(this, getLifecycle(), "initialRoute");
setContentView(flutterView);
}
}
複製程式碼
createFragment方式:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
//container為activity_main佈局中的佔位符FrameLayout
transaction.replace(R.id.container, Flutter.createFragment("initialRoute"));
transaction.commit();
}
}
複製程式碼
這樣就將Flutter預設的首頁載入到應用上了。
從上面兩部分程式碼中我們可以看到都有一個 “initialRoute” 引數,這個引數是用來告訴Dart程式碼在Flutter檢視中顯示哪個小部件。下面我們就來修改module中的main.dart程式碼來載入我們自己的頁面。
我們設定兩個route,分別展示route1Widget,和route2Widget,當沒有匹配的時候展示提醒文字。
import 'package:flutter/material.dart';
import 'dart:ui';
void main() => runApp(MyApp(
//通過window.defaultRouteName獲取從native傳遞過來的引數,需要匯入dart:ui包
initParams: window.defaultRouteName,
));
class MyApp extends StatelessWidget {
final String initParams;
MyApp({Key key, this.initParams}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter_Android混合開發',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: HomePage(initParams: initParams),
);
}
}
class HomePage extends StatefulWidget {
final String initParams;
const HomePage({Key key, this.initParams}) : super(key: key);
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: _widgetRoute(widget.initParams),
),
);
}
}
///路由轉發
Widget _widgetRoute(String route) {
switch (route) {
case "route1":
return route1Widget();
case "route2":
return route2Widget();
default:
return notFoundWidget();
}
}
Widget route1Widget() {
return Center(
child: Text(
"this is route1Widget",
style: TextStyle(color: Colors.red, fontSize: 20),
),
);
}
Widget route2Widget() {
return Center(
child: Text(
"this is route2Widget",
style: TextStyle(color: Colors.blue, fontSize: 20),
),
);
}
Widget notFoundWidget() {
return Center(
child: Text(
"未匹配到路由111",
style: TextStyle(fontSize: 40),
),
);
}
複製程式碼
我們現在將載入Flutter時的initialRoute引數替換為 “route1”,那頁面將載入route1Widget,替換為 “route2”,將載入route2Widget。否則將展示notFoundWidget。當然我們可以直接傳路由引數,但是因為這個引數本身是一個字串,所以我們可以來搞事情。比如傳遞一個json串,那麼是不是可以做很多事呢?這裡我就不貼demo了,因為和上面的邏輯基本一樣,大家可以去試試看。
熱重啟/重新載入
大家在寫純Flutter應用的時候,知道是有熱重啟/重新載入功能的,但是在做混合開發的過程中,你會發現熱重啟/重新載入功能失效了。那麼如何在混合開發中開啟熱重啟/重新載入功能呢?
- 首先接入我們的裝置或者模擬器
- 將我們的App關閉,退出後臺,在terminal中執行 flutter attach命令
$ flutter attach
Waiting for a connection from Flutter on Android SDK built for x86...
複製程式碼
此時就在等待裝置的連線。這裡要注意的是,如果電腦連線了多臺裝置需要使用 -d 命令來指定一臺裝置,引數為裝置的id。
flutter attach -d '你的裝置id'
複製程式碼
- 然後啟動我們的應用會看到控制檯輸出:
Done.
Syncing files to device Android SDK built for x86... 1,393ms
? To hot reload changes while running, press "r". To hot restart (and rebuild state), press "R".
An Observatory debugger and profiler on Android SDK built for x86 is available at: http://127.0.0.1:59354/zRsDBfpesrk=/
For a more detailed help message, press "h". To detach, press "d"; to quit, press "q".
複製程式碼
這樣就表示我們連線成功了。在輸出的日誌中也告訴了我們如何使用熱重啟/重新載入功能。
在Terminal中輸入以下命令:
r : 熱載入;
R : 熱重啟;
h : 獲取幫助;
d : 斷開連線;
q : 退出;
複製程式碼
這裡的的 d 和 q 的命令都有退出除錯,區別在於 d 命令只是單純的斷開而 q 命令會將應用退到後臺。
除錯Dart程式碼
同樣在混合開發過程中我們如何除錯dart程式碼呢?
- 關閉我們的應用
- 點選Android Studio工具欄上的Flutter Attach按鈕(需要安裝Flutter與Dart外掛)
- 啟動我們的應用
接下來就可以像除錯普通Flutter專案一樣來除錯混合開發模式下的Dart程式碼了。
總結
以上就是如何在Android原生專案中接入Flutter模組的基礎講解,主要就是模組的建立、依賴、呼叫以及除錯等等。其它的像iOS接入Flutter模組,Android專案和Flutter專案之間的通訊以及iOS專案和Flutter之間的通訊都將在之後的文章中進行講解。因為寫在一篇中篇幅太長,朋友們讀起來也累。所以後續還會有至少三篇相關的文章和大家見面。動動手關注公眾號,即時獲取相關文章的推送。
全部Demo原始碼已經上傳到後臺,關注公眾號回覆「Android混合開發」即可獲得下載連結。
如果你覺得文章還不錯,請大家點贊分享下,你的肯定是對我最大的鼓勵和支援。
很多朋友私信我說想加我個人微信,坑位有限,限時入坑。
推薦閱讀