1. 程式人生 > >Android 9 行為變更:所有應用

Android 9 行為變更:所有應用

Android 9(API 級別 28)向 Android 系統引入了多項變更。 當應用在 Android 9 平臺上執行時,以下行為變更將影響所有應用,無論這些應用以哪個 API 級別為目標。 所有開發者都應檢視這些變更,並修改其應用以正確支援這些變更(如果適用)。

如需瞭解僅影響以 API 28 或更高級別為目標的應用的變更,請參閱行為變更:以 API 級別 28+ 為目標的應用

電源管理

Android 9 引入了新功能以改善裝置電源管理。 這些變更連同 Android 9 之前已存在的功能可幫助確保系統資源被提供給最需要它們的應用。

詳情請參閱電源管理

隱私權變更

為了增強使用者隱私,Android 9 引入了若干行為變更,如限制後臺應用訪問裝置感測器、限制通過 Wi-Fi 掃描檢索到的資訊,以及與通話、手機狀態和 Wi-Fi 掃描相關的新許可權規則和許可權組。

無論採用哪一種目標 SDK 版本,這些變更都會影響運行於 Android 9 上的所有應用。

後臺對感測器的訪問受限

Android 9 限制後臺應用訪問使用者輸入和感測器資料的能力。 如果您的應用在執行 Android 9 裝置的後臺執行,系統將對您的應用採取以下限制:

  • 您的應用不能訪問麥克風或攝像頭。
  • 使用連續報告模式的感測器(例如加速度計和陀螺儀)不會接收事件。
  • 使用變化一次性報告模式的感測器不會接收事件。

如果您的應用需要在執行 Android 9 的裝置上檢測感測器事件,請使用前臺服務

限制訪問通話記錄

Android 9 引入 CALL_LOG 許可權組並將 READ_CALL_LOGWRITE_CALL_LOG 和 PROCESS_OUTGOING_CALLS 許可權移入該組。 在之前的 Android 版本中,這些許可權位於 PHONE 許可權組。

對於需要訪問通話敏感資訊(如讀取通話記錄和識別電話號碼)的應用,該 CALL_LOG

 許可權組為使用者提供了更好的控制和可見性。

如果您的應用需要訪問通話記錄或者需要處理去電,則您必須向 CALL_LOG 許可權組明確請求這些許可權。 否則會發生 SecurityException

注:因為這些許可權已變更組並在執行時授予,使用者可以拒絕您的應用訪問通話記錄資訊。 在這種情況下,您的應用應該能夠妥善處理無法訪問資訊的狀況。

如果您的應用已經遵循執行時許可權最佳做法,則可以處理許可權組的變更。

限制訪問電話號碼

在未首先獲得 READ_CALL_LOG 許可權的情況下,除了應用的用例需要的其他許可權之外,運行於 Android 9 上的應用無法讀取電話號碼或手機狀態。

與來電和去電關聯的電話號碼可在手機狀態廣播(比如來電和去電的手機狀態廣播)中看到,並可通過 PhoneStateListener 類訪問。 但是,如果沒有 READ_CALL_LOG 許可權,則 PHONE_STATE_CHANGED 廣播和 PhoneStateListener 提供的電話號碼欄位為空。

要從手機狀態中讀取電話號碼,請根據您的用例更新應用以請求必要的許可權:

限制訪問 Wi-Fi 位置和連線資訊

在 Android 9 中,應用進行 Wi-Fi 掃描的許可權要求比之前的版本更嚴格。 詳情請參閱 Wi-Fi 掃描限制

類似的限制也適用於 getConnectionInfo() 函式,該函式返回描述當前 Wi-Fi 連線的 WifiInfo 物件。 如果呼叫應用具有以下許可權,則只能使用該物件的函式來檢索 SSID 和 BSSID 值:

  • ACCESS_FINE_LOCATION  ACCESS_COARSE_LOCATION
  • ACCESS_WIFI_STATE

檢索 SSID 或 BSSID 還需要在裝置上啟用位置服務(在 Settings > Location 下)。

從 Wi-Fi 服務函式中移除的資訊

在 Android 9 中,下列事件和廣播不接收使用者位置或個人可識別資料方面的資訊:

