Flutter Boost的router管理

環(huán)境

FlutterBoost介紹
咸魚(yú)Flutter Boost介紹

Flutter Boost Github

混合開(kāi)發(fā)環(huán)境搭建

原生Android集成Flutter混合開(kāi)發(fā)

Flutter SDK版本:

v1.9.1

Flutter Boost 版本:

flutter_boost: ^0.1.63

FlutterBoost集成

FlutterBoost是以插件方式的引入到我們的native項(xiàng)目工程的辆它。

混合工程

混合開(kāi)發(fā)流程可以參考:
原生Android集成Flutter混合開(kāi)發(fā)

Flutter module項(xiàng)目集成FlutterBoost

在flutter_boost_module項(xiàng)目的pubspec.yaml文件中添加依賴(lài)插件配置

dependencies:
  flutter:
    sdk: flutter

  flutter_boost: ^0.1.63

配置完成后下載依賴(lài)插件到本地

flutter packages get

在native原生項(xiàng)目中rebuild工程浙踢,即可引入flutter boost插件日矫,引入flutter boost后的代碼結(jié)構(gòu)。其中的amap_base_map是引入了地圖插件才顯示的救恨,如果沒(méi)有引入地圖插件則不會(huì)出現(xiàn)該文件。


在這里插入圖片描述

在native的項(xiàng)目中,在app目錄下的build.gradle中添加flutter_boost項(xiàng)目依賴(lài)

 implementation project(':flutter_boost')

FlutterBoost使用

Flutter工程開(kāi)發(fā)

在Flutter項(xiàng)目中創(chuàng)建兩個(gè)測(cè)試頁(yè)面Widget:FirstRouteWidget和SecondRouteWidget腿准。代碼參考了flutter_boost的測(cè)試代碼。

(1)關(guān)于onPressed里面的方法調(diào)用拾碌,其實(shí)就是調(diào)用flutter_boost的api進(jìn)行頁(yè)面的跳轉(zhuǎn)和傳遞參數(shù)吐葱。

class FirstRouteWidget extends StatelessWidget {
  static const KEY_FLUTTER_BOOST_FIRST_ROUTE = "flutterbus://flutterWidget_FirstPage";
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('First Route'),
      ),
      body: Center(
        child: RaisedButton(
          child: Text('open amap widget'),
          onPressed: () {
//            print("open second page!");
            FlutterBoost.singleton.open("flutterbus://flutternativePage", urlParams: {"test": "flutter to flutter "})
                .then((Map value) {print(
                  "call me when page is finished. did recieve second route result $value");});
//            BoostContainerSettings settings = BoostContainer.of(context).settings;
//            FlutterBoost.singleton.close(settings.uniqueId, result: {"result": "data from second"});
          },
        ),
      ),
    );
  }
}

class SecondRouteWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Second Route"),
      ),
      body: Center(
        child: RaisedButton(
          onPressed: () {
            // Navigate back to first route when tapped.
            BoostContainerSettings settings =
                BoostContainer.of(context).settings;
            FlutterBoost.singleton.close(settings.uniqueId,
                result: {"result": "data from second"});
          },
          child: Text('Go back with result!'),
        ),
      ),
    );
  }
}

在main.dart中注冊(cè)注冊(cè)這兩個(gè)頁(yè)面route。

(1)在build方法中初始化Flutter Boost

(2)在initState中注冊(cè)需要native啟動(dòng)的route校翔。這里的pageName一定要和native啟動(dòng)時(shí)配置的一致弟跑,否則會(huì)找不到對(duì)應(yīng)route。

class _MyAppState extends State<MyApp> {
  @override
  void initState() {
    super.initState();
    FlutterBoost.singleton.registerPageBuilders({
    //fisrt widget
      FirstRouteWidget.KEY_FLUTTER_BOOST_FIRST_ROUTE: (pageName, params, _) {
        debugPrint("params :${params.toString()}");
        return FirstRouteWidget();
      },
      //second widget
      'flutterbus://flutterSecondPage': (pageName, params, _) {
        debugPrint("params :${params.toString()}");
        return SecondRouteWidget();
      },
    });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: 'Flutter Boost example',
        //初始化FlutterBoost
        builder: FlutterBoost.init(postPush: _onRoutePushed),
        home: Container());
  }

  void _onRoutePushed(
      String pageName, String uniqueId, Map params, Route route, Future _) {
    debugPrint("pageName :${pageName}" + "params :${params.toString()}");
  }
}

