全部产品

LinkFace Android设备端开发指南

更新时间:2020-10-13 11:39:46

LinkFace SDK封装了设备与云的通讯协议,实现了人员信息增删查,人脸信息增删查和人脸检测/识别事件上云等功能。SDK支持Android Studio开发环境。

SDK集成

LinkFace依赖Linkkit SDK 的通道能力,在集成LinkFace SDK之前,请务必完成Linkkit SDK的集成。

依赖引入

// 1. 在根目录下的build.gradle中添加Aliyun Maven仓库的引用
allprojects {
    repositories {
        maven {
            url "http://maven.aliyun.com/nexus/content/repositories/releases"
        }
        maven {
            url "http://maven.aliyun.com/nexus/content/repositories/snapshot"
        }
    }
}

// 2. App build.gradle中添加依赖
implementation('com.aliyun.iotx:linkface:1.0.0')


// 3. App build.gradle中约束ABI,只使用armeabi-v7a
android {
    defaultConfig {
        externalNativeBuild {
            ndk {
                abiFilters "armeabi-v7a"
            }
        }
    }
}

注意:

如果使用SNAPSHOT包,因Android Studio默认不会主动对SNAPSHOT包拉取更新,因而会导致SNAPSHOT包更新时本地与远程不一致,请在App的build.gradle文件中添加以下配置,以便Android Studio禁用本地cache:

configurations.all { resolutionStrategy.cacheChangingModulesFor 0, 'seconds'}

混淆配置

# keep and don't warn LinkFace
-dontwarn com.aliyun.iotx.linkvisual.linkface.**
-keep class com.aliyun.iotx.linkvisual.linkface.** { *; }

权限说明

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
    <uses-permission android:name="android.permission.INTERNET" />

最佳对接流程

1. 初始化

请在Linkkit SDK初始化完成后对LinkFace进行初始化,设备三元组必须传入。

@Override
public void onInitDone(Object data) {
    Log.d(TAG, "onInitDone() called with: data = [" + JSON.toJSONString(data) + "]");
    linkkitConnectState = ConnectState.CONNECTED;
    getServiceList();
    setServiceHandler();
    //初始化LinkFace SDK
    LinkFaceConfig linkFaceConfig = LinkFaceConfig.newBuilder()
        .productKey(productKey)
        .deviceName(deviceName)
        .deviceSecret(deviceName)
        .log_level(0)
        .build();
    int ret = LinkFace.getInstance().init(linkFaceConfig, MainActivity.this);
    appendLog("LinkFace SDK 初始化完成: " + ret);
}

2. 监听Linkkit通道消息

LinkFace SDK由Linkkit通道的下行消息来驱动,需要在Linkkit的onNotify回调中将下行topic派遣到LinkFace SDK进行处理。

    private IConnectNotifyListener connectNotifyListener = new IConnectNotifyListener() {
        @Override
        public void onNotify(String connectId, String topic, AMessage aMessage) {
            Log.d(TAG, "onNotify() called with: connectId = [" + connectId + "], topic = [" + topic + "], aMessage = ["
                    + new String((byte[]) aMessage.data) + "]");
            /**
             * 添加LinkFace SDK对LinkKit异步消息的监听。
             */
            LinkFace.getInstance().notifyTopicReceived(connectId, topic, aMessage);
        }

        @Override
        public boolean shouldHandle(String connectId, String topic) {
            return true;
        }

        @Override
        public void onConnectStateChange(String connectId, ConnectState connectState) {
            appendLog("Linkkit连接状态变更为"+ connectState);
            linkkitConnectState = connectState;
        }
    };

3. 创建数据库

建议分别建立人员信息表和人脸底库表两个表,两表之间通过人员信息ID进行外键关联,表结构信息如下:

  • 人员信息表 user_info

列名

类型

长度

是否为NULL

含义

id

integer

64

表的主键,递增

person_id

vchar

64

人员信息的唯一ID,实际可能为身份证号,学号,工号之类的。

name

vchar

128

可以

人员的姓名或别名,识别到人脸后,可能需要在面板机上展示识别结果。

