Android 13(T) 适配

最近在做Android13(T) 的Target适配,整理了适配过程中遇到的问题 分以下三部分影响所有应用的变更(包含target33), 只影响TargetSdkVersion = 33的变更 ,其他更改(新增或者改善的功能).

1.影响所有应用的变更

1.1 必须要适配此项

1.1.1 通知的运行时权限

Android 13 中引入了一种新的运行时通知权限POST_NOTIFICATIONS。 如果用户在搭载 Android 13 的设备上安装您的应用,应用的通知默认处于关闭状态。在您请求新的权限且用户向您的应用授予该权限之前,您的应用都将无法发送通知。

申请弹框时选择项目

1)选择“允许”,然后应用程序可以通过任何渠道发送通知,并发布与前台服务相关的通知。
2)选择“不允许”,则应用程序无法通过任何渠道发送通知,只有少数特定规则除外。
3)不去选择,则应用程序只能在系统有临时授权的情况下发送通知。

1)以 Android 13 为目标平台

对于新安装的应用: 应用程序需要在Manifest中声明 android.permission.POST_NOTIFICATION 权限。此权限的级别为“dangerous”,因此应用程序需要向用户显示运行时提示才能被授予权限。未被授予权限的程序包的通知将被系统自动删除。
现有应用更新(系统自动升级到Android13): 系统临时授予应用发送通知的权限持续到首次启动Activity为止。

2)如果您的应用以 12L(API 级别 32)或更低版本为目标平台

对于新安装的应用: 系统会在您创建第一个通知渠道时显示权限对话框。这通常是在应用启动时。
现有应用更新(系统自动升级到Android13): 系统临时授予应用发送通知的权限,直到用户在通知权限运行时对话框中明确选择一个选项。也就是说如果用户在未做出选择的情况下关闭了权限提示,系统会保留应用的临时授权。

获得临时授权的资格要求: 应用必须已具有通知渠道,并且用户未在搭载 12L 或更低版本的设备上明确停用应用的通
知。如果用户在搭载 12L 或更低版本的设备上停用了应用的通知,当设备升级到 Android 13 或更高版本后,该停
用会继续有效。

所以在13的机器上不管是target是13还是13以下 对用户而言关闭通知权限的可能性非常大所有需要做些业务性的引导逻辑,引导用户去开启通知权限

适配方式:

1.注册权限
<manifest ...>
    <uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
    <application ...>
        ...
    </application>
</manifest>

2. 代码申请
public static final String POST_NOTIFICATIONS="android.permission.POST_NOTIFICATIONS";
public static void requestNotificationPermission(Activity activity) {
  
    if (Build.VERSION.SDK_INT >= 33) {
        if (ActivityCompat.checkSelfPermission(activity, POST_NOTIFICATIONS) == PackageManager.PERMISSION_DENIED) {
            if (!ActivityCompat.shouldShowRequestPermissionRationale( activity, POST_NOTIFICATIONS)) {
              enableNotification(activity);  
            }else{
                ActivityCompat.requestPermissions( activity,new String[]{POST_NOTIFICATIONS},100);
            }
        }
    } else {
        boolean enabled = NotificationManagerCompat.from(activity).areNotificationsEnabled();
        if (!enabled) {
            enableNotification(activity);
        }
    }
}

public static void enableNotification(Context context) {
    try {
        Intent intent = new Intent();
        intent.setAction(Settings.ACTION_APP_NOTIFICATION_SETTINGS);
        intent.putExtra(Settings.EXTRA_APP_PACKAGE,context. getPackageName());
        intent.putExtra(Settings.EXTRA_CHANNEL_ID, context.getApplicationInfo().uid);
        intent.putExtra("app_package", context.getPackageName());
        intent.putExtra("app_uid", context.getApplicationInfo().uid);
        context.  startActivity(intent);
    } catch (Exception e) {
        e.printStackTrace();
        Intent intent = new Intent();
        intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
        Uri uri = Uri.fromParts("package",context. getPackageName(), null);
        intent.setData(uri);
        context. startActivity(intent);
    }
}

1.2 如果有涉及以下需求,可以使用新的api实现

