集成要求
合规说明
请注意,在贵司的App中集成小盾提供的SDK产品时:
1.1 根据《网络安全法》《电信条例》《电信和互联网用户个人信息保护规定》等相关法律法规要求及监管实践中的标准,在贵司的最终用户首次启动App并在贵司开始采集信息之前,贵司应以交互界面或设计(如隐私政策弹窗等)向最终用户完整告知收集、使用、与第三方共享最终用户个人信息的目的、方式和范围,并征得最终用户的明示同意。
1.2 为向贵司提供业务安全和风控服务,小盾 SDK 将采集、处理、使用用户的手机终端唯一标志信息IDFA、Android ID、OAID(包含VAID、AAID)、MAC 地址、WIFI列表、无线路由器标识(BSSID、SSID)、设备类型、设备型号、系统类型、粗略位置信息、精准位置信息、应用程序列表、运行中进程信息、网络制式、设备软件版本号、传感器(光传感器、重力传感器、磁场传感器、加速度传感器、陀螺仪传感器、心率传感器)以及传感器列表相关设备信息。为确保贵司使用相关服务的合规性,前述隐私政策应涵盖对小盾SDK提供服务并采集、处理、使用相关信息的授权,以上内容供贵司参考,具体表述可由贵司根据贵司隐私协议的整体框架和内容自行确定。
SDK信息
| 项目 | 内容 |
|---|---|
| SDK名称 | 小盾设备指纹SDK |
| 开发者名称 | 浙江小盾未来科技有限公司 |
| 使用目的 | 提供业务安全和风控服务 |
| 包名 | com.trustdecision.mobrisk |
| MD5值 | 46e7c6e45baa994c78ed866ce03cff1b |
| 版本号 | 5.2.1 |
| 个人信息类处理规则(隐私政策) | https://xiaodun.com/other/privacy/id=4 |
| 使用说明 | 合规使用指导 |
Google Play 的数据安全要求
对于上传到 Google Play 商店的每款应用,Google 都要求向所有用户公开应用的隐私和安全做法。因此,当应用(或新版本)上传到 Play 商店时,Google 要求应用开发者填写数据安全表单。有关详细信息,请参阅为 Google Play 的数据安全部分提供信息。
如果您的应用包含我们的Android SDK,那么您可以使用下表作为参考来填写数据安全表单:
| Google Play 控制台数据安全表单中的问题 | 回复 |
|---|---|
| 您的应用是否收集或共享任何所需的用户数据类型? | 是的 |
| 收集什么类型的数据? | 设备或其他标识符 |
| 这些数据是被收集、共享,还是两者兼而有之? | 收集 |
| 这些数据是暂时处理的吗? | 是的 |
| 为什么要收集这些用户数据? | 欺诈预防、安全和合规 |
环境要求
| 说明 | |
|---|---|
| 兼容版本 | Android 5.0及以上系统 |
| 支持架构 | armeabi-v7a, arm64-v8a, x86, x86_64 |
集成步骤
SDK接入示例代码(sample): https://github.com/trustdecision/mobrisk-android-sample
安装配置
添加仓库
在项目根目录的 build.gradle加入maven库的配置
allprojects {
repositories {
...
mavenCentral()
}
}如果您的 Gradle 版本是 7 或更高版本,请将下方配置添加到工程的 settings.gradle
repositories {
...
mavenCentral()
}添加依赖
在应用主模块的 build.gradle 中,声明SDK包依赖
dependencies {
implementation 'com.trustdecision.android:mobrisk:5.2.1'
}
如果遇到合规性问题,可以在依赖阶段排除相关模块的采集
dependencies {
// 设备指纹
implementation('com.trustdecision.android:mobrisk:5.2.1'){
// 移除后sdk不获取安装包列表
exclude group: 'com.trustdecision.android', module: 'packagelist'
// 移除后sdk不会收集READ_PHONE_STATE相关信息
exclude group: 'com.trustdecision.android', module: 'readphone'
// 移除后sdk不会收集地理位置相关信息
exclude group: 'com.trustdecision.android', module: 'location'
// 移除后sdk不会收集传感器相关信息
exclude group: 'com.trustdecision.android', module: 'sensor'
// 移除后sdk不会收集wifi相关信息
exclude group: 'com.trustdecision.android', module: 'wifiinfo'
}
}配置ABI类型
SDK目前支持 armeabi-v7a、arm64-v8a、x86、x86_64等ABI类型,建议接入方在主模块build.gradle文件内添加 abiFilters配置选择所需要的架构类型,具体架构,请以您自己需要支持的架构为准!
defaultConfig {
...
ndk {
abiFilters 'armeabi-v7a', 'arm64-v8a'
}
}配置AndroidManifest.xml
在应⽤module下的 AndroidManifest.xml ⽂件中声明以下权限
<manifest>
<!--必选权限-->
<!--基础网络通信,数据收集完毕,上报时调用-->
<uses-permission android:name="android.permission.INTERNET"/>
<!--SDK加载后,数据采集完准备上报时调用-->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<!--SDK加载后,数据采集时调用-->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<!--如果您的应用是面向海外市场,在google play 上发布,请添加此项-->
<uses-permission android:name="com.google.android.gms.permission.AD_ID"/>
<!--以下权限是可选权限,不声明此部分权限将放弃部分设备信息的采集,对风险识别有一定影响-->
<!--SDK加载后,数据采集时调用-->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<!-- Android11及以上获取安装包列表需要该权限,采集安装包列表涉及到⻛险合规,是否需要该权限业务⽅⾃⾏选
择 -->
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"
tools:ignore="QueryAllPackagesPermission" />
</manifest>权限说明
| 权限 | 说明 |
|---|---|
| INTERNET(必选) | 允许程序访问网络连接,发送请求与服务器进行通信 |
| ACCESS_NETWORK_STATE(必选) | 获取网络连接状态信息 |
| ACCESS_WIFI_STATE(必选) | 获取当前WiFi接入的状态以及WLAN热点的信息 |
| AD_ID(海外必选) | 获取google 广告ID |
| ACCESS_COARSE_LOCATION | 获取粗略位置信息,精度大概误差在30~1500米 |
| ACCESS_FINE_LOCATION | 获取精确位置信息,定位精度达10米以内 |
| READ_PHONE_STATE | 读取SIM卡相关信息 |
| QUERY_ALL_PACKAGES | 获取应用程序列表 |
加载和采集
注意事项
- 确保在用户同意隐私协议后,再进行SDK加载
- 保证在主进程加载,避免加载出现异常
方法定义
public static void initWithOptions(Context ctx, TDRisk.Builder builder);获取blackBox
注意事项
- 请在initWithOptions后调用getDeviceInfo
- 不要在App内对返回的blackBox进行缓存,获取blackBox请依赖getDeviceInfo方法
- 尽量在首次获取blackBox的异步回调触发之后,再同步获取blackBox
方法定义
// 异步回调获取
public static void getDeviceInfo(TDDeviceInfoCallbackAdapter callback);
// 同步获取
public static TDDeviceInfo getDeviceInfo();最佳实践
- 在应用入口Application的onCreate方法中加载
// 应用入口APPlication的onCreate
TDRisk.Builder builder = new TDRisk.Builder()
/*************************** 必传 ***************************/
.partner("请输入您的合作方编码") // 合作方(partnerCode),请填写partnerCode,不要填partnerKey
.appKey("请输入您的appKey") // 配置AppKey,请联系运营获取
.dataCenter("请输入您接入的数据中心"); // 数据中心参数,列表可以参考下文全部配置说明
/*************************** 必传 ***************************/
if(用户同意隐私协议){
try {
TDRisk.initWithOptions(getApplicationContext(), builder);
} catch (Exception e) {
Log.e("TD", "init error", e);
}
}// 应用入口 APPlication 的 onCreate
val builder = TDRisk.Builder()
/*************************** 必传 ***************************/
.partner("请输入您的合作方编码") // 合作方(partnerCode),请填写partnerCode,不要填partnerKey
.appKey("请输入您的appKey") // 配置 AppKey,请联系运营获取
.dataCenter("请输入您接入的数据中心") // 数据中心参数,列表可以参考下文全部配置说明
/*************************** 必传 ***************************/
if (用户同意隐私协议) {
try {
TDRisk.initWithOptions(applicationContext, builder)
} catch (e: Exception) {
Log.e("TD", "init error", e);
}
}-
在实际业务节点获取blackBox
-
推荐使用异步的方式获取,不影响调用线程
public void register() { ... try { TDRisk.getDeviceInfo(new TDDeviceInfoCallbackAdapter() { @Override public void onResult(TDDeviceInfo deviceInfo) { // 注:回调在子线程中执行,请不要在此处操作UI,code和message用于异常排查,业务接口可直接携带blackBox int code = deviceInfo.getApiStatus().getCode(); String message = deviceInfo.getApiStatus().getMessage(); String blackbox = deviceInfo.getBlackBox(); Log.e("TD", "code:" + code + ", message:" + message + ", blackBox:" + blackBox); } }); } catch (Exception e) { Log.e("TD", "getDeviceInfo error", e); } ... }fun register() { ... try { TDRisk.getDeviceInfo(object : TDDeviceInfoCallbackAdapter() { override fun onResult(deviceInfo: TDDeviceInfo?) { // 注:回调在子线程中执行,请不要在此处操作UI,code和message用于异常排查,业务接口可直接携带blackBox val code = deviceInfo?.apiStatus?.code ?: -1 val message = deviceInfo?.apiStatus?.message ?: "" val blackbox = deviceInfo?.blackBox ?: "" Log.e("TD", "code:$code, message:$message, blackBox:$blackBox") } }) } catch (e: Throwable) { Log.e("TD", "getDeviceInfo error", e) } ... } -
如果此前已经通过异步的方式成功获取过blackBox,则可以使用同步的方式直接获取blackBox
public void pay() { ... try { // 可能耗时,谨慎在主线程调用 TDDeviceInfo deviceInfo = TDRisk.getDeviceInfo(); String blackbox = deviceInfo.blackBox(); } catch (Exception e) { Log.e("TD", "getDeviceInfo error", e); } ... }fun pay() { ... try { // 可能耗时,谨慎在主线程调用 val deviceInfo = TDRisk.getDeviceInfo() val blackbox = deviceInfo.blackBox } catch (e: Exception) { Log.e("TD", "getDeviceInfo error", e) } ... }
-
状态检查
- 加载成功会在 logcat中打印以下日志:
TD_JAVA: TD sdk load success
TD_JAVA: TD sdk init success- SDK上报数据成功,返回的blackBox结果长度为26位字符串。如:
rGPGX1678775227I9NCwcuVJCb。 - 异常情况下,返回的blackBox结果长度可能达到5000字符,详情可查看正常blackBox和降级blackBox的差异
其他说明
获取版本号
TDRisk.getSDKVersion()混淆打包
如果开发者需要使用 proguard 进行混淆打包,请在 proguard 配置文件添加如下代码:
-keep class com.trustdecision.**{*;}全部配置
| 配置 key | 说明 | 示例代码 | 移除字段 |
|---|---|---|---|
| partner(必须) | 合作方编码,请联系运营获取 | builder.partner("your partnerCode") | |
| appKey(必须) | 应用标识,参考 | builder.appKey("appKey") | |
| dataCenter(必须) | 数据中心地区:TDRisk.DATA_CENTER_US (北美) TDRisk.DATA_CENTER_FRA (欧洲) TDRisk.DATA_CENTER_SG (新加坡) TDRisk.DATA_CENTER_IDNA (印尼) TDRisk.DATA_CENTER_CN (中国) ❗️变更点:country已废弃但目前仍能生效,建议改用dataCenter | builder.dataCenter(TDRisk.DATA_CENTER_CN) | |
| appName | 应用名称,请联系运营获取 | builder.appName("appName") | |
| channel | 渠道标识,请联系运营获取 | builder.channel("channel") | |
| httpTimeOut | 网络请求回调的超时时间,单位毫秒,默认15000 | builder.httpTimeOut(5000) | |
| disableOptions | 禁止指定采集项 |
| oaid,gaid,androidId |
| disableDebugger | 配置后,检测到调试后会终止运行,默认允许 | builder.disableDebugger() | |
| disableRunningTasks | 禁止获取正在运行的任务,默认允许 | builder.disableRunningTasks() | running_packages |
| disableGPS | 禁止采集GPS位置信息,默认允许 | builder.disableGPS() | ssid、wifi_list、gps_switch、latitude、longitude、gps_location |
| disableSensor | 禁止采集传感器信息,默认允许 | builder.disableSensor() | mangetic_field_sensor、gyroscope_sensor、light_sensor、accelerator_data、gravity_data |
| disableReadPhone | 禁止采集READ_PHONE_STATE权限相关信息,默认允许 | builder.disableReadPhone() | country_iso、carrier、network_operator、sim_operator、phone_type、radio_type、device_svn |
| disableInstallPackageList | 禁止采集应用列表信息,默认采集 | builder.disableInstallPackageList() | installed_packages |
| customMessage | 自定义消息,sdk支持透传和存储 | builder.customMessage(customMessage) |
响应结果
getDeviceInfo() 函数会在 onResult 方法中返回响应数据,包含以下信息。
| 字段 | 描述 |
|---|---|
| blackBox | 调用日志查询标识 |
| fpVersion | SDK版本号 |
状态码说明
调用TDRisk.getDeviceInfo()方法,回调中TDDeviceAPIStatus类型的参数保存着SDK的状态信息,它的定义如下:
public class TDDeviceAPIStatus {
public TDDeviceAPIStatus(int code, String message) {
this.code = code;
this.message = message;
}
public int getCode() {
return code;
}
public String getMessage() {
return message;
}
private int code;
private String message;
}code和message对应值如下表:
| code | message | 备注 |
|---|---|---|
| 0 | Success. | 成功 |
| 1000 | Access error. | 准入发生异常,可能原因:初始化参数无效或网络环境异常 |
| 1001 | SDK error. | SDK 发生异常,可能原因:未调用初始化函数 |
| 1002 | Network error. | 网络错误 |
| 1003 | API error. | 后端接口返回错误 |
| 1004 | Traffic limit. | 网关限流 |
| 1005 | Traffic shutdown. | 流量关停 |
| 1100 | Unknown error. | 未知错误 |
