和之前一样,这个模块也是对于本地我们开发好的代码,需要到一起开发iOS的同事需要拉代码,调试的时候。这种静态包的方式就会好很多。不用在他的电脑上也搭建flutter环境,以及创建flutter项目的拉取调试等复杂的工作再做一遍。
综上所述,多人协作开发ios的项目,一人负责混合的flutter的module内容的,可以用到这种framework的形式会比较好。
但是他的弊端就是需要每次运行在项目中的时候需要负责混合开发的人员先运行一下flutter项目生成一些必要的framework。
这里我们来进行两种方式来操作我们的framework:
1.还是本地的项目生成之后将framework直接加入到项目中依赖使用
2.将framework通过cocoapods进行版本管理导入项目(就是将第一种作为一个git管理便捷多人开发的一种方式而已)
首先我们来说第一种:
1.1、 创建iOS项目
在电脑桌面Desktop创建外层文件夹 FlutterAddIOSOptionB,并在该文件下创建iOS工程iOSProject,依次执行以下命令
$ cd /Users/caoshixin/Desktop/FlutterAddIOSOptionB/MyApp
$ pod init
$ pod install
1.2. 接下来创建名字为‘ FlutteriOSPod’的Pod库
$ cd /Users/caoshixin/Desktop/FlutterAddIOSOptionB
$ pod lib create FlutteriOSPod
终端依次输入所需类型:
$ pod lib create FlutteriOSPod
Cloning `https://github.com/CocoaPods/pod-template.git` into `FlutteriOSPod`.
Configuring FlutteriOSPod template.
------------------------------
To get you started we need to ask a few questions, this should only take a minute.
What platform do you want to use?? [ iOS / macOS ]
> iOS
What language do you want to use?? [ Swift / ObjC ]
> Swift
Would you like to include a demo application with your library? [ Yes / No ]
> No
Which testing frameworks will you use? [ Specta / Kiwi / None ]
> None
Would you like to do view based testing? [ Yes / No ]
> No
Running pod install on your new library.
创建完成之后会有一个工程自动打开,此工程为Pod工程,在Example->FlutteriOSPod.xcworkspace打开后可以作为独立项目在此编码iOS代码之类的,暂时先不在此进行编写原生代码,关闭退出。
当前项目目录构造:
1.3. 在FlutteriOSPod目录下创建 Flutter Module模块
$ cd /Users/caoshixin/Desktop/FlutterAddIOSOptionB/FlutteriOSPod
$ flutter create -t module flutter_module_for_ios
命令执行完后,目录文件夹下会多出一个名为flutter_module_for_ios的flutter模板项目
该项目模板包含有flutter代码模块+隐藏.ios文件。同时选中三个键可以使隐藏文件显示
command + shift + .
在当前flutter_module_for_ios文件lib中可以编码flutter相关代码,考虑到可能会在flutter项目中使用到相关插件,我们可以在pubspec.yaml中添加一个插件(如果有项目的话就可以使用自己的项目,这里只是模拟一个flutter项目开发,在文中下面我用的是现有的项目)
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^0.1.2
#添加 数据持久化插件 https://pub.flutter-io.cn/packages/shared_preferences
shared_preferences: ^0.5.4+3
1.4、在flutter_module_for_ios项目中执行安装插件操作
$ cd /Users/caoshixin/Desktop/FlutterAddIOSOptionB/FlutteriOSPod/flutter_module_for_ios/
$ flutter pub get
可以看到在.ios文件夹下自动生成出来一个Podfile文件.(这里图中的.lock、Pods文件、.xcworkspace都是下面编译后的产物。这里我就偷懒直接用这个图了。看到这点不同不要惊讶呦)
1.5、执行编译该flutter_module_for_ios项目
编译后会生成Flutter所依赖的相关的库文件。我们在当前先编译出debug版本的库文件方便我们后续调试
$ flutter build ios --debug //编译debug产物
或者
$ flutter build ios --release --no-codesign //编译release产物(选择不需要证书)
观察项目中的变化,可发现有多出编译产物(这些就是flutter中编译出的静态包,引用库不同这里的包也会不同,不要惊讶。这里主要是看位置)(这里的Debug-iphonesimulator文件是在flutter项目下运行flutter run -d all运行在iphone模拟器下生成的,而Release-iphones文件是上一步编译release的产物)
我们所需要的就是这些生成出来的framework库
build目录下
ios->Debug-iphoneos-> FlutterPluginRegistrant.framework
ios->Debug-iphoneos-> 。。。(你项目中的使用第三方).framework
.ios目录下
Flutter-->App.framework Flutter-->engine-->Flutter.framework
当前生成的库都是debug版本库文件。 需要注意的是,后续若想编译出release版本的framework库,修改下面的脚本文件根据注释提示修改。因为在build生成产物之前会先重置文件为初始状态
接下来iOS工程通过Pod把这些库引入到自己的工程中了。为了方便集中快速管理操作我们可以通过创建脚本的方式对其进行管理(思路就是通过脚本创建一个文件夹,将这些散乱在各文件的库统一拷贝进来)
2.1、在flutter_module_for_ios下创建脚本文件
$ cd ../flutter_module_for_ios
$ touch move_file_debug.sh //1. 创建生成debug模式的脚本文件
$ open move_file_debug.sh //2. 打开debug模式的脚本文件
//同样下面的内容修改处做下改动,生成另外一个脚本move_file_release.sh来做release版本生成
添加以下脚本代码
if [ -z $out ]; then
out='ios_frameworks'
fi
echo "准备输出所有文件到目录: $out"
echo "清除所有已编译文件"
find . -d -name build | xargs rm -rf
flutter clean
rm -rf $out
rm -rf build
flutter packages get
addFlag(){
cat .ios/Podfile > tmp1.txt
echo "use_frameworks!" >> tmp2.txt
cat tmp1.txt >> tmp2.txt
cat tmp2.txt > .ios/Podfile
rm tmp1.txt tmp2.txt
}
echo "检查 .ios/Podfile文件状态"
a=$(cat .ios/Podfile)
if [[ $a == use* ]]; then
echo '已经添加use_frameworks, 不再添加'
else
echo '未添加use_frameworks,准备添加'
addFlag
echo "添加use_frameworks 完成"
fi
echo "编译flutter"
flutter build ios --debug
#release下放开下一行注释,注释掉上一行代码
#flutter build ios --release --no-codesign
echo "编译flutter完成"
mkdir $out
cp -r build/ios/Debug-iphoneos/*/*.framework $out
#release下放开下一行注释,注释掉上一行代码
#cp -r build/ios/Release-iphoneos/*/*.framework $out
cp -r .ios/Flutter/App.framework $out
cp -r .ios/Flutter/engine/Flutter.framework $out
echo "复制framework库到临时文件夹: $out"
libpath='../'
rm -rf "$libpath/ios_frameworks"
mkdir $libpath
cp -r $out $libpath
echo "复制库文件到: $libpath"
注意观察脚本文件中的代码意思:将编译生成的debug版本的所需.framework库文件拷贝至ios_frameworks文件下并复制一份到FlutteriOSPod目录下,后续若想编译生成release版本库文件时还需修改脚本文件查找对应上release标识
2.2、执行脚本文件
$ sh move_file_debug(release).sh //3. 执行脚本文件
此时的ios_frameworks文件已经生成拷贝
里面包含有我们前面提到所需要的.framework所有库文件
接下来我们就要通过FlutteriOSPod库的podspec来创建依赖导出
3.1、编辑podspec文件
打开podspec文件在end前一行添加以下命令
s.static_framework = true
p = Dir::open("ios_frameworks")
arr = Array.new
arr.push('ios_frameworks/*.framework')
s.ios.vendored_frameworks = arr
添加之后文件整体长这样
3.2、在iOSProject项目的podfile文件中执行pod引用
在iOSProject工程下的podfile文件中添加
# Uncomment the next line to define a global platform for your project
platform :ios, '10.0'
source 'https://github.com/CocoaPods/Specs.git'
target 'MyApp' do
# Comment the next line if you don't want to use dynamic frameworks
use_frameworks!
pod 'Alamofire'
pod 'SnapKit'
#flutter
pod 'FlutteriOSPod', :path => '../FlutteriOSPod'
end
之后执行
$ pod install
终端提示安装FlutteriOSPod库成功
其中FlutteriOSPod库里就包含有我们所需的上述提到的framework库
OK下面我们来试一下如何在iOS项目中跳转进flutter界面,也就是我们提到的混合开发的代码测试,基本上也就是按照官方提供的模板写
4.1、AppDelegate.swift中修改
//
// AppDelegate.swift
// MyApp
//
// Created by 曹世鑫 on 2020/3/4.
// Copyright © 2020 曹世鑫. All rights reserved.
//
import UIKit
import FlutterPluginRegistrant
import Flutter
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
lazy var flutterEngine = FlutterEngine(name: "com.brainco.gameEngine")
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
self.window?.rootViewController = UINavigationController.init(rootViewController: ViewController())
self.window?.backgroundColor = .white
self.window?.makeKeyAndVisible()
initEngine()
return true
}
private func initEngine() {
flutterEngine.run();
GeneratedPluginRegistrant.register(with: flutterEngine);
}
}
4.2、ViewController.swift
//
// ViewController.swift
// MyApp
//
// Created by 曹世鑫 on 2020/3/4.
// Copyright © 2020 曹世鑫. All rights reserved.
//
import UIKit
import Flutter
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
self.title = "原生页面"
let btn: UIButton = UIButton()
btn.backgroundColor = .cyan
btn.frame = CGRect(x: 50, y: 100, width: 100, height: 50)
btn.addTarget(self, action: #selector(btnChoose), for: .touchUpInside)
self.view.addSubview(btn);
}
@objc func btnChoose() {
let flutterEngine = (UIApplication.shared.delegate as! AppDelegate).flutterEngine
let flutterViewController = FlutterViewController.init(engine: flutterEngine, nibName: nil, bundle: nil)
// self.navigationController?.pushViewController(flutterViewController, animated: true)
present(flutterViewController, animated: true, completion: {
print("结果如下")
})
}
}
集成代码较官方方式有部分不同,这里没有通过 lazy var flutterEngine = FlutterEngine(name: "com.brainco.gameEngine") 这种方式去初始化引擎,是因为FlutterViewContorller在new的时候会自动的创建一个引擎。而通过官方的方式去初始化引擎则需将该引擎设置成一个全局单例去使用
至此。第一种形式的pod本地化引入工程就已经完成。但是我们发现一个问题那就是目前感觉好像还是没有能完全剥离一台电脑上没有flutter环境配置的情况下如何去引入flutter.framework等库文件,难道要手动拷贝么,这样也不是很符合开发的初衷,接下来我会给大家介绍一下如何将创建好的私有库上传至git去托管,然后其他开发同学直接通过Git命令去引入包,这样也就从根源上解决了模块化的剥离,更为干净利落
这里项目中由于我们的代码管理是在github上面,这里我就以github来添加一个处理。至于其他的平台代码管理的话可以参考我之前写的一系列组件库的搭建,已经很详细(这里就不再赘述了)快捷传送门点这里
下面我们就开始github提交库索引。(其实github只是省了一步索引库的创建,弊端就是,git的网络不太稳定,使用git的索引库有点烦网络问题。)
1.1、远程创建仓库FlutteriOSPod
1.2、在FlutteriOSPod项目中与远端建立连接(这里我链接远端之后后面提交不上,使用的是将远端库glone到本地这个文件,将之前的这个pod文件里面的文件全部移过来了)(可以不使用下面的这个git代码,这里主要是要为了将后面我们的代码以及tag能够做到提交远端处理)
$ cd ../FlutteriOSPod
$ git remote add origin https:。。。(你的仓库地址).git
为了防止上传文件过大的限制,可以选择在.gitignore文件中选择不上传flutter_module_for_ios代码,只将ios_frameworks文件中的库文件上传就好
1.2.1、gitignore文件
$ git add .
$ git commit -m "Initial data commit"
$ git push -u origin master
将我们的代码以及tag添加提交到托管平台。
1.3、修改FlutteriOSPod.podspec文件(下面的图片仅供参考,主要是一些信息必须是自己的)
需要注意的地方时你自己创建的gitlab地址与管理员邮箱及tag版本一一对应上
将此修改的文件推至远端仓库并打上tag推送至远端
$ git status
$ git add MyFlutterPod.podspec
$ git commit -m "修改文件"
$ git push origin master
// 给当前代码设置tag版本
$ git tag -a 0.0.1 -m 'Initial tag commit'
$ git push --tags
1.4、验证一下Pod库文件是否可行
$ pod spec lint MyFlutterPod.podspec --verbose
验证通过之后
1.4.1、接下来就是将我们的FlutteriOSPod.podspec索引文件推送至github索引库(这里我的是私有库就不需要了,直接进行1.5的验证就可以了)
1>发布时会验证 Pod 的有效性,如果你在手动验证 Pod 时使用了 --use-libraries 或 --allow-warnings 等修饰符,那么发布的时候也应该使用相同的字段修饰,否则出现相同的报错。
// --use-libraries --allow-warnings
pod trunk push FlutteriOSPod.podspec
如果是公有库还需要发布到cocoaPods trunk上。私有库就不用了。如果私有库发布到trunk上会报错。
[!] Source code for your Pod was not accessible to CocoaPods Trunk. Is it a private repo or behind a username/password on http?
2>等待......................................
3>最后进行验证
在trunk push后,先用"pod search"查找一下你的代码,有结果的话就欢天喜地;
没有的话执行"pod setup"进行本地依赖库更新,再search。
这里github的上传参考我的另一篇文章文章:创建GitHub私有库,制作CocoaPods依赖库
1.5、在MyApp文件中进行添加代码
如果在此之前做过本地化加载pod库,要先卸载掉之前安装过的文件 --1 注释掉podfile文件中的代码 pod 'FlutteriOSPod', :path => '../FlutteriOSPod' --2执行一下 pod install 可以看到之前安装过得库已经从项目中移除
修改podfile文件
# Uncomment the next line to define a global platform for your project
platform :ios, '8.0'
target 'iOSProject' do
# Comment the next line if you don't want to use dynamic frameworks
use_frameworks!
# Pods for iOSProject
# pod 'FlutteriOSPod', :path => '../FlutteriOSPod'
pod 'FlutteriOSPod',:git=>'https:...(对应的git地址).git',:tag=>'0.0.1'
end
安装过程可能会比较慢,这跟网络有关
(扩展延伸)
pod指定路径下载第三方库 pod 版本库名, :git => 版本库地址 pod 'xxx' , :git => 'https://github.com/xxx/xxx_ios.git' 如果下载下来发现缺少了文件,应该是未指定版本号,使用pod+路径+版本号下载 pod 'xxx' , :git => 'https://github.com/xxx/xxx_ios.git' , :tag => '3.4.4'
1.6、下载完毕的项目目录下可以看到添加进的framework库文件
2.1、可以试一下按照方式一中的代码切换进flutter页面,这里就不贴代码了
至此,通过Git远程管理的flutter模块集成进iOS项目已经完成了,以后每次flutter模块代码有更新时,直接推向远端,iOS开发同学直接在podfile文件中进行拉取,后续可以考虑加上tag标识来进行拉取
优点: 对 Flutter 自身的构建流程改动较少并且较彻底第解决了本地耦合的问题; 解决了组件式开发的痛点,各自开发各自的代码,也不用要求每台电脑上都配置flutter环境
缺点: 集成方式上变得貌似更加繁琐,Flutter 内容的变动需要先同步到远程仓库再 同步到 Standalone 模式方能生效;且要各自打包维护iOS安卓的两套代码仓库供不同平台去拉取调用