Runtime Permissions 动态权限
使用Builder构建通知
省电优化
File Provider
FileProvider.getUriForFile(context, getPkg() + "fileprovider", new File(path));
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.setDataAndType(contentUri, "application/vnd.android.package-archive");
安装权限
通知渠道(分组)
通知设置页面
后台限制
广播限制: 干掉了大量的静态广播, 需要开发者动态注册, 例外列表: https://developer.android.com/guide/components/broadcast-exceptions
系统级别弹窗
dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY);
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
//8.0之后的权限申请要用下面这种方式,所以这两个权限都要加上
<uses-permission android:name="android.permission.SYSTEM_OVERLAY_WINDOW" />
刘海适配 DisplayCutout
通知功能的变更
利用 Wi-Fi RTT 进行室内定位
WifiRttManager rtt = (WifiRttManager)Context.getSystemService(Context.WIFI_RTT_RANGING_SERVICE);
// manifest标签里添加
<uses-feature android:name="android.hardware.wifi.rtt" />
非activity中启动activity Intent必须设置启动类型 FLAG_ACTIVITY_NEW_TASK
限制 http
改 https
降级 targetSdkVersion < 27
配置允许开启 http
// res/xml/network_security_config.xml
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config cleartextTrafficPermitted="true" />
</network-security-config>
// application标签
android:networkSecurityConfig="@xml/network_security_config"
前台服务 FOREGROUND_SERVICE
non-sdk 接口限制 1appcompat.sh --dex-file=apk路径
网上有人发现了绕过API检查的方法,也有专门的库允许在Android P上使用反射而没有任何限制,如 FreeReflection
//允许在Android P上使用反射而不受任何限制
implementation 'me.weishu:free_reflection:1.2.0'
//在App.java中加入即可:
Reflection.unseal(this);
设备唯一标识符 被干掉了: 国内广告联盟出台 OAID (手机重置后OAID也会变化,还不如直接用Android_ID+UUID方案)
Scoped Storage(分区存储)
定位权限 ACCESS_BACKGROUND_LOCATION
后台App启动限制: 通知启动页面需要设置notificationBuilder.setFullScreenIntent(fullScreenPendingIntent, true)
Intent fullScreenIntent = new Intent(this, CallActivity.class);
PendingIntent fullScreenPendingIntent = PendingIntent.getActivity(this, 0,
fullScreenIntent, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder notificationBuilder =
new NotificationCompat.Builder(this, CHANNEL_ID)
.setSmallIcon(R.drawable.notification_icon)
.setContentTitle("Incoming call")
.setContentText("(919) 555-1234")
//以下为关键的3行
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setCategory(NotificationCompat.CATEGORY_CALL)
.setFullScreenIntent(fullScreenPendingIntent, true);
NotificationManager notifyManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
notifyManager.notify(notifyId, builder.build());
// if targetVersion>=29
// AndroidManifest中
<uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT" />
Scoped Storage(分区存储),公共分区目录不再需要权限
废弃 Display.getSize() 和 Display.getMetrics()
现在推荐使用 WindowMetrics
, 并且谷歌提供了一个兼容到 Android 4.0 的 WindowManager
兼容库。 通常情况可以使用如下代码代替以前计算屏幕宽高
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R) {
metrics = activity.getWindowManager().getCurrentWindowMetrics();
int width = metrics.getBounds().width();
int height = metrics.getBounds().height();
}
<uses-permission android:name="android.permission.READ_PHONE_STATE"
android:maxSdkVersion="29" />
<uses-permission android:name="android.permission.READ_PHONE_NUMBERS" />
Android 11+ 自定义 view 的 toast 不能在后台显示
新增支持 无线调试
Splash Screen 官方闪屏页, 可在启动时的白屏上过渡
组件导出行为 android:exported, 当为 false 时不允许被其它 APP 调用
SCHEDULE_EXACT_ALARM 特殊权限
禁止从后台启动前台服务,并对启动前台服务作了限制
引入了 BLUETOOTH_SCAN、BLUETOOTH_ADVERTISE 和 BLUETOOTH_CONNECT 权限。不再需要申请设备位置信息相关权限。
OverScroll 滚动动画增加
果你需要特别处理 OverScroll 的动画或者动作,谷歌增加了 float getDistance()
和 float onPullDistance(float deltaDistance, float displacement)
两个 API
来处理 OverScroll 行为, 需要在 onTouchEvent 中使用如上两个 API,再自定义对应行为.
如果你不喜欢这个动画的话,你也可以通过 xml 中设置 android:overScrollMode="never"
或者使用代码设置 recyclerview.setOverScrollMode(View.OVER_SCROLL_NEVER);
来屏蔽默认的滚动动画
引入限制域概念(官方翻译: 限制性应用待机模式存储分区) Android 12 引入了 APP 限制域, 限制域不但会定义应用的优先级(是否容易被系统杀死),处于低限制域的应用还会被限制一些比较消耗系统资源的行为。 而限制域优先级的划分,很大程度上取决于你应用的使用频率以及当前是否在被前台使用。 想获取 APP 当前的限制域可以使用 getAppStandbyBucket 方法得到
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
UsageStatsManager manager = (UsageStatsManager) getSystemService(USAGE_STATS_SERVICE);
if(manager != null) manager.getAppStandbyBucket();
}
如果需要测试 APP 在严格限制域的表现,谷歌也提供了相对应的命令来进行模拟
adb shell am set-standby-bucket PACKAGE_NAME restricted
这个只需要做充分的测试即可,毕竟你也做不了什么,避免被限制的方法很简单,让用户停在你的APP界面以及更经常的使用你的 APP, 这应该是所有应用开发者一直在研究的问题吧
废弃 Display.getRealSize() 和 Display.getRealMetrics()
Android 11 废弃 Display.getSize() 和 Display.getMetrics()
非可信触摸事件会被屏蔽
提供获取屏幕圆角的 API: RoundedCorner
和 WindowInsets.getRoundedCorner(int position)
通知受限,默认关闭,请求用户授权后可打开
细化读取存储权限,READ_EXTERNAL_STORAGE 权限完全失去了作用,使用 READ_MEDIA_IMAGES、READ_MEDIA_VIDEO 替代 READ_EXTERNAL_STORAGE
<!-- Devices running Android 12L (API level 32) or lower -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
<!-- Devices running Android 13 (API level 33) or higher -->
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
// Register ActivityResult handler
val requestPermissions = registerForActivityResult(RequestMultiplePermissions()) { results ->
// Handle permission requests results
// See the permission example in the Android platform samples: https://github.com/android/platform-samples
}
// Permission request logic
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
requestPermissions.launch(arrayOf(READ_MEDIA_IMAGES, READ_MEDIA_VIDEO))
} else {
requestPermissions.launch(arrayOf(READ_EXTERNAL_STORAGE))
}
intent过滤器会屏蔽不匹配的intent
WIFI访问不再需要定位权限 ACCESS_FINE_LOCATION
, 只需要申请 NEARBY_WIFI_DEVICES
, 但是 WifiManager
的 getScanResults()
或 startScan()
扫描WIFI还是需要定位权限的
使用 Google Play 服务广告 ID 需要声明权限 <uses-permission android:name="com.google.android.gms.permission.AD_ID"/>
废弃 PackageManager中的getPackageInfo、getApplicationInfo、resolveActivity等方法
应用图标可以适应主题
大屏多窗口显示
在Android 13中,用户可以在一个大屏幕上显示多个Activity,从而充分利用大屏幕的显示空间。
开发者需要通过创建XML配置文件或调用Jetpack WindowManager API来确定多个Activity在同个大屏上的具体排布方式,如以切割任务窗口来显示两个Activity
前台服务需要指定服务类型,非在范围内的类型建议使用 WorkManager 或 jobs
限制 pending/implicit 的 Intent
隐式 intent 不能打开 exported=false 的组件, 可以加上包名即显式明确指定
创建 mutable pending intent ,但 intent 未指定组件或包,系统现在会抛出异常
运行时注册的广播接收器必须指定导出行为
Android 14+ 的设备,无法安装 targetSdkVersion 低于 23 的应用,但可以使用 adb 安装 adb install --bypass-low-target-sdk-block FILENAME.apk
(允许开发者对较旧 API 级别的应用进行测试)
设备可授予对照片和视频的部分访问权限, 新增用户选择的照片或影片, 即在 Android 13 基础上增加 READ_MEDIA_VISUAL_USER_SELECTED
<!-- Devices running Android 12L (API level 32) or lower -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
<!-- Devices running Android 13 (API level 33) or higher -->
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
<!-- To handle the reselection within the app on devices running Android 14
or higher if your app targets Android 14 (API level 34) or higher. -->
<uses-permission android:name="android.permission.READ_MEDIA_VISUAL_USER_SELECTED" />
// Register ActivityResult handler
val requestPermissions = registerForActivityResult(RequestMultiplePermissions()) { results ->
// Handle permission requests results
// See the permission example in the Android platform samples: https://github.com/android/platform-samples
}
// Permission request logic
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
requestPermissions.launch(arrayOf(READ_MEDIA_IMAGES, READ_MEDIA_VIDEO, READ_MEDIA_VISUAL_USER_SELECTED))
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
requestPermissions.launch(arrayOf(READ_MEDIA_IMAGES, READ_MEDIA_VIDEO))
} else {
requestPermissions.launch(arrayOf(READ_EXTERNAL_STORAGE))
}
Window Insets。强制 edge-to-edge 全面屏
16k Page Size
Android 15 添加了一个标志,阻止与堆栈上顶部 UID 不匹配的应用启动 activity
https://developer.android.com/reference/android/Manifest.permission