官網 [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/) 和公共號:
- 寫在前面的話
- 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