创建CocoaPods的Framework Swift组件化之路(下)

系统: Mac OS 10.15.2, XCode 11.3,swift 5.0
写作时间:2019-12-23

1. 说明

开发iOS App,基本上没有从零开始构建。因为系统以及提供了很多Framework,比如UIKit, Foundation, WebKit,MapKit等,GitHub上也有很多开源的Framework,AlamofireKingfisher等。

动态库与静态库的区别。

  1. Static library - 代码在编译时链接linked, 以后就不会再发生变化.

但是, iOS static libraries不允许包含images/assets (只有代码). 曲线救国的方式是,用一个bundle去加入images/assets .

  1. Dynamic library - 代码或者assets在运行时runtime才链接 linked,也就是里面的内容会发生变化.

但是, 只有Apple官方才允许为iOS创建dynamic libraries. 如果你的项目有动态库,则App会审核失败.

  1. Framework - 编译后的代码实现一个任务… 所以Framework, 可以包含字符串,图片资源文件,storyboard,static frameworkdynamic framework, 或者其它Framework, 并且可以分版本管理.(iOS 8以后允许创建)

此文创建的Framework依赖了第三方的Framework,比如Alamofire。
从零开始创建没有依赖的Framework请参考 – 创建CocoaPods的Framework Swift组件化之路(上)

2. 工程代码下载

https://github.com/zgpeace/IceCreamShopFramework
这里包含

  1. 开始的项目: IceCreamShop_Starter
  2. 完成的项目: IceCreamShop_Finisher
  3. 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的方式集成寄来, 但是. MBProgressHUDObjective-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, 删除 AppIconlogo images。

4.7 工程RWPickFlavor xcworkspace, 需要确认Main.storyboard中的对象链接是正确的. 确认下面3个对象的链接:

  1. Choose Your Flavor
  2. Ice Cream View
  3. Pick Flavor Data Source
    在这里插入图片描述
    因为拷贝storyboard到不同的工程project, 你需要确认上面的对象的Module都设置为CocoaPod的工程RWPickFlavor. 记得保存Command-S.
    在这里插入图片描述

5. 工程IceCreamShop-Stater移除多余文件

  1. 在文件夹中IceCreamShop-Stater打开工程IceCreamShop.xcworkspace, 删除下面4个文件夹
  • Categories
  • Controllers
  • Models
  • Views
  1. 打开Info.plist文件,找到分组Supporting Files group, 删除行Main storyboard file base name

  2. 打开工程中中的Images.xcassets, 删除 background images。

  3. 运行工程,显示的是一个黑屏。

创建Pod的最困难的部分已经完成!恭喜!
在这里插入图片描述

6. 创建Github仓库

  1. 创建一个新的仓库给Framework用
    在这里插入图片描述
    仓库名字为RWPickFlavor,笔者新建的仓库链接如下:
    https://github.com/zgpeace/RWPickFlavor

  2. 新建另一个仓库给Podspec用,名字命名为RWPodSpecs,并勾选初始化README。 CocoaPods要求pod specs repo至少有一个提交,否则不工作.
    链接如下:
    https://github.com/zgpeace/RWPodSpecs

7. 设置Podspec

如果没有Podspec, RWPickFlavor 只是一堆文件. PodspecCocoaPod的描述信息. 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" => "[email protected]" }

# 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). 你不需要包含AlamofirePodfile, 以为依赖以及配置好在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

发布了127 篇原创文章 · 获赞 12 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/zgpeace/article/details/103640985
今日推荐