Android

1. 插件接入步骤

1.1 项目引入插件

1.1.1 dependencyResolutionManagement管理

  • 在工程的根目录下的setting.gradle添加jitpack支持
dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.PREFER_SETTINGS)
    repositories {
        //申明仓库地址
        maven { url 'https://jitpack.io' }
        //其他仓库配置
        ...
    }
}
  • 在App目录下的build.gradle添加依赖
dependencies {
    //申明依赖,X.Y.Z需修改成具体的版本号
    implementation("com.github.YolandaQingniu:qnscalesdkX:X.Y.Z")

    //其他三方依赖
    ...
}

1.1.2 allprojects管理

  • 在工程的根目录下的 build.gradle添加jitpack支持
allprojects {
    repositories {
        //其它仓库配置
        maven { url 'https://jitpack.io' }
        //其他仓库配置
        ...
    }
}
  • 在App目录下的build.gradle添加依赖
dependencies {
    //申明依赖,X.Y.Z需修改成具体的版本号
    implementation("com.github.YolandaQingniu:qnscalesdkX:X.Y.Z")

    //其他三方依赖
    ...
}

1.2 配置项目蓝牙权限使用说明

app的targetSdk>30,且手机的系统版本为安卓12及以上,则需要以下权限

  • android.permission.BLUETOOTH_ADVERTISE

  • android.permission.BLUETOOTH_SCAN

  • android.permission.BLUETOOTH_CONNECT

否则需要以下权限

  • android.permission.BLUETOOTH

  • android.permission.BLUETOOTH_ADMIN

  • android.permission.ACCESS_COARSE_LOCATION

  • android.permission.ACCESS_FINE_LOCATION

1.3 混淆配置

-keep class com.qingniu.scale.model.BleScaleData{*;}
-keep class com.jieli.** {*;}

1.4 初始插件

可在BaseApplication中的onCreate生命周期方法中初始化

//获取项目中授权文件地址
String encryptPath = "file:///android_asset/123456789.qn";
//实例化插件, QNBleApi为单例对象
QNBleApi bleApi = QNBleApi.getInstance(this);
//获取插件授权
bleApi.initSdk("123456789", encryptPath, new QNResultCallback() {
    @Override
    public void onResult(int code, String msg) {
    }
});

1.5 监听系统蓝牙状态变化(QNBleStateListener)

/*
enum QNBLEState {
    Unknown,
    setting,
    Unsupported,
    Unauthiorized,
    PoweredOff,
    PoweredOn;
 */
bleApi.setBleStateListener(new QNBleStateListener() {
    @Override
    public void onBleSystemState(QNBLEState qnbleState) {

    }
});

1.6 监听SDK日志(QNLogListener)

bleApi.setLogListener(new QNLogListener() {
    @Override
    public void onLog(String log) {
        //SDK输出的日志会在这里返回
    }
});

2. 设备扫描

2.1 开启蓝牙扫描

在需要获取蓝牙设备的业务界面,调用以下方法

bleApi.startBleDeviceDiscovery(new QNResultCallback() {
    @Override
    public void onResult(int code, String msg) {
        //此处回调结果仅代表扫描周围设备方法调用是否成功
    }
});

2.2 获取蓝牙扫描的设备

在成功调用SDK的蓝牙扫描方法后,SDK会将扫描到的设备通过QNBleDeviceDiscoveryListener监听进行回调,同时该监听也可获取到SDK的蓝牙扫描相关状态

开发者可按以下示例注册监听回调,该回调监听业务维护上建议注册一次即可

bleApi.setBleDeviceDiscoveryListener(new QNBleDeviceDiscoveryListener() {
    @Override
    public void onDeviceDiscover(QNBleDevice device) {
      //当启动扫描,扫描到设备时会回调该函数。此处仅回调所支持的设备
      //此处可判断device对象是否是目标设备,如果是目标设备,可缓存至内存中,便于后续发起蓝牙连接
    }

    @Override
    public void onStartScan() {
      //启动扫描时,会回调该函数

    }

    @Override
    public void onStopScan() {
      //停止扫描时,会回调该函数

    }

     @Override
     public void onScanFail(int code) {
       //启动扫描失败回调

     }
});

3. 设备连接

3.1 开始设备连接

在通过第2步骤扫描获取到目标设备对象之后,可按以下方法调用设备连接方法

