系统: Mac OS 10.15.2, XCode 11.3,swift 5.0
写作时间:2019-12-23
1. 说明
开发iOS App,基本上没有从零开始构建。因为系统以及提供了很多Framework,比如UIKit, Foundation, WebKit,MapKit等,GitHub上也有很多开源的Framework,Alamofire, Kingfisher等。
动态库与静态库的区别。
- Static library - 代码在编译时链接linked, 以后就不会再发生变化.
但是, iOS static libraries不允许包含images/assets
(只有代码). 曲线救国的方式是,用一个bundle去加入images/assets
.
Dynamic library
- 代码或者assets
在运行时runtime才链接 linked,也就是里面的内容会发生变化.
但是, 只有Apple官方才允许为iOS创建dynamic libraries. 如果你的项目有动态库,则App会审核失败.
- Framework - 编译后的代码实现一个任务… 所以Framework, 可以包含字符串,图片资源文件,storyboard,static framework , dynamic framework, 或者其它Framework, 并且可以分版本管理.(iOS 8以后允许创建)
此文创建的Framework依赖了第三方的Framework,比如Alamofire。
从零开始创建没有依赖的Framework请参考 – 创建CocoaPods的Framework Swift组件化之路(上)
2. 工程代码下载
https://github.com/zgpeace/IceCreamShopFramework
这里包含
- 开始的项目: IceCreamShop_Starter
- 完成的项目: IceCreamShop_Finisher
- Framework: Libraries/RWPickFlavor
3. 创建Framework
File > new > project > Framework & Library > Framework
下一步, Product Name
写为RWPickFlavor, 保存到新建的Libraries文件夹里面
新建Podfile文件
cd ~/yourProjectPath/Libraries/RWPickFlavor
pod init
open -a Xcode Podfile
Podfile内容填充如下
platform :ios, '12.0'
target 'RWPickFlavor' do
pod 'Alamofire', '~> 4.7'
pod 'MBProgressHUD', '~> 1.1.0', :modular_headers => true
end
这样子组件就有了第三方Framework的依赖Alamofire
,
MBProgressHUD
。
4. Swift Static Library
4.1 CocoaPods版本小于1.5.0, CocoaPods不能使用static libraries. 如果pod包含了Swift代码,需要在Podfile中标注 use_frameworks!
. CocoaPods 在1.5.0以后, CocoaPods就可以用静态库static libraries!
如果在Podfile省略了use_frameworks!
, CocoaPods 将用静态库static libraries代替Framework. 你的 Objective-C
依赖需要以module的方式集成寄来, 但是. MBProgressHUD
是Objective-C
不支持modules的依赖. 幸运的是, 在MBProgressHUD依赖的后面,增加脚本 :modular_headers => true
, CocoaPods 会添加 module支持.
4.2 pod安装依赖库
pod install
4.3 打开新工程
open RWPickflavor.xcworkspace
XCode打开的工程视图
4.4 从工程IceCreamShop-Stater拷贝下面5个文件夹到RWPickflavor Framework里面。(文件夹:Categories, Controllers, Models, Views
, Resources)
RWPickflavor在文件夹下显示如下:
4.5 接着,打开工程RWPickFlavor.xcworkspace
,选择File ▸ Add Files to “RWPickFlavor”
… 把新加的5个文件夹加入到工程,显示如下:
4.6 打开RWPickFlavor中的Images.xcassets
, 删除 AppIcon
和 logo
images。
4.7 工程RWPickFlavor xcworkspace
, 需要确认Main.storyboard
中的对象链接是正确的. 确认下面3个对象的链接:
- Choose Your Flavor
- Ice Cream View
- Pick Flavor Data Source
因为拷贝storyboard到不同的工程project, 你需要确认上面的对象的Module都设置为CocoaPod的工程RWPickFlavor. 记得保存Command-S
.
5. 工程IceCreamShop-Stater移除多余文件
- 在文件夹中IceCreamShop-Stater打开工程IceCreamShop.xcworkspace, 删除下面4个文件夹
- Categories
- Controllers
- Models
- Views
-
打开
Info.plist
文件,找到分组Supporting Files group
, 删除行Mainstoryboard file base name
。 -
打开工程中中的
Images.xcassets
, 删除background
images。 -
运行工程,显示的是一个黑屏。
创建Pod的最困难的部分已经完成!恭喜!
6. 创建Github仓库
-
创建一个新的仓库给Framework用
仓库名字为RWPickFlavor,笔者新建的仓库链接如下:
https://github.com/zgpeace/RWPickFlavor -
新建另一个仓库给Podspec用,名字命名为RWPodSpecs,并勾选初始化README。 CocoaPods要求
pod specs repo
至少有一个提交,否则不工作.
链接如下:
https://github.com/zgpeace/RWPodSpecs
7. 设置Podspec
如果没有Podspec, RWPickFlavor
只是一堆文件. Podspec
是CocoaPod
的描述信息. Podspec
包括pod的名字,版本,Git下载地址URL.
你需要为RWPickFlavor
创建创建RWPickFlavor.podspec
. 执行如下命令:
cd ~/yourProjectPath/Libraries/RWPickFlavor
pod spec create RWPickFlavor
open -a Xcode RWPickFlavor.podspec
把RWPickFlavor.podspec
里面的内容,替换为:
Pod::Spec.new do |s|
# 1
s.platform = :ios
s.ios.deployment_target = '12.0'
s.name = "RWPickFlavor"
s.summary = "RWPickFlavor lets a user select an ice cream flavor."
s.requires_arc = true
# 2
s.version = "0.1.0"
# 3
s.license = { :type => "MIT", :file => "LICENSE" }
# 4 - Replace with your name and e-mail address
s.author = { "Keegan Rush" => "keeganrush@gmail.com" }
# 5 - Replace this URL with your own GitHub page's URL (from the address bar)
s.homepage = "https://github.com/TheCodedSelf/RWPickFlavor"
# 6 - Replace this URL with your own Git URL from "Quick Setup"
s.source = { :git => "https://github.com/TheCodedSelf/RWPickFlavor.git",
:tag => "#{s.version}" }
# 7
s.framework = "UIKit"
s.dependency 'Alamofire', '~> 4.7'
s.dependency 'MBProgressHUD', '~> 1.1.0'
# 8
s.source_files = "RWPickFlavor/**/*.{swift}"
# 9
s.resources = "RWPickFlavor/**/*.{png,jpeg,jpg,storyboard,xib,xcassets}"
# 10
s.swift_version = "4.2"
end
8. 创建许可证License
像其它pod, 你需要创建LICENSE许可证文件.
比如拷贝MIT License 的内容, 并保存为文件名为LICENSE — 没有扩展名 — 到路径~/yourProjectPath/Libraries/RWPickFlavor
. 比替换内容里面的年份[year] 和 名字[fullname] !
Choose a License 这是一个特别好的网站,帮助你如何选择一个适合你的开源open-source license.
9. 推送到Git
把Pod推送到远程git,替换掉 [Your RWPickFlavor Git URL]
为你的git地址(比如笔者的https://github.com/zgpeace/RWPickFlavor
).
cd ~/Documents/Libraries/RWPickFlavor
git init
git add .
git commit -m "Initial commit"
git tag 0.1.0
git remote add origin [Your RWPickFlavor Git URL]
git push -u origin master --tags
恭喜你,完成了你的第一个有依赖的Framework。
Last one more thing…
10. 应用你新建的CocoaPod
首先需要把你的Podspec
增加到私有仓库private specs repo
; 这个让CocoaPods找到你安装的pod. 幸运的是, 你已经创建了为Podspec
创建了Git 仓库.
在RWPickFlavor路径下,输入一下命令。替换掉[Your RWPodSpecs Git URL]
为你的Podspec
的路径(比如笔者的为:https://github.com/zgpeace/RWPodSpecs
):
pod repo add RWPodSpecs [Your RWPodSpecs Git URL]
pod repo push RWPodSpecs RWPickFlavor.podspec
上面标示创建了本地的RWPodSpecs
保存在你机器的路径~/.cocoapods
, 并把RWPickFlavor.podspec推送到了里面.
最后在Starter的工程里面,替换掉Podfile
的内容如下:
platform :ios, '12.0'
source 'https://github.com/CocoaPods/Specs.git'
source '[Your RWPodSpecs Git URL Goes Here]'
target 'IceCreamShop' do
pod 'RWPickFlavor', '~> 0.1.0'
pod 'MBProgressHUD', '~> 1.1.0', :modular_headers => true
end
确保替换掉[Your RWPodSpecs Git URL Goes Here]
为你的RWPodSpecs的Git地址(比如笔者的为:https://github.com/zgpeace/RWPodSpecs
). 你不需要包含Alamofire
在Podfile
, 以为依赖以及配置好在RWPickFlavor.podspec
. 你需要增加一行给MBProgressHUD
,这样子可以增加配置信息:modular_headers =>
.
运行
pod install
替换掉AppDelegate.swift
的内容如下:
import UIKit
import RWPickFlavor
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
// MARK: Instance Variables
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
window = UIWindow(frame: UIScreen.main.bounds)
window?.rootViewController = createRootViewController()
window?.makeKeyAndVisible()
return true
}
func createRootViewController() -> UIViewController {
let bundle = Bundle(for: PickFlavorViewController.self)
let storyboard = UIStoryboard(name: "Main", bundle: bundle)
return storyboard.instantiateInitialViewController() ?? UIViewController()
}
}
运行的时候发现错误,重复的Images.xcassets
, XCode 10 以后不能有重复的内容,要不删掉项目的,或者File > Workspace Setting > Build System > Legacy Build System.
最终运行起来:
参考
https://www.raywenderlich.com/5823-how-to-create-a-cocoapod-in-swift
https://stackoverflow.com/questions/15331056/library-static-dynamic-or-framework-project-inside-another-project
https://www.vadimbulavin.com/static-dynamic-frameworks-and-libraries/
https://stackoverflow.com/questions/50718018/xcode-10-error-multiple-commands-produce