native項(xiàng)目中使用FlutterBoost

初始化flutter引擎防症。

(1)Flutter引擎初始化孟辑,代碼參考Flutter_boost demo.

(2)INativeRouter接口需要注意,不僅通過(guò)flutter啟動(dòng)native頁(yè)面會(huì)調(diào)用該方法蔫敲,而且通過(guò)flutter會(huì)用flutter頁(yè)面饲嗽,也會(huì)執(zhí)行該方法。

(3)在Application中調(diào)用FlutterBootManager.init()方法完成初始化奈嘿。

(4)NativePageRouter在啟動(dòng)route會(huì)用到貌虾。可以自行封裝裙犹。


object FlutterBootManager {
    fun init(app: Application) {
        /**
         * 不僅打開(kāi)Native頁(yè)面會(huì)執(zhí)行尽狠,在Flutter頁(yè)面打開(kāi)Flutter  widget也會(huì)執(zhí)行該方法
         **/
        val router = INativeRouter { context, url, urlParams, requestCode, exts ->
            val assembleUrl = Utils.assembleUrl(url, urlParams)
            Timber.e("native open :${url} ${urlParams}")
            NativePageRouter.openPageByUrl(context, assembleUrl, requestCode)
        }

        val pluginsRegister = object : FlutterBoost.BoostPluginsRegister {

            override fun registerPlugins(mRegistry: PluginRegistry?) {
                GeneratedPluginRegistrant.registerWith(mRegistry)
                TextPlatformViewPlugin.register(mRegistry?.registrarFor("TextPlatformViewPlugin"))
            }
        }

        val platform = FlutterBoost.ConfigBuilder(app, router)
                .isDebug(BuildConfig.DEBUG)
                .whenEngineStart(FlutterBoost.ConfigBuilder.ANY_ACTIVITY_CREATED)
                .renderMode(FlutterView.RenderMode.texture)
                .pluginsRegister(pluginsRegister)
                .build()

        FlutterBoost.instance().init(platform)
    }
}

配置Flutter頁(yè)面對(duì)應(yīng)的Native容器。

 <activity
            android:name="com.idlefish.flutterboost.containers.BoostFlutterActivity"
            android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density"
            android:hardwareAccelerated="true"
            android:theme="@style/Theme.AppCompat"
            android:windowSoftInputMode="adjustResize">

頁(yè)面跳轉(zhuǎn)route

頁(yè)面路由跳轉(zhuǎn)我把它分成了三種情況巫财,下面說(shuō)說(shuō)每中情況的代碼實(shí)現(xiàn)哩陕。
一平项、native啟動(dòng)flutter

(1)不攜帶參數(shù):

在native測(cè)可以通過(guò)BoostFlutterActivity通過(guò)構(gòu)建者模式構(gòu)建一個(gè)intent。BoostFlutterActivity要注冊(cè)在manifest文件中悍及。

companion object {
        const val FLUTTER_FIRST_PAGE_URL = "flutterbus://flutterWidget_FirstPage"
    }

    override fun openFlutterWidget(context: Context, params: HashMap<String,Any>?): Boolean {
        try {
            val intent = BoostFlutterActivity.withNewEngine().url(FLUTTER_FIRST_PAGE_URL)
                    .backgroundMode(BoostFlutterActivity.BackgroundMode.opaque).build(context)
            context.startActivity(intent)
            return true
        } catch (e: Exception) {
            return false
        }
    }

在flutter module中打印出請(qǐng)求的url心赶,和params扣讼。

 FirstRouteWidget.KEY_FLUTTER_BOOST_FIRST_ROUTE: (pageName, params, _) {
        debugPrint("params :${params.toString()}");
        return FirstRouteWidget();
      }

(2)攜帶請(qǐng)求參數(shù)
flutter module代碼不變。

companion object {
        const val FLUTTER_FIRST_PAGE_URL = "flutterbus://flutterWidget_FirstPage"
    }

    override fun openFlutterWidget(context: Context, params: HashMap<String,Any>?): Boolean {
        try {
            var params = mutableMapOf<String,Any>()
            params["str"] = "flutter boost"
            params["in"] = 1
            val intent = BoostFlutterActivity.withNewEngine().url(FLUTTER_FIRST_PAGE_URL).params(params)
                    .backgroundMode(BoostFlutterActivity.BackgroundMode.opaque).build(context)
            context.startActivity(intent)
            return true
        } catch (e: Exception) {
            return false
        }
    }

