草庐IT

TargetsdkVersion 升级31(Android12)适配

申国骏 2023-03-28 原文

我们升级到Targetsdk29有大半年时间了,今年为了满足审查去除蓝牙的精确定位权限,以及满足上架Google Play的要求,需要将Targetsdkversion升级到31,适配到Android12。这个过程遇到不少坑,这里记录一下,希望能对大家有所帮助。转载请注明来源「申国骏」

由于我们在适配Android 29的时候已经适配了Scoped storage,因此这篇文章里面没有这部分的描述。

安全组件输出,exported

编译时报错:

android:exported needs to be explicitly specified for element <activity#xxxActivity>. Apps targeting Android 12 and higher are required to specify an explicit value for android:exported when the corresponding component has an intent filter defined. See https://developer.android.com/guide/topics/manifest/activity-element#exported for details.

问题描述:

在target到Android12之后,所有设置了intent filters的activity、services、broadcast receivers都需要设置 android:exported ,否则会导致编译异常。

解决办法:

如果需要被外部其他app访问的component(例如设置了android.intent.category.LAUNCHER 的页面),那么需要exported=true,其他情况设置为exported=false

  • Activity

    true表示当前Activity需要被外部应用调用,例如桌面和应用需要打开当前应用首页,false表示当前Activity只能被当前的应用,或者具有相同userID的应用,或者有调用特权的系统components

  • Service

    true表示可以跟外部应用的component进行交互,false表示只有自己应用内的component以及具有相同userID的应用的component可以启动并绑定这个服务。

  • Receiver

    true表示可以非系统的其他应用的广播,false表示只能收到系统的、自己应用的、具有相同userID应用的广播

对于一些aar或者依赖库有里面component的报错,有两个解决办法:1. 尝试升级对应的依赖库版本,并看看是否已经进行了target android12适配;2. 在主工程中xml拷贝相关component声明,并覆盖exported设置,例如:

android:exported="true"
tools:replace="android:exported"

PendingIntent mutability

运行时报错:

java.lang.RuntimeException: Unable to start activity ComponentInfo{xxx}: java.lang.IllegalArgumentException: Targeting S+ (version 31 and above) requires that one of FLAG_IMMUTABLE or FLAG_MUTABLE be specified when creating a PendingIntent.
Strongly consider using FLAG_IMMUTABLE, only use FLAG_MUTABLE if some functionality depends on the PendingIntent being mutable, e.g. if it needs to be used with inline replies or bubbles.

问题描述:

在target到Android12之后,PendingIntent创建需要指定可变性FLAG_IMMUTABLE 或者 FLAG_MUTABLE

解决办法:

大部分情况下如果不希望创建的PendingIntent被外部应用修改,那么需要设置成PendingIntent.FLAG_IMMUTABLE既可。一些特殊情况可以设置成FLAG_MUTABLE(参考:https://developer.android.com/guide/components/intents-filters#DeclareMutabilityPendingIntent

PendingIntent.getActivity(context, requestCode, intent, PendingIntent.FLAG_IMMUTABLE);

传感器刷新频率问题

运行时报错:

java.lang.SecurityException: To use the sampling rate of 0 microseconds, app needs to declare the normal permission HIGH_SAMPLING_RATE_SENSORS.
at android.hardware.SystemSensorManager$BaseEventQueue.enableSensor(SystemSensorManager.java:884)
at android.hardware.SystemSensorManager$BaseEventQueue.addSensor(SystemSensorManager.java:802)
at android.hardware.SystemSensorManager.registerListenerImpl(SystemSensorManager.java:272)
at android.hardware.SensorManager.registerListener(SensorManager.java:835)
at android.hardware.SensorManager.registerListener(SensorManager.java:742)

问题描述:

当使用SensorManager时,如果监听的频率太快,例如sensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_FASTEST);,且没有改定义permission HIGH_SAMPLING_RATE_SENSORS权限的话会有这个崩溃。

