200、Carthage - BMWB/Fastlane_Swift GitHub Wiki

概念

什么是Carthage

Carthage使用Swift语言编写,只支持动态框架,只支持 iOS8+的Cocoa依赖管理工具。 与现在流行的 CocoaPods 不同,Carthage编译你的依赖,并提供框架的二进制.framework文件,但你仍然保留对项目的结构和设置的完整控制,Carthage不会自动的修改你的项目文件或编译设置。是一个去中心化的Cocoa依赖管理工具。

优点

  • Carthage 是去中心化的依赖管理工具,安装依赖时不需要去中心仓库获取 CocoaPods 所有依赖的索引,节省时间
  • 对项目无侵入性,Carthage 设计上也比较简单,利用的都是 Xcode 自身的功能,开发者在创建依赖时,相比 CocoaPods 也简单许多
  • Carthage 管理的依赖只需编译一次,项目干净编译时,不会再去重新编译依赖,节省时间,大大增加了Achive和Build的时间
  • 是由Swift语言编写的,自动将第三方框架编程为 Dynamic framework( 动态库 )
  • 与 CocoaPods 无缝集成,一个项目能同时拥有 CocoaPods 和 Carthage

缺点:

  • 仅支持 iOS8 +
  • 它只支持Framework,所以不能用来针对 iOS 8 以前的系统版本进行开发
  • 支持的 Carthage 安装的第三方框架和依赖不如 CocoaPods 丰富
  • 无法在 Xcode 里定位到源码,只可以看到一个库的头文件
  • 安装包的大小比用CocoaPods安装的包大
  • 每次update时,需要从git仓库中重新拉取下载,比较耗时
  • CocoaPods是现在主流的 iOS/Mac 的包管理工具
  • 使用方便,除编写 Podfile 以外其他几乎都是自动完成
  • 软件包数量多,主流支持;

Carthage vs CocoaPods

Cathage 和 CocoaPods 到底有何不同,为什么不用 CocoaPods 这个 iOS 最时髦的依赖管理器而要用 Cathage?

1、Carthage 的开发者觉得 CocoaPods 易用但不简单。而 Carthage 的宗旨是工具就应当超级简单。 CocoaPods 为 app 的开发和库的发布过程增加了复杂性:

  • 库必须创建、更新和存储在 Podspec 文件中(或者说,如果某个库不存在的话 app 开发者必须自己来编写这个库)
  • 当向项目中添加 pods 时,CocoaPods 会为每个 pod 新建一个 Xcode 项目和 target,以及一个用于包容这些 pod 的 workspace。你必须使用这个 workspace 并确信该 CocoaPods 项目能够正常运行。想象一下,这会增加多少需要维护的 build settings。
  • CocoaPods 的 Podspec 是集中式存储的,如果因为某种原因它丢失了或者无法访问就会导致问题出现。

2、Carthage 项目的目标是提供一种比 CocoaPods 更简单的工具,更加容易理解、维护和更加的灵活。 它通过许多方式来实现这点:

  • Carthage 不会修改你的 Xcode 项目或者强制你使用 workspace。
  • 它不使用 Podspecs 或者不需要第三方库作者将他们的 pod 提交到集中式存储库。如果你的项目能够以 framework 形式构建,它就可以用在 Carthage 上。它能够直接使用 Git 和 Xcode 中现成的信息。
  • Carthage 其实没有做太多的改变,全都是靠你自己来控制。你手动添加依赖到项目中,Carthage 会下载和编译它们。

注意:Carthage 为了简单起见使用的是动态框架。这意味着你的项目必须支持 iOS 8 以上。

配置项目

1、创建Framework

在已有的工程上,新建一个Target。项目-> File -> New -> Target , 选择Framework ,命名为 CarthageTest

他会自带一个CarthageTestSDK.h的文件,这个文件的作用是告诉其他人我们引用了哪些头文件,我们不要它自动生成的文件,删除CarthageTestSDK.h

2、配置你的framework

  1. 选择你的工程
  2. 选择framework所在的Target
  3. 选择Build Phases
  4. 点击Header左下角的+号把你要暴露的头文件添加到Public里面(默认添加到Project里面,用鼠标把它拽过去)
  5. 在Compile source里面添加实现的.m文件

3、修改framework的Deployment Target

改为和项目工程一样的支持版本,我这边是8.0。 一定要注意这里,要不然,编译会报错,当编译不报错时,低版本的系统会安装不了。报错类似:

