官网 [Android Oreo预览](https://developer.android.com/about/versions/oreo)
项目中的 `targetSdkVersion` 改为 `26(8.0)` 或者 `27(8.1)` 。
如果已经适配过 `Android6.0` 和 `Android7.0` ,那么这次主要关注的是 `通知适配` 以及 `安装APK` 。
[TOC]
## 运行时权限
官网原文:
> 在 Android 8.0 之前,如果应用在运行时请求权限并且被授予该权限,系统会错误地将属于同一权限组并且在清单中注册的其他权限也一起授予应用。
对于针对 Android 8.0 的应用,此行为已被纠正。系统只会授予应用明确请求的权限。然而,一旦用户为应用授予某个权限,则所有后续对该权限组中权限的请求都将被自动批准。
个人理解:
`READ_EXTERNAL_STORAGE` 和 `WRITE_EXTERNAL_STORAGE` 属于同一`STORAGE` 权限,现在用这个举例。
`Android 8.0` 之前 如果申请 `READ_EXTERNAL_STORAGE` 且被授予该权限,那么会同时授予 `WRITE_EXTERNAL_STORAGE` 。但 针对 `Android 8.0` 的应用需要申请 `WRITE_EXTERNAL_STORAGE` 权限,申请会被自动批准。
如果我们之前的项目已经对每个权限都进行了申请,那么这块不需要做特殊处理。
否则最好将申请**单个权限**改为**权限组**,避免遗漏权限的申请而造成异常。
> Android 8.0 引入了多个与电话有关的新权限:
* [`ANSWER_PHONE_CALLS`](https://developer.android.com/reference/android/Manifest.permission#ANSWER_PHONE_CALLS)允许您的应用通过编程方式接听呼入电话。要在您的应用中处理呼入电话,您可以使用 [acceptRingingCall()](https://developer.android.com/reference/android/telecom/TelecomManager#acceptRingingCall() )函数。
* [`READ_PHONE_NUMBERS`](https://developer.android.com/reference/android/Manifest.permission#READ_PHONE_NUMBERS)权限允许您的应用读取设备中存储的电话号码。
这些权限均被划分为[危险](https://developer.android.com/guide/topics/permissions/requesting#normal-dangerous)类别,属于[`PHONE`](https://developer.android.com/reference/android/Manifest.permission_group#PHONE)权限组。
## 通知适配
在 `Android 8.0` 中,我们已重新设计通知,以便为管理通知行为和设置提供更轻松和更统一的方式。这些变更包括:**通知渠道**、**通知标志**、**通知超时**、**背景颜色**。
> 通知渠道:Android 8.0 引入了通知渠道,其允许您为要显示的每种通知类型创建用户可自定义的渠道。用户界面将通知渠道称之为通知类别。
```java
private void createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationManager notificationManager = (NotificationManager)
getSystemService(Context.NOTIFICATION_SERVICE);
//分组(可选)
//groupId要唯一
String groupId = "group_001";
NotificationChannelGroup group = new NotificationChannelGroup(groupId, "广告");
//创建group
notificationManager.createNotificationChannelGroup(group);
//channelId要唯一
String channelId = "channel_001";
NotificationChannel adChannel = new NotificationChannel(channelId,
"推广信息", NotificationManager.IMPORTANCE_DEFAULT);
//补充channel的含义(可选)
adChannel.setDescription("推广信息");
//将渠道添加进组(先创建组才能添加)
adChannel.setGroup(groupId);
//创建channel
notificationManager.createNotificationChannel(adChannel);
//创建通知时,标记你的渠道id
Notification notification = new Notification.Builder(MainActivity.this, channelId)
.setSmallIcon(R.mipmap.ic_launcher)
.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher))
.setContentTitle("一条新通知")
.setContentText("这是一条测试消息")
.setAutoCancel(true)
.build();
notificationManager.notify(1, notification);
}
}
```
**注意**:当Channel已经存在时,后面的`createNotificationChannel`方法仅能更新其 `name/description`,以及对 `importance` 进行降级,其余配置均无法更新。所以如果有必要的修改只能创建新的渠道,删除旧渠道。
删除渠道代码如下:
```java
private void deleteNotificationChannel(String channelId){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationManager mNotificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.deleteNotificationChannel(channelId);
}
}
```
## 悬浮窗适配
使用 `SYSTEM_ALERT_WINDOW` 权限的应用无法再使用以下窗口类型来在其他应用和系统窗口上方显示提醒窗口:
- `TYPE_PHONE`
- `TYPE_PRIORITY_PHONE`
- `TYPE_SYSTEM_ALERT`
- `TYPE_SYSTEM_OVERLAY`
- `TYPE_SYSTEM_ERROR`
相反,应用必须使用名为 `TYPE_APPLICATION_OVERLAY` 的新窗口类型。
也就是说需要在之前的基础上判断一下:
```java
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
mWindowParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
}else {
mWindowParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT
}
```
当然记得需要有权限
```xml
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<uses-permission android:name="android.permission.SYSTEM_OVERLAY_WINDOW" />
```
## 安装APK
`Android 8.0`去除了“允许未知来源”选项,所以如果我们的 `App` 有安装 `App` 的功能(检查更新之类的),那么会无法正常安装。
首先在`AndroidManifest`文件中添加安装未知来源应用的权限:
```xml
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
```
这样系统会自动询问用户完成授权。当然你也可以先使用`canRequestPackageInstalls()`查询是否有此权限,如果没有的话使用`Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES`这个action将用户引导至安装未知应用权限界面去授权。
```java
//判断应用是否具有安装app权限
context.getPackageManager().canRequestPackageInstalls()
```
## 集合的处理
现在,`AbstractCollection.removeAll(null)` 和 `AbstractCollection.retainAll(null)` 始终引发 `NullPointerException`;之前,当集合为空时不会引发 `NullPointerException`。所以我们需要做判空处理。
## [后台执行限制](https://developer.android.google.cn/about/versions/oreo/background)
应用在两个方面受到限制:
- 后台服务限制:处于空闲状态时,应用可以使用的后台服务存在限制。 这些限制不适用于前台服务,因为前台服务更容易引起用户注意。
- 广播限制:除了有限的例外情况,应用无法使用清单注册隐式广播。 它们仍然可以在运行时注册这些广播,并且可以使用清单注册专门针对它们的显式广播。
在大多数情况下,应用都可以使用 `JobScheduler` 克服这些限制。 这种方式让应用安排为在未活跃运行时执行工作,不过仍能够使系统可以在不影响用户体验的情况下安排这些作业。关于的用法可以参考官方例子:[android-JobScheduler](https://github.com/googlesamples/android-JobScheduler)。
后台任务 `google` 推荐方案使用 `WorkManager`,`WorkManager` 可以自动维护后台任务,同时可适应不同的条件,同时满足后台 `Service` 和静态广播,内部维护着 `JobScheduler`,而在`6.0以下系统版本`则可自动切换为 `AlarmManager`!有兴趣的可以了解一下。
## 其他
- `ANDROID_ID` 每个不同签名的 `app` 获取到的不一样。
- 由于 Android 8.0 引入了新的[广播接收器限制](https://developer.android.com/preview/features/background#broadcasts),因此您应该移除所有为*隐式*广播 Intent 注册的广播接收器。将它们留在原位并不会在构建时或运行时令应用失效,但当应用运行在 Android 8.0 上时它们不起任何作用。
*****
文章到这里就全部讲述完啦,若有其他需要交流的可以留言哦~!~!
想阅读作者的更多文章,可以查看我 [个人博客](http://dandanlove.com/) 和公共号:![振兴书城](https://imgconvert.csdnimg.cn/aHR0cDovL3VwbG9hZC1pbWFnZXMuamlhbnNodS5pby91cGxvYWRfaW1hZ2VzLzEzMTk4NzktNjEyYzRjNjZkNDBjZTg1NS5qcGc?x-oss-process=image/format,png)
- 写在前面的话
- Java
- 基础
- Double的比较
- 小数怎么用二进制表示
- 多线程
- 并发和并行
- 线程池
- 线程池背景
- 线程池构造
- 任务阻塞队列
- Flutter
- 基础知识
- Dart基础
- Android
- 项目架构
- View
- 非UI线程更新View
- AlarmManager
- 对比postDelaryed和Timer
- Bitmap
- 加载100M的图片却不撑爆内存
- Bitmap压缩
- Bitmap局部解码
- 计算图片的内存占用
- Android动画
- Android动画类型
- Android动画原理
- 属性动画
- 帧动画
- 补间动画
- 使用动画的注意事项
- Android新特性
- 权限组
- Android23(Marshmallow)-6.0
- Android24(Nougat)-7.0
- Android26(Oreo)-8.0
- Android28(Pie)-9.0
- Android29(Q)-10.0
- AndroidX迁移
- Kotlin
- 关键字
- Kotlin操作符
- CoroutineScope
- Flow
- CoroutineException