关于 AndroidId 读取行为的警示和应用合规的解决方案

910 阅读3分钟

关于 AndroidId 读取行为的警示和应用合规的解决方案

问题描述

随着法律法规的不断完善,部分应用商店对应用读取 IMEI 做出了限制,而现在,读取 AndroidId 也会对你的应用造成影响,前不久我们收到了某应用商店关于软件合规审查的调查报告,认为我们的软件“频繁获取用户隐私信息”,而这里的“隐私信息”就是指 AndroidId。

按理来说,一个甚至不需要权限的,对于同一款签名应用,每次获取都是一样值只是用于简单判断是否是同一设备的公开可使用的 Id,怎么就不让随意获取了呢?根据某应用商店的合规建议,认为“短时长、高频次”也是不可以的,而我们的产品在每个接口都需要以 AndroidId 为参数进行加密判断以防止有非法请求行为,这就导致了这个问题的发生:

为避免此问题继续存在,我们对应用内的读取 AndroidId 行为进行了针对性处理,也将这个处理下放到了 kongzue/BaseFramework 最新版本中,在新版本中,默认限制了 AndroidId 的获取,当用户同意 App 条款和隐私政策后,手动开启允许 AndroidId 的读取,这样最大程度上避免了不合规的审核问题发生。

附图:某应用商店给出的指导建议,请在用户同意 App 用户协议和隐私政策后再允许读取 AndroidId 的行为:

如何处理?

kongzue/BaseFramework 针对性进行了改进,默认情况下,增加了一个设置:

BaseFrameworkSettings.PRIVACY_ALLOWED = false;

PRIVACY_ALLOWED 为 false 时,BaseFramework 的统一获取 AndroidId 行为将返回一个随机生成的临时 UUID,注意此 ID 会存储在本地,只要不卸载 App 重复读取都是一样的,这是为了避免读取到 null 引发程序逻辑异常。

当用户同意 App 用户协议和隐私政策后,请设置 BaseFrameworkSettings.PRIVACY_ALLOWED 值为 true,即可正确读取到 AndroidId。

获取 AndroidId:

App.getAndroidId()		//App 为自己应用的 Application(extends BaseApp) 实例

仅此为止并不能有效解决应用商店关于 “短时长、高频次” 的问题,BaseFramework 也针对性的增加了“AndroidId” 读取缓存功能,当 BaseFramework 首次读取到 AndroidId 后会对其值缓存下来,下次重新读取时直接从缓存读取,并不会真的触发系统读取 AndroidId 的逻辑。

另外我还注意的,在部分厂商设备上,从外部安装(非应用商店)的应用,读取 AndroidId 有概率出现空指针的问题,导致应用逻辑执行异常,对此问题 BaseFramework 也针对性进行了处理,当检测到系统返回的 AndroidId 为空时,会使用生成临时 UUID 来进行使用,最起码保证应用逻辑不会出现问题,生成的 UUID 在应用卸载重装前读取都不会变化。

BaseFramework 内部详细的逻辑如下:

public static String getAndroidId() {
    if (PRIVACY_ALLOWED) {
        if (!isNull(androidId)) {
            return androidId;
        }
        try {
            androidId = BaseApp.Settings.getString("device","androidId",
                                                   android.provider.Settings.Secure.getString(BaseApp.getPrivateInstance().getContentResolver(), android.provider.Settings.Secure.ANDROID_ID)
                                                  );
        } catch (Exception e) {
            return createDeviceId();
        }
        if (!isNull(androidId)) {
            BaseApp.Settings("device").set("androidId", androidId);
            return androidId;
        }else{
            return createDeviceId();
        }
    } else {
        if (!isNull(androidId)) {
            return androidId;
        }
        return createDeviceId();
    }
}

private static String createDeviceId() {
    String id = BaseApp.Settings("device").getString("id");
    if (isNull(id)) {
        id = UUID.randomUUID().toString();
        BaseApp.Settings("device").set("id", id);
    }
    return id;
}

开源在:github.com/kongzue/Bas…