SDK设计的几个原则:稳定性、可扩展性、无侵性、崩溃问题采集、相应位置的打点监听。
一、稳定性
SDK最最重要的一个原则就是稳定向,一般要保持崩溃率在万分之一二以下,否则用户那边是很难过的去的。那么我们要保证我们的稳定性就要做到以下几点来降低崩溃率。
1、对使用的数据进行安全化处理
不要太相信后端传过来的数据,有时候数据是nil让你崩的猝不及防,所以就需要对获取的数据进行安全化处理。
所谓安全化处理,就是我们使用类别的方法,进行安全化处理,比如NSString、NSArray、NSDictonry,要对内部的数据做判空等处理。防止出现调用的数据出现nil或者数组越界从而引发的崩溃。
2、初始化调用的方法要保证在主线程操作
用户调用的时候会有各种奇葩的调用,有的甚至在子线程调用SDK的初始化方法,SDK一些定时操作会失效,导致功能缺失问题。所以在SDK初始化的方法里面要强制进入主线程,杜绝线程方面的问题。
3、各种系统版本需要考虑,尽量要做到新老版本的方法判断调用。
if (@available(iOS 15.0, *)) { //表区头会空出一段距离
[UITableView appearance].sectionHeaderTopPadding = 0;
}
4、接口稳定
接口并不轻易改变调用方法或者参数,有稳定回调、数据格式不发生变化等。这很重要,一旦修改,必然导致所有的客户都要修改,所以这是原则问题,在设计的时候就要考虑到。
1、所有的回调都在主线程。
2、无论成功还是失败,都要给出相应的结果。
5、对应的各个手机类型都要做好适配避免出现UI问题
二、可扩展性
SDK的接口要有扩展性,随着SDK的迭代,可能需要的传参有增加。这就需要我们扩展SDK,如果我们使用直接一个个传递参数的的方式调用就会让SDK的方法调用十分冗长且不优美,而且还要用户修改调用方法,多方面考虑这种方式都不合理。
所以,我们需要创建个对象,将传递的参数做为这个对象的属性,一旦需要增加参数,那么我们只需要增加属性就足够了,用户也只需要增加这个对象的参数配置就行了,调用方式也不用改变。
+ (BOOL)showMessage:(ZNMessageConfig *)config;
三、无侵性
1、不能影响宿主App功能。
SDK对于宿主App的依赖应该足够小,如不能跟宿主App起相同的类名、使用相同的扩展、依赖相同的第三方库等
2、不会导致宿主App卡顿。
内部所有操作应该尽可能放在自定义子线程中
3、尽量不使用第三方库。
使用三方库这个是难免的,所以我们需要注意避免和用户的三方库产生冲突。
a、需要rename类名包括类别以及类别方法,加上本公司的特定标识。
b、extern 声明的外部全局变量,也是都需要修改的。
.h文件声明
初始化接口
extern NSString * const kAPIInitGet;
.m文件实现
NSString * const kAPIInitGet =@"/sdk/api/v4.0/ticket/uploadlog";
拓展:在开发中,我们通常会单独抽一个类来管理一些全局的变量或常量,通常搞一个GlobeConst文件,里面专门定义全局常量或常量。
extern和#defineh定义的区别:
extern与const组合:只需要定义一份全局常量或变量,多个文件共享。编译时刻,有类型检查,const仅仅用来修饰右边的变量,被const修饰的变量是只读的。
#define 预编译,简单的字符串替换,没有类型检查,可以预编译表达式,也可以定义常量
四、崩溃问题采集
由于SDK在线上会面临各种各样的问题,所以我们需要实时统计SDK的崩溃问题,并及时修复,所以需要我们对SDK内的崩溃进行统计并上传。
注册unCaughtExceptionHandler(),发现崩溃及时上报。
1、采集的重点
除了还需要采集崩溃的堆栈信息,还需要添加上附加信息,比如手机系统版本号、手机型号、SDK版本号等等重要标识,方便我们定位问题。
2、发送时机
不能在崩溃的时候直接发送给服务器,会导致我们收不到发送成功还是失败的信息,我们会在下次启动初始化SDK的时候发送出去。
.h文件:
+ (void)setDefaultHandler;
.m文件:
#import "ANCrashHandler.h"
#import "ANExceptionCollection.h" //采集崩溃信息存储起来
#import <math.h>
static NSUncaughtExceptionHandler *defaultExceptionHandler;
// 崩溃时的回调函数
void ANCrashHandler(NSException * exception) {
// 数组越界,字典nil,调用未知方法.等等还有崩溃的控制器以及方法
NSArray *arr = [exception callStackSymbols];
NSString *callStackSymbols = [[arr subarrayWithRange:NSMakeRange(0, fmin(10, arr.count - 1))] componentsJoinedByString:@"\n"];
BOOL isAN = [callStackSymbols containsString:@"ANMSS"];//采集SDK的文件标识
if ([callStackSymbols AN_notEmpty] && isAN) {
NSArray *components = [callStackSymbols componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
components = [components filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"self <> ''"]];
NSString *stacktrace = [components componentsJoinedByString:@" "];
NSString *message = [NSString stringWithFormat:@"%@ %@", exception.name, exception.reason];
[ANExceptionCollection anExceptionMessageSaveWithStacktrace:stacktrace message:message timestamp:@([AHSystemTool getTimestamp]) type:@"fatal"]; //加上自己的崩溃标识,比如版本号、手机型号
}
if (defaultExceptionHandler) {
defaultExceptionHandler(exception);
}
}
@implementation ANCrashHandler
+ (void)setDefaultHandler {
defaultExceptionHandler = NSGetUncaughtExceptionHandler();
NSSetUncaughtExceptionHandler(&ANCrashHandler);
}
@end
网友评论