Wi-Fi 的 NETWORK_STATE_CHANGED_ACTION系統廣播不再包含 SSID(之前為 EXTRA_SSID)、BSSID(之前為 EXTRA_BSSID)或連線資訊(之前為 EXTRA_NETWORK_INFO)。 如果應用需要此資訊,請改為呼叫getConnectionInfo()

電話資訊現在依賴裝置位置設定

如果使用者在執行 Android 9 的裝置上停用裝置定位,則以下函式不提供結果:

對使用非 SDK 介面的限制

為幫助確保應用穩定性和相容性,此平臺對某些非 SDK 函式和欄位的使用進行了限制;無論您是直接訪問這些函式和欄位,還是通過反射或 JNI 訪問,這些限制均適用。 在 Android 9 中,您的應用可以繼續訪問這些受限的介面;該平臺通過 toast 和日誌條目提醒您注意這些介面。 如果您的應用顯示這樣的 toast,則必須尋求受限介面之外的其他實現策略。 如果您認為沒有可行的替代策略,您可以提交錯誤以請求重新考慮此限制。

對非 SDK 介面的限制包含了更多重要資訊。 您應查閱該資訊以確保您的應用繼續正常工作。

安全行為變更

裝置安全性變更

無論應用的目標平臺版本如何,Android 9 新增的若干功能均可令應用的安全性得到改善。

傳輸層安全協議 (TLS) 實現變更

系統的傳輸層安全協議 (TLS) 實現在 Android 9 中經歷了若干次變更:

如需瞭解有關在 Android 應用中進行安全網路請求的更多資訊,請參閱一個 HTTPS 示例

更嚴格的 SECCOMP 過濾器

Android 9 對可供應用使用的系統呼叫做了進一步限制。 此行為是 Android 8.0(API 級別 26)包含的 SECCOMP 過濾器的擴充套件。

注:此更改僅影響使用授權的系統呼叫的應用。

加密變更

Android 9 針對加密演算法的實現和處理引入了幾項變更。

引數和演算法的 Conscrypt 實現

Android 9 在 Conscrypt 中實現了更多的演算法引數。 這些引數包括: AES、DESEDE、OAEP 和 EC。 這些引數和許多演算法的 Bouncy Castle 版本自 Android 9 起已被棄用。

注:EC 引數的 Conscrypt 實現僅支援已命名的曲線。

如果您的應用以 Android 8.1(API 級別 27)或更低版本為目標,則在請求這些已棄用演算法之一的 Bouncy Castle 實現時,您將收到一條警告訊息。 然而,如果您以 Android 9 為目標平臺,則這些請求會各自引發 NoSuchAlgorithmException

其他變更

Android 9 引入了多項與加密有關的其他變更:

  • 使用 PBE 金鑰時,如果 Bouncy Castle 需要初始化向量 (IV),而您的應用未提供 IV,則會收到一條警告訊息。
  • ARC4 加密的 Conscrypt 實現允許您指定 ARC4/ECB/NoPadding 或 ARC4/NONE/NoPadding
  • Crypto Java 加密架構 (JCA) 提供程式現已被移除。 因此,如果您的應用呼叫 SecureRandom.getInstance("SHA1PRNG", "Crypto"),將會發生 NoSuchProviderException
  • 如果您的應用從大於金鑰結構的緩衝區中解析 RSA 金鑰,將不會再發生異常。

如需瞭解有關使用 Android 的加密功能的更多資訊,請參閱加密

不再支援 Android 安全加密檔案

Android 9 完全取消了對 Android 安全加密檔案 (ASEC) 的支援。

在 Android 2.2(API 級別 8)中,Android 引入了 ASEC 以支援 SD 卡載入應用功能。 在 Android 6.0(API 級別 23)上,平臺引入了一個可採用的儲存裝置 技術,開發者可用它來代替 ASEC。

ICU 庫更新

Android 9 使用 ICU 庫版本 60。 Android 8.0(API 級別 26)和 Android 8.1(API 級別 27)使用 ICU 58。

ICU 用於提供 android.icu package 下的公開 API, 供 Android 平臺內部用來提供國際化支援。 例如,它用於實現 java.utiljava.text 和 android.text.format 格式的 Android 類。

對 ICU 60 進行的更新包含許多細微但很有用的變更,這包括 Emoji 5.0 資料支援,改進了日期/時間格式,詳見 ICU 59 和 ICU 60 版本說明中的介紹。

