其實2017年的時候就已經接觸Flutter了,但也只是寫了個HelloWorld,一方面是Flutter在那時候還只是preview版本,另外一方面ReactNative在那時候很是火熱,忙於用ReactNative重構項目,錯過了入坑Flutter的第一梯隊。
在谷歌的2018IO大會上Flutter再一次成爲了跨平臺方案的焦點,而ReactNative也在隨着Airbnb的棄用熱度逐漸冷卻,其實在寫下這篇文章的時候我已經再次入坑了不短的一段時間,Flutter的各類特性也基本上都接觸到了,demo項目也寫了一些,但導致我火燒眉毛的寫下這篇文章的直接緣由是Flutter的這個能力:
Flutter可以無感知的嵌入到Android工程中,不論是從開發者角度仍是用戶角度,你甚至能夠只從一個view開始來讓Flutter參與到你的項目中去,接着替換或者開發某一個頁面甚至功能,而後你就會對它愛不釋手,讓你會有用它重構項目和開發新項目的衝動。android
注意:當前日期是2018-07-29,flutter的beta版本尚未加入這個新功能,使用命令
flutter channel [分支]
切換到dev或master分支才能使用,若是你閱讀本篇文章離這個時間點是好久以後能夠忽略這段。ios
爲了讓Android工程和Flutter工程互不干擾,這裏再也不以Android工程爲工程的跟目錄,而是讓Android工程和平級的Flutter工程的公共目錄做爲根目錄。 最終的目錄結構應該是下面這樣的bash
你的項目根目錄(隨便什麼你喜歡的地方)
├── 原生安卓工程(FlutterInAndroid)
└── Flutter工程 (my_flutter)
複製代碼
因此首先在你的項目根目錄
下用AS建立一個新的Android原生項目,能夠勾選上kotlin支持,這樣更舒服。 建立完成後你會獲得一個這樣的結構app
你的項目根目錄(隨便什麼你喜歡的地方)
└── FlutterInAndroid
複製代碼
FlutterInAndroid目錄內是一個完整的Android工程ide
接下來使用Flutter命令來建立module工程,在你的項目根目錄
下執行:函數
flutter create -t module my_flutter
複製代碼
建立完成後你會獲得一個這樣的結構佈局
你的項目根目錄(隨便什麼你喜歡的地方)
├── FlutterInAndroid
└── my_flutter
複製代碼
my_flutter是一個Flutter的module工程,用來供Android項目引入post
在FlutterInAndroid這個Android工程的setting.gradle文件中追加flutter工程的引入
你的項目跟目錄/FlutterInAndroid/setting.gradle
gradle
include ':app'
//加入下面配置
setBinding(new Binding([gradle: this]))
evaluate(new File(
settingsDir.parentFile,
'my_flutter/.android/include_flutter.groovy'
))
複製代碼
在app的build.gradle文件中加入工程依賴
你的項目跟目錄/FlutterInAndroid/app/build.gradle
ui
...
dependencies {
...
// 加入下面配置
implementation project(':flutter')
}
複製代碼
使用AS打開FlutterInAndroid工程,從新構建項目,便可成功的將Flutter加入Android工程。
Flutter提供了兩種方式讓Android工程來引用組件,一種是View,一種是Fragment,這裏選用View來進行講解,Fragment同理。 這裏咱們用兩種方式來引入FLutter,本質是仍是是做爲一個view引入佈局仍是將FlutterView做爲Activity的根View。
val flutterView = Flutter.createView(this,lifecycle,"route1")
複製代碼
經過上面很簡單的一個方法,咱們就能經過Flutter建立出一個view,這個方法提供三個參數,第一個是Activity,第二個參數是一個Lifecycle對象,咱們之間取Activity的lifecycle便可,第三個參數是告訴Flutter咱們要建立一個什麼樣的view,這個字符串參數能夠在Flutter工程中獲取獲得。
建立出這個FlutterView以後就能夠按常規的操做來將它加入到任何你想要的佈局中去了。
建立一個空的Activity,用Flutter建立一個View做爲頁面的根View:
class FlutterActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_flutter)
val flutterView = Flutter.createView(this@FlutterActivity,lifecycle,"route1")
val layout = FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT)
addContentView(flutterView, layout)
}
}
複製代碼
這裏咱們並無使用setContentView而是是用了addContentView這個方法,緣由是這樣的:
雖然FLutter的加載速度很是快,可是這個過程依然存在,在建立FLutterView以前咱們先給ContentView設置了一個R.layout.activity_flutter佈局,這個佈局能夠做爲FlutterView加載完成以前展現給用戶的界面,固然大部分狀況下用戶根本感知不到這個界面Flutter已經加載完成了,但咱們仍須要它,由於debug模式下形成Flutter的加載速度並非很是快,這個界面能夠給開發人員看,還有就是若是沒有這個界面的話在Activity的加載過程會出現一個黑色的閃屏,而這個狀況對用戶來講並不友好。
用AndroidStudio在你的項目跟目錄/my_flutter
打開Flutter工程,這時候AndroidStudio插件會識別到Flutter工程並以Flutter工程進行加載。
忽略掉.android和.ios文件夾以後你會發現,這個FLutter工程和完整的Flutter工程並無任何不一樣,你依然可以以完整Flutter工程的流程來進行Flutter開發並啓動調試,這是一個很是人性化的設計。
上面咱們在原生Android工程中以View的形式調用了Flutter,而Flutter本質上是隻有一個入口的,也就是main.dart文件中的main函數:
void main() => runApp(new MyApp());
複製代碼
咱們的目的是根據原生工程的調用讓Flutter生成不一樣的組件做爲View來供原生工程使用,那麼咱們就能夠從這個main函數來入手。
經過文檔咱們能夠經過window
的全局變量中獲取到當前的routeName,這個值正是上面經過原生工程傳給Flutter的標識,有了這個標識就能夠簡單的作判斷來進行不一樣的組件建立了:
import 'dart:ui';
import 'package:flutter/material.dart';
void main() => runApp(_widgetForRoute(window.defaultRouteName));
//根據不一樣的標識建立不一樣的組件給原生工程調用
Widget _widgetForRoute(String route) {
switch (route) {
case 'route1':
return SomeWidget(...);
case 'route2':
return SomeOtherWidget(...);
default:
return Center(
child: Text('Unknown route: $route', textDirection: TextDirection.ltr),
);
}
}
複製代碼
首先在Flutter目錄下啓動監聽服務,在你的項目根目錄/my_flutter
下執行
flutter attach
複製代碼
執行後,監聽服務會等待並監聽debug應用中flutter的狀態
而後在打開FlutterInAndroid項目的AS中以正常方式調試運行,在真機或模擬器中運行app後並不會當即出發flutter的監聽服務,當flutter的view或Fragment激活時纔會觸發。
當flutter的監聽服務和app創建鏈接後,終端會出現以下輸出:
$ flutter attach -d W8
Waiting for a connection from Flutter on PLK UL00...
Done.
Syncing files to device PLK UL00... 8.7s
🔥 To hot reload changes while running, press "r". To hot restart (and rebuild state), press "R".
An Observatory debugger and profiler on PLK UL00 is available at: http://127.0.0.1:54218/
For a more detailed help message, press "h". To quit, press "q".
複製代碼
這時咱們修改flutter工程中的dart代碼文件,保存後在終端中點擊r
鍵便可進行熱加載,R
鍵進行熱重啓。
引入flutter工程後,對Android原生工程的構建基本上沒有影響,打包按常規操做便可。
區別 | Flutter的module工程中的Android工程 | 純Flutter工程中的Android工程 |
---|---|---|
文件夾名稱 | .android | android |
包含的module | app和Flutter | app |
說明1 | app只提供了入口Activity,Flutter包含了插件擴展及原生工程調用的接口 | app包含入口Activity及插件擴展 |
說明2 | app供Flutter自身開發調試,Flutter做爲module供Android原生調用 | app做爲Android工程運行及打包 |
爲了方便描述咱們稱前者爲module工程,後者爲完整工程。
因而可知,雖然module工程中提供了名爲Flutter的module供原生工程調用,但仍然保留了app工程,這樣很是大程度的方便了flutter工程師來單獨開發flutter項目,無需依賴任何原生的調用,自身便可啓動調試。
參考
官方wiki
相關文章
騰訊NOW直播團隊方案
閒魚團隊方案
美團技術團隊方案
更多幹貨移步個人我的博客 www.nightfarmer.top/