1.2.1. 语言偏好设置

之前是在设置中统一全局修改系统语言, 现在可以针对单个应用设置语言偏好(中文/英文...),请参考变更记录 其他关于语言的变更有针对性特定国家语言(日语文本换行/非拉丁字母行高/语种输入文本转换api)的优化具体可以参考官方文档

非拉丁语行高 ,日语换行 ,不同语种输入文本转换

1.2.2. 自适应主题图标

应用图标可以跟随用户设置的主题壁纸动态调整显示样式 请参考使用方式变更记录

1.2.3.可降级权限(撤销特定的运行时权限或权限组

从 Android 13 开始,应用可以撤消先前由系统或用户授予的运行时权限。此 API 可以帮助应用保护用户的隐私。

如需撤消特定运行时权限,请将该权限的名称传入 revokeOwnPermissionOnKill()。如需同时撤消一组运行时权限,请将这组权限的名称传入 revokeOwnPermissionsOnKill()。撤消是异步发生的,会终止与应用的 UID 相关联的所有进程。

系统只有在安全的情况下才会触发撤消操作。具体而言,当有应用组件仍在前台运行,或者有另一个应用正在访问您应用的组件(如 content provider)时,不会发生撤消。如果您想立即撤消权限,可以调用 exit()。但是,对 exit() 进行此类调用可能会导致当前正在访问您应用的其他应用出现未定义的行为或崩溃。

1.2.4.照片选择器

没有特殊需求可以用官方的照片选择器 参考文档

1.2.5 剪贴板擦除

剪贴板的内容会在60min之后清除,从剪贴板那数据的操作要注意

2.TargetSdkVersion = 33的变更

2.1.必须要适配

2.1.1.通知权限见上述 通知适配部分

2.1.2.读取媒体文件权限适配

对于目标版本为Android 13,细化READ_EXTERNAL_STORAGE权限,使用READ_MEDIA_IMAGEREAD_MEDIA_VIDEOREAD_MEDIA_AUDIO替代READ_EXTERNAL_STORAGE; 如果traget=33 没有适配会出现异常

Type of media Permission to request
Images and photos READ_MEDIA_IMAGES
Videos READ_MEDIA_VIDEO
Audio files READ_MEDIA_AUDIO

适配方式

<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);


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

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

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

2.1.4. 动态注册的广播需要申明 Export行为

从 Android 12 开始 系统要求在注册清单中带有 intent-filter标签的组件必须用export指明是否可导出(如果的当前Activity Service Provider reciver 不需要让其他应用调用 要设置成false, 例如:我们的启动页面就需要指明export='true'来让launch 启动.)

要实现此安全增强措施,请执行以下操作:

  1. 启用 DYNAMIC_RECEIVER_EXPLICIT_EXPORT_REQUIRED 兼容性框架更改。
  2. 在应用的每个广播接收器中,明确指明其他应用是否可以向其发送广播,如以下代码段所示:
// This broadcast receiver should be able to receive broadcasts from other apps.
// This option causes the same behavior as setting the broadcast receiver's
// "exported" attribute to true in your app's manifest.
context.registerReceiver(sharedBroadcastReceiver, intentFilter,
    RECEIVER_EXPORTED);

// For app safety reasons, this private broadcast receiver should **NOT**
// be able to receive broadcasts from other apps.
context.registerReceiver(privateBroadcastReceiver, intentFilter,
    RECEIVER_NOT_EXPORTED);

注意:如果启用了 DYNAMIC_RECEIVER_EXPLICIT_EXPORT_REQUIRED 兼容性框架更改,则必须为每个广播接收器指定 RECEIVER_EXPORTEDRECEIVER_NOT_EXPORTED。否则,当您尝试注册广播接收器时,系统会抛出 SecurityException

