简介

SDK即Software Develop Kit,开发者将基于此,快速的开发出APP。本文详细介绍iOS平台的SDK。ablecloud为开发者提供了一些通用的云端服务,最终开发出来的APP会和云端服务交互,因此SDK中涉及到和云端交互的接口,均采用异步回调方式,避免阻塞主线程的执行。 在《SDK简介》篇,我们知道SDK大体上提供了6大功能,本文将逐一进行介绍。

交互协议

在上一节中,我们看到整个服务框架采用两种消息进行交互,ACMsg、ACDeviceMsg,其中框架提供了对ACMsg的解析,而ACDeviceMsg则由厂商自定义,框架透传其内容。

基础数据结构

ACMsg为ablecloud自定义数据结构。主要通过put/get方式在其中保存交互所需数据。本质上,put进ACMsg中的数据为json格式,服务框架在传输过程会对其进行序列化/反序列化,因此接收端可以直接get出相应的值。

ACObject

ACObject用于承载交互的具体数据,我们称之为payload(负载)。上文提到通过put存入ACObject的数据内部以json方式处理,因此ACObject中的某一value也可以是嵌套的ACObject,能满足大部分需求场景。

@interface ACObject : NSObject

/**
 * Get各种类型的参数值,务必保证Get和Put参数名和类型是一致的
 * @param name  参数名
 * @return      参数值
 */
- (id)get:(NSString *)name;
- (NSArray *)getArray:(NSString *)name;
- (BOOL)getBool:(NSString *)name;
- (long)getLong:(NSString *)name;
- (NSInteger)getInteger:(NSString *)name;
- (float)getFloat:(NSString *)name;
- (double)getDouble:(NSString *)name;
- (NSString *)getString:(NSString *)name;
- (ACObject *)getACObject:(NSString *)name;

/**
 * Put各种类型的参数值,务必保证Put与Get的参数名和类型是一致的
 * @param name  参数名
 * @param value 参数值
 * @return
 */
- (void)put:(NSString *)name value:(id)value;
- (void)putBool:(NSString *)name value:(BOOL)value;
- (void)putLong:(NSString *)name value:(long)value;
- (void)putInteger:(NSString *)name value:(NSInteger)value;
- (void)putFloat:(NSString *)name value:(float)value;
- (void)putDouble:(NSString *)name value:(double)value;
- (void)putString:(NSString *)name value:(NSString *)value;
- (void)putACObject:(NSString *)name value:(ACObject *)value;

/**
 * 添加一个参数到Array类型中
 * @param name  参数名
 * @param value 参数值
 */
- (void)add:(NSString *)name value:(id)value;
- (void)addBool:(NSString *)name value:(BOOL)value;
- (void)addLong:(NSString *)name value:(long)value;
- (void)addInteger:(NSString *)name value:(NSInteger)value;
- (void)addFloat:(NSString *)name value:(float)value;
- (void)addDouble:(NSString *)name value:(double)value;
- (void)addString:(NSString *)name value:(NSString *)value;
- (void)addACObject:(NSString *)name value:(ACObject *)value;

/**
 * 判断是否存在此参数
 * @param name  参数名
 */
- (BOOL)contains:(NSString *)name;

/**
 * 获取所有参数名列表
 * @param name  参数名
 */
- (NSArray *)getKeys;

/**
 * ACObject对象的序列化和反序列化
 */
- (NSData *)marshal;
+ (NSData *)marshal:(ACObject *)object;
+ (instancetype)unmarshal:(NSData *)data;

@end

注:最常用的三个接口是put/add/get,通过add接口保存在ACObject中的数据实际为NSArray,相应的,get出来也是一个NSArray。

ACMsg

ACMsg继承自ACObject,扩展了一些功能,比如设置了交互的方法名name、交互的上下文context以及其它形式的负载payload信息。通常采用ACMsg进行数据交互,较多的使用OBJECT_PAYLOAD格式,该格式只需要使用ACObject提供的put、get接口获取数据即可。因为在使用OBJECT_PAYLOAD格式时,框架会对数据进行序列化/反序列化。ACMsg也提供另外的数据交互格式,如json、stream等。如果用json格式,则通过setPayload/getPayload设置/获取序列化后的json数据并设置对应的payloadFormat,开发者后续可自行解析。

@interface ACMsg : ACObject

@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) ACContext *context;
@property (nonatomic, strong) NSString *payloadFormat;
@property (nonatomic, assign) NSUInteger payloadSize;
@property (nonatomic, strong, readonly) NSData *payload;
@property (nonatomic, strong, readonly) NSData *streamPayload;

