1. 插件接入步骤
1.1 项目引入插件
1.1.1 通过cocoapods方式
//在项目Podfile文件中,增加插件及指定版本的引入
pod 'QNSDK', '2.29.0' //此处版本号可根据github中显示的最新版本进行引入
GIthub地址:sdk-ios-demo
1.1.2 通过carthage方式
//在项目Cartfile文件中,增加插件引入
github "https://github.com/YolandaQingniu/sdk-ios-demo.git"
1.1.3 手动导入方式
1. 将.a文件放置项目中的指定位置
2. 在【TARGETS】-> 【Build Setting】->【Search Paths】->【LibrarySearch Paths】中添加SDK路径
3. 配置链接器 【TARGETS】-> 【Build Setting】-> 【Linking】-> 【Other Linker Flags】中添加 -ObjC、-all_load、-force_load [SDK路径] 其中之一
1.2 配置项目蓝牙权限使用说明
在项目的Info.plist文件中,增加 Privacy - Bluetooth Peripheral Usage Description、Privacy - Bluetooth Always Usage Description 键,进行蓝牙的使用说明
1.3 导入插件API头文件
#import <QNSDK/QNDeviceSDK.h>
1.4 初始插件
//获取项目中授权文件地址(入参为qn文件的文件名称和文件扩展名)
NSString *file = [[NSBundle mainBundle] pathForResource:@"123456789" ofType:@"qn"];
//实例化插件, QNBleApi为单例对象
QNBleApi *bleApi = [QNBleApi sharedBleApi];
//获取插件授权(入参为appid和qn文件路径)
[bleApi initSdk:@"123456789" firstDataFile:file callback:^(NSError *error) {
if(error) {
//监听异常回调
}
}];
1.5 监听系统蓝牙状态变化(QNBleStateListener)
//设置监听(系统蓝牙状态)
bleApi.bleStateListener = self;
/*
typedef NS_ENUM(NSUInteger, QNBLEState) {
QNBLEStateUnknown = 0, //未知状态
QNBLEStateResetting = 1, //系统蓝牙正在重置
QNBLEStateUnsupported = 2, //系统不支持蓝牙使用
QNBLEStateUnauthorized = 3, //未授权蓝牙使用
QNBLEStatePoweredOff = 4, //系统蓝牙处于关闭状态
QNBLEStatePoweredOn = 5, //系统蓝牙处于开启状态
};
*/
- (void)onBleSystemState:(QNBLEState)state {
}
1.6 监听SDK日志(QNLogProtocol)
//设置监听(SDK日志)
bleApi.logListener = self;
- (void)onLog:(nonnull NSString *)log {
//SDK输出的日志会在此处返回
}
2. 开启蓝牙扫描,拿到设备对象
2.1 开启蓝牙扫描
[bleApi startBleDeviceDiscovery:^(NSError *error) {
}];
2.2 监听扫描状态的变化(QNBleDeviceDiscoveryListener)
//设置监听(扫描设备)
bleApi.discoveryListener = self;
//启动扫描时,会回调该函数
- (void)onStartScan {
}
//停止扫描是,会回调该函数
- (void)onStopScan {
}
//当启动扫描,扫描到设备时会回调该函数。此处仅回调所支持的设备
- (void)onDeviceDiscover:(QNBleDevice *)device {
//后续调用SDK发起连接设备方法时,需要传入该device
}
3. 连接设备
3.1 开始连接设备
//建议先停止扫描
[_bleApi stopBleDeviceDiscorvery:^(NSError *error) { }];
//设置秤端单位
QNConfig *sdkConfig = [QNConfig sharedConfig];
sdkConfig.unit = QNUnitKG;
[sdkConfig save];
//开始连接秤设备
/*
device:需要连接的蓝牙设备,即扫描设备监听方法onDeviceDiscover返回的(QNBleDevice *)device
config:连接用户秤设备时的配置项,可以参考下面示例
*/
[bleApi connectUserScaleDevice:device config:config callback:^(NSError *error) {
}];
//config参数示例:
QNUserScaleConfig *config = [[QNUserScaleConfig alloc] init];
//此次测量的用户信息
QNUser *user = [[QNUser alloc] init];
user.userId = "";//业务逻辑中用户唯一标识,用于业务中用户区分判断
user.height = 170;//用户身高,单位cm
user.gender = @"male";//用户性别,"male" 男性,"female" 女性
user.birthday = [NSDate dateWithTimeIntervalSince1970:631199317];//用户生日,入参是秒级时间戳
user.hmac = lastValidEightHmac; //注意:需要是该用户最近一条(测量体脂率大于0并且是同类型八电极设备的)测量数据的hmac,同类型可根据QNScaleData.newEightModel属性进行判断
/*
测量模式一般分为两种:用户管理模式 和 访客模式,具体使用哪一种,可以根据贵司的APP业务场景决定
*/
//1. 访客模式
/*
访客模式可以理解为临时用秤,传入的用户信息只在此次蓝牙连接过程中生效,秤端不会保存
注意:config.isVisitor字段与user.index是互斥的,isVisitor的优先级更高,即访客模式下,user.index使用默认值即可(user.index是为用户管理模式所设计的字段)
*/
config.isVisitor = YES; //是否使用访客模式;YES-访客,NO-非访客,即用户管理模式;
config.curUser = user;
//2. 用户管理模式
//2.1 注册用户
/*
向秤端注册的用户
注册用户前,需要核实一下秤设备的秤端用户是否已满(秤端最多存储8个用户),可以根据QNBleDevice的registeredUserNum进行判断
注册秤端用户成功后,SDK会拿到秤端返回的user.index,见registerUserComplete回调函数。
注册秤端用户成功后,可以接收到秤端的实时体重数据和结果数据
*/
config.curUser = user;
//2.2访问用户【注册和访问是不能同时进行的】
/*
访问秤端用户(访问秤端已经有的用户),需要传入user.index,用于秤端校验,如果与秤端存储的不一致,则会访问失败
访问用户传入的用户信息,会更新秤端保存的对应信息,例如秤端针对该用户保存的身高是170cm,如果此次传入的时171cm,那么秤端就会更新为171cm
访问秤端用户成功后,可以接收到秤端的实时体重数据和结果数据
*/
user.index = 1; //用户坑位,即秤端用户索引,有效范围[1,8],代表访问的是秤端哪个位置上的用户。该值由向秤端注册用户时,秤端返回,见registerUserComplete回调函数。
config.curUser = user;
//2.3删除用户【SDK会先进行删除用户操作,然后才进行注册用户或者访问用户操作】
//已注册的秤端用户列表,在本次连接时,会向秤端删除该数组不包含的秤端用户
NSMutableArray<QNUser *> *registeredUserList = [NSMutableArray array];
config.userlist = registeredUserList;
3.2 监听设备连接状态变化(QNBleConnectionChangeListener)
//设置监听(设备连接状态变化)
bleApi.connectionChangeListener = self;
//设备正在连接中回调
- (void)onConnecting:(QNBleDevice *)device {
}
//设备连接成功回调
- (void)onConnected:(QNBleDevice *)device {
}
//设备通讯服务已搜索完成,此处一般不涉及逻辑处理
- (void)onServiceSearchComplete:(QNBleDevice *)device {
}
//设备连接失败,会回调失败异常信息
- (void)onConnectError:(QNBleDevice *)device error:(NSError *)error {
}
//设备可以进行交互,即可以下发设备对应的操作指令
- (void)onStartInteracting:(QNBleDevice *)device {
}
//设备正在断开蓝牙连接
- (void)onDisconnecting:(QNBleDevice *)device {
}
//设备已断开
- (void)onDisconnected:(QNBleDevice *)device {
}
4. 拿到设备数据
4.1 监听设备数据交互(QNScaleDataListener)
//设置监听(设备连接状态变化)
bleApi.dataListener = self;
//向秤端注册用户成功,回调秤端分配的用户坑位【适用于用户管理模式,访客模式可以忽略该方法】
- (void)registerUserComplete:(QNBleDevice *)device user:(QNUser *)user {
//注册用户时,秤端分配的坑位。app端应将该坑位、用户id、设备mac进行关联保存。下次该用户连接该设备时需用到该index进行秤端用户访问测量
int index = user.index;
}
/* 秤端交互过程状态变化
typedef NS_ENUM(NSInteger, QNScaleState) {
QNScaleStateDisconnected = 0, //未连接
QNScaleStateLinkLoss = -1, //失去连接
QNScaleStateConnected = 1, //已连接
QNScaleStateConnecting = 2, //正在连接
QNScaleStateDisconnecting = 3, //正在断开
QNScaleStateStartMeasure = 4, //正在测量
QNScaleStateRealTime = 5, //正在测量体重
QNScaleStateBodyFat = 7, //正在测量生物阻抗
QNScaleStateMeasureCompleted = 9, //测量完成
}; 仅需关注该类状态
*/
- (void)onScaleStateChange:(QNBleDevice *)device scaleState:(QNScaleState)state {
}
/* 秤端行为状态变化
typedef NS_ENUM(NSInteger, QNScaleEvent) {
QNScaleEventRegistUserSuccess = 4, //注册用户成功
QNScaleEventRegistUserFail = 5, //注册用户失败
QNScaleEventVisitUserSuccess = 6, //访问用户成功
QNScaleEventVisitUserFail = 7, //访问用户失败
QNScaleEventDeleteUserSuccess = 8, //删除用户成功
QNScaleEventDeleteUserFail = 9, //删除用户失败
QNScaleEventSyncUserInfoSuccess = 10, //同步用户信息成功
QNScaleEventSyncUserInfoFail = 11, //同步用户信息失败
QNScaleEventUpdateIdentifyWeightSuccess = 12, //更新用户识别体重成功
QNScaleEventUpdateIdentifyWeightFail = 13, //更新用户识别体重失败
};仅需关注该类状态
*/
- (void)onScaleEventChange:(QNBleDevice *)device scaleEvent:(QNScaleEvent)scaleEvent {
}
/*
设备测量过程实时重量的回调
@param weight 实时体重,单位kg
*/
- (void)onGetUnsteadyWeight:(QNBleDevice *)device weight:(double)weight {
}
/*
设备测量完成测量数据回调
@param scaleData 测量数据
*/
- (void)onGetScaleData:(QNBleDevice *)device data:(QNScaleData *)scaleData {
//测量完成获取完整测量数据,针对新方案八电极设备,需判断本次测量数据是否异常
if (scaleData.newEightModel == 1) { //新方案八电极设备
//(新方案八电极专属)本次测量是否异常,0-正常;1-异常。
if (scaleData.eightIsAbnormal == 1) {
//(新方案八电极专属)本次测量异常原因,0-正常;1-手部异常;2-腿部异常;3-手脚均异常。
NSInteger reasonMask = scaleData.eightReasonMask;
//根据异常原因,可提示用户重新测量
return;
}
}
NSDate *measureData = scaleData.measureTime;//测量时间
double weight = scaleData.weight;//测量体重
NSArray <QNScaleItemData *> *allTarget = [scaleData getAllItem];
for (QNScaleItemData *item in allTarget) {
item.name //指标名字
item.type //指标类型,见QNScaleType
item.value //指标数值,根据QNValueType确认该value的精确度
}
/*
业务层面也可以对本次测量数据二次判断,如是否有测到体脂
或者与用户的上一笔测量数据中的体重/体脂对比,差异在某个业务阈值外时,也可提示用户重新测量
如果最终需将测量数据保存,业务逻辑上需要额外保存QNScaleData类中的hmac与newEightModel字段,用于下次连接测量时的判断与入参
*/
}
/*
当前访问用户的存储数据及未知存储数据回调
@param storedDataList 存储数据列表
*/
- (void)onGetStoredScale:(QNBleDevice *)device data:(NSArray <QNScaleStoreData *> *)storedDataList {
/*
通过QNScaleStoreData对象中的isDataComplete判断是否为未知存储数据,false为未知存储数据,true为已知存储数据;
1. 针对访客模式,都是未知存储数据;
2. 针对用户管理模式,有已知存储数据(即属于当前访问用户的存储数据)和未知存储数据
3. 对于未知测量数据,可通知相关APP用户进行认领,即让APP用户选择这笔数据是否是自己的
4. 存储数据转化为测量数据分为两步:
4.1 设置该存储数据的拥有者(已知存储数据则不需要这一步) [storeData setUser:<#(QNUser *)#>];
4.2 将存储数据转换为测量数据 [storeData generateScaleDataWithLastEightHmac: lastValidEightHmac]
注意:lastValidEightHmac是数据拥有者的最近一条(测量体脂率大于0并且是同类型八电极设备的)测量数据的hmac,同类型可根据QNScaleData.newEightModel属性进行判断
*/
NSMutableArray<QNScaleStoreData *> *unknowStoreDataList = [NSMutableArray array];
for (QNScaleStoreData *storeData in storedDataList) {
if(!storeData.isDataComplete){
[unknowStoreDataList addObject:storeData];
} else {
NSString *lastValidEightHmac = @"xxxxxx";
QNScaleData *scaleData = [storeData generateScaleDataWithLastEightHmac: lastValidEightHmac];
NSDate *measureData = scaleData.measureTime;//测量时间
double weight = scaleData.weight;//测量体重
NSArray <QNScaleItemData *> *allTarget = [scaleData getAllItem];
for (QNScaleItemData *item in allTarget) {
item.name //指标名字
item.type //指标类型,见QNScaleType
item.value //指标数值,根据QNValueType确认该value的精确度
}
}
}
}
5. 主动断开设备连接
//若有需要,可主动调用断开设备连接方法
[bleApi disconnectDevice:nil callback:^(NSError *error) {
}];
6. 数据计算
6.1 重算指标,也适用于存储数据生成测量数据
/// 重算数据指标
/// @param user 重算数据指标的目标用户
/// @param hmac 重算数据的hmac
/// @param lastEightHmac 上次测量数据的hmac,八电极设备拟合要用
/// @param callback 回调
- (QNScaleData *)calculateScaleDataByHmac:(QNUser *)user hmac:(NSString *)hmac lastEightHmac:(nullable NSString *)lastEightHmac callback:(QNResultCallback)callback;
使用示例:
//目标用户的用户信息
QNUser *user = [[QNUser alloc] init];
user.height = 170;//用户身高,单位cm
user.gender = @"male";//用户性别,"male" 男性,"female" 女性
user.birthday = [NSDate dateWithTimeIntervalSince1970:631199317];//用户生日,传入秒级时间戳
//hmac为重算数据的hmac,可以是存储数据的hmac(对应使用场景是存储数据生成测量数据),也可以是测量数据的hmac(对应使用场景是测量数据 重算指标)
//lastValidEightHmac为目标用户的最近一条(测量体脂率大于0并且是同类型八电极设备的)测量数据的hmac,同类型可根据QNScaleData.newEightModel属性进行判断
QNScaleData scaleData = [bleApi calculateScaleDataByHmac:user hmac:hmac lastEightHmac:lastValidEightHmac callback:^(NSError *error) {
//如果入参检验不通过,此处会报错,而有对应的SDK日志打印
}];