用 Xcode 7 建立依赖其它第三方库静态库

编写 SDK 的时候, 经常会用到一些常用组件, 比如 AFNetworking.
如果直接将AFNetworking编译进 SDK ,那么如果用户在使用你写的 SDK 的同时也使用了 AFNetworking,那么会出现"duplicate symbol _OBJC_CLASS_$_xxx"的问题.
如果自己重新写一个功能类似 AFNetworking 的组件,一来是很麻烦,二来像这种成熟的第三方库, 都是经过很多人测试过,多次修改 bug的,自己写的话,未必比得上,而且重复造轮子也是没有多大意义的.
接下来我们就来开始写一个简单的 SDK,并且使用 AFNetworking库

我们编写一个查询快递信息的 SDK, 使用的是快递100 的API, API 信息源自BeJSON

  1. 创建工程
    与创建其他工程唯一区别是选择模板的时候要选Cocoa Touch Framework,后面就没什么区别了

    选择模板

    至于为何不选择 Cocoa Touch Static Library 是因为虽然后者也能建立静态库,但是最后得到的是一堆头文件加上一个 .a 文件,不容易部署, 而 Framework 则是把头文件和编译好的二进制文件打包为一个. framwork ,容易部署.
  2. 加入 AFNetworking
    既然要使用 AFNetworking ,自然要先引入, 我用 CocoaPods 来管理, 至于你如果问我没用过 CocoaPods,有没有别的办法? 我还真不知道, 我觉得要是直接把源文件放到工程中多半是不行的, 如果不会可以学习一下 CocoaPods 的使用方法,参见这位大神的文章.
    新建一个 Podfile, 内容如下, 推介使用Xcode 插件,比如CocoaPods 插件
    platform :ios, '7.0'
    target 'ExpressInfo' do
     pod 'AFNetworking'
    end
    ExpressInfo 是我的项目名,你可以改成你自己的名字.记得加上 target 'xxx' do ... end, 要不然后面编译要提示can't locate file for: -lPods 错误.
    用命令或是插件执行安装.接下来就可以愉快的使用AFNetworking 了.
  3. 编写 SDK
    源码在这里 GitHub
    注意一点
    ExpressInfo.h,这个文件中,要把所有需要公开的头文件全部列举出来

    引入所有公开头文件
  4. 配置
    打开SDK 这个 target 的 build phase ,找到 Headers, 将 project 中需要公开的头文件选中,移动到 public group 中

    设置头文件

    接下来到 General 中设置需要支持的版本, Build Setting 中加入 armv7s

    添加 armv7s

    既然我们是编写的静态库,就需要将 Mach-O Type 设置为 Static Library

    设置为静态库

    接下来可以编译试试有没有什么错误和警告
    如果没有,就可以进行下一步了
  5. 增加合并模拟器和真机的 Aggregate Target
    由于编译的时候,只会编译当前选中设备的版本,为了编译一份同时能够运行于真机和模拟器的 SDK ,我们再增加一个 target

    Aggregate Target

    在这个 Target 里面选择 Build Phase, 新建一个 Run Script

    添加 Run Sctipt

    代码如下
    #!/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}"
    ps:(简书 Markdown 的代码块里面好像不能插入空行 ? )

    run script

    设置这个 Target 为 Release

    设置为 Release

    接下来可以切换到这个 Target 编译了,完成之后,会自动弹出 Framework 所在的文件夹

    编译好的文件
  6. 小试牛刀
    接下来实际使用一下这个 SDK
    1. 先创建一个普通的项目
    2. 添加刚才创建的 Framework

      添加 Framework 到项目

      3.接下来可以编写代码了, 我的源代码在这里GitHub

      编写源代码
  7. 由于我们的 SDK 使用了 AFNetworking, 而 AFNetworking 是没有编译进入我们 SDK 的. 如果直接编译, 会出现找不到类的错误

    错误

    所以使用的时候, 需要加上AFNetworking, 使用 CocoaPods 或者直接使用源文件都可以.
    5.现在可以运行试试了

    运行测试

    打完收工.若有任何指教,欢迎留言


文/yww(简书作者)
原文链接:http://www.jianshu.com/p/68c0f40a3387
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。









这个问题一般都是引用第三方framework导致,报错示例如下:

dyld: Library not loaded: @loader_path/../Frameworks/Sparkle.framework/Versions/A/Sparkle

  Referenced from: /Users/songping/Library/Developer/Xcode/DerivedData/TestCapture-fgntrtzakrtbkcacvqjagvptjxdh/Build/Products/Debug/TestCapture.app/Contents/MacOS/TestCapture

  Reason: image not found


解决方法是:

1、在Xcode中的Build Phases中的Copy Files项中,将你要引用的framework拖到“Linked Frameworks and Libraries“ 【如果已经添加了,跳过这一步】

2、把Build Phases 里Social.framework后边的选项修改成为Optional就可以了




另外新建一个工程,将合适的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的时候又会出现错误

bitcode bundle could not be generated because ... was built without full bitcode.All object files and libraries for bitcode must be generated from Xcode Archive or Install build for architecture arm64
  
  
  • 1
  • 1

Bitcode是苹果在Xcode7及以后推出的新功能。用于代码的二次编译,针对CPU进行优化,编译工作由苹果AppStore后台来完成。 
针对iOS是可选项,默认打开。watchOS 和 tvOS 是必选项。

所以需要打开库工程的此选项并加上-fembed-bitcode参数,重新编译 

如此archive时就不会出问题了,到此我在制作使用framework时遇到的问题都在这里了。





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值