解决办法:

大部分情况下我们并不需要太快的监听频率,可以设置成SensorManager.SENSOR_DELAY_UI。在某些确实需要快速频率监听的话,需要加上HIGH_SAMPLING_RATE_SENSORS权限

ijkplayer

运行时崩溃:

运行时的native崩溃

问题描述:

在target到Android11并且在64位的安卓系统版本11及以上的手机,使用ijkplayer会产生崩溃。这里的原因是Android11对于64位的处理器中,每个指针的第一个字节将被用作标记位,用于ARM的内存标记扩展(MTE)支持。在释放内存的时候如果修改这个标记位程序就会崩溃。

那么ijkplayer在哪里会导致第一个字节被修改了呢,查看这个issues https://github.com/bilibili/ijkplayer/issues/5206 以及提交记录 https://github.com/bilibili/ijkplayer/commit/e99d640e5fe94c65132379307f92d7180bcde8e7 可以看出,主要的原因是之前将指针转换成了int64_t类型导致了精度丢失,修改的地方是将指针转成String或者无符号整形,避免精度丢失导致的首位字节丢失。

Memory_Tagging_Blog_1040x1040.png-1040x0.png

例如,在上面的图中,访问0x8000的内存是可行的,因为用于进行访问的指针具有与被访问的内存相同的标签(用颜色表示)。但是,对0x9000的访问将会失败,因为指针对内存有不同的标记。

解决办法:

解决办法有两个,一个是拉一下ijkplayer最新的代码重新build一个依赖库更新一下,因为ijkplayer已经修改了这个错误。第二个办法是通过设置<application android:allowNativeHeapPointerTagging="false">暂时禁用Pointer Tagging功能。

TelephonyManager.getNetworkType

运行时崩溃:

************* Crash INFO AT 04/01/2022 10:16 *************java.lang.SecurityException: getDataNetworkTypeForSubscriber
android.os.Parcel.createExceptionOrNull(Parcel.java:2389)
android.os.Parcel.createException(Parcel.java:2373)
android.os.Parcel.readException(Parcel.java:2356)
android.os.Parcel.readException(Parcel.java:2298)
com.android.internal.telephony.ITelephony$Stub$Proxy.getNetworkTypeForSubscriber(ITelephony.java:8762)
android.telephony.TelephonyManager.getNetworkType(TelephonyManager.java:3024)
android.telephony.TelephonyManager.getNetworkType(TelephonyManager.java:2988)

问题描述:

我们使用到的一个一键登录的库调用的TelephonyManager.getNetworkType被标记为deprecated,需要改成使用 getDataNetworkType ,并且需要加上权限READ_PHONE_STATE 或者 READ_BASIC_PHONE_STAT

解决办法:

升级一键登录的库,并且加上对应权限

webview访问文件

运行时问题:

加载file://data目录底下数据时webview报错: 网页无法加载,net:ERR_ACCESS_DENIED

问题描述:

在target到Android11及以上的时候,默认setAllowFileAccess从true改成了false,无法访问到context.getDir()里面的文件,参考:https://developer.android.com/reference/android/webkit/WebSettings#setAllowFileAccess(boolean)

解决办法:

手动调用一下webSettings.setAllowFileAccess(true)

Package可见性

运行时问题:

