Flutter 混合開發FlutterBoost Android 接入流程

最近公司開始推行使用Flutter用於移動端開發,忙活了一個多月的Flutter混合開發迭代端午節後準備上線,寫下此過程的坑以及一些接入流程,以及Flutter技術。

由於我主業是搞Android開發的,iOS還是個菜鳥,先介紹一下Android混合接入流程

1.創建Flutter module

很多情況下,Flutter的接入都是在原有的移動端項目的基礎上接入,這樣相對於侵入原有項目弱,並且接入的成本低,風險也低。

flutter create -t module flutter_module

在命令行界面錄入即可,最好是和原本的項目在相同的目錄下,同級文件夾。我的項目基本是原有項目是一個git倉庫,對應的Flutter代碼是在另一個git倉庫,這樣版本管理也是比較好的

2.Android 開始接入

在原有setting.gradle文件末尾的添加一下代碼

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

這樣就會引入到對應的Flutter的module資源,對應的編譯腳本,Flutter框架已經寫好,後續有時間可以讀讀

在app目錄下的build.gradle文件中添加Flutter依賴

implementation project(':flutter')

主要的依賴鏈如下

flutter_module/.android/include_flutter.groovy ->
flutter_module/.android/Flutter/build.gradle ->
$flutterRoot/packages/flutter_tools/gradle/flutter.gradle 

很方便的完成混合開發的打包操作,接入完之後最好在flutter項目下面的.android文件下,用命令行工具執行以下

gradlew assembleDebug

命令完成對應的Android依賴加載

3.原生顯示Flutter的視圖

Button open = findViewById(R.id.openBtn);
open.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        Intent intent = new Intent();
        intent.setClass(MainActivity.this, MyFlutterActivity.class);
        startActivity(intent);
    }
});

public class MyFlutterActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_flutter);
        final FlutterView flutterView = Flutter.createView(
                this,
                getLifecycle(),
                "route1"
        );
        final FrameLayout layout = findViewById(R.id.flutter_container);
        layout.addView(flutterView);
    
    }
}

只需要在Activity中的addView即可,看起來很簡單,不過存在很多問題,跳轉過程可能會有黑屏情況,以及Flutter視圖的複用也是個問題,以及對應的Flutter 跳轉Native界面也是個問題。於是乎谷歌發現FlutterBoost框架解決了大部分以上的問題。

4.FlutterBoost框架的接入

依照https://github.com/alibaba/flutter_boost官方的文檔,接入發現有很多的坑,不知道是不是開發人員都反感寫文檔一樣的。

接入的流程如下:

4.1 Flutter項目接入FlutterBoost

在對應的pubspec.yaml文件中加入依賴,pubspec.yaml就是一個配置文件。

flutter_boost:
        git:
            url: 'https://github.com/alibaba/flutter_boost.git'
            ref: '0.0.411'

之後調用Package get,右上角即可查看,之後還是在.android 文件下執行
gradlew assembleDebug,完成依賴下載。

4.2 Flutter中main.dart文件中配置

 @override
  void initState() {
    super.initState();
    FlutterBoost.singleton.registerPageBuilders({
        //對應的Page的名字,最好是類Http格式
      'demoPage': (pageName, params, _) {
        return DemoPage();
      },
    });
    FlutterBoost.handleOnStartPage();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: 'Flutter Boost example',
        builder: FlutterBoost.init(postPush: _onRoutePushed),
        home: Container());
  }
 void _onRoutePushed(
  String pageName, String uniqueId, Map params, Route route, Future _) {}

4.3 Android 中的Application的設置

@Override
  public void onCreate() {
    super.onCreate();
    initFlutterBoot();
  }

  private void initFlutterBoot() {
    FlutterBoostPlugin.init(new IPlatform() {
      @Override
      public Application getApplication() {
        return mApplication;
      }


      @Override
      public Activity getMainActivity () {
        //這裏返回null,可以避免跳轉界面的(MainActivity)的頁面整體上移
        return null;
      }

      @Override
      public boolean isDebug() {
        return AppConfig.IS_DEVELOPING;
      }


      @Override
      public boolean startActivity(Context context, String url, int requestCode) {
        //Flutter 跳轉的回調
        return PageRouter.openPageByUrl(context,url,requestCode);
      }

      @Override
      public Map getSettings() {
        return null;
      }
    });
  }

坑1:getMainActivity 如果返回MainActivity,會導致對應的主頁面的佈局整體上移,發現給null也沒啥問題。

4.4 Native和Flutter界面的跳轉

Native–>Fluuter

可以使用官方Demo中的PageRouter

public class PageRouter {

  public static final String COMMISSION_TASK_PAGE = "gamma://flutter/commissionTaskPage";
  public static final String NATIVE_CUST_INFO_PAGE_URL = "gamma://native/custInfo";

  public static boolean openPageByUrl(Context context, String url) {
    return openPageByUrl(context, url, 0, "{}");
  }

  public static boolean openPageByUrl(Context context, String url, String json) {
    return openPageByUrl(context, url, 0, json);
  }

  public static boolean openPageByUrl(Context context, String url, int requestCode) {
    return openPageByUrl(context, url, requestCode, "{}");
  }

  public static boolean openPageByUrl(Context context, String url, int requestCode, String json) {
    try {
      if (url.startsWith(COMMISSION_TASK_PAGE)) {
        //貸後任務
        Intent intent = new Intent(context, FlutterPageActivity.class);
        intent.putExtra("pageName", "gamma://flutter/commissionTaskPage");
        intent.putExtra("json", json);
        context.startActivity(intent);
        return true;
      } else if (url.contains(NATIVE_CUST_INFO_PAGE_URL)) {
        //打開客戶界面
        Map<String, String> params = getUrlParams(url);
          AppUIHelper
              .showCustomerInfoActivity(context, params.get("custId"));
        return true;
      }
    } catch (Throwable t) {
      return false;
    }
  }
//獲取對應url中的參數
  private static Map getUrlParams(String url) {
    Map<String, Object> map = new HashMap<>();
    url = url.replace("?", ";");
    if (!url.contains(";")) {
      return map;
    }
    if (url.split(";").length > 0) {
      String[] arr = url.split(";")[1].split("&");
      for (String s : arr) {
        String key = s.split("=")[0];
        String value = s.split("=")[1];
        map.put(key, value);
      }
      return map;

    } else {
      return map;
    }
  }
}

這樣相對於好管理,Native頁面可以設置以Native開頭,Flutter以flutter開頭,這樣好區分。

對應的FlutterPageActivity可以根據官方Demo自行修改。

坑2:FlutterPageActivity中最好加上以下代碼

@Override
  protected void onCreate(Bundle savedInstanceState) {
    FlutterMain.startInitialization(this);
    super.onCreate(savedInstanceState);
  }

不然會運行報錯

Flutter – >Native

這種類型跳轉和Activity之間互相跳轉有點類似

 FlutterBoost.singleton.openPage(
        "${NativeUrl.NATIVE_CUST_INFO}?custId=${custId};",
        {});

這中類型的跳轉會回調到前面Application中的 FlutterBoostPlugin.init 方法中的startActivity方法中,只會在用PageRouter來接收即可。
之後自行做界面的跳轉

5.打包的坑

在打release包的時候需要在Flutter的跟目錄下執行以下命令

flutter build apk

之後是常規的Android的打包,不然打包出來的apk跳轉到Flutter頁面就會閃退

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章