(3)獲取flutter的處理結(jié)果缨叫。
在native測(cè)通過(guò)startActivityForResult啟動(dòng)flutter container。

override fun openFlutterWidgetForResult(activity: BaseActivity, params: HashMap<String,Any>?, requestCode: Int): Boolean {
        try {
            var params = mutableMapOf<String,Any>()
            params["str"] = "flutter boost"
            params["in"] = 1
            val intent = BoostFlutterActivity.withNewEngine().url(FLUTTER_FIRST_PAGE_URL).params(params)
                    .backgroundMode(BoostFlutterActivity.BackgroundMode.opaque).build(activity)

            activity.startActivityForResult(intent, requestCode)
            return true
        } catch (e: Exception) {
            return false
        }
    }
}

在當(dāng)前activity的onActivityResult獲取請(qǐng)求結(jié)果
注意這里的KEY值销钝,這個(gè)值是定值琐簇,不可修改。并且在flutter獲取native的返回值是也需要用到該值婉商。

 REQUEST_CODE -> {
                Timber.e("flutter data :"+data?.extras?.get(IFlutterViewContainer.RESULT_KEY))
            }
在這里插入圖片描述

在flutter module通過(guò)FlutterBoost的close方法丈秩,把處理結(jié)果返回給上一個(gè)頁(yè)面。

  BoostContainerSettings settings = BoostContainer.of(context).settings;
  FlutterBoost.singleton.close(settings.uniqueId, result: {"result": "data from second"});

最終native獲取的返回值格式:

flutter data :{result=data from second}

二挽唉、flutter啟動(dòng)flutter
(1)直接啟動(dòng),不攜帶參數(shù)
注意筷狼;這里還需要在native層進(jìn)行實(shí)現(xiàn),才能最終啟動(dòng)flutter route埂材,因?yàn)閒lutter route需要一個(gè)native容器。

FlutterBoost.singleton.open("flutterbus://flutterSecondPage");

在native的FlutterBootManager中有個(gè)INativeRouter接口的實(shí)現(xiàn)類(lèi)严拒,在給INativeRouter的openContainer方法中裤唠,能獲取到啟動(dòng)的url,請(qǐng)求參數(shù)urlParams种蘸、和requestCode和當(dāng)前的activity的上下問(wèn)context航瞭。
在openContainer方法中,在調(diào)用啟動(dòng)“native啟動(dòng)flutter”的相關(guān)方法刊侯,啟動(dòng)flutter route。
例如:

 val intent = BoostFlutterActivity.withNewEngine().url(NATIVE_FIRST_PAGE_URL)
                        .backgroundMode(BoostFlutterActivity.BackgroundMode.opaque).build(context)
                if(context is Activity){
                    (context as Activity).startActivityForResult(intent,0x13)
                }

(2)攜帶參數(shù)啟動(dòng)

FlutterBoost.singleton.open("flutterbus://flutterSecondPage", urlParams: {"test": "flutter to flutter "})

(3)獲取返回值
在first route通過(guò)如下代碼啟動(dòng)second route

FlutterBoost.singleton.open("flutterbus://flutternativePage", urlParams: {"test": "flutter to flutter "})
                .then((Map value) {print(
                  "call me when page is finished. did recieve second route result $value");});

在second通過(guò)如下代碼關(guān)閉當(dāng)前頁(yè)面藕届,并返回處理的數(shù)據(jù)

BoostContainerSettings settings =
                BoostContainer.of(context).settings;
            FlutterBoost.singleton.close(settings.uniqueId,
                result: {"result": "data from second"});

三亭饵、flutter 啟動(dòng)native頁(yè)面
(1)直接啟動(dòng),不帶參數(shù)

FlutterBoost.singleton.open("flutterbus://flutternativePage");

