現有Android專案中整合Flutter/Flutter混合開發實戰(一)

歌者寒蜩發表於2019-02-26

最近學了下Flutter,確實挺好的。

單獨的Flutter專案跑起來沒有多大問題。

目前也有一些混合開發的需求,所以找了一些文章來看,收穫頗豐。

一.在現有專案上整合Flutter步驟詳解

1.建立專案

這一步要注意,建立專案的目錄,不是,不是,不是Android專案的根目錄

現有Android專案中整合Flutter/Flutter混合開發實戰(一)

↑不是它!

應該是下圖的目錄結構。flutter_hybrid目錄即為我們要建立的flutter專案,FlutterrHybridDemo是我們現有的Android專案,叫什麼都好。可以像我這樣,建立一個空資料夾,把現有Android專案拖進去,這樣方便查詢和管理,不然flutter_hybrid會和FlutterHybridDemo平級,在一大堆專案中找這兩個也怪麻煩的。

現有Android專案中整合Flutter/Flutter混合開發實戰(一)

在這個目錄下開啟cmd,執行命令:

flutter create -t module xxxx(想要建立的flutter專案名)執行完複製程式碼

執行完後,一個和Android專案平級的flutter專案就已經建立好了。

2.新增flutter到當前Android專案

現有Android專案中整合Flutter/Flutter混合開發實戰(一)

在Android專案根目錄下的settings.gradle檔案中,新增如下程式碼:

setBinding(new Binding([gradle: this]))
evaluate(new File(
        settingsDir.parentFile,
        "flutter_hybrid/.android/include_flutter.groovy"
))
複製程式碼

現有Android專案中整合Flutter/Flutter混合開發實戰(一)

然後,在專案的app目錄下,build.gradle檔案中,新增如下dependency:

implementation project(':flutter')複製程式碼

現有Android專案中整合Flutter/Flutter混合開發實戰(一)

如上。新增完之後,準備工作就完成了。

二.整合Flutter

目前有兩種方式可以新增

1.通過FlutterView方式新增到佈局中

首先通過Flutter.createFlutterView方法來建立一個FlutterView型別的View。它有三個構造引數。

public static FlutterView createView(Activity activity, Lifecycle lifecycle, String initialRoute)複製程式碼

三個引數分別是:

1.Activity,即當前附著的Activity

2.LifeCycle,且是不能為空(NonNull)的,這也就要求我們必須用AppCompatActivity來承載FlutterView了,因為我試過了,如果我們的Activity繼承自android.app.Activity是沒有getLifeCycle()這個方法的。

public class FlutterViewActivity extends AppCompatActivity 複製程式碼

3.initialRoute

這是一個String型別的變數,可以理解為一個需要在Flutter中作為身份標記的變數,根據不同的標識返回不同的Flutter頁面。

那麼在Flutter檔案中我們要這樣寫:

現有Android專案中整合Flutter/Flutter混合開發實戰(一)

在 Flutter檔案頁面中的build方法中,我們可以拿到window物件,通過window.defaultRouteName(就是我們建立的時候傳遞的第三個引數)來區分返回不同介面

@override  Widget build(BuildContext context) {    switch(window.defaultRouteName){      case "flutter_view":        return _flutterHomeView(context);      default:        return Center(          child: Text('Unknown route: route', textDirection: TextDirection.ltr),        );
    }
}
Widget _flutterHomeView(context){    return Scaffold(      appBar: AppBar(title: Text('FlutterView的AppBar'),),      body: Center(        child: Text('現在是Flutter'),      ),    );  }
複製程式碼

在當前Activity的OnCreate方法中,執行

setContentView(R.layout.activity_flutter);
FlutterView flutterView = Flutter.createView(this, getLifecycle(), "flutter_view");
layoutParams = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
addContentView(flutterView, layoutParams);
複製程式碼

由於addContentView這個方法必須要傳遞一個LayoutParams引數,我們就要用ViewGroup的LayoutParams。

這樣執行的結果是:

現有Android專案中整合Flutter/Flutter混合開發實戰(一)

可以看到Flutter頁面已經作為一個View被新增到了Android原生介面中。這樣我們就邁出了成功的第一步。

但是問題在於,我們看到FlutterView仍然不是全屏的,Android的ActionBar和Flutter的AppBar疊了兩層額頭,很不舒服。

這種情況,我們可以去掉兩者任意一個。

比如在Android中,將當前Activity在AndroidManifest.xml檔案中的theme屬性改一下

<activity android:name=".FlutterViewActivity" android:theme="@style/AppTheme.NoActionBar"></activity>複製程式碼

那麼Activity的ActionBar就去掉了

現有Android專案中整合Flutter/Flutter混合開發實戰(一)

不過,現在狀態列不是沉浸式。關於這點,可以用Android程式碼在當前Activity中設定沉浸式狀態列,網上有很多成熟的解決方式,在此筆者就不提供了。

不過僅僅這樣,我還是不滿足的。因為我們的佈局中還有一個TextView控制元件,這時候怎麼沒了...

<RelativeLayotu
    android:id="@+id/rl_container"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="wrap_content">
    <TextView
        android:id="@+id/tv_native"
        android:textSize="50sp"
        android:text="原生文字控制元件"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</RelativeLayout>複製程式碼

所以我要的效果是這樣的:

現有Android專案中整合Flutter/Flutter混合開發實戰(一)

我們都知道,如果使用了RelativeLayout或者FrameLayout的話,View預設addView是可以重疊在一起的。所以我們的根佈局如果是RelativeLayotu的話,要設定LayoutParams,新增Rule規定FlutterView要處於控制元件的下方。

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_flutter);
    rlContainer = findViewById(R.id.rl_container);
    rlContainer.addView(flutterView)
    RelativeLayout.LayoutParams rlLayoutParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
    rlLayoutParams.addRule(BELOW,R.id.tv_native);
    llContainer.addView(flutterView,rlLayoutParams);
複製程式碼

不過我發現,addContentView()來新增的話, 即使是有LayoutParams也是會重疊在一起的。所以我的建議是,使用最外層容器(或者是你要新增進的那個容器).addView來新增。

當然,通過LinearLayout來作為容器,直接addView也是可以的。

通過嘗試,發現只有addView的方式可以達到這樣的效果。

現有Android專案中整合Flutter/Flutter混合開發實戰(一)

不過這也足夠我們開發中使用了。

未完待續...


相關文章