SDK开发----制作framework

一、创建Framework工程(环境:Xcode10, iOS12)

command+shift+n 生成一个Cocoa Touch Framework,并将开发者自己的类加入到工程中。


1.png

二、头文件处理

需要公开给别人的.h文件放到Public中,把不想公开的.h文件放到 Project中。


2.png

项目中公开的需要引入到文件XLBaseProjectFramework.h中,如

#import 
#import 

三、Build Active Architecture Only 设置(不同机型的架构不一样,设置为NO适配不同机型, YES为当前机型)

默认:debug:NO, release:YES


SDK开发----制作framework_第1张图片
image.png

四、Architectures支持

指定工程被编译成可支持哪些指令集类型,而支持的指令集越多,就会编译出包含多个指令集代码的数据包,对应生成二进制包就越大,也就是ipa包会变大。一般做向下兼容原则,只编译了armv7s。


3.png

五、Mach-O配置

Executable:应用的主要二进制
Dylib Library:动态链接库(又称DSO或DLL)
Static Library:静态链接库
Bundle:不能被链接的Dylib,只能在运行时使用dlopen( )加载,可当做macOS的插件
Relocatable Object File:可重定向文件类型


SDK开发----制作framework_第2张图片
4.png

六、工程打包成 Framework方案。

执行到第四步时,command+b编译就制作出了Framework,但是要想在手机、模拟器上使用,还需在对应环境编译并合并。


SDK开发----制作framework_第3张图片
5.png

(一)方案一:手动合并
lipo命令合并

(二)方案二:通过Aggregate,自动合并
File --> New --> File... --> Cross-platform --> other --> Aggregate
1、创建一个Aggregate


6.png

2、加入脚本命令


7.png
#!/bin/sh
#要build的target名
TARGET_NAME=${PROJECT_NAME}
if [[ $1 ]]
then
TARGET_NAME=$1
fi
  UNIVERSAL_OUTPUT_FOLDER="${SRCROOT}/${PROJECT_NAME}_Products/"

#创建输出目录,并删除之前的framework文件
mkdir -p "${UNIVERSAL_OUTPUT_FOLDER}"
rm -rf     "${UNIVERSAL_OUTPUT_FOLDER}/${TARGET_NAME}.framework"

#分别编译模拟器和真机的Framework
xcodebuild -target "${TARGET_NAME}"     ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION}     -sdk iphoneos BUILD_DIR="${BUILD_DIR}"     BUILD_ROOT="${BUILD_ROOT}" clean build
xcodebuild -target "${TARGET_NAME}"     ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION}     -sdk iphonesimulator BUILD_DIR="${BUILD_DIR}"     BUILD_ROOT="${BUILD_ROOT}" clean build

#拷贝framework到univer目录
cp -R "${BUILD_DIR}/${CONFIGURATION}-    iphonesimulator/${TARGET_NAME}.framework"     "${UNIVERSAL_OUTPUT_FOLDER}"

#合并framework,输出最终的framework到build目录
lipo -create -output     "${UNIVERSAL_OUTPUT_FOLDER}/${TARGET_NAME}.framework/${TARGET_NAME}"     "${BUILD_DIR}/${CONFIGURATION}-    iphonesimulator/${TARGET_NAME}.framework/${TARGET_NA    ME}" "${BUILD_DIR}/${CONFIGURATION}-    iphoneos/${TARGET_NAME}.framework/${TARGET_NAME}"

#删除编译之后生成的无关的配置文件
dir_path="${UNIVERSAL_OUTPUT_FOLDER}/${TARGET_NAME}.framework/"
for file in ls $dir_path
do
if [[ ${file} =~ ".xcconfig" ]]
then
rm -f "${dir_path}/${file}"
fi
done
#判断build文件夹是否存在,存在则删除
if [ -d "${SRCROOT}/build" ]
then
rm -rf "${SRCROOT}/build"
fi
rm -rf "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator"     "${BUILD_DIR}/${CONFIGURATION}-iphoneos"
#打开合并后的文件夹
open "${UNIVERSAL_OUTPUT_FOLDER}"

