行為變更:所有應用程式

Android 9 (API 級別 28) 對 Android 系統做出了許多變更。無論指定的 API 級別為何,當所有應用程式在 Android 9 平台上執行時,下列行為變更都會套用至這些應用程式。所有開發人員都應查看這些變更,並視情況修改應用程式以便正確支援這些變更。

如要瞭解僅影響以 API 級別 28 以上為目標的應用程式變更,請參閱「行為變更:以 API 級別 28 以上為目標的應用程式」。

電源管理

Android 9 推出了新功能,可改善裝置電源管理。這些變更與 Android 9 推出前已有的功能,有助於確保系統資源可供最需要的應用程式使用。

詳情請參閱「電源管理」。

隱私權變更

為強化使用者隱私,Android 9 引進了幾項行為變更,例如限制背景應用程式對裝置感應器的存取權、限制從 Wi-Fi 掃描擷取的資訊,以及與電話通話、手機狀態和 Wi-Fi 掃描相關的新權限規則和權限群組。

無論目標 SDK 版本為何,這些變更都會影響在 Android 9 上執行的所有應用程式。

限制背景感應器的存取權

Android 9 限制背景應用程式存取使用者輸入內容和感應器資料的權限。如果應用程式在搭載 Android 9 的裝置上執行背景作業,系統會對應用程式套用下列限制:

  • 您的應用程式無法存取麥克風或相機。
  • 使用連續回報模式的感應器 (例如加速計和陀螺儀) 不會收到事件。
  • 使用on-changeone-shot回報模式的感應器不會收到事件。

如果應用程式需要在搭載 Android 9 的裝置上偵測感應器事件,請使用前景服務

限制通話記錄存取權

Android 9 推出 CALL_LOG 權限群組,並將 READ_CALL_LOGWRITE_CALL_LOGPROCESS_OUTGOING_CALLS 權限移至這個群組。在舊版 Android 中,這些權限位於 PHONE 權限群組中。

這個 CALL_LOG 權限群組可讓使用者進一步控管應用程式,並掌握應用程式需要存取的電話通話相關機密資訊,例如讀取通話記錄和識別電話號碼。

如果您的應用程式需要存取通話記錄,或需要處理撥出的通話,則必須明確要求這些權限,並從 CALL_LOG 權限群組中取得。否則會發生 SecurityException

注意: 由於這些權限已變更群組,且是在執行階段授予,因此使用者可能會拒絕應用程式存取通話記錄資訊。在這種情況下,您的應用程式應能妥善處理無法存取資訊的問題。

如果您的應用程式已遵循執行階段權限最佳做法,則可處理權限群組的變更。

限制存取電話號碼

除了應用程式用途所需的其他權限之外,在 Android 9 上執行的應用程式必須先取得 READ_CALL_LOG 權限,才能讀取電話號碼或電話狀態。

與來電和撥出電話相關聯的電話號碼會顯示在電話狀態廣播訊息中,例如來電和撥出電話,並可透過 PhoneStateListener 類別存取。不過,如果沒有 READ_CALL_LOG 權限,PHONE_STATE_CHANGED 廣播和 PhoneStateListener 提供的電話號碼欄位就會空白。

如要從電話狀態讀取電話號碼,請更新應用程式,根據用途要求必要的權限:

限制存取 Wi-Fi 位置和連線資訊

在 Android 9 中,應用程式執行 Wi-Fi 掃描的權限要求比先前版本更嚴格。詳情請參閱「Wi-Fi 掃描限制」。

類似的限制也適用於 getConnectionInfo() 方法,該方法會傳回 WifiInfo 物件,用於說明目前的 Wi-Fi 連線。只有在呼叫應用程式具備下列權限時,才能使用這個物件的各項方法來擷取 SSID 和 BSSID 值:

  • ACCESS_FINE_LOCATION ACCESS_COARSE_LOCATION
  • ACCESS_WIFI_STATE

如要擷取 SSID 或 BSSID,您必須在裝置上啟用定位服務 (位於「設定」>「位置」下方)。

從 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 中,應用程式可以繼續存取這些受限制的介面;平台會使用彈出式訊息和記錄項目提醒您。如果應用程式顯示這類彈出式訊息,請務必採用其他實作策略,而非使用受限介面。如果您認為沒有其他可行策略,可以提交錯誤報告,要求我們重新考慮限制。

如需進一步瞭解重要資訊,請參閱「非 SDK 介面的相關限制」。您應查看這項資訊,確保應用程式能繼續正常運作。

安全性行為異動

裝置安全性變更

無論應用程式指定的版本為何,Android 9 都新增了多項可提升應用程式安全性的功能。

TLS 實作變更

在 Android 9 中,系統的 TLS 實作方式經歷了幾項變更:

如要進一步瞭解如何在 Android 應用程式中提出安全的網頁要求,請參閱「HTTPS 範例」。

更嚴格的 SECCOMP 篩選器