/**
 * 设置流式负载,主要用于较大二进制数据传输,如上传文件等。
 * @param payload   负载内容
 * @param size      负载大小
 */
- (void)setStreamPayload:(NSData *)streamPayload size:(NSInteger)size;

/**
 * 设置错误信息。在服务端处理错误时,需要显示的调用该结果设置错误信息
 * @param errCode   错误码
 * @param errMsg    错误信息
 */
- (void)setErr:(NSInteger)errCode errMsg:(NSString *)errMsg;

/**
 * 判断服务端响应的处理结果是否有错
 * @return  YES-处理有错,NO-处理成功
 */
- (BOOL)isErr;
- (NSInteger)getErrCode;
- (NSString *)getErrMsg;
- (void)setAck;

extern NSString *const ACMsgObjectPayload;
extern NSString *const ACMsgJsonPayload;
extern NSString *const ACMsgStreamPayload;
extern NSString *const ACMsgMsgNameHeader;
extern NSString *const ACMsgAckMSG;
extern NSString *const ACMsgErrMSG;

@end

ACContext

交互消息中的context主要用于包含重要的上下文信息,其定义如下:

@interface ACContext : NSObject

@property (nonatomic, strong) NSString *os; // 操作系统
@property (nonatomic, strong) NSString *version; // 系统版本
@property (nonatomic, strong) NSString *majorDomain; // 服务所属主域名
@property (nonatomic, strong) NSString *subDomain; // 服务所属子域名
@property (nonatomic, strong) NSNumber *userId; // 用户id
@property (nonatomic, strong) NSString *traceId; // 请求唯一标识,可用于问题追踪
@property (nonatomic, strong) NSString *traceStartTime; // 请求起始时间
@property (nonatomic, strong) NSString *nonce; // 用于签名的随机字符串
@property (nonatomic, strong) NSString *timeout; // 为防止签名被截获,设置签名的有效超时时间,单位秒
@property (nonatomic, strong) NSString *timestamp; // 请求发起的时间戳,单位秒
@property (nonatomic, strong) NSString *signature; // 请求的合法性签名

/**
 * 生成context主要用于包含重要的上下文信息
 * @param subDomain   服务所属子域名
 */
+ (ACContext *)generateContextWithSubDomain:(NSString *)subDomain;

@end

注: 客户端往后端服务发送消息,服务向另一服务发送消息的时候,均需要对所发请求进行签名,具体的签名算法见附录。

SDK

这一章节重点介绍后端服务开发相关的SDK。前面作为铺垫介绍了很多底层的数据结构,实际上大多数开发者在使用ablecloud框架开发服务的时候,仅需简单的使用那些基础数据,专注于实际的业务逻辑,快速的完成开发/测试/发布。

ACloudLib

ACloudLib主要负责设置相关参数,如服务器地址(测试环境为test.ablecloud.cn:5000,线上环境为production.ablecloud.cn:5000)、主域名称、指定服务桩等。

@interface ACloudLib : NSObject

/**
 * 设置云端服务的接入地址,测试环境为test.ablecloud.cn:5000, 线上环境为production.ablecloud.cn:5000
 */
+ (void)setHost:(NSString *)host;
+ (NSString *)getHost;

/**
 * 设置访问云端服务的超时时间,根据开发者服务的性能合理定义,单位是秒
 */
+ (void)setHttpRequestTimeout:(NSString *)timeout;
+ (NSString *)getHttpRequestTimeout;

/**
 * 设置APP所属开发者帐号的主域信息,通过控制台进行查看帐号的主域等私密信息
 */
+ (void)setMajorDomain:(NSString *)majorDomain;
+ (NSString *)getMajorDomain;

/**
 * 设置SDK依赖的云端服务的桩,用于对APP端的单元测试
 */
+ (void)setStubService:(NSString *)serviceName delegate:(id<ACStubDelegate>)delegate;
+ (id<ACStubDelegate>)getStubServiceDelegate:(NSString *)serviceName;
+ (void)removeStubService:(NSString *)serviceName;
+ (BOOL)isStubService:(NSString *)serviceName;


@end

内嵌云端服务

顾名思义,内嵌云端服务,是指ablecloud抽象并实现的多种通用后端服务,避免开发者重复开发这些基础设施。开发者可直接使用这些服务,降低应用服务程序的开发代价,提高开发效率。各个云端服务的对象通过上节介绍的ACC相关接口获取。

