关于Flutter组件你知多少
背景
Flutter已经是大势所趋。 在这里我将不详细介绍Flutter与原生版本的各种比较以及优缺点。 毕竟,我只是一个初学者,只有我使用的感受和总结才是最直接的,对吧? 因此,我们不妨尝试这种以学习态度代表未来的跨终端解决方案。
那么,既然要尝试,肯定不能all in,毕竟大家的老项目要是一把推翻重来,这种风险谁都扛不住的,包括阿里、腾讯这种大厂。而新项目又一般都会很赶时间,不允许我们去慢慢踩坑。当然如果公司有一些小项目,周期又不是很赶的,个人认为是可以拿Flutter练练手的,当然前提是你们的领导也对前沿技术感兴趣,敢于放手让你们去玩。那么排除以上几点情况,我们大多数的应用场景还是想在现有项目中,在一些深层的页面尝试混编,所以业界一般也还是采用这种混编方案,据我了解,包括闲鱼、哈罗、美团等大厂,从他们的分享资料来看,确实也还只是在尝试阶段,在部分功能采取了混编的方案,这样一来,对新技术有探索,对现有功能影响也不大。
好了,以上讲了那么多,下面来分享一下这两天,我搜遍百度、google各种大大小小文章,踩了各种奇奇怪怪、莫名其妙的坑,最后终于集齐七颗龙珠,召唤神龙的故事。🤣🤣🤣
Flutter集成进现有原生应用,Flutter官方提供了3种方案:
方案1:用Flutter官方已经为我们写好的脚本,简单实现集成,我照着尝试了一遍,很方便,但有一个很明显的缺点,需要组内人员都具备Flutter环境。而我们想要的是,组内其他成员无感集成。
方案2:适用于没有使用cocoapods的团队,完全手动集成,手动修改framework的相关属性。但国内,大多数团队还是用的cocoapods,所以适用这一条的也不多。
方案3:使用cocoapods集成,但是用的是本地仓库,并不友好,很难进行版本控制。
综上所述,如果你想自己玩,参考Flutter官方的方案即可,但是如果想要团队开发,并且实现团队内部其他成员无感开发,我们就需要利用一下cocoapods的私有库了。接下来我们进行实战,同时也附带一些原理解析或者注意事项。
实战
一、创建Flutter module
首先第一步,创建Flutter module(这里请注意,是module,而不是工程,我最最开始的时候没注意,用工程试了半天,导致我找不到我们后面需要的framework)
cd到自己的目录,输入flutter create --template module my_flutter(my_flutter是module名,你可以自己取)
cd some/path/
flutter create --template module my_flutter
创建完flutter module,我们可以用VSCode或者Android Studio运行起来看看,因为Flutter自带demo,不像iOS一进来是空白页面。
二、生成framework
从flutter的集成原理上来说,我们其实只需要几个文件。
最简单的来说,有以上几个文件我们团队其他成员就可以集成Flutter了。这两个文件的生成也很简单,用命令“flutter build ios”即可,生成的framework在你创建的Flutter工程的一个隐藏文件夹(.ios)里面。
初期验证,我们只需要这几个文件,当然这几个文件我们需要把它copy出来放到pod仓库指定目录,这里我们可以用脚本完成。想参考的同学可以拿去用,build_path自己修改,后面私有pod库建完之后,可以直接填写pod库的路径。release版本还是debug版本自己选择,debug用于模拟器调试,release用于真机调试或者打包。
#!/bin/sh
#终端输入 echo $PATH 查看PATH路径
# chmod 755 build.sh 获取权限
#PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
#export PATH
export LC_ALL=en_US.UTF-8
export LANG=en_US.UTF-8
echo "Clean old build"
find . -d -name "build" | xargs rm -rf
#flutter clean
echo "开始获取 packages 插件资源"
flutter packages get
echo "开始构建 release for ios"
flutter build ios --debug
echo "构建 release 已完成"
echo "开始 处理framework和资源文件"
build_path="../FlutterMixDemo/build_flutter_ios"
if [ -d ${build_path} ]; then
find ${build_path} -name \*.framework | xargs rm -rf
#find ${build_path} -name \*.h | xargs rm -rf
#find ${build_path} -name \*.m | xargs rm -rf
else
mkdir ${build_path}
fi
#cp -r build/ios/Release-iphoneos/*/*.framework ${build_path}
cp -r .ios/Flutter/App.framework ${build_path}
cp -r .ios/Flutter/engine/Flutter.framework ${build_path}
cp -r .ios/Flutter/FlutterPluginRegistrant/Classes/GeneratedPluginRegistrant.* ${build_path}
# cd ../FlutterMixDemo
# pod install
echo done
三、创建Pod私有库
我们后期是需要把Flutter module放进Pod私有库内,让组内成员一键集成的,所以我们要把Pod私有库创建起来,当然,这一Part你要是已经会了可以跳过。我这里做一个完整版的整合。
参考pod官方文档,注意它的第一步,唉,我这种粗心的人就是这样踩坑的。
请注意,是spec仓库,而不是我们的源码仓库,这是私有库和开源库的区别,私有库需要我们自己去管理Spec仓库。
下面的步骤就简单了,按照官方文档操作。这里建议把源码仓库放在gitlab上,不要放在github上(虽然github已经免费私有库),因为后面的pod repo push或者pod install的速度会让你昏死过去。我已经浪费了很多宝贵的时间,希望你们不要重蹈我的覆辙。
第一步,创建私有库,pod lib create REPO_NAME,用来放我们的Flutter库
第二步,创建spec库,用来放我们的podspec文件
第三步,pod repo add REPO_NAME SOURCE_URL(REPO_NAME:库的名字,SOURCE_URL:spec库的地址,以.git结尾),举例:pod repo add flutterspec http://192.168.100.4/zsy/flutterspec.git
第四步,查看~/.cocoapods/repos/,应该多了一个刚刚添加的仓库,但应该只是一个空的文件夹,我们把远程spec库链接上这里,库需要提交一下,类似于提交一个README那种,初始化一下。
第五步,回到我们的源码库,先pod repo lint --allow-warnings检查一下,然后pod repo push REPO_NAME SPEC_NAME.podspec,把我们的podspec文件push到我们的私有库,成功之后回到我们的~/.cocoapods/repos/,就可以看到那个空文件夹有了具体的版本库。
好,私有库创建完成。
四、一键导入
platform :ios, '11.0'
source 'http://192.168.100.4/zsy/flutterspec.git'
target 'FlutterIOS' do
# Comment the next line if you don't want to use dynamic frameworks
use_frameworks!
# Pods for FlutterIOS
pod 'flutter_test_sdk', '0.1.4'
end
这里要注意的是,因为是私有库,所以我们pod文件需要加一个source链接,就是我们的spec仓库链接,然后就是pod install。
回到我们demo工程里面,可以看到已经集成进来了。
至于如何使用,就很简单了,Flutter官方文档也很详细,我也是copy过来的。
先注册flutter引擎。
import UIKit
import flutter_test_sdk
@UIApplicationMain
class AppDelegate: FlutterAppDelegate {
lazy var flutterEngine = FlutterEngine(name: "my flutter engine")
override func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
flutterEngine.run()
GeneratedPluginRegistrant.register(with: self.flutterEngine)
self.window?.backgroundColor = UIColor.white
self.window?.rootViewController = ViewController()
self.window?.makeKeyAndVisible()
return true
}
}
在需要调用Flutter页面的地方呼出FlutterViewController。
import UIKit
import flutter_test_sdk
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let flutterEngine = (UIApplication.shared.delegate as! AppDelegate).flutterEngine
let flutterVC = FlutterViewController(engine: flutterEngine, nibName: nil, bundle: nil)
present(flutterVC, animated: true, completion: nil)
}
}
我们看一下demo效果。完美呼出Flutter页面。不过我们可以看到,我们dismiss之后,重新呼出,其实Flutter页面并不会初始化的,当然这些都是后话啦。
总结
组件化完成后,后面就是纯开发工作了,做Flutter的同学专心攻Flutter,做原生的同学不需要关心Flutter环境。当然这才是万里长征第一步,后面的踩坑之旅有待我慢慢继续记录😂😂😂。
作者:Nevermore_pig
来源:掘金