group_ids

vchar

1024

人员所在的分组信息,建议实际存储为JSON Array格式以便于检索,比如

["group_1", "group_2", "group_3"]。

group_id_count

integer

64

用来标示@group_ids人员分组的个数。

timestamp_ms

integer

64

此条人员信息更新的时间,不能由端侧自主生成,必须使用SDK传递过来的时间。

extra_info

vchar

1024

可以

附加信息,格式为JSON String,建议长度为1K,可能不存在。

  • 底库图片信息表 image_info

列名

类型

长度

是否为NULL

含义

id

integer

64

表的主键,递增

person_id

vchar

64

人员信息的唯一ID,实际可能为身份证号,学号,工号之类的。

faceimg_md5

vchar

64

图片的md5值,必须使用SDK传递过来的值。

faceimg_size

integer

32

图片的大小

timestamp_ms

integer

64

此条底库图片更新的时间,不能由端侧自主生成,必须使用SDK传递过来的时间。

4. 处理回调接口

4.1 对接人脸底库管理相关接口

4.1.1 批量添加人脸底库

    /**
     * 云端下发底库同步请求时,sdk先缓存人脸图片,再调用该接口将图片批量入库。
     *
     * @param imageInfos 注册人脸图片信息列表
     * @param num 人脸图片信息列表的数量
     * @return 每张图片入库结果. 参考:{@link com.aliyun.iotx.linkvisual.linkface.bean.LinkFaceErrorCode}
     * <p>
     * 注意:<br>
     * 1. 该接口为同步调用,接口不宜耗时过久<br>
     * 2. 该接口不会在多线程中并发调用<br>
     * 3. 每张图片的添加结果,都要按序放入返回数组中<br>
     * 4. 错误码请严格按照 {@link com.aliyun.iotx.linkvisual.linkface.bean.LinkFaceErrorCode} 中的定义<br>
     */
    int[] onAddImageInfo(LinkFaceImageInfo[] imageInfos, int num);

把图片添加到算法特征库并执行SQL语句如下:

INSERT INTO image_info (person_id, faceimg_md5, faceimg_size, timestamp_ms) 
VALUES ("aaa", "asdfasdfasf", 12, 12356337889);

4.1.2 删除人脸底库

    /**
     * 云端需要删除某个人脸底库时,sdk会调用该接口将人脸信息逐个传递给厂商,厂商需要将该人脸从数据库中删除
     * @param   imageInfo 带删除图片信息
     * @ret     如果删除人脸成功,则返回0,否者返回其他值. 参考:{@link com.aliyun.iotx.linkvisual.linkface.bean.LinkFaceErrorCode}
     *
     * 注意:<br>
     * 1. 只有人脸数据真实存在时(personId/faceImageMd5),才返回成功。<br>
     * 2. personId 不存在返回-1。<br>
     * 3. personId 存在而 faceImageMd5 不存在,返回-2。<br>
     */
    int onDeleteImageInfo(LinkFaceImageInfo imageInfo);

把图片特征从算法库中删除并执行删除@image_info表的一行记录,SQL语句如下:

DELETE FROM image_info WHERE person_id = "aaa";

4.1.3 查询人脸底库数据

    /**
     * 基于人员id,查询人脸底库信息
     *
     * @param personId 人员ID
     * @return 人脸图片信息
     */
    LinkFaceImageInfo onQueryImageInfo(String personId);

基于person_id查询image_info的一行记录,SQL语句如下:

SELECT * from image_info WHERE person_id = "aaa";

4.1.4 查询人脸底库总数

    /**
     * 查询端侧人脸底库总数
     *
     * @return 人脸底库总数
     */
    int onQueryImageCount();

SQL语句如下:

SELECT count(*) from image_info;

4.2 对接人员信息管理相关接口

4.2.1 添加人员信息

    /**
     * 添加人员信息
     * @param userInfo 待添加的人员信息.
     * @return  如果人员信息添加成功,则返回0,否者返回其他值. 参考:{@link com.aliyun.iotx.linkvisual.linkface.bean.LinkFaceErrorCode}
     */
    int onAddUserInfo(LinkFaceUserInfo userInfo);