本次更新中的顯著變更:

  • 平臺處理時區的方式已發生更改。
    • 平臺能夠更好地處理 GMT 和 UTC,不再將 UTC 與 GMT 混為一談。

      ICU 現在提供 GMT 和 UTC 的翻譯版時區名稱。 此變更會影響“GMT”、“Etc/GMT”、“Etc/UTC”、“UTC”和“Zulu”之類時區的 android.icu 格式和解析行為。

    • java.text.SimpleDateFormat 現在使用 ICU 提供 UTC /GMT 的顯示名稱,這意味著:
      • 對於許多語言區域而言,設定 zzzz 的格式將會生成很長的本地化字串。之前,對於 UTC 時區,它會生成“UTC”,而對於 GMT,則會生成“GMT+00:00”之類的字串。
      • 解析 zzzz 可識別“Universal Coordinated Time”和“Greenwich Mean Time”之類的字串。
      • 在所有語言裡,如果應用接受“UTC”或“GMT+00:00”作為 zzzz 的輸出,則可能會遇到相容性問題。
    • java.text.DateFormatSymbols.getZoneStrings() 的行為已變更:
      • 與 SimpleDateFormat 類似,現在,UTC 和 GMT 也有長名稱。對於 UTC 時區,DST 型別的時區名稱(例如“UTC”、“Etc/UTC”和“Zulu”)變為 GMT+00:00(而不是硬編碼字串 UTC),這是在沒有其他名稱可用時的標準回退。
      • 某些時區 ID 被正確地識別為其他地區的同義詞,因此,Android 能夠查詢過時時區 ID(例如 Eire)對應的字串,而之前無法解決此問題。
    • 亞洲/河內不再是可識別的時區。 因此,java.util.TimeZones.getAvailableIds() 不再返回此值,java.util.TimeZone.getTimeZone() 也不再識別它。此行為與現有的 android.icu 行為相符。
  • android.icu.text.NumberFormat.getInstance(ULocale, PLURALCURRENCYSTYLE).parse(String) 函式甚至在解析合法相應幣種文字時也會引發 ParseException。 通過對 PLURALCURRENCYSTYLE 型別的相應幣種文字使用自 Android 7.0(API 級別 24)以來所提供的NumberFormat.parseCurrency,可避免此問題。

Android Test 變更

Android 9 引入了多項針對 Android Test 框架庫和類結構的更改。 這些變更可幫助開發者使用支援框架的公共 API,此外,在使用第三方庫或自定義邏輯構建和執行測試時,這些變更還可提供更大的靈活性。

從框架移除的內容庫

Android 9 將基於 JUnit 的類重新整理成三個內容庫: android.test.baseandroid.test.runner 和 android.test.mock。 此變更允許您針對與您的專案依賴項搭配效果最好的 JUnit 版本執行測試。 此版本的 JUnit 可能不同於 android.jar 提供的版本。

如需瞭解有關如何將基於 JUnit 的類組織到這些內容庫中,以及如何準備您的應用專案以編寫和執行測試,請參閱針對 Android 測試設定專案

測試套件版本號變更

移除了 TestSuiteBuilder 類中的 addRequirements() 函式,TestSuiteBuilder 類本身也已棄用。addRequirements() 函式要求開發者提供型別為隱藏 API 的引數,結果令 API 失效。

Java UTF 解碼器

UTF-8 是 Android 中的預設字符集。 UTF-8 位元組序列可由 String(byte[] bytes) 之類的 String 建構函式解碼。

Android 9 中的 UTF-8 解碼器遵循比以前版本中更嚴格的 Unicode 標準: 這些變更包括:

  • 非最短形式的 UTF-8(例如 <C0, AF>)被視為格式不正確。
  • 替代形式的 UTF-8(例如 U+D800..U+DFFF)被視為格式不正確。
  • 最大的子部分被單個 U+FFFD 取代。 例如,在位元組序列“41 C0 AF 41 F4 80 80 41”中,最大子部分為“C0”、“AF”和“F4 80 80”。其中“F4 80 80”可以是“F4 80 80 80”的初始子序列,但“C0”不能是任何形式正確的程式碼單位序列的初始子序列。 因此,輸出應為“A\ufffd\ufffdA\ufffdA”。
  • 要在 Android 9 或更高版本中解碼修改後的 UTF-8/CESU-8 序列,請使用 DataInputStream.readUTF() 函式或 NewStringUTF() JNI 函式。

