Flutter 混合開(kāi)發(fā)FlutterBoost Android 接入流程

最近公司開(kāi)始推行使用Flutter用于移動(dòng)端開(kāi)發(fā)躲胳,忙活了一個(gè)多月的Flutter混合開(kāi)發(fā)迭代端午節(jié)后準(zhǔn)備上線茬暇,寫(xiě)下此過(guò)程的坑以及一些接入流程灵疮,以及Flutter技術(shù)。

由于我主業(yè)是搞Android開(kāi)發(fā)的追他,iOS還是個(gè)菜鳥(niǎo)坟募,先介紹一下Android混合接入流程

1.創(chuàng)建Flutter module

很多情況下,F(xiàn)lutter的接入都是在原有的移動(dòng)端項(xiàng)目的基礎(chǔ)上接入邑狸,這樣相對(duì)于侵入原有項(xiàng)目弱懈糯,并且接入的成本低,風(fēng)險(xiǎn)也低单雾。

flutter create -t module flutter_module

在命令行界面錄入即可赚哗,最好是和原本的項(xiàng)目在相同的目錄下,同級(jí)文件夾硅堆。我的項(xiàng)目基本是原有項(xiàng)目是一個(gè)git倉(cāng)庫(kù)屿储,對(duì)應(yīng)的Flutter代碼是在另一個(gè)git倉(cāng)庫(kù),這樣版本管理也是比較好的

2.Android 開(kāi)始接入

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

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

這樣就會(huì)引入到對(duì)應(yīng)的Flutter的module資源硬萍,對(duì)應(yīng)的編譯腳本扩所,F(xiàn)lutter框架已經(jīng)寫(xiě)好,后續(xù)有時(shí)間可以讀讀

在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 

很方便的完成混合開(kāi)發(fā)的打包操作朴乖,接入完之后最好在flutter項(xiàng)目下面的.android文件下祖屏,用命令行工具執(zhí)行以下

gradlew assembleDebug

命令完成對(duì)應(yīng)的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即可,看起來(lái)很簡(jiǎn)單买羞,不過(guò)存在很多問(wèn)題袁勺,跳轉(zhuǎn)過(guò)程可能會(huì)有黑屏情況,以及Flutter視圖的復(fù)用也是個(gè)問(wèn)題畜普,以及對(duì)應(yīng)的Flutter 跳轉(zhuǎn)Native界面也是個(gè)問(wèn)題期丰。于是乎谷歌發(fā)現(xiàn)FlutterBoost框架解決了大部分以上的問(wèn)題。

4.FlutterBoost框架的接入

依照https://github.com/alibaba/flutter_boost官方的文檔吃挑,接入發(fā)現(xiàn)有很多的坑钝荡,不知道是不是開(kāi)發(fā)人員都反感寫(xiě)文檔一樣的。

接入的流程如下:

4.1 Flutter項(xiàng)目接入FlutterBoost

在對(duì)應(yīng)的pubspec.yaml文件中加入依賴舶衬,pubspec.yaml就是一個(gè)配置文件埠通。

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

之后調(diào)用Package get,右上角即可查看逛犹,之后還是在.android 文件下執(zhí)行
gradlew assembleDebug端辱,完成依賴下載。

4.2 Flutter中main.dart文件中配置

 @override
  void initState() {
    super.initState();
    FlutterBoost.singleton.registerPageBuilders({
        //對(duì)應(yīng)的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的設(shè)置

@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舞蔽,可以避免跳轉(zhuǎn)界面的(MainActivity)的頁(yè)面整體上移
        return null;
      }

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


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

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

坑1:getMainActivity 如果返回MainActivity,會(huì)導(dǎo)致對(duì)應(yīng)的主頁(yè)面的布局整體上移码撰,發(fā)現(xiàn)給null也沒(méi)啥問(wèn)題渗柿。

4.4 Native和Flutter界面的跳轉(zhuǎn)

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)) {
        //貸后任務(wù)
        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)) {
        //打開(kāi)客戶界面
        Map<String, String> params = getUrlParams(url);
          AppUIHelper
              .showCustomerInfoActivity(context, params.get("custId"));
        return true;
      }
    } catch (Throwable t) {
      return false;
    }
  }
