官網 [Android Pie預覽](https://developer.android.com/about/versions/pie)
項目中的 `targetSdkVersion` 改為 `28(9.0)` 。
## Http請求失敗
在`9.0`中默認情況下啟用網絡傳輸層安全協議 (`TLS)`,默認情況下已停用明文支持。也就是不允許使用`http`請求,要求使用`https`。
比如我使用的是`okhttp`,會報錯:
`java.net.UnknownServiceException: CLEARTEXT communication to xxxx not permitted by network security policy`
解決方法是需要我們添加網絡安全配置。首先在`res`目錄下新建`xml`文件夾,添加`network_security_config.xml`文件:
```xml
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config cleartextTrafficPermitted="true" />
</network-security-config>
```
`AndroidManifest.xml`中的`application`添加:
```xml
<manifest ... >
<application android:networkSecurityConfig="@xml/network_security_config">
...
</application>
</manifest>
```
為了安全靈活,我們可以指定支持的`http`域名:
```xml
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<!-- Android 9.0 上部分域名時使用 http -->
<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="true">secure.example.com</domain>
<domain includeSubdomains="true">cdn.example1.com</domain>
</domain-config>
</network-security-config>
```
當然不止這些配置,還有抓包配置、設置自定義CA以及各種場景下靈活的配置,詳細的方法可以查看[官方文檔](https://developer.android.google.cn/training/articles/security-config.html)。
## Apache HTTP 客戶端棄用
在 `Android 6.0` 時,就已經取消了對 `Apache HTTP` 客戶端的支持。 從 `Android 9.0` 開始,默認情況下該庫已從 `bootclasspath` 中移除。但是耐不住有些SDK中還在使用,比如我見到的友盟QQ分享報錯問題。
所以要想繼續使用`Apache HTTP`,需要在應用的 `AndroidManifest.xml` 文件中添加:
```xml
<manifest ... >
<application>
<uses-library android:name="org.apache.http.legacy" android:required="false"/>
...
</application>
</manifest>
```
## 前臺服務
可以試著搜索一下你的代碼,看是否有調用`startForegroundService`或`startForeground`方法來啟動一個前臺服務。
`startForegroundService`主要來源估計都是**8.0適配**時候加上的:
```java
Intent intentService = new Intent(this, MyService.class);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
startForegroundService(intentService);
} else {
startService(intentService);
}
```
`9.0` 要求創建一個前臺服務需要請求`FOREGROUND_SERVICE`權限,否則系統會引發`SecurityException`。
```java
java.lang.RuntimeException: Unable to start service com.weilu.test.MyService@81795be with Intent { cmp=com.weilu.test/.MyService }:
java.lang.SecurityException: Permission Denial: startForeground from pid=28631, uid=10626 requires android.permission.FOREGROUND_SERVICE
at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:3723)
at android.app.ActivityThread.access$1700(ActivityThread.java:201)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1705)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:207)
at android.app.ActivityThread.main(ActivityThread.java:6820)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:547)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:876)
```
解決方法就是`AndroidManifest.xml`中添加`FOREGROUND_SERVICE`權限:
`<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
`
## 啟動Activity
在 `9.0` 中,不能直接非`Activity`環境中(比如`Service`,`Application`)啟動`Activity`,否則會崩潰報錯:
```java
java.lang.RuntimeException: Unable to create service com.weilu.test.MyService: android.util.AndroidRuntimeException: Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?
at android.app.ActivityThread.handleCreateService(ActivityThread.java:3578)
at android.app.ActivityThread.access$1400(ActivityThread.java:201)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1690)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:207)
at android.app.ActivityThread.main(ActivityThread.java:6820)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:547)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:876)
```
這類問題一般會在點擊推送消息跳轉頁面這類場景,解決方法就是 Intent 中添加標志`FLAG_ACTIVITY_NEW_TASK`
```java
Intent intent = new Intent(this, TestActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
```
## 權限
Android 9 引入[`CALL_LOG`](https://developer.android.com/reference/android/Manifest.permission_group#CALL_LOG)[權限組](https://developer.android.com/guide/topics/permissions/overview#perm-groups)并將[`READ_CALL_LOG`](https://developer.android.com/reference/android/Manifest.permission#READ_CALL_LOG)、[`WRITE_CALL_LOG`](https://developer.android.com/reference/android/Manifest.permission#WRITE_CALL_LOG)和[`PROCESS_OUTGOING_CALLS`](https://developer.android.com/reference/android/Manifest.permission#PROCESS_OUTGOING_CALLS)權限移入該組。 在之前的 Android 版本中,這些權限位于`PHONE`權限組。
> 限制訪問通話記錄
如果應用需要訪問通話記錄或者需要處理去電,則您必須向 `CALL_LOG` 權限組明確請求這些權限。 否則會發生 `SecurityException`。
> 限制訪問電話號碼
要通過 `PHONE_STATE` **Intent** 操作讀取電話號碼,同時需要 `READ_CALL_LOG` 權限和 `READ_PHONE_STATE` 權限。
要從 `PhoneStateListener` 的 `onCallStateChanged()` 中讀取電話號碼,只需要 `READ_CALL_LOG` 權限。 不需要 `READ_PHONE_STATE` 權限。
## 其他
在 `Android 9` 中,調用 `Build.SERIAL` 會始終返回 `UNKNOWN` 以保護用戶的隱私。如果你的應用需要訪問設備的硬件序列號,那么需要先請求 `READ_PHONE_STATE` 權限,然后調用 `Build.getSerial()`。
注意非 SDK 接口的限制。主要是一些熱修復、插件化框架涉及比較多,注意及時升級新版本。
多進程使用 `WebView` 注意無法共用同一數據目錄。 [詳細點擊查看
](https://developer.android.google.cn/about/versions/pie/android-9.0-changes-28#web-data-dirs)
*****
文章到這里就全部講述完啦,若有其他需要交流的可以留言哦~!~!
想閱讀作者的更多文章,可以查看我 [個人博客](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