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_LOG
、WRITE_CALL_LOG
和 PROCESS_OUTGOING_CALLS
權限移至這個群組。在舊版 Android 中,這些權限位於 PHONE
權限群組。
這個 CALL_LOG
權限群組可讓使用者進一步控管及掌握需要存取通話機密資訊的應用程式,例如讀取通話記錄和電話號碼。
如果應用程式需要存取通話記錄或處理撥出呼叫,您必須透過 CALL_LOG
權限群組明確要求這些權限。否則會發生 SecurityException
。
注意: 由於這些權限已變更群組並在執行階段授予,因此使用者可能會拒絕您的應用程式存取通話記錄資訊。在這種情況下,應用程式應能妥善處理缺少資訊存取權的情況。
如果您的應用程式已遵循執行階段權限最佳做法,即可處理權限群組中的變更。
限制電話號碼存取權
在 Android 9 上執行的應用程式必須先取得 READ_CALL_LOG
權限,才能讀取電話號碼或手機狀態,以及應用程式用途所需的其他權限。
與來電和撥出通話相關的電話號碼會顯示在電話狀態廣播中 (例如來電和撥出電話,且可透過 PhoneStateListener
類別存取)。不過,在沒有 READ_CALL_LOG
權限的情況下,透過 PHONE_STATE_CHANGED
廣播和 PhoneStateListener
提供的電話號碼欄位會空白。
如要從手機狀態讀取電話號碼,請根據您的用途更新應用程式,以要求必要的權限:
- 如要從
PHONE_STATE
意圖動作讀取數字,您必須具備READ_CALL_LOG
權限和READ_PHONE_STATE
權限。 - 如要從
onCallStateChanged()
讀取數字,您僅需要READ_CALL_LOG
權限。您不需要READ_PHONE_STATE
權限。
限制存取 Wi-Fi 位置資訊和連線資訊
在 Android 9 中,應用程式執行 Wi-Fi 掃描作業的權限要求比先前版本更嚴格。詳情請參閱「Wi-Fi 掃描限制」。
類似的限制也適用於 getConnectionInfo()
方法,此方法會傳回描述目前 Wi-Fi 連線的 WifiInfo
物件。只有在呼叫應用程式具備下列權限時,才能使用這個物件的方法擷取 SSID 和 BSSID 值:
- ACCESS_FINE_LOCATION 或 ACCESS_COARSE_LOCATION
- 存取 Wi-Fi 連線
如要擷取 SSID 或 BSSID,也必須在裝置上啟用定位服務 (位於「設定」>「位置」下方)。
從 Wi-Fi 服務方法中移除的資訊
在 Android 9 中,下列事件和廣播訊息不會收到使用者位置或個人識別資訊的相關資訊:
WifiManager
的getScanResults()
和getConnectionInfo()
方法。WifiP2pManager
的discoverServices()
和addServiceRequest()
方法。NETWORK_STATE_CHANGED_ACTION
廣播。
來自 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 實作變更
系統的 TLS 實作在 Android 9 中經過幾項變更:
- 如果
SSLSocket
的執行個體在建立時無法連線,系統會擲回IOException
,而非NullPointerException
。 SSLEngine
類別會乾淨地處理發生的所有close_notify
快訊。
如要進一步瞭解如何在 Android 應用程式中提出安全的網路要求,請參閱 HTTPS 範例。
更嚴格的 SECCOMP 篩選器
Android 9 會進一步限制應用程式可用的系統呼叫。這個行為是 Android 8.0 (API 級別 26) 包含的 SECCOMP 篩選器的擴充功能。
加密編譯變更
Android 9 針對加密編譯演算法的實作和處理方式推出了幾項變更。
混淆參數和演算法的實作
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/NoPadding 或 ARC4/NONE/NoPadding。
- 已移除 Crypto Java Cryptography Architecture (JCA) 提供者。因此,如果應用程式呼叫
SecureRandom.getInstance("SHA1PRNG", "Crypto")
,會發生NoSuchProviderException
。 - 如果應用程式從大於金鑰結構的緩衝區剖析 RSA 金鑰,就不會發生例外狀況。
如要進一步瞭解如何使用 Android 的加密功能,請參閱「加密編譯」。
系統不再支援 Android 安全加密檔案
Android 9 完全移除對 Android 安全加密檔案 (ASEC) 的支援。
在 Android 2.2 (API 級別 8) 中,Android 推出了 ASEC,以支援 app-on-SD-card 功能。在 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.util
、java.text
和 android.text.format
中實作 Android 類別。
ICU 60 的更新包含許多微小但實用的變更,包括表情符號 5.0 資料支援和改良的日期/時間格式,如 ICU 59 和 ICU 60 版本資訊所述。
本次更新的重要異動:
- 平台處理時區的方式已改變。
- 這個平台較能妥善處理 GMT 和 UTC。UTC 已不再是 GMT 的同義詞。
ICU 現在提供 GMT 和 UTC 的翻譯區域名稱。這項變更會影響「GMT」、「Etc/GMT」、「UTC」、「Etc/UTC」和「Zulu」等區域的
android.icu
格式和剖析行為。 java.text.SimpleDateFormat
現在會使用 ICU 為世界標準時間 /格林威治標準時間提供顯示名稱,也就是說:- 格式化
zzzz
會產生許多語言代碼的長本地化字串。過去,這個值是依照世界標準時間產生,並以「GMT+00:00」等字串表示 GMT。 - 剖析
zzzz
可辨識「世界座標」和「格林威治標準時間」等字串。 - 如果應用程式假設「UTC」或「GMT+00:00」是所有語言的
zzzz
輸出內容,就可能會遇到相容性問題。
- 格式化
java.text.DateFormatSymbols.getZoneStrings()
的行為已變更:- 和
SimpleDateFormat
一樣,世界標準時間和格林威治標準時間現在都有全名。UTC 時區的時區名稱的 DST 變體 (例如「UTC」、「Etc/UTC」和「Zulu」) 會變成 GMT+00:00,這是沒有名稱可用的標準備用項,而非硬式編碼字串UTC
。 - 某些區域 ID 可正確視為其他區域的同義詞,因此 Android 會找出先前無法解析的封存區域 ID 字串,例如
Eire
。
- 和
- 亞洲/河內不再是可識別的區域。因此,
java.util.TimeZones.getAvailableIds()
不會傳回這個值,而java.util.TimeZone.getTimeZone()
無法辨識。這個行為與現有的android.icu
行為一致。
- 這個平台較能妥善處理 GMT 和 UTC。UTC 已不再是 GMT 的同義詞。
- 即使剖析有效貨幣文字,
android.icu.text.NumberFormat.getInstance(ULocale, PLURALCURRENCYSTYLE).parse(String)
方法仍有可能會擲回ParseException
。如要避免這個問題,請使用 Android 7.0 (API 級別 24) 起提供的NumberFormat.parseCurrency
,適用於PLURALCURRENCYSTYLE
樣式文字文字。
Android 測試變更
Android 9 針對 Android Test 架構的程式庫和類別結構推出了幾項變更。這些變更可協助開發人員使用架構支援的公用 API,但這些變更也讓使用第三方程式庫或自訂邏輯的建構和執行測試更有彈性。
已從架構中移除程式庫
Android 9 會將 JUnit 類別重新整理成三個程式庫:android.test.base、android.test.runner 和 android.test.mock。這項變更可讓您針對最適合專案依附元件的 JUnit 版本執行測試。這個版本的 JUnit 可能與 android.jar
提供的版本不同。
如要進一步瞭解如何將 JUnit 類別整理成這些程式庫,以及如何準備應用程式專案來撰寫及執行測試,請參閱「設定 Android Test 的專案」。
測試套件版本變更
已移除 TestSuiteBuilder
類別中的 addRequirements()
方法,並淘汰 TestSuiteBuilder
類別本身。addRequirements()
方法要求開發人員提供類型為隱藏 API 的引數,使得 API 無效。
Java UTF 解碼器
UTF-8 是 Android 中的預設字元集。UTF-8 位元組序列可透過 String
建構函式 (例如 String(byte[] bytes)
) 解碼。
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
)。
不過,CN
的備用內容已在 RFC 2818 中淘汰。因此,Android 不再改回使用 CN
。如要驗證主機名稱,伺服器必須提供與 SAN
相符的憑證。不含 SAN
且符合主機名稱的憑證將不再受到信任。
網路位址查詢可能會導致網路違規事項
需要解析名稱的網路位址查詢可能會涉及網路 I/O,因此屬於封鎖作業。主要執行緒上的封鎖作業可能會導致暫停或卡頓。
StrictMode
類別是一種開發工具,可協助開發人員偵測程式碼中的問題。
在 Android 9 以上版本中,StrictMode
會偵測因為網路位址查詢需要名稱解析而造成的網路違規。
請勿提供已啟用「StrictMode
」的應用程式。否則,應用程式可能會遇到例外狀況,例如在使用 detectNetwork()
或 detectAll()
方法取得偵測網路違規事項的政策時,會遇到 NetworkOnMainThreadException
情形。
解析數字 IP 位址不算是封鎖作業。數字 IP 位址解析的運作方式與 Android 9 以下版本相同。
通訊端標記
在 Android 9 以下版本的平台版本中,如果使用 setThreadStatsTag()
方法標記通訊端,當通訊端透過含有 ParcelFileDescriptor
容器的繫結器 IPC 傳送至其他程序時,系統就不會標記該通訊端。
在 Android 9 以上版本中,當通訊端標記透過繫結器 IPC 傳送至其他程序時,系統會保留通訊端標記。這項變更可能會影響網路流量統計資料,例如使用 queryDetailsForUidTag()
方法時。
如果想保留先前版本的行為 (此版本會取消傳送至其他程序的通訊端標記),可以在傳送通訊端之前呼叫 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_qta 連至 資料夾中的檔案將無法再供應用程式使用
從 Android 9 開始,應用程式無法直接讀取 /proc/net/xt_qtaguid
資料夾中的檔案。原因在於,請務必確保與部分沒有這些檔案的裝置保持一致。
依賴這些檔案的公用 API TrafficStats
和 NetworkStatsManager
可繼續正常運作。然而,不支援的 cutils 函式 (例如 qtaguid_tagSocket()
) 可能無法在不同裝置上正常運作,甚至完全無法在不同裝置上運作。
FLAG_ACTIVITY_NEW_TASK 現已強制執行要求
在 Android 9 中,除非您傳遞意圖旗標 FLAG_ACTIVITY_NEW_TASK
,否則無法從非活動結構定義啟動活動。如果您嘗試在未傳遞此標記的情況下啟動活動,則活動不會啟動,且系統會把訊息列印至記錄中。
畫面旋轉設定變更
從 Android 9 開始,「直向」旋轉模式有重大異動。在 Android 8.0 (API 級別 26) 中,使用者可透過「Quicksettings」資訊方塊或「Display」設定,在「自動旋轉」和「直向」旋轉模式之間切換。直向模式已重新命名為旋轉鎖定,且在自動旋轉關閉時處於啟用狀態。自動旋轉模式沒有任何變更。
裝置處於旋轉鎖定模式時,使用者可以鎖定螢幕,以使用頂端顯示「Activity」支援的任何旋轉角度。Activity 不應假設它一律會以直向算繪。如果頂層 Activity 可在自動旋轉模式下以多個旋轉方式算繪,則相同的選項應可在旋轉鎖定模式下使用,但有些例外狀況則視活動的 screenOrientation
設定而定 (請參閱下表)。
要求特定螢幕方向的活動 (例如 screenOrientation=landscape
) 會忽略使用者鎖定偏好設定,運作方式與 Android 8.0 相同。
螢幕方向偏好設定可在 Android 資訊清單中的活動層級進行設定,也可以使用 setRequestedOrientation() 以程式輔助方式設定。
旋轉鎖定模式的運作方式,是設定 WindowsManager 在處理活動旋轉時使用的使用者旋轉偏好設定。以下情況可能會變更使用者旋轉偏好設定。請注意,仍有偏誤恢復裝置的自然旋轉角度,這通常是手機板型規格裝置的直向顯示:
- 使用者接受旋轉建議時,旋轉偏好設定會變更建議。
- 使用者切換至強制直向應用程式 (包括螢幕鎖定畫面或啟動器) 時,旋轉偏好設定會變更為直向。
下表摘要說明常見螢幕方向的旋轉行為:
螢幕方向 | 行為 |
---|---|
未指定,使用者 | 在自動旋轉和旋轉鎖定時,Activity 可以直向或橫向轉譯 (反之亦然)。應支援直向和橫向版面配置。 |
使用者橫向 | 在自動旋轉和旋轉鎖定時,Activity 能以橫向或反向橫向轉譯。預期僅支援橫向版面配置。 |
使用者直向 | 在自動旋轉和旋轉鎖定時,Activity 能以直向或反向直向轉譯。預期僅支援直向版面配置。 |
完整版使用者 | 在自動旋轉和旋轉鎖定時,Activity 可以直向或橫向轉譯 (反之亦然)。建議同時支援直向和橫向版面配置。 旋轉鎖定功能的使用者將可使用鎖定為反向直向 (通常為 180o) 的選項。 |
感應器, 完整感應器, 感應器直向, SensorLandscape | 系統會忽略旋轉鎖定模式偏好設定,並視為自動旋轉功能已啟用。只有在特殊情況下,才應審慎考慮使用者體驗。 |
Apache HTTP 用戶端淘汰作業會影響使用非標準 ClassLoader 的應用程式
在 Android 6.0 中,我們停止支援 Apache HTTP 用戶端。
大多數未指定 Android 9 以上版本的應用程式,不會受到這項異動的影響。不過,即使應用程式未指定 Android 9 以上版本,這項變更仍可能影響使用非標準 ClassLoader
結構的應用程式。
如果應用程式使用明確委派至系統 ClassLoader
的非標準 ClassLoader
,可能會受到影響。在 org.apache.http.*
中尋找類別時,這些應用程式需要委派給應用程式
ClassLoader
。如果委派給系統 ClassLoader
,應用程式在 Android 9 以上版本中會使用 NoClassDefFoundError
失敗,因為系統 ClassLoader
不再支援這些類別。為了防止日後發生類似問題,應用程式應透過應用程式 ClassLoader
進行一般載入類別,而不是直接存取系統 ClassLoader
。
列舉攝影機
在 Android 9 裝置上執行的應用程式可以呼叫 getCameraIdList()
,探索所有可用的相機。應用程式不應假設裝置只有一個後置鏡頭或只有一個前置鏡頭。
舉例來說,如果應用程式提供切換前置與後置鏡頭的按鈕,可能有多個前置或後置鏡頭可供選擇。建議您逐步查看攝影機清單、檢查每部攝影機的特性,並決定要向使用者顯示哪些攝影機。