iOS Framework 实用开发技巧

时间:2020年7月

版本:Xcode 11.5 (11E608c)

语言:Objective-C

作者:非著名程序员


介绍自己在实际开发SDK过程中遇到的实际问题,以及解决方案。仅供参考。

  1. Framework与主工程(App)实时联调
  2. Framework、主工程(App)以及 Pod 等三个工程实时联调
  3. 使用脚本合并真机、模拟器等多种架构的Framework
  4. Framework中使用.bundle资源文件
  5. Framework中使用Category
  6. Framework支持bitcode


一、Framework与主工程(App)实时联调

① 为什么需要实时联调?

首先说明,Framework指的是我们自己开发的Framework(SDK),主工程(App)泛指那些要接入你的SDK的App。

朕之前在写SDK进行调试的时候都是先创建一个Framework的工程,代码都写完之后打包成Framework静态库,然后再把Framework拉到App的主工程中去验证功能。这样的调试方式没什么不可以,但是非常的浪费时间,需要一遍又一遍的打包Framework,而且Framework中的问题不可以打断点排查。

② 实时联调最终要达到什么效果?

实时联调最终要达到的效果是:仅需要让主工程跑起来就可以同时调试Framework和App两个工程的代码

这样一来,Framework不用每次都去打包一遍,再拖进App工程。大致的流程可以理解为:先build Framework,Framework编译完成后自动添加到App中,最后build App。


③ 干

1. 创建App工程,命名为RealDemo

image.png


2. 创建Framework工程,命名为RealSDK

image.png

注意路径!

image.png


3. 设置Framework工程的Build Settings

image.png
image.png
image.png


4. 创建WorkSpace,命名为RealDemo

image.png

注意路径!

image.png


5. 连接Framework工程和App工程

打开 RealDemo.xcworkspace,毫无疑问,空空如也


image.png

直接把需要连接的Framework工程和App工程拖进来即可


image.png

哎~你瞧,这就有了


image.png


6. 把Framework添加到App工程中

image.png
image.png

添加完是这样的


image.png




有过SDK开发经验的道友到这里应该已经看明白了,所谓实时联调说白了就是用WorkSpace把两个工程连接起来而已,跟Pod的原理有几分相似。

继续,咱们验证一下


7. 给Framework加点功能

增加一个RealDog类,定义一个eat方法,实现里面打印一句话“吃骨头”。最后在SDK的公开头文件RealSDK.h中集中引用一下。

image.png

// RealDog.h

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface RealDog : NSObject

- (void)eat;

@end

NS_ASSUME_NONNULL_END
// RealDog.m

#import "RealDog.h"

@implementation RealDog

- (void)eat {
    NSLog(@"吃骨头");
}

@end

// RealSDK.h

#import <Foundation/Foundation.h>

//! Project version number for RealSDK.
FOUNDATION_EXPORT double RealSDKVersionNumber;

//! Project version string for RealSDK.
FOUNDATION_EXPORT const unsigned char RealSDKVersionString[];

// In this header, you should import all the public headers of your framework using statements like #import <RealSDK/PublicHeader.h>


#import <RealSDK/RealDog.h>


8. 在App的ViewController调用一下SDK的方法

// ViewController.m

#import "ViewController.h"
#import <RealSDK/RealSDK.h>

@interface ViewController ()

@property (nonatomic, strong) RealDog *dog;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.dog = [[RealDog alloc] init];
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    [self.dog eat];
}

@end

OK,实时联调到此结束。


二、Framework、主工程(App)以及 Pod 等三个工程实时联调

再加上Pod之后,三个工程实时联调其实也没什么难的,只要保证刚刚第一部分的工程文件夹层级关系,然后直接创建Podfile,pod install即可。

image.png

注意:此处Podfile里面的target是RealDemo!

platform :ios, '10.0'

target 'RealDemo' do
  
  pod 'AFNetworking', '~> 4.0.1'
  
end

三个工程顺利组到一起,全部可实时联调。

image.png

三、使用脚本合并真机、模拟器等多种架构的Framework

  1. 添加一个Aggregate Target。路径:RealSDK Project -> TARGETS -> "+"(左下角) -> Cross-platform - Other -> Aggregate
    WX20200718-110427@2x.png


  1. Aggregate Target 命名为“RealDemo-Script”
    WX20200718-110553@2x.png

    WX20200718-110835@2x.png


  1. 依赖RealSDK


    WX20200718-112151@2x.png


  1. 添加脚本


    WX20200718-112823@2x.png

    WX20200718-113154@2x.png

脚本源码

这个脚本是通用的,各位道友直接复制粘贴即可~

# Type a script or drag a script file from your workspace to insert its path.
UNIVERSAL_OUTPUTFOLDER=../Framework/

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

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

# 定义真机、模拟器Build文件夹路径变量
IPHONE_BUILD=${BUILD_DIR}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework
SIMULATOR_BUILD=${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework

# 拷贝framework到univer目录
cp -R "${IPHONE_BUILD}" "${UNIVERSAL_OUTPUTFOLDER}/"

#cp -R "${SIMULATOR_BUILD}" "${UNIVERSAL_OUTPUTFOLDER}/"

# 定义输出路径变量
OUTPUT_PATH=${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework

# 合并framework,输出最终的framework到build目录 
lipo -create "${IPHONE_BUILD}/${PROJECT_NAME}" "${SIMULATOR_BUILD}/${PROJECT_NAME}" -output "${OUTPUT_PATH}/${PROJECT_NAME}"



  1. 运行脚本


    WX20200718-120005@2x.png


  1. 运行结果


    WX20200718-115622@2x.png


  1. 检验一下是否合成成功


    WX20200718-120516@2x.png

四、Framework中使用.bundle资源文件

  1. 首先,我们先随便创建一个Bundle工程。


    WX20200718-152228.png


  1. Bundle工程命名为RealSDKResource。在Build Settings中修改Base SDK为iOS。
    WX20200718-152500.png


  1. 去掉Bundle文件的info.plist文件
    WX20200718-153145.png


  1. 修改Bundle文件名称(可依需求选择)


    WX20200718-153421.png


  1. 将Versioning System设置为None,默认Xcode会通过agvtool生成对应的版本信息,并打包进bundle文件中,这会导致后续在SDK跟随使用的App提交到AppStore的时候报错。


    WX20200718-153623.png


  1. 加一张图片资源,打包


    WX20200718-160219.png

    WX20200718-160246.png


  1. 测试一下RealSDK是否可以引用Bundle资源,SDK中什么都不用设置,直接引用Bundle资源即可。注意引用Bundle资源的方式:用字符串路径读取图片。还可以用NSBundle获取文件。
WX20200718-160609.png

用NSBundle获取文件

WX20200718-161242.png


  1. 把Bundle文件拖到App工程中,写一个测试代码
WX20200718-161415.png


  1. 运行起来,看一下效果,OJBK
WX20200718-161706.png

五、Framework中使用Category

在Framework工程的Build Setting中添加-ObjC。另外,使用我们SDK的App的Build Setting中也要添加-ObjC

在网上看到有人建议用-all_load,我个人建议使用-ObjC足矣。-all_load会比-ObjC范围更大,没有必要的事情就不要做,免得浪费性能。具体区别我就不在这里具体说了,网上一大片。

六、Framework支持bitcode

WX20200718-165002.png
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,402评论 6 499
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,377评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,483评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,165评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,176评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,146评论 1 297
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,032评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,896评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,311评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,536评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,696评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,413评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,008评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,659评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,815评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,698评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,592评论 2 353