Android中使用OAID

关于

因传统的移动终端设备标识如国际移动设备识别码(IMEI)等已被部分国家认定为用户隐私的一部分,并存在被篡改和冒用的风险,所以在Android 10及后续版本中非厂商系统应用将无法获取IMEI、MAC等设备信息。无法获取IMEI会在用户行为统计过程中对设备识别产生一定影响。近日移动安全联盟针对该问题联合国内手机厂商推出补充设备标准体系方案,选择OAID字段作为IMEI等的替代字段。OAID字段是由中国信通院联合华为、小米、OPPO、VIVO等厂商共同推出的设备识别字段,具有一定的权威性,可满足用户行为统计的使用场景。

移动安全联盟官网: 移动安全联盟刚官网地址
安全联盟SDK、文档以及申请表格: 安全联盟SDK1.0.29文档及SDK

目前支持的机型

厂商名称支持版本
华为HMS 2.6.2 及以上
小米MIUI 10.2 及以上版本
vivoAndroid 9 及以上版本
OPPOcolorOS 6 大部分覆盖,colorOS 7 及以上全覆盖
联想ZUI 11.4 及以上版本
三星Android 10 版本
魅族Android 10 版本
努比亚Android 10 版本
中兴Android 10 版本
华硕Android 10 版本
一加Android 10 版本
黑鲨Android 10 版本
摩托罗拉Android 10 版本
Freeme OSAndroid 10 版本
酷赛(铂睿智恒)Android 10 版本
RealmecolorOS 6 大部分覆盖,colorOS 7 及以上全覆盖
荣耀Android 10 版本

调用方法

  1. 接入准备——申请证书文件(将需要申请的app信息填写到example_batch.csv表格,然后发送到msa@caict.ac.cn进行申请。注意每个包名对应一个签名,申请时需要将需要申请的全部包名填写到表格中。申请后安全联盟将会把所有申请的证书发送到申请时使用的邮箱)
  • 注意: 关于example_batch.csv表格
    表格中的会员账号:是指在安全联盟登录的账号 可点击进入安全联盟登录页面
    表格中的邮箱:最好填写安全联盟登录账号绑定的邮箱
  1. 把oaid_sdk_x.x.x.aar拷贝到项的libs目录,并设置依赖,其中x.x.x代 表版本号。最新的版本为1.0.29

  2. 将证书文件(应用包名.cert.pem)、 supplierconfig.json 文件拷贝到项目 assets 目录下,(只获取oaid信息则不需要修改json配置文件,只需原样放到assets目录下即可。如果想要使用VAID,可修改里边对应内容,特别是需要设置 appid 的部分,要去对应厂商的应用商店里注册自己的 app,来获取对应appid。)

  3. 设置依赖

    implementation files(‘libs/oaid_sdk_1.0.29.aar’)
    
    
    
  4. 混淆设置

    # sdk
    -keep class com.bun.miitmdid.** { *; }
    # asus
    -keep class com.asus.msa.SupplementaryDID.** { *; }
    -keep class com.asus.msa.sdid.** { *; }
    # freeme
    -keep class com.android.creator.** { *; }
    -keep class com.android.msasdk.** { *; }
    # huawei
    -keep class com.huawei.hms.ads.identifier.** { *; }
    #-keep class com.uodis.opendevice.aidl.** { *; }
    # lenovo
    -keep class com.zui.deviceidservice.** { *; }
    -keep class com.zui.opendeviceidlibrary.** { *; }
    # meizu
    -keep class com.meizu.flyme.openidsdk.** { *; }
    # nubia
    -keep class com.bun.miitmdid.provider.nubia.NubiaIdentityImpl
    # oppo
    -keep class com.heytap.openid.** { *; }
    # samsung
    -keep class com.samsung.android.deviceidservice.** { *; }
    # vivo
    -keep class com.vivo.identifier.** { *; }
    # xiaomi
    -keep class com.bun.miitmdid.provider.xiaomi.IdentifierManager
    # zte
    -keep class com.bun.lib.** { *; }
    # coolpad
    -keep class com.coolpad.deviceidsupport.** { *; }


  1. 设置 gradle 编译选项,开发者可以根据自己对平台的选择进行合理配置

    ndk { abiFilters  'armeabi-v7a','x86','arm64-v8a','x86_64','armeabi' }
    
    
    

    注意:考虑到 sdk 兼容性,sdk 包默认集成了常用 abi 的 so,包括 armeabi-v7a,arm64-v8a, x84, x84_64 共四种。如果需要减小 SDK 体积,可以使用压缩工具打开 aar 文件,手动删除多余的架构。

  2. 添加 oaid管理文件MiitHelper.java