在native的FlutterBootManager中有個(gè)INativeRouter接口的實(shí)現(xiàn)類(lèi)冬骚,在給INativeRouter的openContainer方法中只冻,能獲取到啟動(dòng)的url计技,請(qǐng)求參數(shù)urlParams、和requestCode和當(dāng)前的activity的上下問(wèn)context舍悯。
在openContainer方法中睡雇,在調(diào)用啟動(dòng)startActivity的相關(guān)方法,啟動(dòng)native route秕豫。
例如

 var intent = Intent(context,FlutterOpenNativeTestActivity::class.java)
                if(context is Activity){
                    (context as Activity).startActivityForResult(intent,requestCode)
                }

(2)攜帶請(qǐng)求參數(shù)
在INativeRouter的openContainer方法,可以獲取到請(qǐng)求的參數(shù)祠墅。
這里的請(qǐng)求最終會(huì)執(zhí)行到native的INativeRouter 實(shí)現(xiàn)類(lèi)歌径。

FlutterBoost.singleton.open("flutterbus://flutternativePage", urlParams: {"test": "flutter to flutter "})

(3)獲取返回值
flutter 的代碼實(shí)現(xiàn)

FlutterBoost.singleton.open("flutterbus://flutternativePage", urlParams: {"test": "flutter to flutter "})
                .then((Map value) {print(
                  "call me when page is finished. did recieve second route result $value");});

native的代碼實(shí)現(xiàn)
注意點(diǎn):putExtra的key是定值回铛,并且值只能是map。

close_btn.setOnClickListener{
            var map = mutableMapOf<String,Any>()
            map.put("native","test native")
            intent.putExtra(IFlutterViewContainer.RESULT_KEY,(map as Serializable))

            setResult(Activity.RESULT_OK,intent)
            finish()
        }

四勺届、native啟動(dòng)native
和原生開(kāi)發(fā)沒(méi)有區(qū)別免姿。

PS:主要點(diǎn)不是flutter_boost的API使用,而是獲取返回值的閱讀官方demo遇到的坑故俐,demo寫(xiě)的不夠全面紊婉,一些常見(jiàn)的場(chǎng)景都沒(méi)有覆蓋。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末槽片,一起剝皮案震驚了整個(gè)濱河市肢础,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌剩盒,老刑警劉巖慨蛙,帶你破解...
    沈念sama閱讀 216,692評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件期贫,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡贾铝,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,482評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)玖绿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)叁巨,“玉大人,你說(shuō)我怎么就攤上這事蚀瘸∈鳎” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,995評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)泉孩。 經(jīng)常有香客問(wèn)我寓搬,道長(zhǎng)县耽,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,223評(píng)論 1 292
  • 正文 為了忘掉前任唾琼,我火速辦了婚禮,結(jié)果婚禮上神郊,老公的妹妹穿的比我還像新娘。我一直安慰自己蜻懦,他們只是感情好夕晓,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,245評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著征炼,像睡著了一般谆奥。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上酸些,一...
    開(kāi)封第一講書(shū)人閱讀 51,208評(píng)論 1 299
  • 那天魄懂,我揣著相機(jī)與錄音,去河邊找鬼缀拭。 笑死肃廓,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的铣鹏。 我是一名探鬼主播哀蘑,決...
    沈念sama閱讀 40,091評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼绘迁,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了缀台?” 一聲冷哼從身側(cè)響起膛腐,我...
    開(kāi)封第一講書(shū)人閱讀 38,929評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎辩涝,沒(méi)想到半個(gè)月后勘天,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體捉邢,經(jīng)...
    沈念sama閱讀 45,346評(píng)論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡伏伐,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,570評(píng)論 2 333
  • 正文 我和宋清朗相戀三年秘案,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了潦匈。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,739評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡赤惊,死狀恐怖凰锡,靈堂內(nèi)的尸體忽然破棺而出掂为,到底是詐尸還是另有隱情,我是刑警寧澤昼扛,帶...
    沈念sama閱讀 35,437評(píng)論 5 344
  • 正文 年R本政府宣布抄谐,位于F島的核電站扰法,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏塞颁。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,037評(píng)論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望锤岸。 院中可真熱鬧板乙,春花似錦拳氢、人聲如沸蛋铆。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,677評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)玛瘸。三九已至,卻和暖如春右核,著一層夾襖步出監(jiān)牢的瞬間渺绒,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,833評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工躏鱼, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留殷绍,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,760評(píng)論 2 369
  • 正文 我出身青樓殖侵,卻偏偏與公主長(zhǎng)得像镰烧,于是被迫代替她去往敵國(guó)和親怔鳖。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,647評(píng)論 2 354

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