一、前言:
目前混合開(kāi)發(fā)屬于主流,因?yàn)槎鄶?shù)都在原來(lái)的項(xiàng)目上集成Flutter模塊,除非新的項(xiàng)目用純Flutter;
想要在已有的原生 App 里嵌入一些 Flutter 頁(yè)面,有兩個(gè)辦法:
- 將原生工程作為 Flutter 工程的子工程,由 Flutter 統(tǒng)一管理。這種模式,就是統(tǒng)一管理模式。
-
將 Flutter 工程作為原生工程共用的子模塊,維持原有的原生工程管理方式不變。這種模式,就是三端分離模式。
image.png
三端代碼分離的模式來(lái)進(jìn)行依賴治理,實(shí)現(xiàn)了 Flutter 工程的輕量級(jí)接入,三端代碼分離模式把 Flutter 模塊作為原生工程的子模塊,還可以快速實(shí)現(xiàn) Flutter 功能的“熱插拔”,降低原生工程的改造成本。而 Flutter 工程通過(guò) Android Studio 進(jìn)行管理,無(wú)需打開(kāi)原生工程,可直接進(jìn)行 Dart 代碼和原生代碼的開(kāi)發(fā)調(diào)試;
三端工程分離模式的關(guān)鍵是抽離 Flutter 工程,將不同平臺(tái)的構(gòu)建產(chǎn)物依照標(biāo)準(zhǔn)組件化的形式進(jìn)行管理,即 Android 使用 aar、iOS 使用 pod。換句話說(shuō),接下來(lái)介紹的混編方案會(huì)將 Flutter 模塊打包成 aar 和 pod,這樣原生工程就可以像引用其他第三方原生組件庫(kù)那樣快速接入 Flutter 了
二、集成(以iOS為例),使用Pods方式
官方給出了三種接入方案,這三種方案各有優(yōu)缺點(diǎn),我們先簡(jiǎn)單看看這三種方案:
- 使用 CocoaPods 和 Flutter SDK 集成:ios項(xiàng)目中用CocoaPods直接接入管理flutter module。這種方案需要所有開(kāi)發(fā)人員都配置flutter環(huán)境,且安裝CocoaPods;優(yōu)點(diǎn)是通過(guò)CocoaPods自動(dòng)集成,配置簡(jiǎn)單。
- 在 Xcode 中集成 frameworks:將flutter module先build成FrameWork文件,然后在ios項(xiàng)目中引入文件。這種方案的優(yōu)點(diǎn)是ios開(kāi)發(fā)人員不需要flutter環(huán)境,且項(xiàng)目不需要安裝CocoaPods;缺點(diǎn)是每次修改都需要重新build,重新導(dǎo)入。
- 通過(guò)CocoaPods打包Framework:與2類似,只不過(guò)在build時(shí)加入--cocoapods參數(shù):flutter build ios-framework --cocoapods --xcframework --no-universal --output=some/path/MyApp/Flutter/。打包出來(lái)的是Flutter.podspec 文件,ios項(xiàng)目中通過(guò)CocoaPods管理集成。這個(gè)方案的與2方案差不多,缺點(diǎn)也是每次改動(dòng)需要重新build,優(yōu)點(diǎn)是ios開(kāi)發(fā)人員不需要flutter環(huán)境。
所以要根據(jù)自身的情況來(lái)選擇符合自己的方案。官方推薦第一種方案,我也先嘗試了第一個(gè)方案
若新建pod工程,執(zhí)行pod init可能遇到報(bào)錯(cuò)
[報(bào)錯(cuò) /Library/Ruby/Gems/2.6.0/gems/cocoapods-1.11.3/lib/cocoapods/user_interface/error_report.rb:34:in `force_encoding': can't modify frozen String (FrozenError)](https://www.cnblogs.com/ZhangShengjie/p/17902473.html)
解決方案修改如下

在原生工程中,需要在同級(jí)目錄創(chuàng)建 Flutter 模塊,構(gòu)建 iOS 的 Flutter 依賴庫(kù),Flutter 提供了這樣的命令, 在原生項(xiàng)目的同級(jí)目錄下,執(zhí)行 Flutter 命令創(chuàng)建名為 flutter_library 的模塊即可
flutter create -t module flutter_library
這里的 Flutter 模塊,也是 Flutter 工程,我們用 Android Studio或vs code 打開(kāi)它,其目錄如下圖所示:

打開(kāi) main.dart 文件,將其邏輯更新為以下代碼邏輯,即一個(gè)寫(xiě)著“Hello from Flutter”的全屏紅色的 Flutter Widget:
import 'package:flutter/material.dart';
import 'dart:ui';
void main() => runApp(_widgetForRoute(window.defaultRouteName));//獨(dú)立運(yùn)行傳入默認(rèn)路由
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,
),
),
),
),
);
}
}
接下來(lái),我們要做的事情就是把這段代碼編譯打包,構(gòu)建出對(duì)應(yīng)的 Android 和 iOS 依賴庫(kù),實(shí)現(xiàn)原生工程的接入;
原生項(xiàng)目打開(kāi)Podfile,加入Flutter,如下
// my_flutter 是創(chuàng)建Flutter的模塊名稱
flutter_application_path = '../my_flutter'
load File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')
platform :ios, '9.0'
target 'NativeIOS' do
use_frameworks!
/// 這邊引入
install_all_flutter_pods(flutter_application_path)
/// 其他
...
end
如果flutter sdk使用的是最新3.x版本,執(zhí)行pod update會(huì)報(bào)錯(cuò)如下

解決辦法:
在 podfile文件最后添加
post_install do |installer|
flutter_post_install(installer) if defined?(flutter_post_install)
end
在 iOS 平臺(tái),原生工程對(duì) Flutter 的依賴分別是:
- Flutter 庫(kù)和引擎,即 Flutter.framework;
- Flutter 工程的產(chǎn)物,即 App.framework
iOS 平臺(tái)的 Flutter 模塊抽取,實(shí)際上就是通過(guò)打包命令生成這兩個(gè)產(chǎn)物,并將它們封裝成一個(gè) pod 供原生工程引用
在 Flutter_library 的根目錄下,執(zhí)行 iOS 打包構(gòu)建命令
Flutter build ios --debug
這條命令的作用是編譯 Flutter 工程生成兩個(gè)產(chǎn)物:Flutter.framework 和 App.framework
這里就會(huì)出現(xiàn)簽名問(wèn)題。執(zhí)行上面命令后會(huì)報(bào)錯(cuò)
No valid code signing certificates were found
You can connect to your Apple Developer account by signing in with your Apple ID
in Xcode and create an iOS Development Certificate as well as a Provisioning
Profile for your project by:
1- Open the Flutter project's Xcode target with
open iOS/Runner.xcworkspace
2- Select the 'Runner' project in the navigator then the 'Runner' target
in the project settings
3- Make sure a 'Development Team' is selected. - For Xcode 10, look under General > Signing > Team. - For Xcode 11 and newer, look under Signing & Capabilities > Team.
You may need to:
- Log in with your Apple ID in Xcode first
- Ensure you have a valid unique Bundle ID
- Register your device with your Apple Developer Account
- Let Xcode automatically provision a profile for your app
4- Build or run your project again
5- Trust your newly created Development Certificate on your iOS device
via Settings > General > Device Management > [your new certificate] > Trust
For more information, please visit: https://developer.apple.com/library/content/documentation/IDEs/Conceptual/ AppDistributionGuide/MaintainingCertificates/MaintainingCertificates.html
Or run on an iOS simulator without code signing
可以在build的時(shí)候選擇不簽名,命令如下:
flutter build ios --no-codesign
然后在原生項(xiàng)目下 執(zhí)行 pod install 如果以上不報(bào)錯(cuò),混合開(kāi)發(fā)模式到這里就集成完了
然后編譯工程報(bào)錯(cuò)如下:
iOS Xcode 15 Sandbox: rsync(xxxx) deny(1) file-write-create

解決方案:
設(shè)置里面搜索user 把User Script Sanboxing 改為NO

然后修改原生代碼,啟動(dòng) FlutterEngine 和 FlutterViewController
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.flutterEngine = [[FlutterEngine alloc] initWithName:@"my flutter engine"];
[self.flutterEngine run];
[GeneratedPluginRegistrant registerWithRegistry:self.flutterEngine];
return YES;
}
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
FlutterViewController *flutterViewController =
[[FlutterViewController alloc] initWithEngine:appDelegate.flutterEngine nibName:nil bundle:nil];
flutterViewController.modalPresentationStyle = UIModalPresentationFullScreen;
[self presentViewController:flutterViewController animated:YES completion:nil];
}
注:確保引擎啟動(dòng)完畢后,再調(diào)用FlutterViewController,否則flutter頁(yè)面展示失??;
最后點(diǎn)擊運(yùn)行,一個(gè)寫(xiě)著“Hello from Flutter”的全屏紅色的 Flutter Widget 也展示出來(lái)了。至此,iOS 工程的接入我們也順利搞定了

參考文檔
https://cloud.tencent.com/developer/article/1947233
