Android設備端開發指南
LinkFace SDK封裝了設備與云的通訊協議,實現了人員信息增刪查,信息增刪查和檢測/識別事件上云等功能。SDK支持Android Studio開發環境。
SDK集成
依賴Linkkit SDK的通道能力,在集成本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進行初始化,設備證書(ProductKey、DeviceName、DeviceSecret)必須傳入。
@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 對接檢測接口
無論比對是否成功,均調用SDK
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版本進行封裝和移植,暫不支持設備數據校驗碼查詢。