3、得到可以使用的framework


SDK开发----制作framework_第4张图片
8.png

七、通用配置

(一)设置好最低支持的iOS系统版本

SDK开发----制作framework_第5张图片
image.png

(二)SDK的plist增加配置键值对

1、允许http请求

SDK开发----制作framework_第6张图片
image.png

2、隐私权限相关说明文字( 涉及apple审核政策5.1.1)

参考知名app描述:

QQ: 
获取麦克风权限: 请点击”好”以允许访问.若不允许,你将无法使用视频通话、发送语音消息或录制视频等功能. 
获取相机权限: 请点击”好”以允许访问.若不允许,你将无法使用拍照、录制视频、扫一扫等功能. 
获取定位权限: 若不允许,你将无法使用位置发送、附近的人、群与活动、空间挂件、吃喝玩乐等功能. 
获取相册权限: 若不允许,你将无法给好友发送或在空间上传本地相册图片及视频内容. 
获取通讯录权限: 请点击”好”以允许访问.若不允许,你将无法使用通讯录联系人、添加手机联系人等功能. 
获取Siri权限: 您的部分”QQ”数据将发给Apple以处理您的请求.如果不允许,你将无法使用Siri唤起QQ 
获取活动与体能训练记录权限: 请点击”好”以允许访问.若不允许,你将无法同步运动健康数据至QQ运动.

微信:       
获取麦克风权限: 如果不允许,你将无法在微信中发送语音消息,或进行音频通话. 
获取相机权限: 如果不允许,你将无法再微信中拍摄照片和视频,也无法使用视频通话、扫一扫等功能 
获取相册权限: 如果不允许,你将无法发送系统相册里的照片给朋友. 
获取定位权限: 如果不允许,你将无法在聊天中共享你的位置,也无法使用”摇一摇”和”附近的人”等基于位置的服务.微信还会使用这些信息提供关联搜索结果,并在你的注册或登录微信时保障你的账户安全
获取通讯录权限: 如果不允许,微信将无法推荐通讯录中的朋友给你.微信仅使用特征码用于匹配识别,不会保存你的通讯录内容 
获取Siri权限: 您的部分”微信”数据将发给Apple以处理您的请求.如果不允许,您将无法通过Siri发送微信消息 
获取活动与体能训练记录权限: 如果不允许,你将无法参与微信运动排行榜. 
上传通讯录提示: 微信将上传手机通讯录至微信服务器以匹配及推荐朋友.(上传通讯录仅用于匹配,不会保存资料,亦不会用作它用) 

淘宝:     
获取定位权限: “手机淘宝”想访问您的位置,为了提供附近的商品、店铺及优惠资讯 
获取相机权限: “手机淘宝”想访问您的相机,为了帮您扫描二维码或者商品和互动等功能 
获取麦克风权限: “手机淘宝”想访问您的麦克风,为了帮您用语音搜索卖家商品等功能 
获取相册权限: “手机淘宝”想访问您的照片,为了帮您实现晒买家秀等上传照片的功能 

支付宝:    
获取定位权限: 若不允许,你将无法在支付宝中使用商家服务、本都生活、发送地理位置等定位相关功能 
获取通讯录权限: 支付宝讲上传通讯录至服务器以匹配及推荐朋友,给朋友转账更方便(未经您同意,通讯录信息不会用于其他用途). 
获取相册权限: 若不允许,你将无法在支付宝中发送及保存照片 
获取相机权限: 若不允许,你将无法在支付宝中使用扫码、刷脸、拍照及拍摄小视频等功能. 
获取麦克风权限:若不允许,你将无法在支付宝使用语音消息、小视频及语音搜索等功能. 

(三)Build Phases配置

1、Link Binary With Libraries里添加项目的依赖库
2、Copy Bundle Resources里添加项目中使用到的资源文件,如图片、xib文件、plist文件等
3、 Headers里有三个选项是 Public、Private、Project;
      把需要公开给别人的头文件拖到Public 中,
      把不想公开的(即隐藏的)头文件拖到Project中。
     (Private下的头文件依然是可以暴露出来的,因此名字可能有些误导。事实上Project下的头文件对你的工程来说才是“私有”的,因此,一般的头文件或者在Public或者Project下)