Android 9 進一步限制應用程式可使用的系統呼叫。這項行為是 Android 8.0 (API 級別 26) 所包含的 SECCOMP 篩選器的擴充功能

密碼學變更

Android 9 針對加密編譯演算法的實作和處理方式,推出了幾項變更。

參數和演算法的 Conscrypt 實作

Android 9 在 Conscrypt 中提供額外的演算法參數實作。這些參數包括 AES、DESEDE、OAEP 和 EC。自 Android 9 起,這些參數和許多演算法的 Bouncy Castle 版本已淘汰。

如果應用程式指定 Android 8.1 (API 級別 27) 以下版本,您會在要求 Bouncy Castle 實作其中一個已淘汰的演算法時收到警告。不過,如果您指定 Android 9,這些要求會各自擲回 NoSuchAlgorithmException

其他變更

Android 9 推出了幾項與密碼學相關的其他變更:

  • 使用 PBE 金鑰時,如果 Bouncy Castle 預期初始化向量 (IV),但應用程式未提供,您會收到警告。
  • 您可以使用 Conscrypt 實作 ARC4 密碼,指定 ARC4/ECB/NoPaddingARC4/NONE/NoPadding
  • 已移除加密 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.textandroid.text.format 中實作 Android 類別。

更新至 ICU 60 後,您將可使用許多小但實用的變更,包括表情符號 5.0 資料支援和改善的日期/時間格式,詳情請參閱 ICU 59 和 ICU 60 的發布說明。

本次更新的重大變更:

  • 平台處理時區的方式已變更。
    • 平台可更妥善地處理 GMT 和 UTC,UTC 不再是 GMT 的同義詞。

      ICU 現在提供 GMT 和 UTC 的翻譯時區名稱。這項變更會影響 android.icu 格式和剖析行為,適用於「GMT」、「Etc/GMT」、「UTC」、「Etc/UTC」和「Zulu」等時區。

    • java.text.SimpleDateFormat 現在會使用 ICU 提供 UTC /GMT 的顯示名稱,也就是說:
      • 格式化 zzzz 會為許多語言代碼產生長的本地化字串。先前,系統會針對世界標準時間產生「UTC」,針對格林威治標準時間產生「GMT+00:00」之類的字串。
      • 剖析 zzzz 會辨識「世界協調時」和「格林威治標準時間」等字串。
      • 如果應用程式假設「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) 的字串。
    • Asia/Hanoi 不再是系統認可的時區。因此 java.util.TimeZones.getAvailableIds() 不會傳回這個值,而 java.util.TimeZone.getTimeZone() 也不會辨識這個值。這項行為與現有的 android.icu 行為一致。
  • 即使在剖析合法貨幣文字時,android.icu.text.NumberFormat.getInstance(ULocale, PLURALCURRENCYSTYLE).parse(String) 方法也可能會擲回 ParseException。如要避免這個問題,請使用 NumberFormat.parseCurrency 來顯示 PLURALCURRENCYSTYLE 樣式的貨幣文字,此功能自 Android 7.0 (API 級別 24) 起便可使用。

Android 測試變更

Android 9 對 Android 測試架構的程式庫和類別結構做出了幾項變更。這些變更可協助開發人員使用架構支援的公開 API,但也讓開發人員在使用第三方程式庫或自訂邏輯時,能更靈活地建構及執行測試。

從架構中移除的程式庫

Android 9 會將以 JUnit 為基礎的類別重新整理為三個程式庫:android.test.baseandroid.test.runnerandroid.test.mock。這項異動可讓您針對與專案依附元件最相容的 JUnit 版本執行測試。這個 JUnit 版本可能與 android.jar 提供的版本不同。

如要進一步瞭解如何將以 JUnit 為基礎的類別組織到這些程式庫中,以及如何準備應用程式專案以編寫及執行測試,請參閱「為 Android 測試設定專案」。

測試套件建構作業異動

TestSuiteBuilder 類別中的 addRequirements() 方法已遭移除,而 TestSuiteBuilder 類別本身已淘汰。addRequirements() 方法要求開發人員提供類型為隱藏 API 的引數,導致 API 無效。

Java UTF 解碼器

UTF-8 是 Android 的預設字元集。String 建構函式 (例如 String(byte[] bytes)) 可以解碼 UTF-8 位元組序列。

Android 9 中的 UTF-8 解碼器比先前版本更嚴格地遵循萬國碼標準。變更內容包括:

  • 非最短形式的 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() 方法為一個 Socket 加上標記,當該 Socket 透過 ParcelFileDescriptor 容器搭配 binder IPC 傳送至另一個程序時,就會取消標記。

在 Android 9 以上版本中,當套接字標記透過 Binder IPC 傳送至其他程序時,會保留該標記。這項變更可能會影響網路流量統計資料,例如使用 queryDetailsForUidTag() 方法時。

如果您想保留先前版本的行為,也就是將傳送至其他程序的 Socket 取消標記,您可以在傳送 Socket 前呼叫 untagSocket()

通訊端連接埠中可用的位元組數量

