编写 SDK 的时候, 经常会用到一些常用组件, 比如 AFNetworking.
如果直接将AFNetworking编译进 SDK ,那么如果用户在使用你写的 SDK 的同时也使用了 AFNetworking,那么会出现"duplicate symbol _OBJC_CLASS_$_xxx"的问题.
如果自己重新写一个功能类似 AFNetworking 的组件,一来是很麻烦,二来像这种成熟的第三方库, 都是经过很多人测试过,多次修改 bug的,自己写的话,未必比得上,而且重复造轮子也是没有多大意义的.
接下来我们就来开始写一个简单的 SDK,并且使用 AFNetworking库
我们编写一个查询快递信息的 SDK, 使用的是快递100 的API, API 信息源自BeJSON
- 创建工程
与创建其他工程唯一区别是选择模板的时候要选Cocoa Touch Framework,后面就没什么区别了
至于为何不选择 Cocoa Touch Static Library 是因为虽然后者也能建立静态库,但是最后得到的是一堆头文件加上一个 .a 文件,不容易部署, 而 Framework 则是把头文件和编译好的二进制文件打包为一个. framwork ,容易部署. - 加入 AFNetworking
既然要使用 AFNetworking ,自然要先引入, 我用 CocoaPods 来管理, 至于你如果问我没用过 CocoaPods,有没有别的办法? 我还真不知道, 我觉得要是直接把源文件放到工程中多半是不行的, 如果不会可以学习一下 CocoaPods 的使用方法,参见这位大神的文章.
新建一个 Podfile, 内容如下, 推介使用Xcode 插件,比如CocoaPods 插件
ExpressInfo 是我的项目名,你可以改成你自己的名字.记得加上 target 'xxx' do ... end, 要不然后面编译要提示can't locate file for: -lPods 错误.platform :ios, '7.0' target 'ExpressInfo' do pod 'AFNetworking' end
用命令或是插件执行安装.接下来就可以愉快的使用AFNetworking 了. - 编写 SDK
源码在这里 GitHub
注意一点
ExpressInfo.h,这个文件中,要把所有需要公开的头文件全部列举出来
- 配置
打开SDK 这个 target 的 build phase ,找到 Headers, 将 project 中需要公开的头文件选中,移动到 public group 中
接下来到 General 中设置需要支持的版本, Build Setting 中加入 armv7s
既然我们是编写的静态库,就需要将 Mach-O Type 设置为 Static Library
接下来可以编译试试有没有什么错误和警告
如果没有,就可以进行下一步了 - 增加合并模拟器和真机的 Aggregate Target
由于编译的时候,只会编译当前选中设备的版本,为了编译一份同时能够运行于真机和模拟器的 SDK ,我们再增加一个 target
在这个 Target 里面选择 Build Phase, 新建一个 Run Script
代码如下
ps:(简书 Markdown 的代码块里面好像不能插入空行 ? )#!/bin/sh UNIVERSAL_OUTPUTFOLDER=${BUILD_DIR}/${CONFIGURATION}-universal WORKSPACE_NAME=${PROJECT_NAME}.xcworkspace # make sure the output directory exists mkdir -p "${UNIVERSAL_OUTPUTFOLDER}" # Step 1. Build Device and Simulator versions xcodebuild -workspace "${WORKSPACE_NAME}" -scheme "${PROJECT_NAME}" -configuration ${CONFIGURATION} -sdk iphoneos ONLY_ACTIVE_ARCH=NO BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build xcodebuild -workspace "${WORKSPACE_NAME}" -scheme "${PROJECT_NAME}" -configuration ${CONFIGURATION} -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build # Step 2. Copy the framework structure (from iphoneos build) to the universal folder cp -R "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework" "${UNIVERSAL_OUTPUTFOLDER}/" # Step 3. Copy Swift modules from iphonesimulator build (if it exists) to the copied framework directory SIMULATOR_SWIFT_MODULES_DIR="${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework/Modules/${PROJECT_NAME}.swiftmodule/." if [ -d "${SIMULATOR_SWIFT_MODULES_DIR}" ]; then cp -R "${SIMULATOR_SWIFT_MODULES_DIR}" "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/Modules/${PROJECT_NAME}.swiftmodule" fi # Step 4. Create universal binary file using lipo and place the combined executable in the copied framework directory lipo -create -output "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/${PROJECT_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework/${PROJECT_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework/${PROJECT_NAME}" # Step 5. Convenience step to copy the framework to the project's directory cp -R "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework" "${PROJECT_DIR}" # Step 6. Convenience step to open the project's directory in Finder open "${PROJECT_DIR}"
设置这个 Target 为 Release
接下来可以切换到这个 Target 编译了,完成之后,会自动弹出 Framework 所在的文件夹
- 小试牛刀
接下来实际使用一下这个 SDK- 先创建一个普通的项目
- 添加刚才创建的 Framework
3.接下来可以编写代码了, 我的源代码在这里GitHub
- 由于我们的 SDK 使用了 AFNetworking, 而 AFNetworking 是没有编译进入我们 SDK 的. 如果直接编译, 会出现找不到类的错误
所以使用的时候, 需要加上AFNetworking, 使用 CocoaPods 或者直接使用源文件都可以.
5.现在可以运行试试了
打完收工.若有任何指教,欢迎留言
原文链接:http://www.jianshu.com/p/68c0f40a3387
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。
dyld: Library not loaded: @loader_path/../Frameworks/Sparkle.framework/Versions/A/Sparkle
另外新建一个工程,将合适的framework导入到工程内,编写代码使用,由于framework中使用到了AFNetworking,但是并没有将其打包到Framework中,所以新建的工程需要自己手动导入一个framework。如果在代码中遇到如下错误:
dyld: Library not loaded: @rpath/TTTTTTTT.framework/TTTTTTTT
Referenced from: /Users/mxy/Library/Developer/CoreSimulator/Devices/72AF601F-3B90-4720-ACB0-E98EE7FD26FE/data/Containers/Bundle/Application/5B492415-EB7E-4188-8342-3C4099502F42/testFFFFFF.app/testFFFFFF
Reason: image not found
上面这个错误我个人理解,是工程编译的过程中没有找到我们自己写的framework。
在工程的buildsetting中搜索runpath search paths,添加$(SRCROOT),然后运行正常。
bitCode错误
在项目中引入静态库后,archive的时候又会出现错误
- 1
- 1
Bitcode是苹果在Xcode7及以后推出的新功能。用于代码的二次编译,针对CPU进行优化,编译工作由苹果AppStore后台来完成。
针对iOS是可选项,默认打开。watchOS 和 tvOS 是必选项。
所以需要打开库工程的此选项并加上-fembed-bitcode参数,重新编译
如此archive时就不会出问题了,到此我在制作使用framework时遇到的问题都在这里了。