不得不看的Flutter與Android混合開發

記得在flutter剛出來時,筆者就開始學習flutter。但因爲當時嫌棄flutter複雜的層級組合且未推出穩定版,因此當時就放棄了深刻學習,現現在隨着flutter的蓬勃發展及大佬們的力推,就又入坑flutter。android

clipboard.png
雖然說flutter可以跨平臺,但因爲如今幾乎都是現成的項目,因此不可能用flutter來重頭開發,因此目前幾乎都是採用native+flutter的混合開發方案。那麼該方案該如何實現尼?
一、flutter模塊的導入
首先,切換到native項目的根目錄的上一級目錄。以筆者項目爲例,路徑爲D:FlutterHybridFlutterHybridAndroid,而後經過命令cd ../切換到上一級目錄。再執行下面命令來建立一個flutter模塊。面試

flutter create -t module flutter_module

上面的flutter_module就是咱們建立的flutter模塊名稱。json

當flutter模塊建立成功後,咱們就須要經過如下步驟來導入該模塊。
1.首先在在settings.gradle文件中添加以下代碼。app

setBinding(new Binding([gradle:this]))
    evaluate(new File(
            settingsDir.parentFile,'flutter_module/.android/include_flutter.groovy'
    ))

添加完成後,就可以在Android Studio中看到flutter模塊,以下圖less

clipboard.png
2.其次,在可以正確顯示flutter模塊後,咱們就須要經過implementation project(':flutter')來導入該模塊。添加成功後就開始編譯項目,這時候就可能會遇到以下錯誤。socket

clipboard.png

這就是咱們須要注意的一點,native項目的minSdkVersion不能小於Flutter模塊的minSdkVersion。解決方案就是把native項目的minSdkVersion的值修改成大於flutter模塊的minSdkVersion的值。
通過上面兩步後,native項目就成功導入了flutter模塊,這時候就能夠來運行native項目。但在運行native項目時卻又可能出現以下錯誤ide

clipboard.png

該問題該怎麼解決尼?其實在上圖的最下面已經給出解決方案了,就是native項目必須使用Java 8,不然不讓運行。因此咱們須要在app目錄下的build.gradle文件中添加以下代碼。工具

android {
        compileOptions {
            sourceCompatibility 1.8
            targetCompatibility 1.8
        }
    }

而後繼續運行native項目,這時候就可以在設備上跑起來了,但如何驗證flutter模塊是否打包進apk里尼?這時候就能夠藉助Android Studio的apk分析工具。經過該工具能夠發現apk包由如下內容組成。學習

clipboard.png

其中flutter_assets存放的就是flutter代碼,到這裏native項目就成功的導入了flutter模塊。gradle

注意:如在果項目中使用AndroidX,就會致使很嚴重的兼容性問題。因此若是項目中使用了AndroidX,則要慎重導入flutter模塊。若是必定要導入,則能夠去閱讀flutter官方提供的解決方案——AndroidX compatibility。

二、native項目加載flutter頁面
通過前面的一些操做,咱們就在Native項目中成功依賴了flutter模塊,那麼下面學習如何在Native項目中加載flutter頁面。經過查看flutter模塊代碼能夠發現,該模塊提供瞭如下兩種方式來加載flutter頁面。

1.將flutter頁面構建成View,經過addView來顯示flutter頁面
2.將flutter頁面構建成Fragment,經過對fragment的操做來顯示flutter頁面

2.一、將flutter頁面構建成View
在flutter模塊的Flutter類中給咱們提供了一個方法——createView。經過該方法,咱們能夠將flutter頁面構建成一個View。而View的相關操做想必對於Android開發者來講都不陌生,因此就經過addView將flutter頁面添加到相應的地方。實現代碼以下:

public void onLoadFlutter(View view) {
        View flutterView = Flutter.createView(this, getLifecycle(), "route1");
        FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(600, 600);
        layoutParams.topMargin = 100;
        addContentView(flutterView, layoutParams);
    }

