iOS混编Flutter实战
准备工作
本文基于Android Stuido编写,使用VSCode的同学在命令面板上可以找到大部分对应的操作
技能基础
- Flutter(
Dart
) - iOS(
Objective-C
/Swift
)
Flutter环境搭建可以查看同目录下阿政的文章《Mac 配置 Flutter 环境》,或者Flutter中文网在MacOS上搭建Flutter开发环境
IDE
- Xcode
- Android Studio/VSCode
其他工具
- Flutter SDK,Android Studio需要
Dart
Flutter
插件 - Cocopoads
混编Flutter
-
创建Flutter Module
- 使用Android Studio选择New Flutter Project
- 使用命令行
flutter create --template module my_flutter
更多关于flutter create
命令可以使用 flutter create --help
查看,如下图:
在当前的工程目录下,可以执行flutter
的命令,比如flutter run --debug
或者 flutter build ios
,当然也可以使用Android Studio/IntelliJ 或者 VS Code。
Module的目录结构
my_flutter/
├── .ios/
│ ├── Runner.xcworkspace
│ └── Flutter/podhelper.rb
├── lib/
│ └── main.dart
├── test/
└── pubspec.yaml
在lib/
目录中编写你的Dart代码,在 my_flutter/pubspec.yaml
添加Flutter依赖,包括 Flutter packages 和 plugins。
ios的工程文件隐藏在.ios文件夹中
-
导入Flutter Module
在iOS原生工程中导入Flutter Module有三种方式
Plan A
使用Cocoapods和Flutter SDK集成
-
在
podfile
文件中添加下面代码:-
# 与原生项目在同级目录的情况下 flutter_application_path = '../my_flutter' load File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb'
-
-
在需要集成Flutter的
target
下,执行install_all_flutter_pods(flutter_application_path)
-
target 'MyApp' do install_all_flutter_pods(flutter_application_path) end
-
-
在
Podfile
的post_install
部分,调用flutter_post_install(installer)
-
post_install do |installer| flutter_post_install(installer) if defined?(flutter_post_install) end
-
-
运行
pod install
Plan B
在Xcode中集成frameworks。与选项3类似,只是需要手动管理添加到工程中,一般不推荐使用
-
创建 frameworks,下面的示例假设你想在
some/path/MyApp/Flutter/
目录下-
flutter build ios-framework --output=some/path/MyApp/Flutter/
-
-
链接到框架 可以将导出目录
some/path/MyApp/Flutter/Release/
拖到你的目标项目中,然后点击以下步骤build settings > Build Phases > Link Binary With Libraries
-
内嵌框架,将导出的框架拖到‘ build settings > Build Phases > Embed Frameworks。然后从下拉菜单中选择 “Embed & Sign”。
Plan C
使用Cocoapods在Xcode和Flutter框架中内嵌应用
-
生成
Flutter.podspec
和框架-
flutter build ios-framework --cocoapods --output=some/path/MyApp/Flutter/
-
-
在podfile中引用
-
pod 'Flutter', :podspec => 'some/path/MyApp/Flutter/[build mode]/Flutter.podspec'
-
这边采取的是使用在同级目录的方式,当然也可以使用git管理,相关操作不再赘述。
三种方式的优缺点
第一种方式的优势在于,开发期Flutter端修改了代码,直接在原生运行程序即能看到最新的效果,但是需要本地有Flutter环境(运行Flutter doctor
成功)。
后两种的方式不依赖于Flutter SDK,因为已经全部打包在了frameworks中,缺点就是麻烦,代码更新较慢,当然第二中的手动引入的方式一般是不推荐使用的。
当然可以根据各自的需要进行选择整合。
在Apple M系列芯片机器上运行模拟器
M系列芯片的产品由于是ARM架构,模拟器也是ARM架构,尽管Flutter已经支持arm64模拟器,但是部分插件可能尚未支持,如果运行报错类似Undefined symbols for architecture arm64的错误,请在模拟器上移除arm架构,操作如下:
原生端代码集成
在原生端集成Flutter的内容需要用到下面元素:
- FlutterEngine
- FlutterViewController
- FlutterMethodChannel、FlutterBasicMessageChannel、FlutterEventChannel
代码示例:
/// 在使用前
- (void)startEngine {
[self.flutterEngine run];
[GeneratedPluginRegistrant registerWithRegistry:self.flutterEngine];
/// 建立Native与Dart通信
[self registerMessageChannel];
}
/// Native与Dart通信
- (void)registerMessageChannel {
WeakifySelf();
[self.messageChannel setMessageHandler:^(id _Nullable message, FlutterReply _Nonnull callback) { /// 处理Navtive端接收到Dart通信 [weakSelf handleMessage:message callback:callback];
}];
}
/// Native向Flutter发送消息
- (void)sendMessage:(NSDictionary *)parameters call:(FlutterReply)callback {
[self.messageChannel sendMessage:parameters.mj_JSONString reply:callback];
}
/// kEBGlobalFlutterEngineName、kGlobalXAppMessageChannel为常量字符串
- (FlutterEngine *)flutterEngine {
if (!_flutterEngine) {
_flutterEngine = [[FlutterEngine alloc] initWithName:kEBGlobalFlutterEngineName];
}
return _flutterEngine;
}
- (FlutterBasicMessageChannel *)messageChannel {
if (!_messageChannel) {
_messageChannel = [FlutterBasicMessageChannel messageChannelWithName:kGlobalXAppMessageChannel binaryMessenger:self.flutterEngine.binaryMessenger codec:FlutterStringCodec.sharedInstance];
}
return _messageChannel;
}
转载自:https://juejin.cn/post/7251931932421767205