根据官网源文件DemoHelper.java修改而来,可以根据自己需求修改,这里是cocos工程,这里将文件MiitHelper.java放到org.cocos2dx.javascript目录中。

package org.cocos2dx.javascript;

import android.content.Context;
import android.util.Log;

import com.bun.miitmdid.core.InfoCode;
import com.bun.miitmdid.core.MdidSdkHelper;
import com.bun.miitmdid.interfaces.IIdentifierListener;
import com.bun.miitmdid.interfaces.IdSupplier;
import com.bun.miitmdid.pojo.IdSupplierImpl;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

public class MiitHelper implements IIdentifierListener {
    public static final String TAG = "MiitHelper";
    public static final int HELPER_VERSION_CODE = 20210928; // DemoHelper版本号
    private AppIdsUpdater appIdsUpdater;
    private boolean isCertInit = false;

    public final boolean isSDKLogOn = true;                           // 1)设置 是否开启sdk日志
    public static String ASSET_FILE_NAME_CERT = "";             // 2)设置 asset证书文件名

    public static void Init(Context context, AppIdsUpdater listener){
        MiitHelper miitHelper = new MiitHelper();

        ASSET_FILE_NAME_CERT = context.getPackageName()+".cert.pem";
        Log.e(TAG,ASSET_FILE_NAME_CERT);

        System.loadLibrary("nllvm1632808251147706677");  // 加固版本在调用前必须载入SDK安全库
        if(MdidSdkHelper.SDK_VERSION_CODE != HELPER_VERSION_CODE){
            Log.w(TAG,"SDK version not match.");
            throw new RuntimeException("SDK version not match.");
        }
        miitHelper.appIdsUpdater = listener;

        // 获取设备号
        miitHelper.getDeviceIds(context);
    }

    /**
     * 获取OAID
     * @param cxt
     */
    public void getDeviceIds(Context cxt){
        // TODO (4)初始化SDK证书
        if(!isCertInit){ // 证书只需初始化一次
            // 证书为PEM文件中的所有文本内容(包括首尾行、换行符)
            isCertInit = MdidSdkHelper.InitCert(cxt, loadPemFromAssetFile(cxt, ASSET_FILE_NAME_CERT));
            if(!isCertInit){
                Log.w(TAG, "getDeviceIds: cert init failed");
            }
        }

        //(可选)设置InitSDK接口回调超时时间(仅适用于接口为异步),默认值为5000ms.
        // 注:请在调用前设置一次后就不再更改,否则可能导致回调丢失、重复等问题
        MdidSdkHelper.setGlobalTimeout(5000);

        // TODO (5)调用SDK获取ID
        int code = MdidSdkHelper.InitSdk(cxt, isSDKLogOn, this);

        // TODO (6)根据SDK返回的code进行不同处理
        IdSupplierImpl unsupportedIdSupplier = new IdSupplierImpl();
        if(code == InfoCode.INIT_ERROR_CERT_ERROR){                         // 证书未初始化或证书无效,SDK内部不会回调onSupport
            // APP自定义逻辑
            Log.w(TAG,"cert not init or check not pass");
            onSupport(unsupportedIdSupplier);
        }else if(code == InfoCode.INIT_ERROR_DEVICE_NOSUPPORT){             // 不支持的设备, SDK内部不会回调onSupport
            // APP自定义逻辑
            Log.w(TAG,"device not supported");
            onSupport(unsupportedIdSupplier);
        }else if( code == InfoCode.INIT_ERROR_LOAD_CONFIGFILE){            // 加载配置文件出错, SDK内部不会回调onSupport
            // APP自定义逻辑
            Log.w(TAG,"failed to load config file");
            onSupport(unsupportedIdSupplier);
        }else if(code == InfoCode.INIT_ERROR_MANUFACTURER_NOSUPPORT){      // 不支持的设备厂商, SDK内部不会回调onSupport
            // APP自定义逻辑
            Log.w(TAG,"manufacturer not supported");
            onSupport(unsupportedIdSupplier);
        }else if(code == InfoCode.INIT_ERROR_SDK_CALL_ERROR){             // sdk调用出错, SSDK内部不会回调onSupport
            // APP自定义逻辑
            Log.w(TAG,"sdk call error");
            onSupport(unsupportedIdSupplier);
        } else if(code == InfoCode.INIT_INFO_RESULT_DELAY) {             // 获取接口是异步的,SDK内部会回调onSupport
            Log.i(TAG, "result delay (async)");
        }else if(code == InfoCode.INIT_INFO_RESULT_OK){                  // 获取接口是同步的,SDK内部会回调onSupport
            Log.i(TAG, "result ok (sync)");
        }else {
            // sdk版本高于DemoHelper代码版本可能出现的情况,无法确定是否调用onSupport
            // 不影响成功的OAID获取
            Log.w(TAG,"getDeviceIds: unknown code: " + code);
        }
    }

