美文网首页
IMEI弃用,OAID集成教程

IMEI弃用,OAID集成教程

作者: 上帝死了众神在堕落 | 来源:发表于2022-03-18 14:59 被阅读0次

    原文地址:https://juejin.cn/post/7072741392178479140

    补充设备标识体系

    中文缩写 中文名称 描述 重置性 场景
    UUID 设备唯一标识符 设备唯一硬件标识,由设备出厂时的硬件信息生成,如IMEI 出厂后无法重置 设备唯一标识,如广告业务在广告投放时进行效果归因
    OAID 匿名设备标识符 OAID是UUID的替代品,是设备维度的ID。在终端首次启动时生成,同一设备的OAID相同 恢复出厂设置后,OAID会重置 设备唯一标识,如广告业务在广告投放时进行效果归因
    VAID 开发者匿名设备标识符 VAID是开发者维度的ID。在应用安装时生成,同一设备上且同一开发者的所有应用VAID相同,其他情况VAID不同 恢复出厂设置、重新安装应用后,VAID会重置(例外情况:卸载应用时如果设备中另有相同开发者的应用且读取过VAID则不会重置) 开发者唯一标识,如果统一开发者不同莹莹之间的推荐
    AAID 应用匿名设备标识符 AAID是应用沙盒维度的ID。在应用安装时生成,即使是统一设备且同一个开发者的应用,AAID也不同 恢复出厂设置、重新安装、清除用户数据,AAID会重置例外情况:卸载应用时如果设备中另有相同开发者的应用且读取过AAID,则不会重置) 应用唯一标识,可用于用户统计

    集成与封装

    interface IOAIDApi {
    
        /**
         * 1. 初始化,确保用户同意《隐私政策》之后,再初始化 OAID SDK
         * 2. 加固版本在调用前必须载入SDK安全库,因为加载有延迟,推荐在 Application 中调用 loadLibrary 方法
         *
         * @param debug 是否调试,debug 状态会开启 SDK 日志输出
         */
        fun init(debug: Boolean)
    
        /**
         * 获取 ID,回调可能是同步的,也可能是异步的
         */
        @AnyThread
        fun fetchDeviceIds(callback: (OAIDResult) -> Unit)
    }
    
    internal class OAID private constructor(
        context: Context
    ) : IOAIDApi {
    
        // ApplicationContext
        private val context: Context = context.applicationContext
    
        /**
         * 证书初始化标记,true:已经初始化
         */
        @Volatile
        private var isCertInit: Boolean = false
    
        /**
         * 证书是否有效,true:有效
         */
        private var isCertValid: Boolean = false
    
        /**
         * 证书过期时间,null:证书无效
         */
        private var certExpDate: Date? = null
    
        /**
         * 调试开关
         */
        private var debug: Boolean = false
    
        companion object {
    
            @Volatile
            private var _oaid: IOAIDApi? = null
    
            @AnyThread
            fun oaid(context: Context): IOAIDApi {
                if (null == _oaid) {
                    synchronized(IOAIDApi::class.java) {
                        if (null == _oaid) {
                            _oaid = OAIDImpl(context)
                        }
                    }
                }
                return _oaid!!
            }
        }
    
        override fun init(debug: Boolean) {
            System.loadLibrary("msaoaidsec")
    
            this.debug = debug
        }
    
        override fun fetchDeviceIds(callback: (OAIDResult) -> Unit) {
            // 1. 验证与初始化证书
            checkCertValidity()
    
            // 2.1 提供空信息的 ID 提供器
            val unsupportedIdSupplier = IdSupplierImpl()
    
            // 2.2 统一的回调接收器
            val listener = IIdentifierListener { supplier: IdSupplier? ->
                supplier?.let {
                    // 回调
                    callback(
                        OAIDResult(
                            supplier.isSupported, supplier.isLimited, supplier.oaid, supplier.vaid, supplier.aaid
                        )
                    )
                }
            }
    
            if (!isCertValid) {
                // 证书无效,直接回调空信息
                listener.onSupport(unsupportedIdSupplier)
                return
            }
    
            // 3. 调用 SDK 接口获取 OAID
            val code = try {
                MdidSdkHelper.InitSdk(context, debug, listener)
            } catch (error: Error) {
                error.printStackTrace()
                -1
            }
            // 4. 处理异常情况
            when (code) {
                InfoCode.INIT_ERROR_CERT_ERROR,             // 证书未初始化或证书无效,SDK 内部不会回调 onSupport
                InfoCode.INIT_ERROR_DEVICE_NOSUPPORT,       // 不支持的设备, SDK 内部不会回调 onSupport
                InfoCode.INIT_ERROR_LOAD_CONFIGFILE,        // 加载配置文件出错, SDK 内部不会回调 onSupport
                InfoCode.INIT_ERROR_MANUFACTURER_NOSUPPORT, // 不支持的设备厂商, SDK 内部不会回调 onSupport
                InfoCode.INIT_ERROR_SDK_CALL_ERROR          // SDK 调用出错, SDK 内部不会回调 onSupport
                -> {
                                    // 异常情况,直接回调空信息
                    listener.onSupport(unsupportedIdSupplier)
                }
                InfoCode.INIT_INFO_RESULT_DELAY,            // 获取接口是异步的,SDK 内部会回调 onSupport
                InfoCode.INIT_INFO_RESULT_OK                // 获取接口是同步的,SDK 内部会回调 onSupport
                -> {
                    // do nothing
                }
                else -> {
                    // do nothing
                }
            }
        }
    
        /**
         * 验证与初始化证书
         * @return true:证书初始化成功;false:证书初始化失败
         */
        private fun checkCertValidity() {
    
            /**
             * 从asset文件读取证书内容
             *
             * @return 证书字符串
             */
            fun loadPemFromAssetFile(): String {
                return try {
                    // 证书文件名
                    val certFileName = context.packageName + ".cert.pem"
                    val inputStream = context.assets.open(certFileName)
                    val bufferReader = BufferedReader(InputStreamReader(inputStream))
                    val builder = StringBuilder()
                    var line: String?
                    while (bufferReader.readLine().also { line = it } != null) {
                        builder.append(line)
                        builder.append('\n')
                    }
                    builder.toString()
                } catch (e: IOException) {
                    ""
                }
            }
    
            /**
             * 解析证书过期时间
             * @return 过期时间,证书不合法时返回 null
             */
            fun getCertExpDate(certStr: String): Date? {
                return try {
                    // 证书实体
                    val cert = CertificateFactory.getInstance("X.509").generateCertificate(certStr.byteInputStream()) as X509Certificate
                    // 验证证书有效性,如果证书过期会抛出异常
                    cert.checkValidity()
                    cert.notAfter
                } catch (ex: Exception) {
                    // 证书无效
                    null
                }
            }
    
            // DCL
            if (isCertInit) {
                // 初始化只需要进行一次,返回上一次的结果
                return
            }
            synchronized(IOAID::class) {
                if (isCertInit) {
                    return
                }
                // 证书文件名
                val certStr = loadPemFromAssetFile()
                // 证书过期时间
                certExpDate = getCertExpDate(certStr)
                // TODO 如果你的应用场景对证书有效性要求非常高,可以在这个时机提前下载更新证书
                // 初始化证书,证书只需要初始化一次
                isCertValid = MdidSdkHelper.InitCert(context, certStr)
                isCertInit = true
            }
        }
    }
    
    

    第三方库
    https://github.com/gzu-liyujiang/Android_CN_OAID

    相关文章

      网友评论

          本文标题:IMEI弃用,OAID集成教程

          本文链接:https://www.haomeiwen.com/subject/tzvidrtx.html