(四)Bulid Settings配置

1、Prefix Header 创建pch文件索引
  名字不能用默认名,一般都通过下划线加上项目名来命名,如PrefixHeader_SDK.pch
  索引为:$(PROJECT_DIR)/$(PRODUCT_NAME)/PrefixHeader_XLCommonKitSDK.pch

2、Precompile Prefix Header设置为YES,pch会被预编译,预编译后的pch文件会被缓存起来,从而提高编译速度
  
3、Enable Bitcode 设置为NO来关闭该功能。
    Bitcode有一致性要求,这就意味着工程开启Bitcode之后必须要求所有打进Bundle的Binary都需要支持Bitcode,也就是说我们依赖的静态库都要含有Bitcode的,不然会报错。
(如果你要开启Bitcode,开启之后需要特别注意崩溃定位的问题:
  由于最终的可执行文件是Apple自动生成的,同时产生新的符号表文件,所以我们使用原本打包生成的dSYM符号化文件是无法完成符号化的。
  所以我们需要在上传至App Store时需要勾选Include app symbols for your application to receive symboilcated crash logs from Apple,勾选之后Apple会给我们生成dSYM,
然后就可以在Xcode -> Organizer或者iTunes Connect中下载对应的dSYM来进行符号化了)
(bitcode是被编译程序的一种中间形式的代码。包含bitcode配置的程序将会在App store上被编译和链接。 bitcode允许苹果在后期重新优化程序的二进制文件,而不需要重新提交一个新的版本到App store上。)

4、Other Linker Flags
  当你的SDK项目使用了分类,别人在用你的库时需要在里面加入-ObjC参数。
  <1>ObjC:加了这个参数后,链接器就会把静态库中所有的Objective-C类和分类都加载到最后的可执行文件中,
        如果使用了分类就要加这个参数。
  <2>all_load:会让链接器把所有找到的目标文件都加载到可执行文件中,
      但是千万不要随便使用这个参数!
      假如你使用了不止一个静态库文件,然后又使用了这个参数,
      那么你很有可能会遇到ld: duplicate symbol错误,因为不同的库文件里面可能会有相同的目标文件,
      所以建议在遇到-ObjC失效的情况下使用-force_load参数。
  <3>force_load:所做的事情跟-all_load其实是一样的,
      但是-force_load需要指定要进行全部加载的库文件的路径,
      这样的话,你就只是完全加载了一个库文件,不影响其余库文件,
      按需加载。

5、Build Active Architecture Only
  <1>NO, 这个配置的作用是生成所有平台的二进制文件
  <2>YES,只是为了在Debug的时候速度更快,它只编译当前的architecture 版本
6、Architectures
  点击Other..增加armv7s支持,
  不过如果不需要支持iPhone5和iPhone5C的话,则不需要加(同样的,当少了一个平台时,编译出来库的大小就会相应的变小)
7、Mach-O Type
   设置为Static Library;我们创建的framework默认是动态库,所以我们要将其改为静态库
8、Product Name
    这里设置的名称是编译出来的framework文件名称
9、Base SDK,
    设置SDK支持平台
10、Dead Code Stripping
    设置为YES。这时会过滤掉”dead”、”unreachable”的代码,即不会执行到的代码
11、Debug Information Level
    设置为Line tables only。
    这时调试信息允许获得带有函数名、文件名和行号的函数调用栈,
    但是不包含其他数据(比如局部变量和函数参数),即断点依然会中断,但是无法在调试器中查看局部变量的值。
12、Link With Standard Libraries 设置为NO。
     这时会避免重复链接。(不过有可能造成链接库找不到而报错)
13、Strip Style
    设置为Non-Global Symbols。(Strip Linked Product为YES时Strip Style才生效;
    对于库而言,最高去除符号的级别为Non-Global Symbols,如果为All Symbols则无法找到符号,从而引发报错)

