iOS SDK应该注意的问题和tips

到webank以后一直在做sdk相关的开发,包括微动力,云客服,以及云刷脸项目.其中遇到一些常见的sdk中开发应该避免的误区,以及一些可能会踩到的坑.

重中之重的前缀

iOS中使用OC开发,由于OC没有命名空间概念,很大问题是重名问题.有以下几个地方都需要注意添加前缀,前缀一定要有辨识度,类名、宏定义、枚举、通知、类别等命名时加静态库统一特殊前缀,以避免命名冲突:

  • 自定义的类: WBFaceSDKxxxxxxClass
  • category的方法名最好添加: wbfacesdk_xxxxMethod()
  • 对于项目中的c、c++中的方法,需要加前缀,全局c方法: WBFaceSDKCGRectXXXX()
  • 全局常量,包括字符串等等:常见的有通知名称WBFaceSDKxxxxxNotification
  • 使用typedef/NS_ENUM/NS_OPTIONS定义的struc或enum的名称

第三方公用库或静态库不要打入SDK进行编译

我们常用的网络库使用AFNetworking,SDWebImage,虽然引入到项目中,但是.m不要勾选"target membership"选项,只需要引入.h就OK.或者通过cocoapod,创建sdk工程,通过cocopads管理项目依赖.

常见的第三方框架,比如libssl.a,opencv.a,libcrypto.a等等,拖入工程的时候"Add to Target"(taget membership)都不要打勾.也就是sdk对这些公共库有依赖关系,但是最终生成的sdk不包含公共库的源码文件.

尽量减少使用Category

iOS中Category使用的很频繁,如果静态库里面使用了category,由于OC的runtime和静态度的静态资源的加载问题.需要进行以下操作:

那么需要在Build settings->Other Linker Flags中添加-ObjC参数,解决运行时unrecognized selector send to instance的crash错误.

此外,如果在category的.m文件中只有一个category分类,此时需要额外添加参数-all_load或者使用-force_load /path/to/sdk来强制加载sdk.为了不使用这个参数,最好的方法是在.m文件中,写一个空的Class来占位:

// Use dummy class for category in static library.
#ifndef DUMMY_CLASS
#define DUMMY_CLASS(name) \
    @interface DUMMY_CLASS_ ## name : NSObject @end \
    @implementation DUMMY_CLASS_ ## name @end
#endif
 
//使用示例:
//UIColor+YYAdd.m
#import "UIColor+YYAdd.h"
DUMMY_CLASS(UIColor+YYAdd)
 
@implementation UIColor(YYAdd)
...
@end

使用-all_load或者-force_load xxx在编译期间非常耗时.
为了减少耗时,本人是将通用的类创建成常用的全局函数,static函数,inline函数(注意添加前缀)

支持通用平台arm,x86等