ACStubDelegate

ablecloud定义了代理ACStubDelegate,开发者只需要实现该代理即可模拟设备或者云端服务进行单元测试。定义如下:

@protocol ACStubDelegate <NSObject>
@optional
- (void)handleControlMsg:(ACMsg *)req callback:(void (^)(ACMsg *responseObject, NSError *error))callback;
@end

账号管理

该服务用于管理和某一智能设备相关的用户,比如查看用户的基本信息/状态等。发现异常用户时,服务程序能及时做出相应操作。

引入头文件

#import "ACAccountManager.h"

接口说明

@interface ACAccountManager : NSObject

/**
 * 发送手机验证码 (有关规定每天向同一个手机号发送的短信数量有严格限制)
 * @param account 手机号码或者邮箱地址,目前只支持手机号码
 */
+ (void)sendVerifyCodeWithAccount:(NSString *)account
                         callback:(void (^)(NSError *error))callback;
/**
 * 校验手机验证码
 * @param account 手机号码
 * @param verifyCode 验证码
 */
+ (void)checkVerifyCodeWithAccount:(NSString *)account
                        verifyCode:(NSString *)verifyCode
                          callback:(void (^)(BOOL valid,NSError *error))callback;
/**
 * 注册帐号
 * @param phone 手机号码(与邮箱地址二选一或者都填)
 * @param email 邮箱地址(与手机号码二选一或者都填)
 * @param password 帐号密码
 * @param verifyCode 验证码
 */
+ (void)registerWithPhone:(NSString *)phone
                    email:(NSString *)email
                 password:(NSString *)password
               verifyCode:(NSString *)verifyCode
                 callback:(void (^)(NSString *uid, NSError *error))callback;
/**
 * 登陆帐号
 * @param account 手机号码或者邮箱地址(与邮箱地址二选一或者都填)
 * @param password 帐号密码
 */
+ (void)loginWithAccount:(NSString *)account
                password:(NSString *)password
                callback:(void (^)(NSString *uid, NSError *error))callback;
/**
 * 重置密码
 * @param account 手机号码或者邮箱地址,目前只支持手机号码
 * @param verifyCode 验证码
 * @param password 帐号的新密码
 */
+ (void)resetPasswordWithAccount:(NSString *)account
                      verifyCode:(NSString *)verifyCode
                        password:(NSString *)password
                        callback:(void (^)(NSString *uid, NSError *error))callback;
/**
 * 修改密码
 * @param oldPassword 帐号旧密码
 * @param newPassword 帐号新密码
 */
+ (void)changePasswordWithOld:(NSString *)oldPassword
                          new:(NSString *)newPassword
                     callback:(void (^)(NSString *uid, NSError *error))callback;

@end

绑定管理

该服务用于基于某一单个设备的绑定授权管理,比如查看所有绑定的设备列表等,绑定、解绑、分享设备等操作。第一个绑定设备的人是设备的Owner管理员,管理员Owner具有超级权限,可以分享授权,可以通过删除或解绑,解除设备所有的已绑定关系,也可以转让Owner身份给已绑定设备的普通用户。

引入头文件

#import "ACBindManager.h"

接口说明

@interface ACBindManager : NSObject

/**
 *  获取设备列表
 *  
 *  @param callback     数组:devices保存的对象是ACUserDevice的对象
 */
+ (void)listDevicesWithCallback:(void(^)(NSArray *devices,NSError *error))callback;

/**
 *  获取用户列表
 *
 *  @param deviceId 设备唯一标识
 *  @param callback 数组:users保存的对象是ACBindUser的对象
 */
+ (void)listUsersWithSubDomain:(NSString *)subDomain
                      deviceId:(NSInteger)deviceId
                     calllback:(void(^)(NSArray *users,NSError *error))callback;

/**
 *  绑定设备
 *
 *  @param physicalDeviceId 设备物理ID
 *  @param name             设备名称
 *  @param callback         回调 deviceId 设备的逻辑Id
 */
+ (void)bindDeviceWithSubDomain:(NSString *)subDomain
               physicalDeviceId:(NSString *)physicalDeviceId
                           name:(NSString *)name
                       callback:(void(^)(ACUserDevice *userDevice,NSError *error))callback;

/**
 *  根据分享码 绑定设备
 *
 *  @param shareCode        分享码
 *  @param subDomain        主域名
 *  @param deviceId         逻辑  ID
 *  @param callback         回调 ACUserDevice 设备的对象
 */
