一、前言:
目前混合开发属于主流,因为多数都在原来的项目上集成Flutter模块,除非新的项目用纯Flutter;
想要在已有的原生 App 里嵌入一些 Flutter 页面,有两个办法:
- 将原生工程作为 Flutter 工程的子工程,由 Flutter 统一管理。这种模式,就是统一管理模式。
-
将 Flutter 工程作为原生工程共用的子模块,维持原有的原生工程管理方式不变。这种模式,就是三端分离模式。
三端代码分离的模式来进行依赖治理,实现了 Flutter 工程的轻量级接入,三端代码分离模式把 Flutter 模块作为原生工程的子模块,还可以快速实现 Flutter 功能的“热插拔”,降低原生工程的改造成本。而 Flutter 工程通过 Android Studio 进行管理,无需打开原生工程,可直接进行 Dart 代码和原生代码的开发调试;
三端工程分离模式的关键是抽离 Flutter 工程,将不同平台的构建产物依照标准组件化的形式进行管理,即 Android 使用 aar、iOS 使用 pod。换句话说,接下来介绍的混编方案会将 Flutter 模块打包成 aar 和 pod,这样原生工程就可以像引用其他第三方原生组件库那样快速接入 Flutter 了
二、集成(以iOS为例),使用Pods方式
官方给出了三种接入方案,这三种方案各有优缺点,我们先简单看看这三种方案:
- 使用 CocoaPods 和 Flutter SDK 集成:ios项目中用CocoaPods直接接入管理flutter module。这种方案需要所有开发人员都配置flutter环境,且安装CocoaPods;优点是通过CocoaPods自动集成,配置简单。
- 在 Xcode 中集成 frameworks:将flutter module先build成FrameWork文件,然后在ios项目中引入文件。这种方案的优点是ios开发人员不需要flutter环境,且项目不需要安装CocoaPods;缺点是每次修改都需要重新build,重新导入。
- 通过CocoaPods打包Framework:与2类似,只不过在build时加入--cocoapods参数:flutter build ios-framework --cocoapods --xcframework --no-universal --output=some/path/MyApp/Flutter/。打包出来的是Flutter.podspec 文件,ios项目中通过CocoaPods管理集成。这个方案的与2方案差不多,缺点也是每次改动需要重新build,优点是ios开发人员不需要flutter环境。
所以要根据自身的情况来选择符合自己的方案。官方推荐第一种方案,我也先尝试了第一个方案
若新建pod工程,执行pod init可能遇到报错
[报错 /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)
解决方案修改如下
在原生工程中,需要在同级目录创建 Flutter 模块,构建 iOS 的 Flutter 依赖库,Flutter 提供了这样的命令, 在原生项目的同级目录下,执行 Flutter 命令创建名为 flutter_library 的模块即可
flutter create -t module flutter_library
这里的 Flutter 模块,也是 Flutter 工程,我们用 Android Studio或vs code 打开它,其目录如下图所示:
打开 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,
),
),
),
),
);
}
}
接下来,我们要做的事情就是把这段代码编译打包,构建出对应的 Android 和 iOS 依赖库,实现原生工程的接入;
原生项目打开Podfile,加入Flutter,如下
// my_flutter 是创建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版本,执行pod update会报错如下
解决办法:
在 podfile文件最后添加
post_install do |installer|
flutter_post_install(installer) if defined?(flutter_post_install)
end
在 iOS 平台,原生工程对 Flutter 的依赖分别是:
- Flutter 库和引擎,即 Flutter.framework;
- Flutter 工程的产物,即 App.framework
iOS 平台的 Flutter 模块抽取,实际上就是通过打包命令生成这两个产物,并将它们封装成一个 pod 供原生工程引用
在 Flutter_library 的根目录下,执行 iOS 打包构建命令
Flutter build ios --debug
这条命令的作用是编译 Flutter 工程生成两个产物:Flutter.framework 和 App.framework
这里就会出现签名问题。执行上面命令后会报错
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的时候选择不签名,命令如下:
flutter build ios --no-codesign
然后在原生项目下 执行 pod install 如果以上不报错,混合开发模式到这里就集成完了
然后编译工程报错如下:
iOS Xcode 15 Sandbox: rsync(xxxx) deny(1) file-write-create
解决方案:
设置里面搜索user 把User Script Sanboxing 改为NO
然后修改原生代码,启动 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];
}
注:确保引擎启动完毕后,再调用FlutterViewController,否则flutter页面展示失败;
最后点击运行,一个写着“Hello from Flutter”的全屏红色的 Flutter Widget 也展示出来了。至此,iOS 工程的接入我们也顺利搞定了
参考文档
https://cloud.tencent.com/developer/article/1947233