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日志打印     
}];

results matching ""

    No results matching ""