背景
我们公司一直用 Objective-C 语言来开发iOS的项目,最近提出要用跨平台混合语言flutter来研发新的功能,并计划逐步过渡到flutter项目。花了一整天的时间来研究flutter在Objective-C中的集成,现将探索过程分享如下:
参考Flutter官方文档
一、安装Flutter SDK
1、下载最新版的Flutter SDK
flutter_macos_2.2.3-stable.zip
2、将下载好的sdk解压到合适的目录
cd /Users/jim
unzip ~/Downloads/flutter_macos_2.2.3-stable.zip
3、添加flutter环境变量
3.1 在.zshrc中添加下面一行代码(我用的zsh)
export PATH="$PATH:[PATH_OF_FLUTTER_GIT_DIRECTORY]/bin"
3.2 验证是否添加成功
echo $PATH
3.3 查看 flutter 和 dart
$ which flutter dart
# 打印:
/path-to-flutter-sdk/bin/flutter
/path-to-flutter-sdk/bin/dart
如果你操作的结果如上所示,说明安装成功了!
二、iOS配置
1、到AppStore下载并安装最新版本的Xcode;
2、配置Xcode command-line tools,在终端运行如下命令:
sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer
sudo xcodebuild -runFirstLaunch
二、安装并配置开发工具Visual Studio Code
VS Code是一个轻量级的编辑器,支持Flutter app 的执行和调试。
1、安装
下载最新版本: Visual Studio Code 下载完成后,双击安装即可!
2、安装Flutter 和 Dart插件
- Start VS Code.
- Invoke View > Command Palette….
- Type “install”, and select Extensions: Install Extensions.
- Type “flutter” in the extensions search field, select Flutter in the list, and click Install. This also installs the required Dart plugin.
3、使用Flutter doctor验证配置是否成功
- Invoke View > Command Palette….
- Type “doctor”, and select the Flutter: Run Flutter Doctor.
- Review the output in the OUTPUT pane for any issues. Make sure to select Flutter from the dropdown in the different Output Options.
4、测试驱动
4.1 创建App
- Invoke View > Command Palette.
- Type “flutter”, and select the Flutter: New Application Project.
- Create or select the parent directory for the new project folder.
- Enter a project name, such as
myapp, and press Enter.- Wait for project creation to complete and the
main.dartfile to appear.·
4.2 运行App
4.2.1 查看VS Code底部的状态栏:
4.2.2 选择设备
从Device Selector区域,选择一个设备,如果设备不存在,就点击No Devices来创建一个模拟器。
4.2.3 运行
Invoke Run > Start Debugging or press
F5.
三、原生Objective-C项目集成Flutter
Flutter可以作为嵌入式框架增量地添加到现有的iOS应用程序中。
1、将开发好的 Flutter 项目放到与原生工程同级目录下;
some/path/
├── my_flutter/
│ └── .ios/
│ └── Flutter/
│ └── podhelper.rb
└── MyApp/
└── Podfile
2、Use the CocoaPods dependency manager and installed Flutter SDK
2.0 升级为最新版本的 CocoaPods
安装 rvm
RVM 是一个命令行工具,可以提供一个便捷的多版本 Ruby 环境的管理和切换。
$ gpg2 --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB
$ \curl -sSL https://get.rvm.io | bash -s stable
$ source ~/.bashrc
$ source ~/.bash_profile
修改 RVM 的 Ruby 安装源到 Ruby China 的 Ruby 镜像服务器,这样能提高安装速度
$ echo "ruby_url=https://cache.ruby-china.com/pub/ruby" > ~/.rvm/user/db
Ruby 的安装与切换
rvm list known # 列出已知的 Ruby 版本
rvm install 3.3.3 --disable-binary # 安装一个 Ruby 版本
rvm use 3.3.3 # 切换 Ruby 版本
rvm use 3.3.3 --default # 如果想设置为默认版本,这样一来以后新打开的控制台默认的 Ruby 就是这个版本
rvm list # 查询已经安装的 ruby
rvm remove 1.8.7 # 卸载一个已安装版本
CocoaPods 的安装与使用
sudo gem update --system
gem sources -l
gem sources --remove https://rubygems.org/
gem sources --add https://gems.ruby-china.com/
sudo gem install -n /usr/local/bin cocoapods
pod --version
pod setup
pod install
2.1、 在 Podfile中添加下面的代码:
flutter_application_path = '../my_flutter'
load File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')
2.2、 For each Podfile target that needs to embed Flutter, call install_all_flutter_pods(flutter_application_path).
platform :ios, '12.0'
inhibit_all_warnings!
target 'MyApp' do
install_all_flutter_pods(flutter_application_path)
end
post_install do |installer|
flutter_post_install(installer) if defined? (flutter_post_install)
end
2.3、 Run pod install.
2.4、 注意事项
flutter 的工作目录是在iOS 原生工程的同级目录下,可以通过 git 来管理 flutter 的版本,这样每次 flutter 开发的内容有更新直接 git pull --rebase origin master 就可以了,很方便。
每次 flutter 内容有更新的时候执行如下过程:
# 1、在 flutter 的目录下执行
flutter clean # 清除 flutter 工程,包括 build 好的 iOS 项目
flutter pub get # 更新下载依赖库
flutter build ios # 编译 iOS 的项目,也有用`flutter create .`命令的
# 2、在 iOS 的目录下执行
pod install
3、添加Flutter screen到iOS app
3.1 、创建一个FlutterEngine
In AppDelegate.h:
@import UIKit;
@import Flutter;
@interface AppDelegate : FlutterAppDelegate // More on the FlutterAppDelegate below.
@property (nonatomic,strong) FlutterEngine *flutterEngine;
@end
In AppDelegate.m:
// Used to connect plugins (only if you have plugins with iOS platform code).
#import <FlutterPluginRegistrant/GeneratedPluginRegistrant.h>
#import "AppDelegate.h"
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary<UIApplicationLaunchOptionsKey, id> *)launchOptions {
self.flutterEngine = [[FlutterEngine alloc] initWithName:@"my flutter engine"];
// Runs the default Dart entrypoint with a default Flutter route.
[self.flutterEngine run];
// Used to connect plugins (only if you have plugins with iOS platform code).
[GeneratedPluginRegistrant registerWithRegistry:self.flutterEngine];
return [super application:application didFinishLaunchingWithOptions:launchOptions];
}
@end
3.2 、使用FlutterEngine来展示一个FlutterViewController
@import Flutter;
#import "AppDelegate.h"
#import "ViewController.h"
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Make a button to call the showFlutter function when pressed.
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button addTarget:self
action:@selector(showFlutter)
forControlEvents:UIControlEventTouchUpInside];
[button setTitle:@"Show Flutter!" forState:UIControlStateNormal];
button.backgroundColor = UIColor.blueColor;
button.frame = CGRectMake(80.0, 210.0, 160.0, 40.0);
[self.view addSubview:button];
}
- (void)showFlutter {
FlutterEngine *flutterEngine =
((AppDelegate *)UIApplication.sharedApplication.delegate).flutterEngine;
FlutterViewController *flutterViewController =
[[FlutterViewController alloc] initWithEngine:flutterEngine nibName:nil bundle:nil];
[self presentViewController:flutterViewController animated:YES completion:nil];
}
@end
四、后续开发工作
当修改my_flutter/pubspec.yaml插件依赖的时候,需要在
Flutter module 目录下执行flutter pub get命令,用被podhelper.rb脚本来刷新插件列表,最后在原生项目目录下some/path/MyApp,执行pod install即可。
四、常见报错及解决办法
1、 如果发现项目报target of uri doesn't exist
此时直接在Android studio软件底部的terminal里运行flutter upgrade
2、flutter 基于oc的flutter项目使用基于swift的plugin导致报错问题?
3、flutter 中引用的 plugins 可能跟原工程定义的类有重复的
解决办法:删除原生工程里面的第三方类;
4、iOS14 系统一启动 App 就闪退
Due to low-level changes in iOS’s debugger mechanisms, developers using versions of Flutter earlier than 1.20.4 stable won’t be able to launch apps (by using
flutter runor a Flutter-enabled IDE) on physical iOS devices running iOS 14. This affects debug, profile, and release builds. Simulator builds, add-to-app modules, and running directly from Xcode are unaffected.Upgrading to Flutter 1.22 beta allows you to build, test, and deploy to iOS without issue. Upgrading to 1.20.4 stable allows you to build and deploy to iOS 14, but not debug.
翻译:
由于iOS调试器机制的低级变化,使用
1.20.4 stable之前版本的开发者将无法在运行iOS 14的物理iOS设备上启动应用(通过使用flutter run运行或Flutter-enabled IDE)。这将影响调试、profile和发布构建。模拟器构建、添加到应用程序的模块,以及直接从Xcode运行都不受影响。升级到
Flutter 1.22 beta版可以让你毫无问题地构建、测试和部署到iOS上。升级到1.20.4 stable允许你构建和部署到iOS 14,但不能调试。
解决: 将 scheme 改成 release 即可
5、页面白屏,报错[ERROR:flutter/shell/common/platform_view.cc(76)] Failed to create platform view rendering surface
这个报错发生在继承FlutterViewController的时候,子类里面不要出现ViewDidLoad相关的内容,移除该内容之后就正常了。
参考资料:
2、RVM实用指南