本文首發於微信公衆號「Android開發之旅」,歡迎關注 ,獲取更多技術乾貨java
目前在國內開發純Flutter的應用仍是比較少的,絕大部分使用Flutter來開發的公司也都是使用混合開發。那麼混合開發的主要使用場景有哪些呢?android
既然是作混合開發,那麼咱們確定是由Android原生項目的。假如native項目的路徑是這樣的:flutter/flutter_hybrid/native,那麼咱們須要在native上一層目錄flutter_hybrid中建立Flutter module。git
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 參數。json
輸入後控制檯打印以下:bash
$ 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文件。微信
module項目建立好後就須要添加到Android項目中了。咱們打開Android項目的setting.gradle文件,添加以下代碼:app
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的方式存在。less
而後打開app/build.gradle在dependencies標籤中添加依賴:ide
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模塊來建立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應用的時候,知道是有熱重啓/從新加載功能的,可是在作混合開發的過程當中,你會發現熱重啓/從新加載功能失效了。那麼如何在混合開發中開啓熱重啓/從新加載功能呢?
$ 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代碼呢?
接下來就能夠像調試普通Flutter項目同樣來調試混合開發模式下的Dart代碼了。
以上就是如何在Android原生項目中接入Flutter模塊的基礎講解,主要就是模塊的建立、依賴、調用以及調試等等。其它的像iOS接入Flutter模塊,Android項目和Flutter項目之間的通訊以及iOS項目和Flutter之間的通訊都將在以後的文章中進行講解。由於寫在一篇中篇幅太長,朋友們讀起來也累。因此後續還會有至少三篇相關的文章和你們見面。動動手關注公衆號,即時獲取相關文章的推送。
所有Demo源碼已經上傳到後臺,關注公衆號回覆「Android混合開發」便可得到下載連接。
若是你以爲文章還不錯,請你們點贊分享下,你的確定是對我最大的鼓勵和支持。
推薦閱讀