本文首發於微信公衆號「Android開發之旅」,歡迎關注 ,獲取更多技術乾貨
目前在國內開發純Flutter的應用仍是比較少的,絕大部分使用Flutter來開發的公司也都是使用混合開發。那麼混合開發的主要使用場景有哪些呢?java
既然是作混合開發,那麼咱們確定是由Android原生項目的。假如native項目的路徑是這樣的:flutter/flutter_hybrid/native,那麼咱們須要在native上一層目錄flutter_hybrid中建立Flutter module。android
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 參數。git
輸入後控制檯打印以下:json
$ 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文件。segmentfault
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
而後打開app/build.gradle在dependencies標籤中添加依賴:less
implementation project(':flutter')
這樣兩步就完成了依賴的添加,這裏爲何添加的叫「flutter」 而不是 「flutter_module」呢?由於項目編譯完成後會在Android項目的目錄下生成叫Flutter的目錄,這就是須要咱們依賴的。還有個須要注意是gradle中的minSdkVersion必需要大於等於16,由於這個flutter支持的最低版本。同時添加使用java8來編譯。在app/build.gradle中的android標籤中添加:ide
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混合開發」便可得到下載連接。
若是你以爲文章還不錯,請你們點贊分享下,你的確定是對我最大的鼓勵和支持。
Flutter混合開發(二):iOS項目集成Flutter模塊詳細指南
Flutter混合開發(三):Android與Flutter之間通訊詳細指南