//獲取對(duì)應(yīng)url中的參數(shù)
  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;
    }
  }
}

這樣相對(duì)于好管理,Native頁(yè)面可以設(shè)置以Native開(kāi)頭脖岛,F(xiàn)lutter以flutter開(kāi)頭做祝,這樣好區(qū)分砾省。

對(duì)應(yīng)的FlutterPageActivity可以根據(jù)官方Demo自行修改。

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

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

不然會(huì)運(yùn)行報(bào)錯(cuò)

Flutter -- >Native

這種類型跳轉(zhuǎn)和Activity之間互相跳轉(zhuǎn)有點(diǎn)類似

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

這中類型的跳轉(zhuǎn)會(huì)回調(diào)到前面Application中的 FlutterBoostPlugin.init 方法中的startActivity方法中混槐,只會(huì)在用PageRouter來(lái)接收即可编兄。
之后自行做界面的跳轉(zhuǎn)

5.打包的坑

在打release包的時(shí)候需要在Flutter的跟目錄下執(zhí)行以下命令

flutter build apk

之后是常規(guī)的Android的打包,不然打包出來(lái)的apk跳轉(zhuǎn)到Flutter頁(yè)面就會(huì)閃退

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末声登,一起剝皮案震驚了整個(gè)濱河市狠鸳,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌悯嗓,老刑警劉巖件舵,帶你破解...
    沈念sama閱讀 217,406評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異脯厨,居然都是意外死亡铅祸,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門(mén)合武,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)临梗,“玉大人,你說(shuō)我怎么就攤上這事稼跳∶伺樱” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,711評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵汤善,是天一觀的道長(zhǎng)什猖。 經(jīng)常有香客問(wèn)我,道長(zhǎng)红淡,這世上最難降的妖魔是什么不狮? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,380評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮在旱,結(jié)果婚禮上摇零,老公的妹妹穿的比我還像新娘。我一直安慰自己颈渊,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,432評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布终佛。 她就那樣靜靜地躺著俊嗽,像睡著了一般。 火紅的嫁衣襯著肌膚如雪铃彰。 梳的紋絲不亂的頭發(fā)上绍豁,一...
    開(kāi)封第一講書(shū)人閱讀 51,301評(píng)論 1 301
  • 那天,我揣著相機(jī)與錄音牙捉,去河邊找鬼竹揍。 笑死敬飒,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的芬位。 我是一名探鬼主播无拗,決...
    沈念sama閱讀 40,145評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼昧碉!你這毒婦竟也來(lái)了英染?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,008評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤被饿,失蹤者是張志新(化名)和其女友劉穎四康,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體狭握,經(jīng)...
    沈念sama閱讀 45,443評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡闪金,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,649評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了论颅。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片哎垦。...
    茶點(diǎn)故事閱讀 39,795評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖嗅辣,靈堂內(nèi)的尸體忽然破棺而出撼泛,到底是詐尸還是另有隱情,我是刑警寧澤澡谭,帶...
    沈念sama閱讀 35,501評(píng)論 5 345
  • 正文 年R本政府宣布愿题,位于F島的核電站,受9級(jí)特大地震影響蛙奖,放射性物質(zhì)發(fā)生泄漏潘酗。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,119評(píng)論 3 328
  • 文/蒙蒙 一雁仲、第九天 我趴在偏房一處隱蔽的房頂上張望仔夺。 院中可真熱鬧,春花似錦攒砖、人聲如沸缸兔。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,731評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)惰蜜。三九已至,卻和暖如春受神,著一層夾襖步出監(jiān)牢的瞬間抛猖,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,865評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留财著,地道東北人联四。 一個(gè)月前我還...
    沈念sama閱讀 47,899評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像撑教,于是被迫代替她去往敵國(guó)和親朝墩。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,724評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容