ERROR: Install failed. Got error "ApplicationVerificationFailed" with code 0xe8008019: Failed to verify code signature of /private/var/installd/Library/Caches/com.apple.mobile.installd.staging/temp.xY9xAg/extracted/Payload/Spec.app/Frameworks/MGLiveDetect.framework : 0xe8008019 (The application does not have a valid signature.)Build step 'Execute shell' marked build as failureFinished: FAILURE

4、更改framework的名字

不需要更改可以直接忽略。项目Target -> Build Setting -> Product Module Name/Produce Name ,改成 CarthageTestSDK

5、配置类别和支持Bitcode

如果你使用了类别,那么你需要在Build Settings的Linking的Other Linker Flags里加上 -all_load 如果你想你的工程支持bitcode,需要在Other C Flags 里加上 -fembed-bitcode   

以上都不需要,可以忽略这一步,跳到第5步。

6、分享你的工程

选择 Manager Schemes,给CarthageTestSDK勾上shared

本地验证

到这里,基本上你已经成功了,那么我们来验证一下,我们cd到项目文件夹,运行

$ carthage build --no-skip-current

命令运行完成后,你会发现你的项目文件夹里面多了一个Carthage文件夹

Carthage->Build->iOS->CarthageTestSDK.framework

1、把framework拖进工程中,点击copy

2、添加动态库

target->Build Phases ->左上角+号 ->New Copy Files Phase 然后在Copy Files下 Destination选择Frameworks ->添加你自己的动态库

3、测试验证成功

我们首先编译一下,没报错,导入头文件,正常输出,编译成功。验证成功。

4、发布并打上Tag

将代码上传到git上面,Carthage -> Build 目录是不需要上传的。

git tag 0.1.0
git push --tags

至此你的库以及支持 Carthage 了,可以让其他开发者使用 Carthage 来管理你的项目依赖了。

使用Carthage

1、先进入到项目所有的文件夹
$ cd 项目路径
2、创建一个空的Carthage文件
$ touch Cartfile
3、编辑cartfile文件,添加要依赖的框架
github "https://github.com/AFNetworking/AFNetworking"

指定版本可以这样

github "https://github.com/AFNetworking/AFNetworking" ~> 1.1.9
4、保存并关闭cartfile文件,进行安装
$ carthage update --no-use-binaries --platform ios

--platform ios :限定只有iOS平台

安装完之后根目录会出现一个叫Carthage的文件夹,里面包含Build和Checkouts两个文件夹。

Build:iOS路径下的就是framework包,需要自行引用进来。

Checkouts:是从Github上获取来的源码,所以理论上来说你在这个文件夹里对源码进行任何的修改,再次执行 carthage build 就会根据这里的源码打包出相应的framework出来。

但需要注意的是当每次执行carthage update后这里的源码又被覆盖了。所以你有特别需要修改的地方可以加例外防止覆盖!!!! 重要

5、项目Target -> Build Setting -> Search Paths -> Framework Search Paths添加。这一步,感觉【carthage update】之后,默认会有了,有的话跳到第6步。
$(PROJECT_DIR)/Carthage/Build/iOS
6、项目Target -> General最底下的Linked Frameworks and Libraries里手动添加【Add Other...】需要用的framework.
7、项目Target -> Build Phases -> '+' -> New Run Script Phase, 添加脚本 。这一步可以不操作,直接操作第8步;第7步和第8步只需要操作其中一步就可以了。
/usr/local/bin/Carthage copy-frameworks

同时要注意,添加【input Files】,如:$(SRCROOT)/Carthage/Build/iOS/AFNetworking.framework 。

如果不添加【input Files】,会报 dyld: Library not loaded 出错

8、【注:第7步操作了,这一步跳过】不想通过脚本并且【input Files】的方式添加路径的话,可以通过【Copy File】的方式来添加,项目Target -> Build Phases -> '+' -> New Copy File Phase, 添加Copy文件

292326-20190129194721281-2140702816

第三方静态库转为动态库

由于动态库不会增加ipa的包大小,因而将第三方的静态库转为动态库也是很有必要的。下面就腾讯的人脸识别SDK做验证。官网文档:https://cloud.tencent.com/document/product/655/13825。

需要SDK的话,可以直接找腾讯的相关人员拿。我拿到sdk包(iOS_OCR_SDK_V2.2.0),是可以直接跑起来,相关代码结构如下:

