Categories
程式開發

如何無縫的將Flutter引入現有應用?



{“type”:”doc”,”content”:[{“type”:”heading”,”attrs”:{“align”:null,”level”:2},”content”:[{“type”:”text”,”text”:”为什么写thrio?”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”paragraph” ,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”在早期Flutter发布的时候,谷歌虽然提供了iOS和Android App上的Flutter嵌入方案,但主要针对的是纯Flutter的情形,混合开发支持的并不友好。”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”paragraph” ,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”所谓的纯RN、纯weex应用的生命周期都不存在,所以也不会存在一个纯Flutter的App的生命周期,因为我们总是有需要复用现有模块。”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”paragraph” ,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”所以我们需要一套足够完整的Flutter嵌入原生App的路由解决方案,所以我们自己造了个轮子 “},{“type”:”link”,”attrs”:{“href”:”https://github.com/hellobike/thrio”,”title”:null},”content”:[{“type”:”text”,”text”:”thrio”}]},{“type”:”text”,”text”:” ​,現已開源,遵循MIT協議。”}]},{“type”:”heading”,”attrs”:{“align”:null,”level”:2},”content”:[{“type”:”text”,”text”:”thrio的设计原则”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”bulletedlist” ,”content”:[{“type”:”listitem”,”content”:[{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”原则一,dart端最小改动接入”}]}]},{“type”:”listitem”,”content”:[{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”原则二,原生端最小侵入”}]}]},{“type”:”listitem”,”content”:[{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”原则三,三端保持一致的API”}]}]}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”paragraph” ,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”thrio所有功能的设计,都会遵守这三个原则。下面会逐步对功能层面一步步展开进行说明,后面也会有原理性的解析。”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”heading” ,”attrs”:{“align”:null,”level”:2},”content”:[{“type”:”text”,”text”:”thrio的页面路由”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”paragraph” ,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”以dart中的 “},{“type”:”codeinline”,”content”:[{“type”:”text”,”text”:”Navigator”}]},{“type”:”text”,”text”:” 為主要參照,提供以下路由能力:”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”bulletedlist” ,”content”:[{“type”:”listitem”,”content”:[{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”push,打开一个页面并放到路由栈顶”}]}]},{“type”:”listitem”,”content”:[{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”pop,关闭路由栈顶的页面”}]}]},{“type”:”listitem”,”content”:[{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”popTo,关闭到某一个页面”}]}]},{“type”:”listitem”,”content”:[{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”remove,删除任意页面”}]}]}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”paragraph” ,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”Navigator中的API几乎都可以通过组合以上方法实现,”},{“type”:”codeinline”,”content”:[{“type”:”text”,”text”:”replace”}]},{“type”:”text”,”text”:” 方法暫未提供。”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”paragraph” ,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”不提供iOS中存在的 “},{“type”:”codeinline”,”content”:[{“type”:”text”,”text”:”present”}]},{“type”:”text”,”text”:” 功能,因為會導致原生路由棧被覆蓋,維護複雜度會非常高,如確實需要可以通過修改轉場動畫實現。”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”heading” ,”attrs”:{“align”:null,”level”:3},”content”:[{“type”:”text”,”text”:”页面的索引”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”paragraph” ,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”要路由,我们需要对页面建立索引,通常情况下,我们只需要给每个页面设定一个 “},{“type”:”codeinline”,”content”:[{“type”:”text”,”text”:”url”}]},{“type”:”text”,”text”:” 就可以了,如果每個頁面都只打開一次的話,不會有任何問題。但是當一個頁面被打開多次之後,僅僅通過url是無法定位到明確的頁面實例的,所以在”},{“type”:”codeinline”,”content”:[{“type”:”text”,”text”:”thrio”}]},{“type”:”text”,”text”:” 中我們增加了頁面索引的概念,具體在API中都會以 “},{“type”:”codeinline”,”content”:[{“type”:”text”,”text”:”index”}]},{“type”:”text”,”text”:” 來表示,同一個url第一個打開的頁面的索引為 “},{“type”:”codeinline”,”content”:[{“type”:”text”,”text”:”1″}]},{“type”:”text”,”text”:” ,之後同一個 “},{“type”:”codeinline”,”content”:[{“type”:”text”,”text”:”url”}]},{“type”:”text”,”text”:” 的索引不斷累加。”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”paragraph” ,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null},”content”:[{“type”:”text””text”:”如此,唯一定位一個頁面的方式為”}{“type”:”codeinline””content”:[{“type”:”text””text”:”如此,唯一定位一个页面的方式为”}{“type”:”codeinline””content”:[{“type”:”text””text”:”如此,唯一定位一個頁面的方式為”}{“type”:”codeinline””content”:[{“type”:”text””text”:”如此,唯一定位一个页面的方式为”}{“type”:”codeinline””content”:[{“type”:”text”,”text”:”url”}]},{“type”:”text”,”text”:” + “},{“type”:”codeinline”,”content”:[{“type”:”text”,”text”:”index”}]},{“type”:”text”,”text”:”,在dart中 “},{“type”:”codeinline”,”content”:[{“type”:”text”,”text”:”route”}]},{“type”:”text”,”text”:” 的 “},{“type”:”codeinline”,”content”:[{“type”:”text”,”text”:”name”}]},{“type”:”text”,”text”:” 就是由 “},{“type”:”codeinline”,”content”:[{“type”:”text”,”text”:”‘$url.$index'”}]},{“type”:”text”,”text”:” 組合而成。”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”paragraph” ,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null},”content”:[{“type”:”text””text”:”很多時候,使用者不需要關注”}{“type”:”codeinline””content”:[{“type”:”text””text”:”很多时候,使用者不需要关注”}{“type”:”codeinline””content”:[{“type”:”text””text”:”很多時候,使用者不需要關注”}{“type”:”codeinline””content”:[{“type”:”text””text”:”很多时候,使用者不需要关注”}{“type”:”codeinline””content”:[{“type”:”text”,”text”:”index”}]},{“type”:”text”,”text”:”,只有當需要定位到多開的 “},{“type”:”codeinline”,”content”:[{“type”:”text”,”text”:”url”}]},{“type”:”text”,”text”:” 的頁面中的某一個時才需要關注 “},{“type”:”codeinline”,”content”:[{“type”:”text”,”text”:”index”}]},{“type”:”text”,”text”:”。最簡單獲取 “},{“type”:”codeinline”,”content”:[{“type”:”text”,”text”:”index”}]},{“type”:”text”,”text”:” 的方式為 “},{“type”:”codeinline”,”content”:[{“type”:”text”,”text”:”push”}]},{“type”:”text”,”text”:” 方法的回調返回值。”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”heading” ,”attrs”:{“align”:null,”level”:3},”content”:[{“type”:”text”,”text”:”页面的push”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”numberedlist” ,”attrs”:{“start”:1,”normalizeStart”:1},”content”:[{“type”:”listitem”,”content”:[{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:1,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”dart 端打开页面”}]}]}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”codeblock” ,”attrs”:{“lang”:”javascript”},”content”:[{“type”:”text”,”text”:”ThrioNavigator.push(url: ‘flutter1’);n// 传入参数nThrioNavigator.push(url: ‘native1’, params: { ‘1’: {‘2’: ‘3’}});n// 是否动画,目前在内嵌的dart页面中动画无法取消,原生iOS页面有效果nThrioNavigator.push(url: ‘native1’, animated:true);n// 接收锁打开页面的关闭回调nThrioNavigator.push(n url: ‘biz2/flutter2’,n params: {‘1’: {‘2’: ‘3’}},n poppedResult: (params) => ThrioLogger.v(‘biz2/flutter2 popped: $params’),n);”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”numberedlist” ,”attrs”:{“start”:2,”normalizeStart”:2},”content”:[{“type”:”listitem”,”content”:[{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:2,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”iOS 端打开页面”}]}]}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”codeblock” ,”attrs”:{“lang”:”objectivec”},”content”:[{“type”:”text”,”text”:”[ThrioNavigator pushUrl:@”flutter1″];n// 接收所打開頁面的關閉回調n[ThrioNavigator pushUrl:@”biz2/flutter2″ poppedResult:^(id _Nonnull params) {n ThrioLogV(@”biz2/flutter2 popped: %@”, params);n}];”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”numberedlist” ,”attrs”:{“start”:3,”normalizeStart”:3},”content”:[{“type”:”listitem”,”content”:[{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:3,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”Android 端打开页面”}]}]}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”codeblock” ,”attrs”:{“lang”:”kotlin”},”content”:[{“type”:”text”,”text”:”ThrioNavigator.push(this, “biz1/flutter1”,n mapOf(“k1” to 1),n false,n poppedResult = {n Log.e(“Thrio”, “native1 popResult call params $it”)n }n)”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”numberedlist” ,”attrs”:{“start”:4,”normalizeStart”:4},”content”:[{“type”:”listitem”,”content”:[{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:4,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”连续打开页面”}]}]}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”bulletedlist” ,”content”:[{“type”:”listitem”,”content”:[{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”dart端只需要await push,就可以连续打开页面”}]}]},{“type”:”listitem”,”content”:[{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”原生端需要等待push的result回调返回才能打开第二个页面”}]}]}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”numberedlist” ,”attrs”:{“start”:5,”normalizeStart”:5},”content”:[{“type”:”listitem”,”content”:[{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:5,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”获取所打开页面关闭后的回调参数”}]}]}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”bulletedlist” ,”content”:[{“type”:”listitem”,”content”:[{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”三端都可以通过闭包 poppedResult 来获取”}]}]}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”heading” ,”attrs”:{“align”:null,”level”:3},”content”:[{“type”:”text”,”text”:”页面的pop”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”numberedlist” ,”attrs”:{“start”:1,”normalizeStart”:1},”content”:[{“type”:”listitem”,”content”:[{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:1,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”dart 端关闭顶层页面”}]}]}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”codeblock” ,”attrs”:{“lang”:”dart”},”content”:[{“type”:”text”,”text”:”// 默认动画开启nThrioNavigator.pop();n// 不开启动画,原生和dart页面都生效nThrioNavigator.pop(animated: false);n// 关闭当前页面,并传递参数给push这个页面的回调nThrioNavigator.pop(params: ‘popped flutter1’),”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”numberedlist” ,”attrs”:{“start”:2,”normalizeStart”:2},”content”:[{“type”:”listitem”,”content”:[{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:2,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”iOS 端关闭顶层页面”}]}]}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”codeblock” ,”attrs”:{“lang”:”objectivec”},”content”:[{“type”:”text”,”text”:”// 默认动画开启n[ThrioNavigator pop];n// 關閉動畫n[ThrioNavigator popAnimated:NO];n// 關閉當前頁面,並傳遞參數給push這個頁面的回調n[ThrioNavigator popParams:@{@”k1″: @3}];”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”numberedlist” ,”attrs”:{“start”:3,”normalizeStart”:3},”content”:[{“type”:”listitem”,”content”:[{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:3,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”Android 端关闭顶层页面”}]}]}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”codeblock” ,”attrs”:{“lang”:”kotlin”},”content”:[{“type”:”text”,”text”:”ThrioNavigator.pop(this, params, animated)”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”heading” ,”attrs”:{“align”:null,”level”:3},”content”:[{“type”:”text”,”text”:”页面的popTo”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”numberedlist” ,”attrs”:{“start”:1,”normalizeStart”:1},”content”:[{“type”:”listitem”,”content”:[{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:1,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”dart 端关闭到页面”}]}]}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”codeblock” ,”attrs”:{“lang”:”dart”},”content”:[{“type”:”text”,”text”:”// 默认动画开启nThrioNavigator.popTo(url: ‘flutter1’);n// 不开启动画,原生和dart页面都生效nThrioNavigator.popTo(url: ‘flutter1’, animated: false);”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”numberedlist” ,”attrs”:{“start”:2,”normalizeStart”:2},”content”:[{“type”:”listitem”,”content”:[{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:2,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”iOS 端关闭到页面”}]}]}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”codeblock” ,”attrs”:{“lang”:”objectivec”},”content”:[{“type”:”text”,”text”:”// 默认动画开启n[ThrioNavigator popToUrl:@”flutter1″];n// 關閉動畫n[ThrioNavigator popToUrl:@”flutter1″ animated:NO];”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”numberedlist” ,”attrs”:{“start”:3,”normalizeStart”:3},”content”:[{“type”:”listitem”,”content”:[{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:3,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”Android 端关闭到页面”}]}]}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”codeblock” ,”attrs”:{“lang”:”kotlin”},”content”:[{“type”:”text”,”text”:”ThrioNavigator.popTo(context, url, index)”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”heading” ,”attrs”:{“align”:null,”level”:3},”content”:[{“type”:”text”,”text”:”页面的remove”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”numberedlist” ,”attrs”:{“start”:1,”normalizeStart”:1},”content”:[{“type”:”listitem”,”content”:[{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:1,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”dart 端关闭特定页面”}]}]}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”codeblock” ,”attrs”:{“lang”:”dart”},”content”:[{“type”:”text”,”text”:”ThrioNavigator.remove(url: ‘flutter1’);n// 只有当页面是顶层页面时,animated参数才会生效nThrioNavigator.remove(url: ‘flutter1’, animated: true);”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”numberedlist” ,”attrs”:{“start”:2,”normalizeStart”:2},”content”:[{“type”:”listitem”,”content”:[{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:2,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”iOS 端关闭特定页面”}]}]}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”codeblock” ,”attrs”:{“lang”:”objectivec”},”content”:[{“type”:”text”,”text”:”[ThrioNavigator removeUrl:@”flutter1″];n// 只有當頁面是頂層頁面時,animated參數才會生效n[ThrioNavigator removeUrl:@”flutter1″ animated:NO];”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”numberedlist” ,”attrs”:{“start”:3,”normalizeStart”:3},”content”:[{“type”:”listitem”,”content”:[{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:3,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”Android 端关闭特定页面”}]}]}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”codeblock” ,”attrs”:{“lang”:”kotlin”},”content”:[{“type”:”text”,”text”:”ThrioNavigator.remove(context, url, index)”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”heading” ,”attrs”:{“align”:null,”level”:2},”content”:[{“type”:”text”,”text”:”thrio的页面通知”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”paragraph” ,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”页面通知一般来说并不在路由的范畴之内,但我们在实际开发中却经常需要使用到,由此产生的各种模块化框架一个比一个复杂。”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”paragraph” ,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”那么问题来了,这些模块化框架很难在三端互通,所有的这些模块化框架提供的能力无非最终是一个页面通知的能力,而且页面通知我们可以非常简单的在三端打通。”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”paragraph” ,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”鉴于此,页面通知作为thrio的一个必备能力被引入了thrio。”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”heading” ,”attrs”:{“align”:null,”level”:3},”content”:[{“type”:”text”,”text”:”发送页面通知”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”numberedlist” ,”attrs”:{“start”:1,”normalizeStart”:1},”content”:[{“type”:”listitem”,”content”:[{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:1,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”dart 端给特定页面发通知”}]}]}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”codeblock” ,”attrs”:{“lang”:”dart”},”content”:[{“type”:”text”,”text”:”ThrioNavigator.notify(url: ‘flutter1’, name: ‘reload’);”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”numberedlist” ,”attrs”:{“start”:2,”normalizeStart”:2},”content”:[{“type”:”listitem”,”content”:[{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:2,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”iOS 端给特定页面发通知”}]}]}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”codeblock” ,”attrs”:{“lang”:”objectivec”},”content”:[{“type”:”text”,”text”:”[ThrioNavigator notifyUrl:@”flutter1″ name:@”reload”];”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”numberedlist” ,”attrs”:{“start”:3,”normalizeStart”:3},”content”:[{“type”:”listitem”,”content”:[{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:3,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”Android 端给特定页面发通知”}]}]}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”codeblock” ,”attrs”:{“lang”:”kotlin”},”content”:[{“type”:”text”,”text”:”ThrioNavigator.notify(url, index, params)”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”heading” ,”attrs”:{“align”:null,”level”:3},”content”:[{“type”:”text”,”text”:”接收页面通知”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”numberedlist” ,”attrs”:{“start”:1,”normalizeStart”:1},”content”:[{“type”:”listitem”,”content”:[{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:1,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”dart 端接收页面通知”}]}]}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”paragraph” ,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”使用 “},{“type”:”codeinline”,”content”:[{“type”:”text”,”text”:”NavigatorPageNotify”}]},{“type”:”text”,”text”:” 這個 “},{“type”:”codeinline”,”content”:[{“type”:”text”,”text”:”Widget”}]},{“type”:”text”,”text”:” 來實現在任何地方接收當前頁面收到的通知。”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”codeblock” ,”attrs”:{“lang”:”dart”},”content”:[{“type”:”text”,”text”:”NavigatorPageNotify(n name: ‘page1Notify’,n onPageNotify: (params) =>n ThrioLogger.v(‘flutter1 receive notify: $params’),n child: Xxxx());”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”numberedlist” ,”attrs”:{“start”:2,”normalizeStart”:2},”content”:[{“type”:”listitem”,”content”:[{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:2,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”iOS 端接收页面通知”}]}]}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”paragraph” ,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null},”content”:[{“type”:”codeinline”,”content”:[{“type”:”text”,”text”:”UIViewController”}]},{“type”:”text”,”text”:”實現協議”},{“type”:”codeinline”,”content”:[{“type”:”text”,”text”:”NavigatorPageNotifyProtocol”}]},{“type”:”text”,”text”:”,通過 “},{“type”:”codeinline”,”content”:[{“type”:”text”,”text”:”onNotify”}]},{“type”:”text”,”text”:” 來接收頁面通知”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”codeblock” ,”attrs”:{“lang”:”objectivec”},”content”:[{“type”:”text”,”text”:”- (void)onNotify:(NSString )name params:(NSDictionary )params {n ThrioLogV(@”native1 onNotify: %@, %@”, name, params);n}”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”numberedlist” ,”attrs”:{“start”:3,”normalizeStart”:3},”content”:[{“type”:”listitem”,”content”:[{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:3,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”Android 端接收页面通知”}]}]}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”paragraph” ,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null},”content”:[{“type”:”codeinline”,”content”:[{“type”:”text”,”text”:”Activity”}]},{“type”:”text”,”text”:”實現協議”},{“type”:”codeinline”,”content”:[{“type”:”text”,”text”:”OnNotifyListener”}]},{“type”:”text”,”text”:”,通過 “},{“type”:”codeinline”,”content”:[{“type”:”text”,”text”:”onNotify”}]},{“type”:”text”,”text”:” 來接收頁面通知”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”codeblock” ,”attrs”:{“lang”:”kotlin”},”content”:[{“type”:”text”,”text”:”class Activity : AppCompatActivity(), OnNotifyListener {n override fun onNotify(name: String, params: Any?) {n }n}”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”paragraph” ,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”因为Android activity在后台可能会被销毁,所以页面通知实现了一个懒响应的行为,只有当页面呈现之后才会收到该通知,这也符合页面需要刷新的场景。”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”heading” ,”attrs”:{“align”:null,”level”:2},”content”:[{“type”:”text”,”text”:”thrio的模块化”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”paragraph” ,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”模块化在thrio里面只是一个非核心功能,仅仅为了实现原则二而引入原生端。”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”paragraph” ,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”thrio的模块化能力由一个类提供,”},{“type”:”codeinline”,”content”:[{“type”:”text”,”text”:”ThrioModule”}]},{“type”:”text”,”text”:”,很小巧,主要提供了 “},{“type”:”codeinline”,”content”:[{“type”:”text”,”text”:”Module”}]},{“type”:”text”,”text”:” 的註冊鍊和初始化鏈,讓代碼可以根據路由url進行文件分級分類。”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”paragraph” ,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”注册链将所有模块串起来,字母块由最近的父一级模块注册,新增模块的耦合度最低。”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”paragraph” ,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”初始化链将所有模块需要初始化的代码串起来,同样是为了降低耦合度,在初始化链上可以就近注册模块的页面的构造器,页面路由观察者,页面生命周期观察者等,也可以在多引擎模式下提前启动某一个引擎。”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”paragraph” ,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”模块间通信的能力由页面通知实现。”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”codeblock” ,”attrs”:{“lang”:”dart”},”content”:[{“type”:”text”,”text”:”mixin ThrioModule {n /// A function for registering a module, which will calln /// the onModuleRegister function of the module.n ///n void registerModule(ThrioModule module);n n /// A function for module initialization that will calln /// the onPageRegister, onModuleInit and onModuleAsyncInitn /// methods of all modules.n ///n void initModule();n n /// A function for registering submodules.n ///n void onModuleRegister() {}nn /// A function for registering a page builder.n ///n void onPageRegister() {}nn /// A function for module initialization.n ///n void onModuleInit() {}nn /// A function for module asynchronous initialization.n ///n void onModuleAsyncInit() {}n n /// Register an page builder for the router.n ///n /// Unregistry by calling the return value VoidCallback.n ///n VoidCallback registerPageBuilder(String url, NavigatorPageBuilder builder);nn /// Register observers for the life cycle of Dart pages.n ///n /// Unregistry by calling the return value VoidCallback.n ///n /// Do not override this method.n ///n VoidCallback registerPageObserver(NavigatorPageObserver pageObserver);n n /// Register observers for route action of Dart pages.n ///n /// Unregistry by calling the return value VoidCallback.n ///n /// Do not override this method.n ///n VoidCallback registerRouteObserver(NavigatorRouteObserver routeObserver);n}”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”heading” ,”attrs”:{“align”:null,”level”:2},”content”:[{“type”:”text”,”text”:”thrio的页面生命周期”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”paragraph” ,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”原生端可以获得所有页面的生命周期,Dart 端只能获取自身页面的生命周期”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”numberedlist” ,”attrs”:{“start”:1,”normalizeStart”:1},”content”:[{“type”:”listitem”,”content”:[{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:1,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”dart 端获取页面的生命周期”}]}]}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”codeblock” ,”attrs”:{“lang”:”dart”},”content”:[{“type”:”text”,”text”:”class Module with ThrioModule, NavigatorPageObserver {n @overriden void onPageRegister() {n registerPageObserver(this);n }nn @overriden void didAppear(RouteSettings routeSettings) {}nn @overriden void didDisappear(RouteSettings routeSettings) {}nn @overriden void onCreate(RouteSettings routeSettings) {}nn @overriden void willAppear(RouteSettings routeSettings) {}nn @overriden void willDisappear(RouteSettings routeSettings) {}n}”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”numberedlist” ,”attrs”:{“start”:2,”normalizeStart”:2},”content”:[{“type”:”listitem”,”content”:[{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:2,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”iOS 端获取页面的生命周期”}]}]}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”codeblock” ,”attrs”:{“lang”:”objectivec”},”content”:[{“type”:”text”,”text”:”@interface Module1 : [email protected]@implementation Module1nn- (void)onPageRegister {n [self registerPageObserver:self];n}nn- (void)onCreate:(NavigatorRouteSettings )routeSettings { }nn- (void)willAppear:(NavigatorRouteSettings )routeSettings { }nn- (void)didAppear:(NavigatorRouteSettings )routeSettings { }nn- (void)willDisappear:(NavigatorRouteSettings )routeSettings { }nn- (void)didDisappear:(NavigatorRouteSettings *)routeSettings { }[email protected]”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”heading” ,”attrs”:{“align”:null,”level”:2},”content”:[{“type”:”text”,”text”:”thrio的页面路由观察者”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”paragraph” ,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”原生端可以观察所有页面的路由行为,dart 端只能观察 dart 页面的路由行为”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”numberedlist” ,”attrs”:{“start”:1,”normalizeStart”:1},”content”:[{“type”:”listitem”,”content”:[{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:1,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”dart 端获取页面的路由行为”}]}]}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”codeblock” ,”attrs”:{“lang”:”dart”},”content”:[{“type”:”text”,”text”:”class Module with ThrioModule, NavigatorRouteObserver {n @overriden void onModuleRegister() {n registerRouteObserver(this);n }nn @overriden void didPop(n RouteSettings routeSettings,n RouteSettings previousRouteSettings,n ) {}nn @overriden void didPopTo(n RouteSettings routeSettings,n RouteSettings previousRouteSettings,n ) {}nn @overriden void didPush(n RouteSettings routeSettings,n RouteSettings previousRouteSettings,n ) {}nn @overriden void didRemove(n RouteSettings routeSettings,n RouteSettings previousRouteSettings,n ) {}n}”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”numberedlist” ,”attrs”:{“start”:2,”normalizeStart”:2},”content”:[{“type”:”listitem”,”content”:[{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:2,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”iOS 端获取页面的路由行为”}]}]}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”codeblock” ,”attrs”:{“lang”:”objectivec”},”content”:[{“type”:”text”,”text”:”@interface Module2 : [email protected]@implementation Module2nn- (void)onPageRegister {n [self registerRouteObserver:self];n}nn- (void)didPop:(NavigatorRouteSettings )routeSettingsn previousRoute:(NavigatorRouteSettings Nullable)previousRouteSettings {n}nn- (void)didPopTo:(NavigatorRouteSettings )routeSettingsn previousRoute:( NavigatorRouteSettings Nullable)previousRouteSettings {n}nn- (void)didPush:(NavigatorRouteSettings )routeSettingsn previousRoute:(NavigatorRouteSettings Nullable)previousRouteSettings {n}nn- (void)didRemove:(NavigatorRouteSettings )routeSettings n previousRoute:(NavigatorRouteSettings Nullable)previousRouteSettings {n}[email protected]”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”heading” ,”attrs”:{“align”:null,”level”:2},”content”:[{“type”:”text”,”text”:”thrio的额外功能”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”heading” ,”attrs”:{“align”:null,”level”:3},”content”:[{“type”:”text”,”text”:”iOS 显隐当前页面的导航栏”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”paragraph” ,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”原生的导航栏在 dart 上一般情况下是不需要的,但切换到原生页面又需要把原生的导航栏置回来,thrio 不提供的话,使用者较难扩展,我之前在目前一个主流的Flutter接入库上进行此项功能的扩展,很不流畅,所以这个功能最好的效果还是 thrio 直接内置,切换到 dart 页面默认会隐藏原生的导航栏,切回原生页面也会自动恢复。另外也可以手动隐藏原生页面的导航栏。”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”codeblock” ,”attrs”:{“lang”:”objectivec”},”content”:[{“type”:”text”,”text”:”viewController.thrio_hidesNavigationBar = NO;”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”heading” ,”attrs”:{“align”:null,”level”:3},”content”:[{“type”:”text”,”text”:”支持页面关闭前弹窗确认的功能”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”paragraph” ,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”如果用户正在填写一个表单,你可能经常会需要弹窗确认是否关闭当前页面的功能。”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”paragraph” ,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null},”content”:[{“type”:”text””text”:”在dart中,有一個”}{“type”:”codeinline””content”:[{“type”:”text””text”:”在dart中,有一个”}{“type”:”codeinline””content”:[{“type”:”text””text”:”在dart中,有一個”}{“type”:”codeinline””content”:[{“type”:”text””text”:”在dart中,有一个”}{“type”:”codeinline””content”:[{“type”:”text”,”text”:”Widget”}]},{“type”:”text”,”text”:” 提供了該功能,thrio 完好的保留了這個功能。”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”codeblock” ,”attrs”:{“lang”:”dart”},”content”:[{“type”:”text”,”text”:”WillPopScope(n onWillPop: () async => true,n child: Container(),n);”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”paragraph” ,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”在 iOS 中,thrio 提供了类似的功能,返回 “},{“type”:”codeinline”,”content”:[{“type”:”text”,”text”:”NO”}]},{“type”:”text”,”text”:” 表示不會關閉,一旦設置會將側滑返回手勢禁用”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”codeblock” ,”attrs”:{“lang”:”objectivec”},”content”:[{“type”:”text”,”text”:”viewController.thriowillPopBlock = ^(ThrioBoolCallback Nonnull result) {n result(NO);n};”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”关于 “},{“type”:”codeinline”,”content”:[{“type”:”text”,”text”:”FlutterViewController”}]},{“type”:”text”,”text”:” 的側滑返回手勢,Flutter 默認支持的是純Flutter應用,僅支持單一的”},{“type”:”codeinline”,”content” :[{“type”:”text”,”text”:”FlutterViewController”}]},{“type”:”text”,”text”:” 作為整個App的容器,內部已經將 “},{“type”:”codeinline”,”content”:[{“type”:”text”,”text”:”FlutterViewController”}]},{“type”:”text”,”text”:” 的側滑返回手勢去掉。但thrio 要解決的是Flutter 與原生應用的無縫集成,所以必須將側滑返回的手勢加回來。” }]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”paragraph” ,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”heading”,”attrs”:{“align”: null,”level”:2},”content”:[{“type”:”text”,”text”:”thrio的设计解析”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”paragraph” ,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”目前开源 Flutter 嵌入原生的库,主要的还是通过切换 FlutterEngine 上的原生容器来实现的,这是 Flutter 原本提供的原生容器之上最小改动而实现,需要小心处理好容器切换的时序,否则在页面导航时会产生崩溃。基于 Flutter 提供的这个功能, thrio 构建了三端一致的页面管理API。”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”heading” ,”attrs”:{“align”:null,”level”:3},”content”:[{“type”:”text”,”text”:”dart 的核心类”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”paragraph” ,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”dart 端只管理 dart页面”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”numberedlist” ,”attrs”:{“start”:1,”normalizeStart”:1},”content”:[{“type”:”listitem”,”content”:[{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:1,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”基于 “},{“type”:”codeinline”,”content”:[{“type”:”text”,”text”:”RouteSettings”}]},{“type”:”text”,”text”:” 進行擴展,復用現有的字段”}]}]}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”bulletedlist” ,”content”:[{“type”:”listitem”,”content”:[{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”name = url.index”}]}]},{“type”:”listitem”,”content”:[{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”isInitialRoute = !isNested”}]}]},{“type”:”listitem”,”content”:[{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”arguments = params”}]}]}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”numberedlist” ,”attrs”:{“start”:2,”normalizeStart”:2},”content”:[{“type”:”listitem”,”content”:[{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:2,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”基于 “},{“type”:”codeinline”,”content”:[{“type”:”text”,”text”:”MaterialPageRoute”}]},{“type”:”text”,”text”:” 擴展的 “},{“type”:”codeinline”,”content”:[{“type”:”text”,”text”:”NavigatorPageRoute”}]}]}]}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”bulletedlist” ,”content”:[{“type”:”listitem”,”content”:[{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”主要提供页面描述和转场动画的是否配置的功能”}]}]}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”numberedlist” ,”attrs”:{“start”:2,”normalizeStart”:2},”content”:[{“type”:”listitem”,”content”:[{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:2,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”基于 “},{“type”:”codeinline”,”content”:[{“type”:”text”,”text”:”Navigator”}]},{“type”:”text”,”text”:” 擴展,封裝 “},{“type”:”codeinline”,”content”:[{“type”:”text”,”text”:”NavigatorWidget”}]},{“type”:”text”,”text”:”,提供以下方法”}]}]}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”codeblock” ,”attrs”:{“lang”:”dart”},”content”:[{“type”:”text”,”text”:” Future push(RouteSettings settings, {n bool animated = true,n NavigatorParamsCallback poppedResult,n });n n Future pop(RouteSettings settings, {bool animated = true});n n Future popTo(RouteSettings settings, {bool animated = true});nn Future remove(RouteSettings settings, {bool animated = false});n “}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”numberedlist” ,”attrs”:{“start”:3,”normalizeStart”:3},”content”:[{“type”:”listitem”,”content”:[{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:3,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”封装 “},{“type”:”codeinline”,”content”:[{“type”:”text”,”text”:”ThrioNavigator”}]},{“type”:”text”,”text”:” 路由API”}]}]}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”codeblock” ,”attrs”:{“lang”:”dart”},”content”:[{“type”:”text”,”text”:”abstract class ThrioNavigator {n /// Push the page onto the navigation stack.n ///n /// If a native page builder exists for the url, open the native page,n /// otherwise open the flutter page.n ///n static Future push({n @required String url,n params,n bool animated = true,n NavigatorParamsCallback poppedResult,n });n n /// Send a notification to the page.n ///n /// Notifications will be triggered when the page enters the foreground.n /// Notifications with the same name will be overwritten.n /// n static Future notify({n @required String url,n int index,n @required String name,n params,n });n n /// Pop a page from the navigation stack.n ///n static Future pop({params, bool animated = true})nn static Future popTo({n @required String url,n int index,n bool animated = true,n });n n /// Remove the page with url in the navigation stack.n /// n static Future remove({n @required String url,n int index,n bool animated = true,n });n}”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”heading” ,”attrs”:{“align”:null,”level”:3},”content”:[{“type”:”text”,”text”:”iOS 的核心类”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”numberedlist” ,”attrs”:{“start”:1,”normalizeStart”:1},”content”:[{“type”:”listitem”,”content”:[{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:1,”align”:null,”origin”:null},”content”:[{“type”:”codeinline”,”content”:[{“type”:”text”,”text”:”NavigatorRouteSettings”}]},{“type”:”text”,”text”:” 對應於 dart 的 “},{“type”:”codeinline”,”content”:[{“type”:”text”,”text”:”RouteSettings”}]},{“type”:”text”,”text”:” 類,並提供相同數據結構”}]}]}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”codeblock” ,”attrs”:{“lang”:”objectivec”},”content”:[{“type”:”text”,”text”:”[email protected] NavigatorRouteSettings : [email protected] (nonatomic, copy, readonly) NSString url;[email protected] (nonatomic, strong, readonly) NSNumber index;[email protected] (nonatomic, assign, readonly) BOOL nested;[email protected] (nonatomic, copy, readonly, nullable) id params;[email protected]”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”numberedlist” ,”attrs”:{“start”:2,”normalizeStart”:2},”content”:[{“type”:”listitem””content”:[{“type”:”paragraph””attrs”:{“indent”:0″number”:2″align”:null”origin”:null}”content”:[{“type”:”codeinline””content”:[{“type”:”listitem””content”:[{“type”:”paragraph””attrs”:{“indent”:0″number”:2″align”:null”origin”:null}”content”:[{“type”:”codeinline””content”:[{“type”:”listitem””content”:[{“type”:”paragraph””attrs”:{“indent”:0″number”:2″align”:null”origin”:null}”content”:[{“type”:”codeinline””content”:[{“type”:”listitem””content”:[{“type”:”paragraph””attrs”:{“indent”:0″number”:2″align”:null”origin”:null}”content”:[{“type”:”codeinline””content”:[{“type”:”text”,”text”:”NavigatorPageRoute”}]},{“type”:”text”,”text”:” 對應於 dart 的 “},{“type”:”codeinline”,”content”:[{“type”:”text”,”text”:”NavigatorPageRoute”}]},{“type”:”text”,”text”:” 類”}]}]}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”bulletedlist” ,”content”:[{“type”:”listitem”,”content”:[{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”存储通知、页面关闭回调、NavigatorRouteSettings”}]}]},{“type”:”listitem”,”content”:[{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”route的双向链表”}]}]}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”numberedlist” ,”attrs”:{“start”:3,”normalizeStart”:3},”content”:[{“type”:”listitem”,”content”:[{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:3,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”基于 “},{“type”:”codeinline”,”content”:[{“type”:”text”,”text”:”UINavigationController”}]},{“type”:”text”,”text”:” 擴展,功能類似 dart 的 “},{“type”:”codeinline”,”content”:[{“type”:”text”,”text”:”NavigatorWidget”}]}]}]}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”bulletedlist” ,”content”:[{“type”:”listitem”,”content”:[{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”提供一些列的路由内部接口”}]}]},{“type”:”listitem”,”content”:[{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”并能兼容非 thrio 体系内的页面”}]}]}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”numberedlist” ,”attrs”:{“start”:4,”normalizeStart”:4},”content”:[{“type”:”listitem”,”content”:[{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:4,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”基于 “},{“type”:”codeinline”,”content”:[{“type”:”text”,”text”:”UIViewController”}]},{“type”:”text”,”text”:” 擴展”}]}]}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”bulletedlist” ,”content”:[{“type”:”listitem””content”:[{“type”:”paragraph””attrs”:{“indent”:0″number”:0″align”:null”origin”:null}”content”:[{“type”:”text””text”:”提供”}{“type”:”codeinline””content”:[{“type”:”listitem””content”:[{“type”:”paragraph””attrs”:{“indent”:0″number”:0″align”:null”origin”:null}”content”:[{“type”:”text””text”:”提供”}{“type”:”codeinline””content”:[{“type”:”listitem””content”:[{“type”:”paragraph””attrs”:{“indent”:0″number”:0″align”:null”origin”:null}”content”:[{“type”:”text””text”:”提供”}{“type”:”codeinline””content”:[{“type”:”listitem””content”:[{“type”:”paragraph””attrs”:{“indent”:0″number”:0″align”:null”origin”:null}”content”:[{“type”:”text””text”:”提供”}{“type”:”codeinline””content”:[{“type”:”text”,”text”:”FlutterViewController”}]},{“type”:”text”,”text”:” 容器上的 dart 頁面的管理功能”}]}]},{“type”:”listitem”,”content”:[{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”提供 popDisable 等功能”}]}]}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”numberedlist” ,”attrs”:{“start”:5,”normalizeStart”:5},”content”:[{“type”:”listitem”,”content”:[{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:5,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”封装 “},{“type”:”codeinline”,”content”:[{“type”:”text”,”text”:”ThrioNavigator”}]},{“type”:”text”,”text”:” 路由API”}]}]}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”codeblock” ,”attrs”:{“lang”:”objc”},”content”:[{“type”:”text”,”text”:”@interface ThrioNavigator : NSObjectnn/// Push the page onto the navigation stack.n///n/// If a native page builder exists for the url, open the native page,n/// otherwise open the flutter page.n///n+ (void)pushUrl:(NSString )urln params:(id)paramsn animated:(BOOL)animatedn result:(ThrioNumberCallback)resultn poppedResult:(ThrioIdCallback)poppedResult;nn/// Send a notification to the page.n///n/// Notifications will be triggered when the page enters the foreground.n/// Notifications with the same name will be overwritten.n///n+ (void)notifyUrl:(NSString )urln index:(NSNumber )indexn name:(NSString )namen params:(id)paramsn result:(ThrioBoolCallback)result;nn/// Pop a page from the navigation stack.n///n+ (void)popParams:(id)paramsn animated:(BOOL)animatedn result:(ThrioBoolCallback)result;nn/// Pop the page in the navigation stack until the page with url.n///n+ (void)popToUrl:(NSString )urln index:(NSNumber )indexn animated:(BOOL)animatedn result:(ThrioBoolCallback)result;nn/// Remove the page with url in the navigation stack.n///n+ (void)removeUrl:(NSString )urln index:(NSNumber )indexn animated:(BOOL)animatedn result:(ThrioBoolCallback)result;[email protected]”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”heading” ,”attrs”:{“align”:null,”level”:3},”content”:[{“type”:”text”,”text”:”dart 与 iOS 路由栈的结构”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”paragraph” ,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”image”,”attrs”:{“src”: “https://static001.geekbang.org/infoq/ed/edad7fed11c163e34f8842f9f7bfeb13.png”,”alt”:null,”title”:null,”style”:null,”href”:null,”fromPaste”:true, “pastePass”:true}},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{” type”:”numberedlist”,”attrs”:{“start”:1,”normalizeStart”:1},”content”:[{“type”:”listitem”,”content”:[{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:1,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”一个应用允许启动多个Flutter引擎,可让每个引擎运行的代码物理隔离,按需启用,劣势是启动多个Flutter引擎可能导致资源消耗过多而引起问题;”}]}]},{“type”:”listitem”,”content”:[{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:2,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”一个Flutter引擎通过切换可以匹配到多个FlutterViewController,这是Flutter优雅嵌入原生应用的前提条件”}]}]},{“type”:”listitem”,”content”:[{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:3,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”一个FlutterViewController可以内嵌多个Dart页面,有效减少单个FlutterViewController只打开一个Dart页面导致的内存消耗过多问题,关于内存消耗的问题,后续会有提到。”}]}]}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”heading” ,”attrs”:{“align”:null,”level”:3},”content”:[{“type”:”text”,”text”:”dart 与 iOS push的时序图”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”image” ,”attrs”:{“src”:”https://static001.geekbang.org/infoq/54/54f71d54a7f69f35e05b63542dd49e2c.png”,”alt”:null,”title”:null,”style”:null,”href “:null,”fromPaste”:true,”pastePass”:true}},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null, “origin”:null}},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{” type”:”numberedlist”,”attrs”:{“start”:1,”normalizeStart”:1},”content”:[{“type”:”listitem”,”content”:[{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:1,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”所有路由操作最终汇聚于原生端开始,如果始于 dart 端,则通过 channel 调用原生端的API”}]}]},{“type”:”listitem”,”content”:[{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:2,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”通过 “},{“type”:”codeinline”,”content”:[{“type”:”text”,”text”:”url+index”}]},{“type”:”text”,”text”:” 定位到頁面”}]}]},{“type”:”listitem”,”content”:[{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:3,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”如果页面是原生页面,则直接进行相关操作”}]}]},{“type”:”listitem”,”content”:[{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:4,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”如果页面是 Flutter 容器,则通过 channel 调用 dart 端对应的路由 API”}]}]},{“type”:”listitem”,”content”:[{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:5,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”接4步,如果 dart 端对应的路由 API 操作完成后回调,如果成功,则执行原生端的路由栈同步,如果失败,则回调入口 API 的result”}]}]},{“type”:”listitem”,”content”:[{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:6,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”接4不,如果 dart 端对应的路由 API操作成功,则通过 route channel 调用原生端对应的 route observer,通过 page channel 调用原生端对应的 page observer。”}]}]}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”heading” ,”attrs”:{“align”:null,”level”:3},”content”:[{“type”:”text”,”text”:”dart 与 iOS pop的时序图”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”image” ,”attrs”:{“src”:”https://static001.geekbang.org/infoq/9e/9e51af7c3802c90fbbe4e5ad76fea420.png”,”alt”:null,”title”:null,”style”:null,”href “:null,”fromPaste”:true,”pastePass”:true}},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null, “origin”:null}},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{” type”:”numberedlist”,”attrs”:{“start”:1,”normalizeStart”:1},”content”:[{“type”:”listitem”,”content”:[{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:1,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”pop 的流程与 push 基本一致;”}]}]},{“type”:”listitem”,”content”:[{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:2,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”pop 需要考虑页面是否可关闭的问题;”}]}]},{“type”:”listitem”,”content”:[{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:3,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”但在 iOS 中,侧滑返回手势会导致问题, “},{“type”:”codeinline”,”content”:[{“type”:”text”,”text”:”popViewControllerAnimated:”}]},{“type”:”text”,”text”:” 會在手勢開始的時候調用,導致dart 端的頁面已經被pop 掉,但如果手勢被放棄了,則導致兩端的頁面棧不一致,thrio 已經解決了這個問題,具體流程稍複雜,源碼可能更好的說明。”}]}]}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”heading” ,”attrs”:{“align”:null,”level”:3},”content”:[{“type”:”text”,”text”:”dart 与 iOS popTo的时序图”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”image” ,”attrs”:{“src”:”https://static001.geekbang.org/infoq/00/00db1ca11c7cfa335cc3ad27323e2d22.png”,”alt”:null,”title”:null,”style”:null,”href “:null,”fromPaste”:true,”pastePass”:true}},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null, “origin”:null}},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{” type”:”numberedlist”,”attrs”:{“start”:1,”normalizeStart”:1},”content”:[{“type”:”listitem”,”content”:[{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:1,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”popTo 的流程与 push 基本一致;”}]}]},{“type”:”listitem”,”content”:[{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:2,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”但在多引擎模式下,popTo需要处理多引擎的路由栈同步的问题;”}]}]},{“type”:”listitem”,”content”:[{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:3,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”另外在 Dart 端,popTo实际上是多个pop或者remove构成的,最终产生多次的didPop或didRemove行为,需要将多个pop或remove组合起来形成一个didPopTo行为。”}]}]}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”heading” ,”attrs”:{“align”:null,”level”:3},”content”:[{“type”:”text”,”text”:”dart 与 iOS remove的时序图”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”image” ,”attrs”:{“src”:”https://static001.geekbang.org/infoq/d4/d49886dde7eaf2b5a6c524c955434567.png”,”alt”:null,”title”:null,”style”:null,”href “:null,”fromPaste”:true,”pastePass”:true}},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null, “origin”:null}},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{” type”:”numberedlist”,”attrs”:{“start”:1,”normalizeStart”:1},”content”:[{“type”:”listitem”,”content”:[{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:1,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”remove 的流程与 push 基本一致。”}]}]}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”heading” ,”attrs”:{“align”:null,”level”:2},”content”:[{“type”:”text”,”text”:”总结”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”paragraph” ,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”目前 Flutter 接入原生应用主流的解决方案应该是[boost](https://github.com/alibaba/flutter_boost),筆者的團隊在項目深度使用過boost,也積累了很多對boost 改善的需求,遇到的最大問題是內存問題,每打開一個Flutter 頁面的內存開銷基本到了很難接受的程度,[thrio](https://github.com/hellobike/thrio)把解決內存問題作為頭等任務,最終效果還是不錯的,比如以連續打開5 個Flutter 頁面計算,boost 的方案會消耗91.67M 內存,thrio 只消耗42.76內存,模擬器上跑出來的數據大致如下:”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”image” ,”attrs”:{“src”:”https://static001.geekbang.org/infoq/50/50d898b0d35f444f8b2351e199aaff04.png”,”alt”:null,”title”:null,”style”:null,”href “:null,”fromPaste”:true,”pastePass”:true}},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null, “origin”:null}},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{” type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null},”content”:[{“type”:”text”,”text”:”同样连续打开 5 个页面的场景,thrio 打开第一个页面跟 boost 耗时是一样的,因为都需要打开一个新的 Activity,之后 4 个页面 thrio 会直接打开 Flutter 页面,耗时会降下来,以下单位为 ms:”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}},{“type”:”image” ,”attrs”:{“src”:”https://static001.geekbang.org/infoq/13/1366afb69ca22f9845cef17a93a87cb7.png”,”alt”:null,”title”:null,”style”:null,”href “:null,”fromPaste”:true,”pastePass”:true}},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null, “origin”:null}},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null},”content” :[{“type”:”text”,”text”:”当然,thrio 跟 boost 的定位还是不太一样的,thrio 更多的偏向于解决我们业务上的需求,尽量做到开箱即用。”}]},{“type”:”paragraph”,”attrs”:{“indent”:0,”number”:0,”align”:null,”origin”:null}}]}