2.二、將flutter頁面構建成fragment
一樣,flutter模塊也提供了方法——createFragment,經過該方法就將flutter頁面構建成一個fragment,而後根據fragment的操做將flutter頁面添加到相應的地方。實現代碼以下:

public void onLoadFlutter(View view) {
       FragmentTransaction transaction= getSupportFragmentManager().beginTransaction();
       transaction.replace(R.id.someContainer,Flutter.createFragment("這裏是flutter頁面"));
       transaction.commit();
    }

2.三、flutter頁面
在前面講述瞭如何在native項目中加載flutter頁面,下面就來看一下flutter頁面的代碼。代碼還使很簡單的,基本的都是建立module時自動生成的代碼。

import 'package:flutter/material.dart';
import 'dart:ui';

void main() => runApp(MyApp(
      initParams: window.defaultRouteName,
    ));

class MyApp extends StatelessWidget {
  final String initParams;

  MyApp({Key key, @required this.initParams}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(
        title: 'Flutter Demo Home Page',
        initParams: initParams,
      ),
    );
  }
}

class MyHomePage extends StatefulWidget {
  final String initParams;

  MyHomePage({Key key, this.title, this.initParams}) : super(key: key);
  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState(initParams);
}

class _MyHomePageState extends State<MyHomePage> {
  final String initParams;

  _MyHomePageState(this.initParams);

  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'initParams:$initParams',
              style: TextStyle(color: Colors.red),
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.display1,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}

能夠發現,在上面代碼中,咱們傳入了一個初始化屬性,它其實就是一個路由名稱,但其實咱們也傳入一個json或者其餘類型的數據,從而來作一些其餘操做。其實這樣就能夠看作native與flutter之間的一種通訊。

三、flutter模塊的調試
3.一、flutter模塊的熱重載
flutter的優點之一就是在開發過程當中可以經過熱重載功能來實現快速的調試,但經過運行上面代碼就會發現,flutter模塊代碼修改後沒法當即生效,須要從新打包Native才能生效。這樣就讓flutter的一個重大優點失效了,下降了調試效率。那麼咱們能不能在混合項目中作到flutter模塊的熱重載尼?其實也是能夠的,但須要通過一些步驟。

1.首先,關閉當前應用,注意:是要殺死當前應用所在進程,而不是退出應用。
2.其次,在flutter模塊中輸入命令flutter attach,就會顯示如下內容。

clipboard.png

3.最後,再次打開應用,就會出現以下內容。

clipboard.png
請注意圖中的這段話

🔥 To hot reload changes while running, press "r". To hot restart (and rebuild state), press "R".

它告訴咱們若是要熱重載就按r鍵,想要熱重啓就按R鍵。當修改flutter代碼後,按下r鍵,就會出現如下提示,表明修改爲功。

clipboard.png

通過上面的一些步驟,咱們就能夠在混合項目中使用flutter的熱重載功能,作到flutter修改後的當即生效。
3.二、flutter模塊的調試
其實混合項目的flutter模塊調試與flutter項目的的惟一卻別就是如何在Android Studio與設備之間創建socket鏈接。在flutter項目中,咱們能夠直接點擊debug按鈕來進行調試,但在混合項目中,該按鈕就不起做用了,得經過其餘方式來創建鏈接。Android Studio給咱們提供了flutter attach按鈕,經過該按鈕,flutter模塊就能跟設備創建鏈接,就能對flutter模塊進行調試。

clipboard.png

四、總結
經過上面的一些講解,相信就可以使用native+flutter的混合開發了。但細心一點就會發現,在前面的講解中,flutter模塊並無與native項目進行通訊,那麼該如何通訊尼?在筆者的下一篇文章會進行詳細講解。

若是想要獲取更多相關Android相關資料或者面試資料請加QQ羣:925019412
圖片描述
相關文章
相關標籤/搜索