14、Strip Linked Product
  设置为YES,此时运行APP,断点不会中断,
  在程序中打印 [NSThread callStackSymbols]也无法看到类名和方法名。
  而在程序崩溃时,函数调用栈中也无法看到类名和方法名;
  当该项为NO时,包的体积会变大,
  因为它容纳了本要去除掉的调试信息。
  <<>>

15、Strip Debug Symbols During Copy
  设置为YES;与Strip Linked Product类似,
  但是这个是将那些拷贝进项目包的第三方库、资源或者Extension的Debug Symbol去除掉,同样也是使用的strip命令。
  这个选项没有前置条件,所以我们只需要在Release模式下开启,不然就不能对第三方库进行断点调试和符号化了。
 <<<如果依赖的Target是独立签名的(比如App Extension),
  strip操作就会失效,并伴随着Warning:warning: skipping copy phase strip, binary is code signed: xxxx。
  此情况将依赖的Target 中的Strip Linked Product修改为YES,
  保证依赖的Target是已经去除了符号即可,
  Waning忽略掉就可以了>>>

16、Strip Swift Symbols
设置为YES;
此时移除相应Target中的所有的Swift符号,这个选项是默认打开的。 
<<>>

17、Generate Debug Symbols
  设置为NO来禁用Debug符号生成;
  当值为YES时,APP crash会跳进framework源码,泄露了framework所有源代码,很不安全。
  <<<当为YES时,可以通过Level of Debug Symbols来控制生成符号的级别>>>
18、Debug Information Format
  设置为DWARF。这一项是设置是否将调试信息加入到可执行文件中。
  改为DWARF后,如果程序崩溃,将无法输出崩溃位置对应的函数堆栈,但由于Debug模式下可以在XCode中查看调试信息,所以改为DWARF影响并不大。
  不过,既然这个设置叫做Debug Information Format,所以首先得有调试信息。
  如果此时Generate Debug Symbols选择的是NO的话,是没法产出dSYM文件的。
  dSYM文件的生成,是在Strip等命令执行之前。
  所以无论Strip Linked Product是否开启,生成的dSYM文件都不会受影响。
  注意,静态库是无法生成dSYM文件的,即使设置为DWARF with dSYM File,构建过程中依然不会有生成dSYM文件的步骤。

  <<<需要注意的是,将Debug Information Format改为DWARF之后,
会导致在Debug窗口无法查看相关类类型的成员变量的值。
当需要查看这些值时,可以将Debug Information Format改回DWARF with dSYM file,
clean(必须)之后重新编译即可>>>

提示:
---   Level of Debug Symbols有3个值:
      used: 只引用符号
      full: 所有符号
      default: 使用编译器默认

---  Strip Style 表示的是我们需要去除的符号的类型的选项,其分为三个选择项:
      All Symbols: 去除所有符号,一般是在主工程中开启。
      Non-Global Symbols:去除一些非全局的Symbol
                  (保留全局符号,Debug Symbols同样会被去除),
                    链接时会被重定向的那些符号不会被去除,
                    此选项是静态库/动态库的建议选项。
      Debug Symbols:去除调试符号,去除之后将无法断点调试

---  iOS的调试符号是DWARF格式,相关概念如下:
      Mach-O: 可执行文件,源文件编译链接的结果。
              包含映射调试信息(对象文件)具体存储位置的Debug Map。

      DWARF:一种通用的调试文件格式,支持源码级别的调试,
             调试信息存在于对象文件中,一般都比较大。
             Xcode调试模式下一般都是使用DWARF来进行符号化的。

      dSYM:独立的符号表文件,主要用来做发布产品的崩溃符号化。
            dSYM 是一个压缩包,里面包含了DWARF文件。
            使用Xcode编译打包的时候会先通过可执行文件的Debug Map获取到所有对象文件的位置,
            然后使用dsymutil来将对象文件中的DWARF提取出来生成dSYM文件

参考文章:使用workspace搭建SDK开发框架

你可能感兴趣的:(SDK开发----制作framework)