以下的步骤,和上面【让你的项目支持Carthage】差不多,具体配图看上面。

1、创建Framework

在已有的工程上,新建一个Target。项目-> File -> New -> Target , 选择Framework ,命名为 WBOCRFramework ,并删除创建多出来的 WBOCRFramework.h

2、将SDK的头文件公布出来

将 WBOCRService.framework 的头文件拉出来,放在libs文件夹里面,注意,虽然是拉了出来,但文件的路径是和原来一样的。

3、配置你的framework
  1. 选择你的工程
  2. 选择framework所在的Target
  3. 选择Build Phases
  4. 点击Header左下角的+号把你要暴露的头文件添加到Public里面(默认添加到Project里面,用鼠标把它拽过去)
  5. 在Compile source里面添加实现的.m文件。由于没有.m文件,可以直接忽略掉
  6. 在Link Binary With Libraries 中,将libs的文件全部增加进去,同时,还需要将所有依赖的系统framework也增加进去。

292326-20190130194253753-114301205

4、修改framework的Deployment Target

改为和项目工程一样的支持版本,我这边是8.0。 一定要注意这里,要不然,编译会报错,当编译不报错时,低版本的系统会安装不了。报错类似:

ERROR: Install failed. Got error "ApplicationVerificationFailed" with code 0xe8008019: Failed to verify code signature of /private/var/installd/Library/Caches/com.apple.mobile.installd.staging/temp.xY9xAg/extracted/Payload/Spec.app/Frameworks/MGLiveDetect.framework : 0xe8008019 (The application does not have a valid signature.)Build step 'Execute shell' marked build as failureFinished: FAILURE

5、更改framework的名字

不需要更改可以直接忽略。项目Target -> Build Setting -> Product Module Name/Produce Name ,改成 WBOCR

6、配置类别和支持Bitcode

在Build Settings的Linking的Other Linker Flags里加上 -all_load 工程需要支持bitcode,需要在Other C Flags 里加上 -fembed-bitcode

7、分享你的工程

选择 Manager Schemes,给WBOCRFrame勾上shared

8、生成framework并验证

到这里,基本上你已经成功了,那么我们来验证一下,我们cd到项目文件夹,运行

carthage build --no-skip-current

但是,我们发现,报错了。在终端上,会告诉我们,报错的日志输出在哪里

接下来,我们前往报错的日志,通过查看日志,是因为librecdetect.a文件需要支持Bitcode。

最简单的解决方法,就是开启BitCode,如下图:

命令运行完成后,你会发现你的项目文件夹里面多了一个Carthage文件夹,这个就是我们需要的framework了,那么接下来,我们在本地验证一下。参照上面【让你的项目支持Carthage】的步骤。

存在的问题

使用动态库跑起来之后,我们发现,界面的图片资源不见了,我们在打动态库的时候,明明已经加了WBOCRService.bundle。通过代码验证分析,原来是SDK加载图片,写死了是从根目录读取,写法如:

但我们打包成动态库之后,Bundle文件已经不在根目录了,根本就找不到。

通过查资料,参照一下github上的开源库MJRefresh(https://github.com/CoderMJLee/MJRefresh)的写法,先读取存在类的Bundle路径,再找到图片的路径。这样,不管封装多少层,bundle图片资源都不会丢失。

我们可以写在一个NSBundle的分类里,写法如下:

目前,通过和腾讯的人沟通,资源包的问题已经解决,解决方案如下:

SDK里面对资源bundle加了一个判断:

  1. main bundle 下是否存在WBOCRService.bundle,存在就直接使用
  2. 如果1找不到,就会到SDK可执行文件对应的目录下面去找WBOCRService.bundle

如果是动态库集成,资源就会位于第二个位置,但是要注意的是,在做动态库的时候,一定要把资源bundle加进去

碰到的问题

1、dyld: Library not loaded 出错

dyld: Library not loaded: @rpath/CarthageTestSDK.framework/CarthageTestSDK

Referenced from: /Users/vipshop/Library/Developer/CoreSimulator/Devices/948C970C-2338-4BCB-A62D-E28A71C7A47B/data/Containers/Bundle/Application/AB8C53FC-9779-44EA-8E23-23E1E63C6E89/PodTest.app/PodTest

Reason: image not found

注意,Copy File 默认是Resources,需要改为framework

292326-20190129162845630-1808774664

参考:

Carthage 让项目支持及使用,第三方静态库转为动态库

官网