我们可以通过如下命令查询具体.a或者framework文件支持的平台:lipo -info /path/to/.a or lipo -info /*.framework/xxx.

平时项目开发中,可能使用第三方提供的静态库.a,如果.a提供方技术不成熟,使用的时候就会出现问题,例如:

  • 在真机上编译报错:No architectures to compile for (ONLY_ACTIVE_ARCH=YES, active arch=x86_64, VALID_ARCHS=i386).
  • 在模拟器上编译报错:No architectures to compile for (ONLY_ACTIVE_ARCH=YES, active arch=armv7s, VALID_ARCHS=armv7 armv6).
    要解决以上问题,就要了解一下Apple移动设备处理器指令集相关的一些细节知识。

通常我们生成.a文件或者static framework默认配置的Valid Architectures支持arm64,armv6,ramv7s.sdk也就只能在真机上跑,如果需要在模拟器中跑,需要使其支持x86_64``i386.

Xcode中指令集相关选项(Build Setting中):

  • Architectures: 工程被编译成可支持哪些指令集类型,而支持的指令集越多,就会编译出包含多个指令集代码的数据包,对应生成二进制包就越大,也就是ipa包会变大.默认为 Standard architectures(armv7,arm64)
  • Valid Architectures:限制可能被支持的指令集的范围,也就是Xcode编译出来的二进制包类型最终从这些类型产生,而编译出哪种指令集的包,将由Architectures与Valid Architectures(因此这个不能为空)的交集来确定.

例如:Valid Architectures设置的支持arm指令集版本有:armv7/armv7s/arm64,对应的Architectures设置的支持arm指令集版本有:armv7s,这时Xcode只会生成一个armv7s指令集的二进制包。

  • Build Active Architecture Only:指定是否只对当前连接设备所支持的指令集编译.当这个属性设置是yes时候,一般为了debug速度更快,只编译当前的architecture版本.默认debug:yes, release:no.

在我们制作sdk时候,要做到比较大的兼容性(iPhone 4,iOS7以上),可以进行如下设置:

  • ValidArchitectures设置为:armv7|armv7s|arm64|i386|x86_64
  • Architectures设置不变(或根据你需要): armv7|arm64

然后分别选择iOS设备和模拟器进行编译,最后找到相关的.a进行合包.(xctool或者pod帮助打包).如果是手动创建framework,那么使用如下脚本

if [ "${ACTION}" = "build" ]
then
INSTALL_DIR=${SRCROOT}/Products/${PROJECT_NAME}.framework

DEVICE_DIR=${BUILD_ROOT}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework

SIMULATOR_DIR=${BUILD_ROOT}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework


if [ -d "${INSTALL_DIR}" ]
then
rm -rf "${INSTALL_DIR}"
fi

mkdir -p "${INSTALL_DIR}"

cp -R "${DEVICE_DIR}/" "${INSTALL_DIR}/"
#ditto "${DEVICE_DIR}/Headers" "${INSTALL_DIR}/Headers"

lipo -create "${DEVICE_DIR}/${PROJECT_NAME}" "${SIMULATOR_DIR}/${PROJECT_NAME}" -output "${INSTALL_DIR}/${PROJECT_NAME}"

open "${DEVICE_DIR}"
open "${SRCROOT}/Products"
fi

同时,如果第三方库不支持模拟式尽量使用预编译指令,屏蔽第三方库:

#if TARGET_IPHONE_SIMULATOR//模拟器

#elif TARGET_OS_IPHONE//真机

#endif

arm64:iPhone5S以上| iPad Air| iPad mini2(iPad mini with Retina Display)

armv7s:iPhone5|iPhone5C|iPad4(iPad with Retina Display)

armv7:iPhone3GS|iPhone4|iPhone4S|iPad|iPad2|iPad3(The New iPad)|iPad mini|iPod Touch 3G|iPod Touch4

i386 :5及以下模拟器
x86_64:5s及以上模拟器

Debug模式,必要Log输出与crash日志收集

在sdk中要提供完整的Log信息的输出,尤其是错误日志,并且如何处理这个错误的步骤.当要收集crash日志时,可以通过系统NSException中提供的NSSetUncaughtExceptionHandler和NSGetUncaughtExceptionHandler方法,收集一些简单的crash日志信息,然后将收集到的crash日志同步到服务端.

具体如何进行Log模块的设计,crash日志简单上报暂时没有很好的方案.

涉及UI界面问题

需要考虑到界面旋转带来的潜在问题.布局时候尽量使用autolayout.对于必须使用硬编码的地方才使用硬编码.

对于硬编码,获取屏幕的宽度和高度,与普通的位置不一样:

#define ScreenHeight MAX([[UIScreen mainScreen] bounds].size.height,[[UIScreen mainScreen] bounds].size.width)//获取屏幕高度,兼容性测试
#define ScreenWidth  MIN([[UIScreen mainScreen] bounds].size.height,[[UIScreen mainScreen] bounds].size.width)//获取屏幕宽度,兼容性测试

所有的viewController的BaseVC中最好增加以下方法仅支持竖屏:

#pragma mark - viewController orientation
- (UIInterfaceOrientationMask)supportedInterfaceOrientations//支持哪些方向
{
    return UIInterfaceOrientationMaskPortrait;
}

/**
 初始化自己的方向, 这个在旋转屏幕时候非常重要
 If you do not implement this method, the system presents the view controller using the current orientation of the status bar.
 
 说明如果我们没有override这个方法,系统会根据当前statusbar来决定当前使用的orientation
 */
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation//默认显示的方向
{
    return UIInterfaceOrientationPortrait;
}

/**
 如果返回NO,则无论你的项目如何设置,你的ViewController都只会使用preferredInterfaceOrientationForPresentation的返回值来初始化自己的方向,如果你没有重新定义这个函数,那么它就返回父视图控制器的preferredInterfaceOrientationForPresentation的值。
 */
- (BOOL)shouldAutorotate//是否支持旋转屏幕
{
    return NO;
}

所有资源提供到bundle中,命名问题

...

sdk测试完整性

...

SDK中多次使用缓存状态问题

在调用SDK时,一定要先清理SDK原有的配置状态,缓存状态等等!!!!

参考文献

写iOS SDK注意事项

iOS 如何创建和使用静态库

IOS生成同时支持armv7,armv7s,i386,x86_64,arm64的静态库.a文件

iOS开发~制作同时支持armv7,armv7s,arm64,i386,x86_64的静态库.a

apple官方文档-制作framework

iOS开发——创建你自己的Framework

用lipo合并模拟器Framework与真机Framework

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

推荐阅读更多精彩内容