    /**
     * APP自定义的getDeviceIds(Context cxt)的接口回调
     * @param supplier
     */
    @Override
    public void onSupport(IdSupplier supplier) {
        if(supplier==null) {
            Log.w(TAG, "onSupport: supplier is null");
            return;
        }
        if(appIdsUpdater ==null) {
            Log.w(TAG, "onSupport: callbackListener is null");
            return;
        }
        // 获取Id信息
        // 注:IdSupplier中的内容为本次调用MdidSdkHelper.InitSdk()的结果,不会实时更新。 如需更新,需调用MdidSdkHelper.InitSdk()
        boolean isSupported = supplier.isSupported();
        boolean isLimited  = supplier.isLimited();
        String oaid=supplier.getOAID();
        String vaid=supplier.getVAID();
        String aaid=supplier.getAAID();

        //TODO (7) 自定义后续流程,以下显示到UI的示例
        String idsText= "support: " + (isSupported ? "true" : "false") +
                "\nlimit: " + (isLimited ? "true" : "false") +
                "\nOAID: " + oaid +
                "\nVAID: " + vaid +
                "\nAAID: " + aaid + "\n";
        Log.d(TAG, "onSupport: ids: \n" + idsText);
        appIdsUpdater.onIdsValid(oaid);
    }

    public interface AppIdsUpdater {
        void onIdsValid(String oaid);
    }

    /**
     * 从asset文件读取证书内容
     * @param context
     * @param assetFileName
     * @return 证书字符串
     */
    public static String loadPemFromAssetFile(Context context, String assetFileName){
        try {
            InputStream is = context.getAssets().open(assetFileName);
            BufferedReader in = new BufferedReader(new InputStreamReader(is));
            StringBuilder builder = new StringBuilder();
            String line;
            while ((line = in.readLine()) != null){
                builder.append(line);
                builder.append('\n');
            }
            return builder.toString();
        } catch (IOException e) {
            Log.e(TAG, "loadPemFromAssetFile failed");
            return "";
        }
    }
}


  1. 调用

ActivityonCreate函数中添加初始化。这是异步调用,使用需要注意一下。

public class AppActivity extends Cocos2dxActivity implements ActivityCompat.OnRequestPermissionsResultCallback {
    public static String oaid = "";

    ...

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        ...

        MiitHelper.Init(this, new MiitHelper.AppIdsUpdater(){
            @Override
            public void onIdsValid(String oaid){
                AppActivity.oaid = oaid;
            }
        });
    }

    ....
}

最后

如果想要成为架构师或想突破20~30K薪资范畴,那就不要局限在编码,业务,要会选型、扩展,提升编程思维。此外,良好的职业规划也很重要,学习的习惯很重要,但是最重要的还是要能持之以恒,任何不能坚持落实的计划都是空谈。

如果你没有方向,这里给大家分享一套由阿里高级架构师编写的《Android八大模块进阶笔记》,帮大家将杂乱、零散、碎片化的知识进行体系化的整理,让大家系统而高效地掌握Android开发的各个知识点。
在这里插入图片描述
相对于我们平时看的碎片化内容,这份笔记的知识点更系统化,更容易理解和记忆,是严格按照知识体系编排的。

全套视频资料:

一、面试合集

在这里插入图片描述
二、源码解析合集
在这里插入图片描述

三、开源框架合集
在这里插入图片描述
欢迎大家一键三连支持,若需要文中资料,直接扫描文末CSDN官方认证微信卡片免费领取↓↓↓

PS:群里还设有ChatGPT机器人,可以解答大家在工作上或者是技术上的问题

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值