將 targetSdkVersion 26 升級到 28 之后,遇到以下的問題。
1. 阿里云OSS上傳圖片失敗
- 阿里云上傳圖片的接口沒有回調
- java.net.UnknownServiceException: CLEARTEXT communication to XXX not permitted by network security policy
問題原因:
- 從 Android 9.0 開始,默認情況下移除HTTP客戶端。項目使用的阿里云OSS的sdk 2.8.1使用到HTTP客戶端,所以會找不到該庫拋出異常。
- 阿里云OSS的sdk 2.8.1中的網絡請求是http。而Android 9.0限制了明文流量的網絡請求,非加密的流量請求都會被系統禁止掉。
解決方案:
解決方案以下兩種:
- 開啟 Android 9.0 兼容 http 的請求
在 AndroidManifest文件中加入:
<application
android:usesCleartextTraffic="true">
<uses-library
android:name="org.apache.http.legacy"
android:required="false"/>
</application>
- 將本地的 oss 的 sdk 2.8.1版本升級到 2.9.0 以上,api 'com.aliyun.dpa:oss-android-sdk:+'
當然還是推薦第二種解決方案。
2. Android 9.0上QQ分享報錯
在Android 9.0的手機上進行QQ分享報錯,提示找不到org/apache/http/conn/scheme/SchemeRegistry。
問題原因:
從 Android 9.0 開始,默認情況下移除HTTP客戶端。QQ分享中SDK 使用到HTTP客戶端,所以會找不到該庫拋出異常。
解決方案:
- 繼續兼容HTTP 客戶端,在 AndroidManifest文件中加入:
<application
android:usesCleartextTraffic="true">
<uses-library
android:name="org.apache.http.legacy"
android:required="false"/>
</application>
參考文檔:https://developer.umeng.com/docs/66632/detail/94386
3.限制非 SDK 接口的調用
當你調用了非SDK接口時,會有類似Accessing hidden XXX的日志:
Accessing hidden field Landroid/os/Message;->flags:I (light greylist, JNI)
名單分類:
- Light grey list: targetSDK>=P時,警告;
- Dark grey list: targetSDK<P時,警告;>=p時,不允許調用;
- Black list:三方應用不允許調用;
4.移除對 Build.serial 的直接訪問(設備唯一標識符)
問題原因:
((TelephonyManager) getActivity().getSystemService(Context.TELEPHONY_SERVICE)).getDeviceId()
獲得設備ID,會返回空值(targetSDK<=P)或者報錯(targetSDK==Q)。且官方所說的READ_PRIVILEGED_PHONE_STATE權限只提供給系統app,所以這個方法算是廢了。
解決方案:
由于唯一標識符權限的更改會導致android.os.Build.getSerial()返回unknown,但是由于m_szDevIDShort是由硬件信息拼出來的,所以仍然保證了UUID的唯一性和持久性。參考代碼如下:
public static String getUUID() {
String serial = null;
String m_szDevIDShort = "35" +
Build.BOARD.length() % 10 + Build.BRAND.length() % 10 +
Build.CPU_ABI.length() % 10 + Build.DEVICE.length() % 10 +
Build.DISPLAY.length() % 10 + Build.HOST.length() % 10 +
Build.ID.length() % 10 + Build.MANUFACTURER.length() % 10 +
Build.MODEL.length() % 10 + Build.PRODUCT.length() % 10 +
Build.TAGS.length() % 10 + Build.TYPE.length() % 10 +
Build.USER.length() % 10; //13 位
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
serial = android.os.Build.getSerial();
} else {
serial = Build.SERIAL;
}
//API>=9 使用serial號
return new UUID(m_szDevIDShort.hashCode(), serial.hashCode()).toString();
} catch (Exception exception) {
//serial需要一個初始化
serial = "serial"; // 隨便一個初始化
}
//使用硬件信息拼湊出來的15位號碼
return new UUID(m_szDevIDShort.hashCode(), serial.hashCode()).toString();
}
5. 前臺服務權限
拋出 SecurityException 異常
Caused by: java.lang.SecurityException: Permission Denial:
startForeground from pid=6175, uid=10189 requires android.permission.FOREGROUND_SERVICE
問題原因:
在 Android 9.0 中,應用在使用前臺服務之前必須先申請 FOREGROUND_SERVICE 權限,否則就會拋出 SecurityException 異常。
解決方案:
在 AndroidManifest文件中加入:
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
6.不允許共享WebView數據目錄
應用程序不能再跨進程共享單個WebView數據目錄。如果您的應用有多個使用WebView,CookieManager或android.webkit包中的其他API的進程,則當第二個進程調用WebView方法時,您的應用將崩潰。
7.SELinux 禁止訪問應用的數據目錄
系統強制每個應用的 SELinux 沙盒對每個應用的私有數據目錄強制執行逐個應用的 SELinux 限制。現在,不允許直接通過路徑訪問其他應用的數據目錄。應用可以繼續使用進程間通信 (IPC) 機制(包括通過傳遞 FD)共享數據
8.限制訪問通話記錄
- Android 9.0 引入 CALL_LOG 權限組并將 READ_CALL_LOG、WRITE_CALL_LOG 和 PROCESS_OUTGOING_CALLS 權限移入該組。 在之前的 Android 版本中,這些權限位于 PHONE 權限組。
- 如果應用需要訪問通話記錄或者需要處理去電,則您必須向 CALL_LOG 權限組明確請求這些權限。 否則會發生SecurityException
9.限制訪問電話號碼
- 在未首先獲得 READ_CALL_LOG 權限的情況下,除了應用的用例需要的其他權限之外,運行于 Android 9.0 上的應用無法讀取電話號碼或手機狀態。
- 與來電和去電關聯的電話號碼可在手機狀態廣播(比如來電和去電的手機狀態廣播)中看到,并可通過 PhoneStateListener 類訪問。 但是,如果沒有 READ_CALL_LOG 權限,則 PHONE_STATE_CHANGED 廣播和 PhoneStateListener“提供的電話號碼字段為空”。