当使用[queryIntentActivities()](https://developer.android.com/reference/android/content/pm/PackageManager#queryIntentActivities(android.content.Intent, int)), [getPackageInfo()](https://developer.android.com/reference/android/content/pm/PackageManager#getPackageInfo(java.lang.String, int))或者 getInstalledApplications()查询是其他应用信息的话会查不到

问题描述:

当应用target到Android11之后,Package可见性受到了限制,查询其他应用信息需要加上QUERY_ALL_PACKAGES权限或者使用queries方式获取。

解决办法:

  1. 在AndroidManifest.xml中加入权限<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />,这个需要谨慎使用,因为应用市场上线检查可能会需要提供使用的必要性说明,例如Google Play政策:https://support.google.com/googleplay/android-developer/answer/10158779

  2. 在AndroidMainifest.xml中定义需要访问的应用信息,例如

    • 需要访问某个应用信息,直接指定应用包名

      <queries>
        <package android:name="com.example.store" />
      </queries>
      
    • 需要访问具有某些intent的外部组件,指定需要访问的intent

      <queries>
        <intent>
          <action android:name="android.intent.action.SEND" />
          <data android:mimeType="image/jpeg" />
        </intent>
      </queries>
      
    • 需要访问某些外部content provider,指定authoritites

      <queries>
        <provider android:authorities="com.example.settings.files" />
      </queries>
      

微博SDK

运行时问题:

微博SDK更新到最新版支持适配安卓11,遇到一个初始化的报错please init sdk before use it. Wb.install()

问题描述:

在微博进行登录授权的时候,需要获取授权信息,不过获取授权信息的时候,有一个断言判断失败了。需要在初始化之后等待一段时间。

解决办法:

通过循环等待的方式等待初始化断言通过再进行其他SDK操作:

public static void waitForWeiboSDKValid() {
    // 微博sdk初始化需要等待一下
    // https://github.com/sinaweibosdk/weibo_android_sdk/issues/608
    // https://xie.infoq.cn/article/974795351e87627681cc353b5
    int retryCount = 0;
    while (retryCount <= 10) {
        try {
            a.b();
            break;
        } catch (Exception ignore) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException ignored) {
            }
            retryCount++;
        }
    }
}

private void installWbSdk() {
   WBAPIFactory.createWBAPI(getApplicationContext());
   mWBAPI.registerApp(getApplicationContext(), authInfo);
   waitForWeiboSDKValid();
}

后台启动前台服务

运行时崩溃:

Caused by: android.app.ForegroundServiceStartNotAllowedException: Service.startForeground() not allowed due to mAllowStartForeground false: service XXXXService 16 at android.app.ForegroundServiceStartNotAllowedException$1.createFromParcel(ForegroundServiceStartNotAllowedException.java:54) 17 at android.app.ForegroundServiceStartNotAllowedException$1.createFromParcel(ForegroundServiceStartNotAllowedException.java:50) 18 at android.os.Parcel.readParcelable(Parcel.java:3345) 19 at android.os.Parcel.createExceptionOrNull(Parcel.java:2432) 20 at android.os.Parcel.createException(Parcel.java:2421) 21 at android.os.Parcel.readException(Parcel.java:2404) 22 at android.os.Parcel.readException(Parcel.java:2346) 23 at android.app.IActivityManagerProxy.setServiceForeground(IActivityManager.java:8040) 24 at android.app.Service.startForeground(Service.java:733)

问题描述:

应用在target到Android12之后,如果应用在后台启用前台服务,那么就会报ForegroundServiceStartNotAllowedException

解决办法:

  1. 使用WorkManager来处理后台任务
  2. 避免在后台启动前台服务

蓝牙权限

运行崩溃:

Caused by: java.lang.SecurityException: Need android.permission.BLUETOOTH_CONNECT permission for android.content.AttributionSource@db46d647: enable 37 at android.os.Parcel.createExceptionOrNull(Parcel.java:2425) 38 at android.os.Parcel.createException(Parcel.java:2409) 39 at android.os.Parcel.readException(Parcel.java:2392) 40 at android.os.Parcel.readException(Parcel.java:2334) 41 at android.bluetooth.IBluetoothManagerProxy.enable(IBluetoothManager.java:611) 42 at android.bluetooth.BluetoothAdapter.enable(BluetoothAdapter.java:1217)

问题描述:

在target到Android12之后,查找蓝牙设备需要添加 BLUETOOTH_SCAN 权限,与匹配的蓝牙设备传输数据需要获取BLUETOOTH_CONNECT 权限