+ (void)bindDeviceWithShareCode:(NSString *)shareCode
                      subDomain:(NSString *)subDomain
                       deviceId:(NSInteger )deviceId
                       callback:(void(^)(ACUserDevice *userDevice,NSError *error))callback;

/**
 *  根据账户绑定设备
 *
 *  @param subDomain 子域
 *  @param deviceId  设备ID
 *  @param phone     电话号码
 */
+ (void)bindDeviceWithUserSubdomain:(NSString *)subDomain
                           deviceId:(NSInteger)deviceId
                            account:(NSString *)account
                           callback:(void(^)(NSError *error))callback;
/**
 *  解绑设备
 *
 *  @param subDomain    子域名称
 *  @param deviceId     设备唯一标识
 */
+ (void)unbindDeviceWithSubDomain:(NSString *)subDomain
                         deviceId:(NSInteger)deviceId
                         callback:(void(^)(NSError *error))callback;


/**
 *  管理员取消 某个用户的绑定  (管理员接口)
 *
 *  @param subDomain 子域
 *  @param userId    用户ID
 *  @param deviceId  设备逻辑ID
 *  @param callback  回调
 */
+ (void)unbindDeviceWithUserSubDomain:(NSString *)subDomain
                               userId:(NSInteger)userId
                             deviceId:(NSInteger)deviceId
                             callback:(void(^)(NSError *error))callback;


/**
 *  设备管理员权限转让 (管理员接口)
 *
 *  @param subDomain    子域名称
 *  @param deviceId     设备逻辑ID
 *  @param userId       新的管理员ID
 */
+ (void)changeOwnerWithSubDomain:(NSString *)subDomain
                        deviceId:(NSInteger)deviceId
                          userId:(NSInteger)userId
                        callback:(void(^)(NSError *error))callback;
/**
 *  更换物理设备 (管理员接口)
 *
 *  @param subDomain        子域名称
 *  @param physicalDeviceId 设备物理ID
 *  @param deviceId         设备逻辑ID
 *  @param bindCode         绑定码(可选)
 */
+ (void)changeDeviceWithSubDomain:(NSString *)subDomain
                 physicalDeviceId:(NSString *)physicalDeviceId
                         deviceId:(NSInteger)deviceId
                         callback:(void(^)(NSError *error))callback;


/**
 *  修改设备名称 (管理员接口)
 *
 *  @param subDomain    子域名称
 *  @param deviceId     设备逻辑ID
 *  @param name         设备的新名称
 */
+ (void)changNameWithSubDomain:(NSString *)subDomain
                      deviceId:(NSInteger)deviceId
                          name:(NSString *)name
                      callback:(void(^)(NSError *error))callback;


/**
 *  获取分享码  (管理员接口)
 *
 *  @param subDomain 子域名称
 *  @param deviceId  设备唯一标识
 *  @param timeout   超时时间(秒)
 *  @callback        shareCode 分享码
 */
+ (void)getShareCodeWithSubDomain:(NSString *)subDomain
                         deviceId:(NSInteger)deviceId
                          timeout:(NSTimeInterval)timeout
                         callback:(void(^)(NSString *shareCode,NSError *error))callback;
@end

开发环境设置

系统准备

在进行开发前,需要对系统以及环境进行设置。目前框架支持Objective-C、C语言,因此系统准备基本都是和iOS开发相关,如Mac OS X、Xcode等。 + OS X 系统建议采用Mac OS X 10.8以上的版本 + Xcode 安装Xcode,建议采用6.0以上版本 + ablecloud 下载ablecloud开发框架并解压

Xcode

  1. 新建工程 选择新建iOS Application,根据需要选择,建议选择Single View Application。 点击Next进入下一个页面,根据情况填写Product Name/Organization Name/Organization Identifier等信息。 填好后点击Next,进入下一步,填写好存放路径。 至此,新建工程完成。
  2. 导入AbleCloudLib 按照步骤1完成了工程的新建,接下来需要将AbleCloudLib导入到工程中。 右键点击工程中想要导入的Group选择 Add Files to "your project name"... 选择AbleCloudLib的路径,勾选Copy items if needed,点击Add添加。 完成上述步骤后,我们将在工程视图里面看到该目录。 至此,开发者开发服务所以来的ablecloud开发框架库添加成功。
  3. 本地运行 Xcode下直接Command + R运行。

    注:如果是模拟器运行请导入模拟器的静态库,如果是真机运行则导入真机静态库,否则在编译的过程中会失败。

Demo