Android 13适配

一、获取Android 13

        获取通用系统映像 (GSI)

        Android 通用系统映像 (GSI) 二进制文件可供开发者在受支持且符合 Treble 标准的设备上进行应用测试和验证。您可以使用这些映像解决所有兼容性问题,并发现和报告操作系统和框架方面的问题。

        如需了解设备要求、刷机说明以及有关为设备选择正确映像类型的信息,请参阅 GSI 文档。准备好下载 GSI 二进制文件后,请参阅 GSI 二进制文件页面上的“下载”部分

二、变更行为

1、通知运行时权限

        Android 13(API 级别 33)引入了新的运行时权限,用于从应用发送非豁免通知:POST_NOTIFICATIONS。 此更改有助于用户专注于最重要的通知。

<manifest ...>
    <uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
    <application ...>
        ...
    </application>
</manifest>
  • 代码申请:
val POST_NOTIFICATIONS = "android.permission.POST_NOTIFICATIONS"
fun requestNotificationPermission(activity: Activity) {
    when {
        Build.VERSION.SDK_INT >= 33 -> {
            if (ActivityCompat.checkSelfPermission(activity, POST_NOTIFICATIONS) == PackageManager.PERMISSION_DENIED) {
                when {
                    !ActivityCompat.shouldShowRequestPermissionRationale(activity, POST_NOTIFICATIONS) -> {
                        enableNotification(activity)
                    }
                    else -> {
                        ActivityCompat.requestPermissions(activity, arrayOf(POST_NOTIFICATIONS), 100)
                    }
                }
            }
        }
        else -> {
            if (!NotificationManagerCompat.from(activity).areNotificationsEnabled()) {
                enableNotification(activity)
            }
        }
    }
}

fun enableNotification(context: Context) {
    try {
        Intent().apply {
            action = Settings.ACTION_APP_NOTIFICATION_SETTINGS
            putExtra(Settings.EXTRA_APP_PACKAGE, context.getPackageName())
            putExtra(Settings.EXTRA_CHANNEL_ID, context.getApplicationInfo().uid)
            putExtra("app_package", context.getPackageName())
            putExtra("app_uid", context.getApplicationInfo().uid)
            context.startActivity(this)
        }
    } catch (e: Exception) {
        e.printStackTrace()
        Intent().apply {
            action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
            val uri: Uri = Uri.fromParts("package", context.getPackageName(), null)
            data = uri
            context.startActivity(intent)
        }
    }
}

2、复制和粘贴改进

        从 Android 13 开始,将内容添加到剪贴板时,系统会显示标准视觉确认界面。新确认界面会执行以下操作:

  • 确认内容已成功复制。
  • 提供所复制内容的预览。

        在 Android 12L(API 级别 32)及更低版本中,用户经常不确定他们是否成功复制了内容或者复制了什么内容。

        此功能可将应用在用户复制内容后显示的各种通知标准化,并让用户可以更好地控制剪贴板。

3、照片选择器

        Android 13(API 级别 33)支持新的照片选择器工具。此工具为用户提供了一种安全的内置媒体文件选择方式,让其无需向应用授予对整个媒体库的访问权限。

  • 单选模式下启动照片选择器:
val intent = Intent(MediaStore.ACTION_PICK_IMAGES)
startActivityForResult(intent, PHOTO_PICKER_REQUEST_CODE)
  • 多张照片或多个视频:
val maxNumPhotosAndVideos = 10  //该值表示在向用户显示时照片选择器中显示的媒体文件数量上限。
val intent = Intent(MediaStore.ACTION_PICK_IMAGES)
intent.putExtra(MediaStore.EXTRA_PICK_IMAGES_MAX, maxNumPhotosAndVideos)
startActivityForResult(intent, PHOTO_PICKER_MULTI_SELECT_REQUEST_CODE)
  • 默认情况下,照片选择器会既显示照片又显示视频。您还可以在 setType() 方法中设置 MIME 类型,以便按“仅显示照片”或“仅显示视频”进行过滤。例如,如需在照片选择器中仅显示视频,请将 video/* 传入 setType():
val intent = Intent(MediaStore.ACTION_PICK_IMAGES)
intent.type = "video/*"
startActivityForResult(intent, PHOTO_PICKER_VIDEO_SINGLE_SELECT_REQUEST_CODE)
  • 处理照片选择器结果

        照片选择器启动后,使用新的 ACTION_PICK_IMAGES intent 来处理结果。该选择器会返回一组 URI:

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) {
    super.onActivityResult(requestCode, resultCode, data)
    if (resultCode != Activity.RESULT_OK) {
        // Handle error
        return
    }
    when (requestCode) {
        REQUEST_PHOTO_PICKER_SINGLE_SELECT -> {
            // Get photo picker response for single select.
            val currentUri: Uri = data.data

            // Do stuff with the photo/video URI.
            return
        }
        REQUEST_PHOTO_PICKER_MULTI_SELECT -> {
            // Get photo picker response for multi select.
            var i = 0
            while (i < data.clipData!!.itemCount) {
                val currentUri: Uri = data.clipData!!.getItemAt(i).uri
                ......

                i++
            }
        }
    }
}

4、读取媒体文件权限适配细化

        如果您的应用以 Android 13 为目标平台,您必须请求一个或多个新权限,而不是 READ_EXTERNAL_STORAGE 和 WRITE_EXTERNAL_STORAGE 权限。

        以 Android 13 为目标平台后,请声明您的应用所需的媒体权限。为了保持与旧版 Android 的兼容性,请在将 maxSdkVersion 设置为 32 时声明 READ_EXTERNAL_STORAGE 权限,如以下代码段所示:

<manifest ...>
    <!-- Required only if your app targets Android 13. -->
    <!-- Declare one or more the following permissions only if your app needs
    to access data that's protected by them. -->
    <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
    <uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
    <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />

    <!-- Required to maintain app compatibility. -->
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
                     android:maxSdkVersion="32" />
    <application ...>
        ...
    </application>
</manifest>

代码中获取:

32及以下版本
ActivityCompat.requestPermissions( activity,new String[]{"android.permission.READ_EXTERNAL_STORAGE"},100);

33及以上版本
ActivityCompat.requestPermissions( activity,new String[]{"android.permission.READ_MEDIA_IMAGES"},100);
ActivityCompat.requestPermissions( activity,new String[]{"android.permission.READ_MEDIA_AUDIO"},100);
ActivityCompat.requestPermissions( activity,new String[]{"android.permission.READ_MEDIA_VIDEO"},100);

        注意:如果您的应用只需要访问图片、照片和视频,请考虑使用照片选择器,而不是声明 READ_MEDIA_IMAGES 和 READ_MEDIA_VIDEO 权限。 您无需再声明 WRITE_EXTERNAL_STORAGE 权限。

5、在后台使用身体传感器需要新的权限

        Android 13 中引入了“在使用时”访问身体传感器(例如心率、体温和血氧饱和度)的概念。此访问模式与 Android 10(API 级别 29)系统为位置信息引入的模式非常相似。

        如果您的应用以 Android 13 为目标平台,并且在后台运行时需要访问身体传感器信息,那么除了现有的 BODY_SENSORS 权限外,您还必须声明新的 BODY_SENSORS_BACKGROUND 权限。

6、intent 过滤器会屏蔽不匹配的 intent

        当您的应用向以 Android 13 或更高版本为目标平台的其他应用的导出组件发送 intent 时,仅当该 intent 与接收应用中的 <intent-filter> 元素匹配时,系统才会传送该 intent。不匹配的 intent 会被屏蔽。

不强制要求匹配 intent 的例外情况包括:

  • 传送到未声明任何 intent 过滤器的组件中的 intent。
  • 源自同一应用内的 intent。
  • 源自系统的 intent;也就是说,从“系统 UID”(uid=1000) 发送的 intent。系统应用包括 system_server 和将 android:sharedUserId 设置为 android.uid.system 的应用。
  • 源自根的 intent。

        如果接收方应用升级到 Android 13 或更高版本,仅当 intent 与其声明的 <intent-filter> 元素匹配时,源自外部应用的所有 intent 才会传送到导出组件,而不考虑发送应用的目标 SDK 版本。

7、针对附近 Wi-Fi 设备的新运行时权限

        由于可以通过跟踪附近的Wi-Fi AP和蓝牙设备来推断设备的位置,谷歌决定禁止应用程序访问蓝牙Wi-Fi扫描结果,除非这类应用需要声明 ACCESS_FINE_LOCATION 权限。

        Android 13(API 级别 33)引入了 NEARBY_WIFI_DEVICES 运行时权限,该权限属于 NEARBY_DEVICES 权限组,适用于会管理设备与附近 Wi-Fi 接入点连接情况的应用。借助此权限,您可以更轻松地说明应用为何访问附近的 Wi-Fi 设备;在以前的 Android 版本中,这类应用需要声明 ACCESS_FINE_LOCATION 权限。

如果您的应用以 Android 13 为目标平台并调用多个不同的 Wi-Fi API,则必须从用户处获得这项新权限。

  • 需要新权限的 API

        如果您的应用以 Android 13 或更高版本为目标平台,您必须声明 NEARBY_WIFI_DEVICES 权限才能调用以下任何 Wi-Fi API:

WifiManager
    startLocalOnlyHotspot()
WifiAwareManager
    attach()
WifiAwareSession
    publish()
    subscribe()
WifiP2pManager
    addLocalService()
    connect()
    createGroup()
    discoverPeers()
    discoverServices()
    requestDeviceInfo()
    requestGroupInfo()
    requestPeers()
WifiRttManager
    startRanging()

        在以 Android 13 为目标平台时,请考虑您的应用是否会通过 Wi-Fi API 推导物理位置;如果不会,则应坚定声明此情况。如需做出此声明,请在应用的清单文件中将 usesPermissionFlags 属性设为 neverForLocation,如以下代码段所示。此过程类似于您声明绝不会将蓝牙设备信息用于获取位置信息时的过程:

<manifest ...>
    <uses-permission android:name="android.permission.NEARBY_WIFI_DEVICES"
                     android:usesPermissionFlags="neverForLocation" />
    <application ...>
        ...
    </application>
</manifest>
  • 需要位置信息权限(ACCESS_FINE_LOCATION)的API
WifiManager:
    getScanResults()
    startScan()

        由于 NEARBY_WIFI_DEVICES 权限仅适用于 Android 13 或更高版本,因此您应保留对 ACCESS_FINE_LOCATION 的所有声明,以便在您的应用中提供向后兼容性。不过,只要您坚定声明应用不会使用 Wi-Fi API 推导物理位置信息,就可以将此权限的最高 SDK 版本设为 32,如下以下代码段所示:

<manifest ...>
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"
                     android:maxSdkVersion="32" />
    <application ...>
        ...
    </application>
</manifest>

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值