时间:2020年7月
版本:Xcode 11.5 (11E608c)
语言:Objective-C
作者:非著名程序员
介绍自己在实际开发SDK过程中遇到的实际问题,以及解决方案。仅供参考。
- Framework与主工程(App)实时联调
- Framework、主工程(App)以及 Pod 等三个工程实时联调
- 使用脚本合并真机、模拟器等多种架构的Framework
- Framework中使用
.bundle
资源文件 - Framework中使用Category
- 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.png2. 创建Framework工程,命名为RealSDK
image.png注意路径!
image.png3. 设置Framework工程的Build Settings
image.png image.png image.png4. 创建WorkSpace,命名为RealDemo
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
中集中引用一下。
// 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
即可。
注意:此处Podfile里面的target是RealDemo!
platform :ios, '10.0'
target 'RealDemo' do
pod 'AFNetworking', '~> 4.0.1'
end
三个工程顺利组到一起,全部可实时联调。
image.png三、使用脚本合并真机、模拟器等多种架构的Framework
- 添加一个
Aggregate
Target。路径:RealSDK Project -> TARGETS -> "+"(左下角) -> Cross-platform - Other -> Aggregate
WX20200718-110427@2x.png
-
Aggregate
Target 命名为“RealDemo-Script”
WX20200718-110553@2x.png
WX20200718-110835@2x.png
-
依赖RealSDK
WX20200718-112151@2x.png
-
添加脚本
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}"
-
运行脚本
WX20200718-120005@2x.png
-
运行结果
WX20200718-115622@2x.png
-
检验一下是否合成成功
WX20200718-120516@2x.png
四、Framework中使用.bundle
资源文件
-
首先,我们先随便创建一个Bundle工程。
WX20200718-152228.png
- Bundle工程命名为
RealSDKResource
。在Build Settings中修改Base SDK为iOS。
WX20200718-152500.png
- 去掉Bundle文件的
info.plist
文件
WX20200718-153145.png
-
修改Bundle文件名称(可依需求选择)
WX20200718-153421.png
-
将Versioning System设置为None,默认Xcode会通过agvtool生成对应的版本信息,并打包进bundle文件中,这会导致后续在SDK跟随使用的App提交到AppStore的时候报错。
WX20200718-153623.png
-
加一张图片资源,打包
WX20200718-160219.png
WX20200718-160246.png
- 测试一下RealSDK是否可以引用Bundle资源,SDK中什么都不用设置,直接引用Bundle资源即可。注意引用Bundle资源的方式:用字符串路径读取图片。还可以用NSBundle获取文件。
用NSBundle获取文件
WX20200718-161242.png- 把Bundle文件拖到App工程中,写一个测试代码
- 运行起来,看一下效果,OJBK
五、Framework中使用Category
在Framework工程的Build Setting中添加-ObjC
。另外,使用我们SDK的App的Build Setting中也要添加-ObjC
。
在网上看到有人建议用-all_load
,我个人建议使用-ObjC
足矣。-all_load
会比-ObjC
范围更大,没有必要的事情就不要做,免得浪费性能。具体区别我就不在这里具体说了,网上一大片。
网友评论