对应SQL:

INSERT INTO user_info (person_id, name, group_ids, group_id_count, timestamp_ms, extra_info) 
VALUES ("aaa", "阿里巴巴", "[\"aaa\", \"bbb\"]", 2, 12356337889, "");

4.2.2 删除人员信息

    /**
     * 删除用户信息
     * @param userInfo 待删除的人员信息
     * @return 如果删除人员信息成功,则返回0,否者返回其他值. 参考:{@link com.aliyun.iotx.linkvisual.linkface.bean.LinkFaceErrorCode}
     */
    int onDeleteUserInfo(LinkFaceUserInfo userInfo);

对应SQL:

DELETE FROM user_info WHERE person_id = "aaa";

4.2.3 查询人员信息

    /**
     * 基于人员id,查询人员信息
     *
     * @param personId 人员ID
     * @return 人员信息
     */
    LinkFaceUserInfo onQueryUserInfo(String personId);

对应SQL:

SELECT * from image_info WHERE person_id = "aaa";

4.3 对接其他接口

4.3.1 删除用户组下的所有数据

    /**
     * 清除用户分组下的所有用户信息和相关人脸数据
     * @param groupId 用户组ID
     * @return 如果删除用户组成功,则返回0,否者返回具体错误码. 参考:{@link com.aliyun.iotx.linkvisual.linkface.bean.LinkFaceErrorCode}
     */
    int onClearUserGroup(String groupId);

4.3.2 清除所有数据

    /**
     * 将算法特征库的内容完全清空并删除数据库记录
     * @return 如果清空成功,则返回0,否者返回具体错误码. 参考:{@link com.aliyun.iotx.linkvisual.linkface.bean.LinkFaceErrorCode}
     */
    int onClearAll();

对应SQL:

DELETE FROM user_info;
DELETE FROM image_info;

4.3.2 对接Linkkit通道状态感知接口

LinkFace内部的运行需要参考Linkkit通道的连接状态,需实现onLinkKitCheckStateNormal回调方法。

    @Override
    public int onLinkKitCheckStateNormal() {
        appendLog("查询连接状态" + linkkitConnectState);
        return linkkitConnectState == ConnectState.CONNECTED ? 1 : 0;
    }

5 对接人脸检测接口

无论人脸比对是否成功,均调用LinkFace.

getInstance

().uploadMatchResult(linkFaceMatchResult)接口,差异在于比对失败的case里,person id可以填空。

    /**
     * 当人脸门禁机检测到人脸后,无论是否能正确识别出该人脸,均需要调用本接口将识别结果上报到云端。
     *
     * @param linkFaceMatchResult 识别结果,如果识别成功,需要包含已识别的人的基本信息。
     * @return 成功返回0,失败返回-1
     * 
     * 注意:
     * 1. 该接口为同步接口,请勿并发调用。
     * 2. 若接口返回失败,建议最多重试3次。
     */
    public int uploadMatchResult(LinkFaceMatchResult linkFaceMatchResult);

6. 销毁

LinkFace应在长生命周期组件中运行,确认不使用时,请销毁.

    @Override
    protected void onDestroy() {
        super.onDestroy();
        faceDBHelper.close();
        LinkKit.getInstance().unRegisterOnPushListener(connectNotifyListener);
        // 销毁LinkFace
        LinkFace.getInstance().destroy();
    }

包内容介绍

├── README.pdf             // 本文档
├── api-doc                // java-doc api文档
└── sample                 // 示例工程源码

FAQ

1. 人员信息表和人脸底库表是否需要做关联删除?

不需要,删除人员信息和删除人脸底图都是原子操作;假如需要同时删除人员信息及其底图,SDK会分别调用两次接口来完成,设备实现层无需做关联删除操作。

2. 运行时报liblinkface.so not found错误。

如果使用了SNAPSHOT包,遇到这种情况请Rebuild一下工程。

3.与LinkFace Linux 版本SDK有什么区别?

Android版本基于Linux C版本进行封装和移植,暂不支持设备数据校验码查询。