<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                今天,我來和你聊聊如何在原生應用中接入 Flutter。 在前面兩篇文章中,我與你分享了如何在 Dart 層引入 Android/iOS 平臺特定的能力,來提升 App 的功能體驗。 使用 Flutter 從頭開始寫一個 App,是一件輕松愜意的事情。但,對于成熟產品來說,完全摒棄原有 App 的歷史沉淀,而全面轉向 Flutter 并不現實。用 Flutter 去統一 iOS/Android 技術棧,把它作為已有原生 App 的擴展能力,通過逐步試驗有序推進從而提升終端開發效率,可能才是現階段 Flutter 最具吸引力的地方。 那么,Flutter 工程與原生工程該如何組織管理?不同平臺的 Flutter 工程打包構建產物該如何抽取封裝?封裝后的產物該如何引入原生工程?原生工程又該如何使用封裝后的 Flutter 能力? 這些問題使得在已有原生 App 中接入 Flutter 看似并不是一件容易的事情。那接下來,我就和你介紹下如何在原生 App 中以最自然的方式接入 Flutter。 ## 準備工作 既然是要在原生應用中混編 Flutter,相信你一定已經準備好原生應用工程來實施今天的改造了。如果你還沒有準備好也沒關系,我會以一個最小化的示例和你演示這個改造過程。 首先,我們分別用 Xcode 與 Android Studio 快速建立一個只有首頁的基本工程,工程名分別為 iOSDemo 與 AndroidDemo。 這時,Android 工程就已經準備好了;而對于 iOS 工程來說,由于基本工程并不支持以組件化的方式管理項目,因此我們還需要多做一步,將其改造成使用 CocoaPods 管理的工程,也就是要在 iOSDemo 根目錄下創建一個只有基本信息的 Podfile 文件: ~~~ use_frameworks! platform :ios, '8.0' target 'iOSDemo' do #todo end ~~~ 然后,在命令行輸入 pod install 后,會自動生成一個 iOSDemo.xcworkspace 文件,這時我們就完成了 iOS 工程改造。 ## Flutter 混編方案介紹 如果你想要在已有的原生 App 里嵌入一些 Flutter 頁面,有兩個辦法: * 將原生工程作為 Flutter 工程的子工程,由 Flutter 統一管理。這種模式,就是統一管理模式。 * 將 Flutter 工程作為原生工程共用的子模塊,維持原有的原生工程管理方式不變。這種模式,就是三端分離模式。 :-: ![](https://img.kancloud.cn/43/95/43959076df5aadeb751dff0d7b1134e3_1304x326.png) 圖 1 Flutter 混編工程管理方式 由于 Flutter 早期提供的混編方式能力及相關資料有限,國內較早使用 Flutter 混合開發的團隊大多使用的是統一管理模式。但是,隨著功能迭代的深入,這種方案的弊端也隨之顯露,不僅三端(Android、iOS、Flutter)代碼耦合嚴重,相關工具鏈耗時也隨之大幅增長,導致開發效率降低。 所以,后續使用 Flutter 混合開發的團隊陸續按照三端代碼分離的模式來進行依賴治理,實現了 Flutter 工程的輕量級接入。 除了可以輕量級接入,三端代碼分離模式把 Flutter 模塊作為原生工程的子模塊,還可以快速實現 Flutter 功能的“熱插拔”,降低原生工程的改造成本。而 Flutter 工程通過 Android Studio 進行管理,無需打開原生工程,可直接進行 Dart 代碼和原生代碼的開發調試。 **三端工程分離模式的關鍵是抽離 Flutter 工程,將不同平臺的構建產物依照標準組件化的形式進行管理**,即 Android 使用 aar、iOS 使用 pod。換句話說,接下來介紹的混編方案會將 Flutter 模塊打包成 aar 和 pod,這樣原生工程就可以像引用其他第三方原生組件庫那樣快速接入 Flutter 了。 聽起來是不是很興奮?接下來,我們就開始正式采用三端分離模式來接入 Flutter 模塊吧。 ## 集成 Flutter 我曾在前面的文章中提到,Flutter 的工程結構比較特殊,包括 Flutter 工程和原生工程的目錄(即 iOS 和 Android 兩個目錄)。在這種情況下,原生工程就會依賴于 Flutter 相關的庫和資源,從而無法脫離父目錄進行獨立構建和運行。 原生工程對 Flutter 的依賴主要分為兩部分: * Flutter 庫和引擎,也就是 Flutter 的 Framework 庫和引擎庫; * Flutter 工程,也就是我們自己實現的 Flutter 模塊功能,主要包括 Flutter 工程 lib 目錄下的 Dart 代碼實現的這部分功能。 在已經有原生工程的情況下,我們需要在同級目錄創建 Flutter 模塊,構建 iOS 和 Android 各自的 Flutter 依賴庫。這也很好實現,Flutter 就為我們提供了這樣的命令。我們只需要在原生項目的同級目錄下,執行 Flutter 命令創建名為 Flutter\_library 的模塊即可: ~~~ Flutter create -t module Flutter_library ~~~ 這里的 Flutter 模塊,也是 Flutter 工程,我們用 Android Studio 打開它,其目錄如下圖所示: :-: ![](https://img.kancloud.cn/61/d3/61d3530bcf7a23e1708c536b53ced789_872x1268.png) 圖 2 Flutter 模塊工程結構 可以看到,和傳統的 Flutter 工程相比,Flutter 模塊工程也有內嵌的 Android 工程與 iOS 工程,因此我們可以像普通工程一樣使用 Android Studio 進行開發調試。 仔細查看可以發現,**Flutter 模塊有一個細微的變化**:Android 工程下多了一個 Flutter 目錄,這個目錄下的 build.gradle 配置就是我們構建 aar 的打包配置。這就是模塊工程既能像 Flutter 傳統工程一樣使用 Android Studio 開發調試,又能打包構建 aar 與 pod 的秘密。 實際上,iOS 工程的目錄結構也有細微變化,但這個差異并不影響打包構建,因此我就不再展開了。 然后,我們打開 main.dart 文件,將其邏輯更新為以下代碼邏輯,即一個寫著“Hello from Flutter”的全屏紅色的 Flutter Widget: ~~~ import 'package:flutter/material.dart'; import 'dart:ui'; void main() => runApp(_widgetForRoute(window.defaultRouteName));// 獨立運行傳入默認路由 Widget _widgetForRoute(String route) { switch (route) { default: return MaterialApp( home: Scaffold( backgroundColor: const Color(0xFFD63031),//ARGB 紅色 body: Center( child: Text( 'Hello from Flutter', // 顯示的文字 textDirection: TextDirection.ltr, style: TextStyle( fontSize: 20.0, color: Colors.blue, ), ), ), ), ); } } ~~~ 注意:我們創建的 Widget 實際上是包在一個 switch-case 語句中的。這是因為封裝的 Flutter 模塊一般會有多個頁面級 Widget,原生 App 代碼則會通過傳入路由標識字符串,告訴 Flutter 究竟應該返回何種 Widget。為了簡化案例,在這里我們忽略標識字符串,統一返回一個 MaterialApp。 接下來,我們要做的事情就是把這段代碼編譯打包,構建出對應的 Android 和 iOS 依賴庫,實現原生工程的接入。 現在,我們首先來看看 Android 工程如何接入。 ### Android 模塊集成 之前我們提到原生工程對 Flutter 的依賴主要分為兩部分,對應到 Android 平臺,這兩部分分別是: * Flutter 庫和引擎,也就是 icudtl.dat、libFlutter.so,還有一些 class 文件。這些文件都封裝在 Flutter.jar 中。 * Flutter 工程產物,主要包括應用程序數據段 isolate\_snapshot\_data、應用程序指令段 isolate\_snapshot\_instr、虛擬機數據段 vm\_snapshot\_data、虛擬機指令段 vm\_snapshot\_instr、資源文件 Flutter\_assets。 搞清楚 Flutter 工程的 Android 編譯產物之后,我們對 Android 的 Flutter 依賴抽取步驟如下: 首先在 Flutter\_library 的根目錄下,執行 aar 打包構建命令: ~~~ Flutter build apk --debug ~~~ 這條命令的作用是編譯工程產物,并將 Flutter.jar 和工程產物編譯結果封裝成一個 aar。你很快就會想到,如果是構建 release 產物,只需要把 debug 換成 release 就可以了。 **其次**,打包構建的 flutter-debug.aar 位于.android/Flutter/build/outputs/aar/ 目錄下,我們把它拷貝到原生 Android 工程 AndroidDemo 的 app/libs 目錄下,并在 App 的打包配置 build.gradle 中添加對它的依賴: ~~~ ... repositories { flatDir { dirs 'libs' // aar 目錄 } } android { ... compileOptions { sourceCompatibility 1.8 //Java 1.8 targetCompatibility 1.8 //Java 1.8 } ... } dependencies { ... implementation(name: 'flutter-debug', ext: 'aar')//Flutter 模塊 aar ... } ~~~ Sync 一下,Flutter 模塊就被添加到了 Android 項目中。 再次,我們試著改一下 MainActivity.java 的代碼,把它的 contentView 改成 Flutter 的 widget: ~~~ protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); View FlutterView = Flutter.createView(this, getLifecycle(), "defaultRoute"); // 傳入路由標識符 setContentView(FlutterView);// 用 FlutterView 替代 Activity 的 ContentView } ~~~ 最后點擊運行,可以看到一個寫著“Hello from Flutter”的全屏紅色的 Flutter Widget 就展示出來了。至此,我們完成了 Android 工程的接入。 :-: ![](https://img.kancloud.cn/36/48/3648bb9b0ec126fe07963d5e4cbede5b_1440x2560.png) 圖 3 Android 工程接入示例 ### iOS 模塊集成 iOS 工程接入的情況要稍微復雜一些。在 iOS 平臺,原生工程對 Flutter 的依賴分別是: * Flutter 庫和引擎,即 Flutter.framework; * Flutter 工程的產物,即 App.framework。 iOS 平臺的 Flutter 模塊抽取,實際上就是通過打包命令生成這兩個產物,并將它們封裝成一個 pod 供原生工程引用。 類似地,首先我們在 Flutter\_library 的根目錄下,執行 iOS 打包構建命令: ~~~ Flutter build ios --debug ~~~ 這條命令的作用是編譯 Flutter 工程生成兩個產物:Flutter.framework 和 App.framework。同樣,把 debug 換成 release 就可以構建 release 產物(當然,你還需要處理一下簽名問題)。 **其次**,在 iOSDemo 的根目錄下創建一個名為 FlutterEngine 的目錄,并把這兩個 framework 文件拷貝進去。iOS 的模塊化產物工作要比 Android 多一個步驟,因為我們需要把這兩個產物手動封裝成 pod。因此,我們還需要在該目錄下創建 FlutterEngine.podspec,即 Flutter 模塊的組件定義: ~~~ Pod::Spec.new do |s| s.name = 'FlutterEngine' s.version = '0.1.0' s.summary = 'XXXXXXX' s.description = <<-DESC TODO: Add long description of the pod here. DESC s.homepage = 'https://github.com/xx/FlutterEngine' s.license = { :type => 'MIT', :file => 'LICENSE' } s.author = { 'chenhang' => 'hangisnice@gmail.com' } s.source = { :git => "", :tag => "#{s.version}" } s.ios.deployment_target = '8.0' s.ios.vendored_frameworks = 'App.framework', 'Flutter.framework' end ~~~ pod lib lint 一下,Flutter 模塊組件就已經做好了。趁熱打鐵,我們再修改 Podfile 文件把它集成到 iOSDemo 工程中: ~~~ ... target 'iOSDemo' do pod 'FlutterEngine', :path => './' end ~~~ pod install 一下,Flutter 模塊就集成進 iOS 原生工程中了。 再次,我們試著修改一下 AppDelegate.m 的代碼,把 window 的 rootViewController 改成 FlutterViewController: ~~~ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];FlutterViewController *vc = [[FlutterViewController alloc]init];[vc setInitialRoute:@"defaultRoute"]; // 路由標識符self.window.rootViewController = vc;[self.window makeKeyAndVisible];return YES;} ~~~ 最后點擊運行,一個寫著“Hello from Flutter”的全屏紅色的 Flutter Widget 也展示出來了。至此,iOS 工程的接入我們也順利搞定了。 :-: ![](https://img.kancloud.cn/a5/11/a511d31edbbbf2949763af49453ac642_828x1792.png) 圖 4 iOS 工程接入示例 ## 總結 通過分離 Android、iOS 和 Flutter 三端工程,抽離 Flutter 庫和引擎及工程代碼為組件庫,以 Android 和 iOS 平臺最常見的 aar 和 pod 形式接入原生工程,我們就可以低成本地接入 Flutter 模塊,愉快地使用 Flutter 擴展原生 App 的邊界了。 但,我們還可以做得更好。 如果每次通過構建 Flutter 模塊工程,都是手動搬運 Flutter 編譯產物,那很容易就會因為工程管理混亂導致 Flutter 組件庫被覆蓋,從而引發難以排查的 Bug。而要解決此類問題的話,我們可以引入 CI 自動構建框架,把 Flutter 編譯產物構建自動化,原生工程通過接入不同版本的構建產物,實現更優雅的三端分離模式。 而關于自動化構建,我會在后面的文章中和你詳細介紹,這里就不再贅述了。 接下來,我們簡單回顧一下今天的內容。 原生工程混編 Flutter 的方式有兩種。一種是,將 Flutter 工程內嵌 Android 和 iOS 工程,由 Flutter 統一管理的集中模式;另一種是,將 Flutter 工程作為原生工程共用的子模塊,由原生工程各自管理的三端工程分離模式。目前,業界采用的基本都是第二種方式。 而對于三端工程分離模式最主要的則是抽離 Flutter 工程,將不同平臺的構建產物依照標準組件化的形式進行管理,即:針對 Android 平臺打包構建生成 aar,通過 build.gradle 進行依賴管理;針對 iOS 平臺打包構建生成 framework,將其封裝成獨立的 pod,并通過 podfile 進行依賴管理。 我把今天分享所涉及到的知識點打包到了 GitHub([flutter\_module\_page](https://github.com/cyndibaby905/28_module_page)、[iOS\_demo](https://github.com/cyndibaby905/28_iOSDemo)、[Android\_Demo](https://github.com/cyndibaby905/28_AndroidDemo))中,你可以下載下來,反復運行幾次,加深理解與記憶。 ## 思考題 最后,我給你下留一個思考題吧。 對于有資源依賴的 Flutter 模塊工程而言,其打包構建的產物,以及抽離 Flutter 組件庫的過程會有什么不同嗎?
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看