使用證書的主機名驗證

RFC 2818中介紹了兩種對照證書匹配域名的方法—使用 subjectAltName (SAN) 擴充套件程式中的可用名稱,或者在沒有SAN 擴充套件程式的情況下,回退到 commonName (CN)。

然而,在 RFC 2818 中,回退到 CN 已被棄用。因此,Android 不再回退到使用 CN。 要驗證主機名,伺服器必須出示具有匹配 SAN 的證書。 不包含與主機名匹配的 SAN 的證書不再被信任。

網路地址查詢可能會導致網路違規

要求名稱解析的網路地址查詢可能會涉及網路 I/O,因此會被視為阻塞性操作。 對於主執行緒的阻塞性操作可能會導致停頓或卡頓。

StrictMode 類是一個有助於開發者檢測程式碼問題的開發工具。

在 Android 9 及更高版本中,StrictMode 可以檢測需要名稱解析的網路地址查詢所導致的網路違規。

您在交付應用時不應啟用 StrictMode。 否則,您的應用可能會遭遇異常,例如,在使用 detectNetwork() 或 detectAll() 函式獲取用於檢測網路違規的政策時,會出現NetworkOnMainThreadException

解析數字 IP 地址不被視為阻塞性操作。 數字 IP 地址解析的工作方式與 Android 9 以前的版本中所採用的方式相同。

套接字標記

在低於 Android 9 的平臺版本上,如果使用 setThreadStatsTag() 函式標記某個套接字,則當使用帶 ParcelFileDescriptor 容器的 binder 程序間通訊將其傳送給其他程序時,套接字會被取消標記。

在 Android 9 及更高版本中,利用 binder 程序間通訊將套接字傳送至其他程序時,其標記將得到保留。 此變更可能影響網路流量統計,例如,使用 queryDetailsForUidTag() 函式時。

如果您要保留以前版本的行為,即取消已傳送至其他程序的套接字的標記,您可以在傳送此套接字之前呼叫 untagSocket()

報告的套接字中可用位元組數

在呼叫 shutdownInput() 函式後,available() 函式會在呼叫時返回 0

更詳盡的 VPN 網路功能報告

在 Android 8.1(API 級別 28)及更低版本中,NetworkCapabilities 類僅報告 VPN 的有限資訊,例如 TRANSPORT_VPN,但會省略 NET_CAPABILITY_NOT_VPN。 資訊有限導致難以確定使用 VPN 是否會導致對應用的使用者收費。 例如,檢查 NET_CAPABILITY_NOT_METERED 並不能確定底層網路是否按流量計費。

從 Android 9 及更高版本開始,當 VPN 呼叫 setUnderlyingNetworks() 函式時,Android 系統將會合並任何底層網路的傳輸和能力並返回 VPN 網路的有效網路能力作為結果。

在 Android 9 及更高版本中,已經檢查NET_CAPABILITY_NOT_METERED 的應用將收到關於 VPN 網路能力和底層網路的資訊。

應用不再能訪問 xt_qtaguid 資料夾中的檔案

從 Android 9 開始,不再允許應用直接讀取 /proc/net/xt_qtaguid 資料夾中的檔案。 這樣做是為了確保與某些根本不提供這些檔案的裝置保持一致。

依賴這些檔案的公開 API TrafficStats 和 NetworkStatsManager 繼續按照預期方式執行。 然而,不受支援的 cutils函式(例如 qtaguid_tagSocket())在不同裝置上可能不會按照預期方式執行 — 甚至根本不執行。

現在強制執行 FLAG_ACTIVITY_NEW_TASK 要求

在 Android 9 中,您不能從非 Activity 環境中啟動 Activity,除非您傳遞 Intent 標誌 FLAG_ACTIVITY_NEW_TASK。 如果您嘗試在不傳遞此標誌的情況下啟動 Activity,則該 Activity 不會啟動,系統會在日誌中輸出一則訊息。

注:在 Android 7.0(API 級別 24)之前,標誌要求一直是期望的行為並被強制執行。 Android 7.0 中的一個錯誤會臨時阻止實施標誌要求。