解决办法:

在查找和匹配蓝牙设备之前,先动态申请 BLUETOOTH_SCAN 权限以及BLUETOOTH_CONNECT 权限。

其他

检查依赖的SDK中是否有新的版本,并进行更新,因为安全组件输出Exported以及包可见性的问题对于大多数SDK都可能会存在,所以最好都检查一下,例如华为小米OV相关的产商推送SDK,以及微信QQ微博等登录和分享的SDK。

参考

  1. Bluetooth permissions
  2. Target API level requirements for Play Console
  3. Sensor Rate-Limiting
  4. Behavior changes: Apps targeting Android 12
  5. Behavior changes: Apps targeting Android 11
  6. vivo Android 12应用适配指南
  7. vivo Android 11应用适配指南
  8. oppo Android 12 应用兼容性适配指导
  9. oppo Android 11 应用兼容性适配指导
  10. 小米 Android 12应用适配指南
  11. Tagged Pointers
  12. Memory Tagging Extension: Enhancing memory safety through architecture
  13. Package visibility filtering on Android
  14. Declaring package visibility needs

有关TargetsdkVersion 升级31(Android12)适配的更多相关文章

  1. ruby - 通过 rvm 升级 ruby​​gems 的问题 - 2

    尝试通过RVM将RubyGems升级到版本1.8.10并出现此错误:$rvmrubygemslatestRemovingoldRubygemsfiles...Installingrubygems-1.8.10forruby-1.9.2-p180...ERROR:Errorrunning'GEM_PATH="/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/ruby-1.9.2-p180@global:/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/rub

  2. ruby-on-rails - 项目升级后 Pow 不会更改 ruby​​ 版本 - 2

    我在我的Rails项目中使用Pow和powifygem。现在我尝试升级我的ruby​​版本(从1.9.3到2.0.0,我使用RVM)当我切换ruby​​版本、安装所有gem依赖项时,我通过运行railss并访问localhost:3000确保该应用程序正常运行以前,我通过使用pow访问http://my_app.dev来浏览我的应用程序。升级后,由于错误Bundler::RubyVersionMismatch:YourRubyversionis1.9.3,butyourGemfilespecified2.0.0,此url不起作用我尝试过的:重新创建pow应用程序重启pow服务器更新战俘

  3. ruby - 如何在 Lion 上安装 Xcode 4.6,需要用 RVM 升级 ruby - 2

    我实际上是在尝试使用RVM在我的OSX10.7.5上更新ruby,并在输入以下命令后:rvminstallruby我得到了以下回复:Searchingforbinaryrubies,thismighttakesometime.Checkingrequirementsforosx.Installingrequirementsforosx.Updatingsystem.......Errorrunning'requirements_osx_brew_update_systemruby-2.0.0-p247',pleaseread/Users/username/.rvm/log/138121

  4. ruby - 在不使用 RVM 的情况下在 Mac 上卸载和升级 Ruby - 2

    我最近决定从我的系统中卸载RVM。在thispage提出的一些论点说服我:实际上,我的决定是,我根本不想担心Ruby的多个版本。我只想使用1.9.2-p290版本而不用担心其他任何事情。但是,当我在我的Mac上运行ruby--version时,它告诉我我的版本是1.8.7。我四处寻找如何简单地从我的Mac上卸载这个Ruby,但奇怪的是我没有找到任何东西。似乎唯一想卸载Ruby的人运行linux,而使用Mac的每个人都推荐RVM。如何从我的Mac上卸载Ruby1.8.7?我想升级到1.9.2-p290版本,并且我希望我的系统上只有一个版本。 最佳答案

  5. 安卓apk修改(Android反编译apk) - 2

    最近因为项目需要,需要将Android手机系统自带的某个系统软件反编译并更改里面某个资源,并重新打包,签名生成新的自定义的apk,下面我来介绍一下我的实现过程。APK修改,分为以下几步:反编译解包,修改,重打包,修改签名等步骤。安卓apk修改准备工作1.系统配置好JavaJDK环境变量2.需要root权限的手机(针对系统自带apk,其他软件免root)3.Auto-Sign签名工具4.apktool工具安卓apk修改开始反编译本文拿Android系统里面的Settings.apk做demo,具体如何将apk获取出来在此就不过多介绍了,直接进入主题:按键win+R输入cmd,打开命令窗口,并将路

  6. Python 刷Leetcode题库,顺带学英语单词(31) - 2

    ValidPalindromeGivenastring,determineifitisapalindrome,consideringonlyalphanumericcharactersandignoringcases. [#125]Example:"Aman,aplan,acanal:Panama"isapalindrome."raceacar"isnotapalindrome.Haveyouconsiderthatthestringmightbeempty?Thisisagoodquestiontoaskduringaninterview.Forthepurposeofthisproblem

  7. ruby - 我正在学习编程并选择了 Ruby。我应该升级到 Ruby 1.9 吗? - 2

    我完全不是程序员,正在学习使用Ruby和Rails框架进行编程。我目前正在使用Ruby1.8.7和Rails3.0.3,但我想知道我是否应该升级到Ruby1.9,因为我真的没有任何升级的“遗留”成本。缺点是什么?我是否会遇到与普通gem的兼容性问题,或者甚至其他我不太了解甚至无法预料的问题? 最佳答案 你应该升级。不要坚持从1.8.7开始。如果您发现不支持1.9.2的gem,请避免使用它们(因为它们很可能不被维护)。如果您对gem是否兼容1.9.2有任何疑问,您可以在以下位置查看:http://www.railsplugins.or

  8. ruby-on-rails - 从 Rails 2.3 升级到 Rails 4.0 - 2

    我们有一个目前在Rails2.3.12版和Ruby1.8.7版上运行的应用程序。我们想将我们的应用程序更新到Rails4.0和Ruby2.1.0。我们有大约200个模型和150个Controller。我想知道升级过程需要多大的努力。您还可以提供升级可以遵循的步骤。我们应该先升级Ruby然后再升级Rails还是相反? 最佳答案 您想要实现的目标将是史诗般的努力。我无法为您提供分步说明,因为不可能在一个答案中涵盖所有情况。我建议不要同时升级Ruby和Rails,而是分步升级。升级本身的复杂性是巨大的,但只要您的应用程序具有合理的测试覆盖

  9. 深度学习12. CNN经典网络 VGG16 - 2

    深度学习12.CNN经典网络VGG16一、简介1.VGG来源2.VGG分类3.不同模型的参数数量4.3x3卷积核的好处5.关于学习率调度6.批归一化二、VGG16层分析1.层划分2.参数展开过程图解3.参数传递示例4.VGG16各层参数数量三、代码分析1.VGG16模型定义2.训练3.测试一、简介1.VGG来源VGG(VisualGeometryGroup)是一个视觉几何组在2014年提出的深度卷积神经网络架构。VGG在2014年ImageNet图像分类竞赛亚军,定位竞赛冠军;VGG网络采用连续的小卷积核(3x3)和池化层构建深度神经网络,网络深度可以达到16层或19层,其中VGG16和VGG

  10. ruby-on-rails - Rails 4.1.0.beta1 升级失败 - 2

    我最近尝试安装rails4.1.0.beta1,但是railss导致以下错误。[RVM]/gems/ruby-2.0.0-p247/gems/activesupport-4.1.0.beta1/lib/active_support/core_ext/module/aliasing.rb:32:in`alias_method':undefinedmethod`graft'forclass`ActiveRecord::Associations::JoinDependency'(NameError)[RVM]/gems/ruby-2.0.0-p247/gems/activesupport-4

随机推荐