//持续的蓝牙扫描会耗电,建议在执行连接之前停止扫描
//谷歌官方建议:https://developer.android.com/develop/connectivity/bluetooth/ble/find-ble-devices?hl=zh-cn
bleApi.stopBleDeviceDiscovery(new QNResultCallback() {
    @Override
    public void onResult(int code, String msg) {

    }
});

//设置秤端单位
QNConfig sdkConfig = bleApi.getConfig()
sdkConfig.unit = 0; //0-kg,1-lb,2-斤,3-st:lb,4-st,
sdkConfig.save();

QNUserScaleConfig config = new QNUserScaleConfig();
//已注册的秤端用户列表,在本次连接时,会向秤端删除该数组不包含的秤端用户
ArrayList<QNUser> deviceUserList = new ArrayList<>();
config.setUserlist(deviceUserList);

//以下3种描述对应不同的业务逻辑,接入方按需配置
//1、如果使用访客(即无需向秤端注册用户,秤端不会保存该用户的信息), 注意该字段与user.index中互斥,优先取isVisitor
//该值设为true的情况下,代表使用访客,会忽略config.setRegist(boolean)以及config.setChange(boolean)设置
config.setVisitor(true)
int index = 0;

//2、如果不使用访客,那么需要告知秤端,本次连接时,是向秤端注册用户还是访问秤端用户
//如果是注册秤端用户
//注册⽤户前,需要核实⼀下秤设备的秤端⽤户是否已满(秤端最多存储8个⽤户),可以根据QNBleDevice.this.getRegisteredUserNum()进⾏判断
//注册秤端⽤户成功后,SDK会拿到秤端返回的user.index,⻅registerUserComplete回调函数。
//注册秤端⽤户成功后,可以接收到秤端的实时体重数据和结果数据
config.setVisitor(false)
config.setRegist(true)
config.setChange(false)
int index = 0;

//3、如果是访问秤端用户
//访问⽤户传⼊的⽤户信息,会更新秤端保存的对应信息,例如秤端针对该⽤户保存的身⾼是170cm,如果此次传⼊的时171cm,那么秤端就会更新为171cm
//访问秤端⽤户成功后,可以接收到秤端的实时体重数据和结果数据
config.setVisitor(false)
config.setRegist(false)
config.setChange(true)
int index = 1; //有效范围[1,8],代表访问的是秤端哪个位置上的用户。该值由向秤端注册用户时,秤端返回,见registerUserComplete回调函数。

//构建本次连接的用户信息
String userId = "";//业务逻辑中用户唯一标识,用于业务中用户区分判断
int height = 170;//用户身高,单位cm
String gender = "male"; //用户性别,"male" 男性,"female" 女性
Date birthday = new Date(631199317000L);//用户生日

QNUser user = bleApi.buildUser(userId, height, gender, birthday, 0, UserShape.SHAPE_NONE, UserGoal.GOAL_NONE, 0, index, 0,
        new QNResultCallback() {
            @Override
            public void onResult(int code, String msg) {

            }
        });
//lastHmac需要是上笔测量体脂率大于0并且与hmac同类型的数据,同类型可根据QNScaleData.this.getNewEightModel()是否一致判断
user.setHmac(lastHmac);

config.setCurUser(user);

bleApi.connectUserScaleDevice(device, config, new QNResultCallback() {
    @Override
    public void onResult(int code, String msg) {

    }
});

3.2 设备连接状态监听(QNBleConnectionChangeListener)

bleApi.setBleConnectionChangeListener(new QNBleConnectionChangeListener() {
    @Override
    public void onConnecting(QNBleDevice device) {
    //设备正在连接时回调

    }

    //已连接
    @Override
    public void onConnected(QNBleDevice device) {
    //设备已连接时回调

    }

    @Override
    public void onServiceSearchComplete(QNBleDevice device) {
    //设备的服务搜索完成
    }

    @Override
    public void onDisconnecting(QNBleDevice device) {
    //设备正在断开时回调

    }

    @Override
    public void onDisconnected(QNBleDevice device) {
    //设备已断开时回调

    }

    @Override
    public void onConnectError(QNBleDevice device, int errorCode) {
    //设备出现了连接错误回调
    }

    @Override
    public void onStartInteracting(QNBleDevice device) {
    //设备可以进行交互,即可以下发设备对应的操作指令

    }
});