螢幕旋轉變更

從 Android 9 開始,對縱向旋轉模式做出了重大變更。 在 Android 8.0(API 級別 26)中,使用者可以使用 Quicksettings 圖塊或 Display 設定在自動螢幕旋轉縱向旋轉模式之間切換。 縱向模式已重新命名為旋轉鎖定,它會在自動螢幕旋轉關閉時啟用。 自動螢幕旋轉模式沒有任何變更。

當裝置處於旋轉鎖定模式時,使用者可將其螢幕鎖定到頂層可見 Activity 所支援的任何旋轉。 Activity 不應假定它將始終以縱向呈現。 如果頂層 Activity 可在自動螢幕旋轉模式下以多種旋轉呈現,則應在旋轉鎖定模式下提供相同的選項,根據 Activity 的 screenOrientation 設定,允許存在一些例外情況(見下表)。

請求特定螢幕方向(例如,screenOrientation=landscape)的 Activity 會忽略使用者鎖定首選項,並且行為與 Android 8.0 中的行為相同。

可在 Android Manifest 中,或以程式設計方式通過 setRequestedOrientation() 在 Activity 級別設定螢幕方向首選項。

旋轉鎖定模式通過設定 WindowManager 在處理 Activity 旋轉時使用的使用者旋轉首選項來發揮作用。 使用者旋轉首選項可能在下列情況下發生變更。 請注意,恢復裝置的自然旋轉存在偏差,對於外形與手機類似的裝置通常設定為縱向:

  • 當用戶接受旋轉建議時,旋轉首選項變為建議方向。
  • 當用戶切換到強制縱向應用(包括鎖定螢幕或啟動器)時,旋轉首選項變為縱向。

下表總結了常見螢幕方向的旋轉行為:

螢幕方向 行為
未指定、user 在自動螢幕旋轉和旋轉鎖定下,Activity 可以縱向或橫向(以及顛倒縱向或橫向)呈現。 預期同時支援縱向和橫向佈局。
userLandscape 在自動螢幕旋轉和旋轉鎖定下,Activity 可以橫向或顛倒橫向呈現。 預期只支援橫向佈局。
userPortrait 在自動螢幕旋轉和旋轉鎖定下,Activity 可以縱向或顛倒縱向呈現。 預期只支援縱向佈局。
fullUser 在自動螢幕旋轉和旋轉鎖定下,Activity 可以縱向或橫向(以及顛倒縱向或橫向)呈現。 預期同時支援縱向和橫向佈局。

旋轉鎖定使用者將可選擇鎖定到顛倒縱向,通常為 180º。
sensor、fullSensor、sensorPortrait、sensorLandscape 忽略旋轉鎖定模式首選項,視為自動螢幕旋轉已啟用。 請僅在例外情況下並經過仔細的使用者體驗考量後再使用此項。

Apache HTTP 客戶端棄用影響採用非標準 ClassLoader 的應用

在 Android 6.0 中,我們取消了對 Apache HTTP 客戶端的支援

此變更對大多數不以 Android 9 或更高版本為目標的應用沒有任何影響。 不過,此變更會影響使用非標準 ClassLoader結構的某些應用,即使這些應用不以 Android 9 或更高版本為目標平臺。

如果應用使用顯式委託到系統 ClassLoader 的非標準 ClassLoader,則應用會受到影響。 在 org.apache.http.* 中查詢類時,這些應用需要委託給應用 ClassLoader。 如果它們委託給系統 ClassLoader,則應用在 Android 9 或更高版本上將失敗並顯示 NoClassDefFoundError,因為系統 ClassLoader 不再識別這些類。 為防止將來出現類似問題,一般情況下,應用應通過應用 ClassLoader 載入類,而不是直接訪問系統 ClassLoader

列舉相機

在 Android 9 裝置上執行的應用可以通過呼叫 getCameraIdList() 發現每個可用的攝像頭。 應用不應假定裝置只有一個後置攝像頭或只有一個前置攝像頭。

例如,如果您的應用有一個用來切換前置和後置攝像頭的按鈕,則裝置可能有多個前置或後置攝像頭可供選擇。 您應瀏覽一下攝像頭列表,檢查每個攝像頭的特徵,然後決定向使用者顯示哪些攝像頭。