在呼叫 shutdownInput() 方法後呼叫 available() 方法時,會傳回 0

針對 VPN 提供更詳細的網路功能報表

在 Android 8.1 (API 級別 27) 以下版本中,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 資料夾中的檔案。原因是為了確保與完全沒有這些檔案的裝置保持一致。

依賴這些檔案 (TrafficStatsNetworkStatsManager) 的公用 API 仍可正常運作。不過,未支援的 cutils 函式 (例如 qtaguid_tagSocket()) 可能無法在不同裝置上正常運作,甚至完全無法運作。

FLAG_ACTIVITY_NEW_TASK 規定現已生效

在 Android 9 中,您必須傳遞意圖旗標 FLAG_ACTIVITY_NEW_TASK,才能從非活動內容啟動活動。如果您嘗試啟動活動時未傳遞此旗標,活動就不會啟動,系統也會在記錄檔中輸出訊息。

螢幕旋轉變更

從 Android 9 開始,直向旋轉模式有重大變更。在 Android 8.0 (API 級別 26) 中,使用者可以使用「快速設定」資訊方塊或「顯示」設定,在「自動旋轉」和「直向」旋轉模式之間切換。直向模式已重新命名為「旋轉鎖定」,並在自動旋轉功能關閉時啟用。自動旋轉模式不會有任何變更。

當裝置處於旋轉鎖定模式時,使用者可以將螢幕鎖定為頂端可見 Activity 支援的任何旋轉模式。活動不應假設一律會以直向模式顯示。如果頂層活動可以在自動旋轉模式下以多種旋轉方式算繪,旋轉鎖定模式應可使用相同的選項,但有些例外狀況則取決於活動的 screenOrientation 設定 (請參閱下表)。

要求特定方向的活動 (例如 screenOrientation=landscape) 會忽略使用者鎖定偏好設定,並以與 Android 8.0 相同的方式運作。

您可以在 Android 資訊清單的活動層級設定螢幕方向偏好設定,也可以透過程式設計使用 setRequestedOrientation()

旋轉鎖定模式會設定使用者旋轉偏好設定,WindowManager 在處理活動旋轉時會使用此偏好設定。在下列情況下,使用者旋轉偏好設定可能會變更。請注意,系統會偏向將畫面旋轉回裝置的自然方向,通常是直向,適用於手機板型規格的裝置:

  • 使用者接受旋轉建議後,旋轉偏好設定就會變更為建議值。
  • 當使用者切換至強制直向的應用程式 (包括鎖定畫面或啟動器) 時,旋轉偏好設定會變更為直向。

下表概略說明常見螢幕方向的旋轉行為:

螢幕方向 行為
未指定、使用者 在自動旋轉和旋轉鎖定模式中,Activity 可以直向或橫向 (以及反向) 呈現。應同時支援直向和橫向版面配置。
userLandscape 在自動旋轉和旋轉鎖定模式下,活動可以以橫向或反向橫向模式轉譯。預期僅支援橫向版面配置。
userPortrait 在自動旋轉和旋轉鎖定模式下,活動可以以直向或反向直向呈現。預期僅支援直向版面配置。
fullUser 在自動旋轉和旋轉鎖定模式中,Activity 可以直向或橫向 (以及反向) 呈現。請同時支援直向和橫向版面配置。

旋轉鎖定功能的使用者可以選擇鎖定反向直向 (通常為 180º)。
sensor、fullSensor、sensorPortrait、sensorLandscape 系統會忽略旋轉鎖定模式偏好設定,並視為自動旋轉功能已啟用。請只在非常特殊的情況下使用,並仔細考量使用者體驗。

Apache HTTP 用戶端淘汰作業會影響使用非標準 ClassLoader 的應用程式

在 Android 6.0 中,我們已移除對 Apache HTTP 用戶端的支援。這項變更不會影響大多數未指定 Android 9 以上版本的應用程式。不過,即使應用程式未指定 Android 9 以上版本,這項變更仍可能影響使用非標準 ClassLoader 結構的特定應用程式。

如果應用程式使用明確委派至系統 ClassLoader 的非標準 ClassLoader,就可能受到影響。這些應用程式在 org.apache.http.* 中尋找類別時,需要改為委派至 app ClassLoader。如果委派至系統 ClassLoader,應用程式將在 Android 9 以上版本中失敗,並顯示 NoClassDefFoundError,因為系統 ClassLoader 不再認識這些類別。為避免日後發生類似問題,應用程式通常應透過應用程式 ClassLoader 載入類別,而非直接存取系統 ClassLoader

列舉攝影機

在 Android 9 裝置上執行的應用程式可以呼叫 getCameraIdList(),找出所有可用的相機。應用程式不應假設裝置只有一個後置鏡頭或一個前置鏡頭。

舉例來說,如果應用程式有切換前後置鏡頭的按鈕,可能會有多個前置或後置鏡頭可供選擇。您應瀏覽攝影機清單、檢查每部攝影機的特性,並決定要向使用者顯示哪些攝影機。