4. 设备数据获取

4.1 设备数据交互监听(QNUserScaleDataListener)

在执行3.1步骤,与设备蓝牙连接上后,相关数据获取示例如下

bleApi.setDataListener(new QNUserScaleDataListener() {
    //向秤端注册用户成功,回调秤端分配的用户坑位
    @Override
    public void registerUserComplete(QNBleDevice device, QNUser user) {
    //注册用户时,秤端分配的坑位。app端应将该坑位、用户id、设备mac进行关联保存。下次该用户连接该设备时需用到该index进行秤端用户访问测量
        int index = user.index;
    }

    //设备测量过程实时重量的回调, weight实时体重,单位kg
    @Override
    public void onGetUnsteadyWeight(QNBleDevice device, double weight) {

    }

    //设备测量完成测量数据回调, data 测量数据
    @Override
    public void onGetScaleData(QNBleDevice device, QNScaleData data) {
        //测量完成获取完整测量数据,针对新⽅案⼋电极设备,可判断本次测量数据是否异常
        if (data.getNewEightModel() == 1) {
            //本次测量是否异常,0-正常;1-异常
            int isAbnormal = data.getEightIsAbnormal();
            if (isAbnormal == 1) {
                //本次测量异常原因,0-正常,1-手部接触异常;2-腿部接触异常;3-手脚接触均异常
                int reasonMask = data.getEightReasonMask();
                //根据异常原因,可提示用户重新测量
                //可参考[附表-八电极异常测量提示]

                return;
            }
        }

        //本次测量手脚各部位接触正常
        Date measureDate = data.getMeasureTime();
        double weight = data.getWeight();//测量体重
        List<QNScaleItemData> allTarget = data.getAllItem();

        for (QNScaleItemData item: allTarget) {
            item.getType() //指标类型,见QNScaleType
            item.getValue() //指标数值
        }

        //业务层面也可以对本次测量数据二次判断,如是否有测到体脂
        //或者与用户的上一笔测量数据中的体重/体脂对比,差异在某个业务阈值外时,也可提示用户重新测量

        //如果最终需将测量数据保存,业务逻辑上需要额外保存QNScaleData类中的hmac与newEightModel字段,用于下次连接测量时的判断与入参

    }

    // 当前访问用户存储数据及未知存储回调,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属性进⾏判断
    @Override
    public void onGetStoredScale(QNBleDevice device, List<QNScaleStoreData> storedDataList) {
        //对于未知测量数据,可通知相关用户,让用户选择这笔数据是否是自己的
        ArrayList<QNScaleStoreData> unknowStoreDataList = new ArrayList<>();
        for (QNScaleStoreData storeData : storedDataList) {
            if(!storeData.isDataComplete()){
                unknowStoreDataList.add(storeData);
            } else {
            //已知当前用户的存储数据,该存储数据可直接归属到该用户下
                QNScaleData scaleData = storeData.generateScaleData();
                for (QNScaleItemData item: scaleData.getAllItem()) {
                    item.type //指标类型,见QNScaleType
                    item.value //指标数值
                }
            }
        }
    }

    //测量过程中的连接状态
    @Override
    public void onScaleStateChange(QNBleDevice device, int status) {

    }

});

5. 设备断开

5.1 断开设备连接

//若有需要,可主动调用断开设备连接方法
bleApi.disconnectDevice(bleApi, new QNResultCallback() {
    @Override
    public void onResult(int code, String msg) {

    }
});

6. 数据计算

6.1 未知数据计算、重新计算

//未知存储数据归属用户的用户信息
String userId = "";
int height = 170;//用户身高,单位cm
String gender = "male"; //用户性别,"male" 男性,"female" 女性
Date birthday = new Date(631199317000L);//用户生日
QNUser user = mQNBleApi.buildUser(userId, height, gender, birthday, new QNResultCallback() {
    @Override
    public void onResult(int code, String msg) {

    }
});

//hmac为本次未知测量数据中的hmac,即QNScaleStoreData中的hmac
//lastHmac需要是上笔测量体脂率大于0并且与hmac同类型的数据,同类型可根据QNScaleData.this.getNewEightModel()是否一致判断
QNScaleData scaleData = mQNBleApi.calculateScaleDataByHmac(user, hmac,lastHmac);

results matching ""

    No results matching ""