Android P下获取AdvertisingId触发SecurityException问题求助
解决Android P上获取AdvertisingId触发SecurityException的问题
这个坑我之前踩过,核心原因是Android P(API 28)开始彻底封杀了MODE_WORLD_READABLE这种不安全的SharedPreferences模式,而你用的旧版Google Play Services库内部还在硬编码使用这个模式读取google_ads_flags配置,直接触发了系统的安全校验。下面给你两种解决方案,优先推荐第一种:
1. 升级Google Play Services依赖(最稳妥)
Google早就修复了这个问题,只要把相关依赖升级到足够新的版本就行。现在AdvertisingId的API已经单独拆到了play-services-ads-identifier库,直接替换成这个库的最新稳定版即可:
在你的Module级别build.gradle里修改依赖:
implementation 'com.google.android.gms:play-services-ads-identifier:18.0.1'
(注:可以去Google Maven仓库查最新版本号,18.x及以上版本肯定已经修复了模式问题)
升级后,内部的getAdvertisingIdInfo方法会自动使用MODE_PRIVATE读取SharedPreferences,不需要修改你的业务代码,亲测有效。
2. 临时反射 workaround(不推荐,仅应急)
如果因为项目依赖限制暂时没法升级库,可以试试用反射强行把内部的模式参数改成MODE_PRIVATE,但这个方法依赖Google库的内部实现,后续版本可能失效:
// 先在调用getAdvertisingIdInfo前执行反射修改 try { // 获取MODE_PRIVATE的常量值 Field modePrivateField = Context.class.getField("MODE_PRIVATE"); int modePrivate = modePrivateField.getInt(null); // 找到AdvertisingIdClient里控制SharedPreferences模式的字段 Class<?> adIdClientClass = Class.forName("com.google.android.gms.ads.identifier.AdvertisingIdClient"); Field sharedPrefModeField = adIdClientClass.getDeclaredField("SHARED_PREF_MODE"); sharedPrefModeField.setAccessible(true); sharedPrefModeField.set(null, modePrivate); } catch (NoSuchFieldException | IllegalAccessException | ClassNotFoundException e) { e.printStackTrace(); // 反射失败就正常走原逻辑,大概率还是会报错,所以优先升级依赖 } // 然后再执行你原来的获取逻辑 Thread backgroundWorker = new Thread(new Runnable() { @Override public void run() { try { AdvertisingIdClient.Info adInfo = AdvertisingIdClient.getAdvertisingIdInfo(appContext); if (adInfo != null){ Log.d("some tag", adInfo.getId()); } } catch (IllegalStateException | GooglePlayServicesRepairableException | IOException | GooglePlayServicesNotAvailableException | SecurityException e){ e.printStackTrace(); } } }); backgroundWorker.start();
额外提醒
- 尽量把你的App的
targetSdkVersion升级到28及以上,适配Android P的安全规则,避免其他类似的兼容性问题。 - 确保测试设备上的Google Play Services也是最新版本,旧的系统服务配合新的客户端库也可能出问题。
内容的提问来源于stack exchange,提问作者neuman8
相关产品推荐
相关产品推荐