适配方式可以全局修改 注册的地方加上exported flag 三方sdk中的注册依赖于各SDK平台的适配,我们可以在 Applocation 和 BaseActivity中 复写registerReceiver在复写方法里判断有没有添加RECEIVER_EXPORTEDRECEIVER_NOT_EXPORTED,如果没有先手动添加ECEIVER_EXPORTED

 boolean flagExported = (flags & Context.RECEIVER_EXPORTED) != 0;
 boolean flagNotExported = (flags & Context.RECEIVER_NOT_EXPORTED) != 0;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU && !flagExported && !flagNotExported) {
    try {
        intent = super.registerReceiver(receiver, filter, flags|Context.RECEIVER_EXPORTED);
    } catch (Exception ex) {
        e.printStackTrace();
    }
}

2.1.5 附近的WIFI设备权限

由于可以通过跟踪附近的Wi-Fi AP和蓝牙设备来推断设备的位置,谷歌决定禁止应用程序访问蓝牙Wi-Fi扫描结果,除非这类应用需要声明 ACCESS_FINE_LOCATION 权限。
在Android 13中,Google将Wi-Fi扫描与位置分离。Android 13 为管理设备与周围 Wi-Fi 热点连接的应用添加 NEARBY_WIFI_DEVICES运行时权限 (属于 NEARBY_DEVICES 权限组)。调用许多常用 Wi-Fi API 的应用都会需要这个权限,从而在不需要ACCESS_FINE_LOCATION权限 的情况下,更轻松地说明应用为何访问附近的 Wi-Fi 设备。此前,对于仅需要连接 Wi-Fi 设备,但实际上并不需要了解设备位置的应用来说,以 Android 13 为目标平台的应用现在可以通过 “neverForLocation” 属性来完善申请 NEARBY_WIFI_DEVICES 权限,这将有助于促进应用设计的隐私性和友好性,同时减少开发者们面临的阻碍。

以 Android 13 为目标平台的应用程序,访问附近的 WI-FI 设备。除特例API需要申请ACCESS_FINE_LOCATION外,其他需要申请android.permission.NEARBY_WIFI_DEVICES运行时权限; 对于用户来说,如果应用没有适配且对调用API没有保护。会出现应用报错或功能异常等现象;

1、开发需要区分不同api对应的权限;
需要新权限(NEARBY_WIFI_DEVICES)的 API:
1)WifiManager:startLocalOnlyHotspot()
2)WifiAwareManager:attach()
3)WifiAwareSession:publish()、subscribe()
4)WifiP2pManager:addLocalService()、connect()、createGroup()、discoverPeers()、discoverServices()、requestDeviceInfo()、requestGroupInfo()、requestPeers()
5)WifiRttManager:startRanging()

仍需要位置信息权限(ACCESS_FINE_LOCATION )的API:
1)WifiManager:getScanResults()、startScan()

2、由于 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、以 Android 13 为目标平台时,如果应用不会通过 Wi-Fi API 推导物理位置,请在清单文件中将 usesPermissionFlags 属性设为 neverForLocation。

<manifest ...>
    <uses-permission android:name="android.permission.NEARBY_WIFI_DEVICES"
                     android:usesPermissionFlags="neverForLocation" />
    <application ...>
        ...
    </application>
</manifest>

3. 新增/改善功能

3.1. open JDk 11 更新

Android 13 开始刷新 Android 的核心库,以与 OpenJDK 11 LTS 版本保持一致,并增添了适合应用和平台开发者的库更新和 Java 11 语言支持,使用jdk中的一些新的方法 参考文档

3.2. 自定义快捷图款

类似于在桌面下拉菜单中的 蓝牙/WIFI/手电筒等快捷按钮, 这个功能7.0 就提供了本次修改是可以将自定义的快捷图块直接显示在默认栏里不需要手动去添加.参考文档

3.3 TextView 的断字性能优化

断字让分行的文本更易于阅读,并且有助于使界面更具自适应性。在 Android 13 中,我们将断字性能优化了多达 200%,因此您现在可以在 TextView 中启用断字功能,这几乎不影响渲染性能。如需启用更快断字功能,请在 setHyphenationFrequency() 中使用新的 fullFastnormalFast 频率。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,948评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,371评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,490评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,521评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,627评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,842评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,997评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,741评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,203评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,534评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,673评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,339评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,955评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,770评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,000评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,394评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,562评论 2 349

推荐阅读更多精彩内容