文章摘要
1、后臺執行限制
2、Android 后臺位置限制
3、應用快捷鍵
4、語言區域和國際化
5、提醒窗口
6、輸入和導航
7、網頁表單自動填充
8、無障礙功能
9、網絡連接和 HTTP(S) 連接
10、藍牙
11、無縫連接
12、安全性
13、隱私性
14、記錄未捕獲的異常
15、聯系人提供程序使用情況統計方法的變更
16、集合的處理
17、Android 企業版
Android O 除了提供諸多新特性和功能外,還對系統和 API 行為做出了各種變更。本文重點介紹您應該了解并在開發應用時加以考慮的一些主要變更。
其中大部分變更會影響所有應用,而不論應用針對的是何種版本的 Android。不過,有幾項變更僅影響針對 Android O 的應用。為清楚起見,本頁面分為兩個部分:針對所有 API 級別的應用和針對 Android O 的應用。
一、針對所有 API 級別的應用
這些行為變更適用于 在 Android O 平臺上運行的 所有應用,無論這些應用是針對哪個 API 級別構建。所有開發者都應查看這些變更,并修改其應用以正確支持這些變更(如果適用)。
1.1、后臺執行限制
Android O 為提高電池續航時間而引入的變更之一是,當您的應用進入已緩存狀態時,如果沒有活動的組件,系統將解除應用具有的所有喚醒鎖。
此外,為提高設備性能,系統會限制未在前臺運行的應用的某些行為。具體而言:
- 現在,在后臺運行的應用對后臺服務的訪問受到限制。
- 應用無法使用其清單注冊大部分隱式廣播(即,并非專門針對此應用的廣播)。
默認情況下,這些限制僅適用于針對 O 的應用。不過,用戶可以從 Settings --> Display 為任意應用啟用這些限制,即使應用并不是以 O 為目標平臺。
Android O 還對特定函數做出了以下變更:
- 如果針對 Android O 的應用嘗試在不允許其創建后臺服務的情況下使用 startService() 函數,則該函數將引發一個 IllegalStateException。
- 新的 Context.startForegroundService() 函數將啟動一個前臺服務。現在,即使應用在后臺運行,系統也允許其調用 Context.startForegroundService()。不過,應用必須在創建服務后的五秒內調用該服務的 startForeground() 函數。
1.2、Android 后臺位置限制
為節約電池電量、保持良好的用戶體驗和確保系統健康運行,在運行 Android O 的設備上使用后臺應用時,降低了后臺應用接收位置更新的頻率。此行為變更會影響包括 Google Play 服務在內的所有接收位置更新的應用。
此類變更會影響以下 API:
- Fused Location Provider (FLP)
- Geofencing
- GNSS Measurements
- Location Manager
- Wi-Fi Manager
為確保您的應用按預期方式運行,請完成以下步驟:
- 查看您的應用的邏輯,并確保您使用的是最新的位置 API。
- 測試您的應用是否在每個用例中都表現出預期行為。
- 考慮使用 Fused Location Provider (FLP) 或地理圍欄來處理依賴于用戶當前位置的用例。
1.3、應用快捷鍵
Android O 對應用快捷方式做出了以下變更:
- com.android.launcher.action.INSTALL_SHORTCUT 廣播不再會對您的應用有任何影響,因為它現在是私有的隱式廣播。相反,您應使用 ShortcutManager 類中的 requestPinShortcut() 函數創建應用快捷方式。
- 現在,ACTION_CREATE_SHORTCUT Intent 可以創建可使用 ShortcutManager 類進行管理的應用快捷方式。此 Intent 還可以創建不與 ShortcutManager 交互的舊版啟動器快捷方式。在以前,此 Intent 只能創建舊版啟動器快捷方式。
- 現在,使用 requestPinShortcut() 創建的快捷方式和在處理 ACTION_CREATE_SHORTCUT Intent 的操作組件中創建的快捷方式均已轉換為功能齊全的應用快捷方式。因此,應用現在可以使用 ShortcutManager 中的函數來更新這些快捷方式。
1.4、語言區域和國際化
Android 7.0(API 級別 24)引入能指定默認類別語言區域的概念,但是某些 API 在本應使用默認 DISPLAY 類別語言區域時,仍然使用不帶參數的通用 Locale.getDefault() 函數。現在,在 Android O 中,以下函數使用 Locale.getDefault(Category.DISPLAY) 來代替:
- Locale.getDefault():
- Currency.getDisplayName()
- Currency.getSymbol()
- Locale.getDisplayScript()
當為 Locale 參數指定的 displayScript 值不可用時,Locale.getDisplayScript(Locale) 同樣回退到 Locale.getDefault()。
與語言區域和國際化有關的其他變更如下:
調用 Currency.getDisplayName(null) 會引發 NullPointerException,以與文檔規定的行為保持一致。
時區名稱的分析方法發生變化。之前,Android設備使用在啟動時取樣的系統時鐘值,緩存用于分析日期時間的時區名稱。因此,如果在啟動時或其他較為罕見的情況下系統時鐘出錯,可能對分析產生負面影響。
現在,一般情況下,在分析時區名稱時分析邏輯將使用 ICU 和當前系統時鐘值。此項變更可提供更加準確的結果,如果您的應用使用 SimpleDateFormat 等類,此結果可能與之前的 Android 版本不同。Android O 將 ICU 的版本更新至版本 58。
1.5、提醒窗口
如果應用使用 SYSTEM_ALERT_WINDOW 權限并且嘗試使用以下窗口類型之一來在其他應用和系統窗口上方顯示提醒窗口:
- TYPE_PHONE
- TYPE_PRIORITY_PHONE
- TYPE_SYSTEM_ALERT
- TYPE_SYSTEM_OVERLAY
- TYPE_SYSTEM_ERROR
...那么,這些窗口將始終顯示在使用 TYPE_APPLICATION_OVERLAY 窗口類型的窗口下方。如果應用針對的是 Android O,則應用會使用 TYPE_APPLICATION_OVERLAY 窗口類型來顯示提醒窗口。
1.6、輸入和導航
隨著 Android 應用出現在 Chrome 操作系統和平板電腦等其他大尺寸設備上,我們看到,用戶在 Android 應用中又重新開始使用鍵盤導航。在 Android O 中,我們又再次使用鍵盤作為導航輸入設備,從而為基于箭頭鍵和 Tab 鍵的導航構建了一種更可靠并且可預測的模型。
尤其要指出的是,我們對元素焦點行為做出以下變更:
現在,如果您沒有為 View 對象(前景或背景圖片)定義任何焦點狀態顏色,框架會為 View 設置默認的焦點突出顯示顏色。此焦點突出顯示標志是基于操作組件主題背景的漣漪圖片。
如果您不希望 View 對象在接收焦點時使用此默認突出顯示標志,請在包含 View 的布局 XML 文件中將 android:defaultFocusHighlightEnabled 屬性設置為 false,或者將 false 傳遞至應用界面邏輯中的 setDefaultFocusHighlightEnabled()。要測試鍵盤輸入對界面元素焦點有何影響,您可以啟用 Drawing > Show layout bounds 開發者選項。在 Android O 中,此選項在當前具有焦點的元素上顯示一個“X”圖標。
另外,Android O 中的所有工具欄元素自動組成鍵盤導航鍵區,用戶可以更加輕松地導航進入和離開每個作為一個整體的工具欄。
1.7、網頁表單自動填充
現在,Android 自動填充框架提供對自動填充功能的內置支持,對于安裝到運行 Android O 的設備上的應用,與 WebView 對象相關的下列函數已經發生變化:
WebSettings
- getSaveFormData() 函數現在返回 false。之前,此函數返回 true。
調用 setSaveFormData() 不再有任何效果。
WebViewDatabase
- 調用 clearFormData() 不再有任何效果。
hasFormData() 函數現在返回 false。之前,當表單包含數據時,此函數返回 true。
1.8、無障礙功能
現在,無障礙服務可識別應用的 TextView 對象內部的所有 ClickableSpan 實例。
1.9、網絡連接和 HTTP(S) 連接
Android O 對網絡連接和 HTTP(S) 連接行為做出了以下變更:
- 無正文的 OPTIONS 請求具有 Content-Length: 0 標頭。之前,這些請求沒有 Content-Length 標頭。
- HttpURLConnection 在包含斜線的主機或頒發機構名稱后面附加一條斜線,使包含空路徑的網址規范化。例如,它將 http://example.com 轉化為 http://example.com/。
- 通過 ProxySelector.setDefault() 設置的自定義代理選擇器僅針對所請求的網址(架構、主機和端口)。因此,僅可根據這些值選擇代理。傳遞至自定義代理選擇器的網址不包含所請求的網址的路徑、查詢參數或片段。
- URI 不能包含空白標簽。
之前,平臺支持一種權宜方法,即允許主機名稱中包含空白標簽,但這是對 URI 的非法使用。此權宜方法只是為了確保與舊版 libcore 兼容。開發者如果對 API 使用不當,將會看到一條 ADB 消息:“URI example..com 的主機名包含空白標簽。此格式不正確,將不被未來的 Android 版本所接受。”Android O 廢除了此權宜方法;系統對格式錯誤的 URI 會返回 null。
Android O 在實現 HttpsURLConnection 時不會執行不安全的 TLS/SSL 協議版本回退。 - 對隧道 HTTP(S) 連接處理進行了如下變更:
- 在通過連接建立隧道 HTTP(S) 連接時,系統會在 Host 行中正確放置端口號 (:443) 并將此信息發送至中間服務器。之前,端口號僅出現在 CONNECT 行中。
- 系統不再將隧道連接請求中的 user-agent 和 proxy-authorization 標頭發送至代理服務器。
在建立隧道時,系統不再將隧道 Http(s)URLConnection 中的 proxy-authorization 標頭發送至代理。相反,由系統生成 proxy-authorization 標頭,在代理響應初始請求發送 HTTP 407 后將其發送至此代理。
同樣地,系統不再將 user-agent 標頭由隧道連接請求復制到建立隧道的代理請求。相反,庫為此請求生成 user-agent 標頭。
- 如果之前執行的 connect() 函數失敗,send(java.net.DatagramPacket) 函數將會引發 SocketException。
- 如果存在內部錯誤,DatagramSocket.connect() 會引發 pendingSocketException。對于 Android O 之前的版本,即使 send() 調用成功,后續的 recv() 調用也會引發 SocketException。為確保一致性,現在這兩個調用均會引發 SocketException。
- 在回退到 TCP Echo 協議之前,InetAddress.isReachable() 會嘗試執行 ICMP。
- 對于某些屏蔽端口 7 (TCP Echo) 的主機(例如 google.com),如果它們接受 ICMP Echo 協議,現在也許能夠訪問它們。
- 對于確實無法訪問的主機,此項變更意味著調用需要兩倍的時間才能返回結果。
1.10、藍牙
Android O 對 ScanRecord.getBytes() 函數檢索的數據長度做出以下變更:
- getBytes() 函數對于所接收的字節數不作任何假定。因此,應用不應受所返回的任何最小或最大字節數的影響。相反,應用應當計算所返回數組的長度。
- 兼容藍牙 5 的設備返回的數據長度可能會超出之前最大約 60 個字節的限制。
- 如果遠程設備未提供掃描響應,則也可能返回少于 60 個字節的數據。
1.11、無縫連接
Android O 對 WLAN 設置進行了多項改進,這樣可以更輕松地選擇能夠提供最佳用戶體驗的 WLAN 網絡。具體變更包括:
- 穩定性和可靠性改進。
- 更加直觀的界面。
- 一個合并的 WLAN 首選項菜單。
- 當附近存在優質的已保存網絡時在兼容設備上自動激活 WLAN。
1.12、安全性
Android O 包含以下與安全性有關的變更:
- 此平臺不再支持 SSLv3。
- 在與未正確實現 TLS 協議版本協商的服務器建立 HTTPS 連接時,HttpsURLConnection 不再嘗試回退到之前的 TLS 協議版本并重試的權宜方法。
- Android O 將使用安全計算 (SECCOMP) 過濾器來過濾所有應用。允許的系統調用列表僅限于通過 bionic 公開的系統調用。此外,還提供了其他幾個后向兼容的系統調用,但我們不建議使用這些系統調用。
- 現在,您的應用的 WebView 對象將在多進程模式下運行。網頁內容在獨立的進程中處理,此進程與包含應用的進程相隔離,以提高安全性。
- 您無法再假定 APK 駐留在名稱以 -1 或 -2 結尾的目錄中。應用應使用 sourceDir 獲取此目錄,而不能直接使用目錄格式。
1.13、隱私性
Android O 對平臺做出了以下與隱私性有關的變更。
- 現在,平臺改變了標識符的處理方式。
- 對于在 OTA 之前安裝到某個版本 Android O(API 級別 26)的應用,除非在 OTA 后卸載并重新安裝,否則 ANDROID_ID 的值將保持不變。要在 OTA 后在卸載期間保留值,開發者可以使用密鑰/值備份關聯舊值和新值。
- 對于安裝在運行 Android O 的設備上的應用,ANDROID_ID 的值現在將根據應用簽署密鑰和用戶確定作用域。應用簽署密鑰、用戶和設備的每個組合都具有唯一的 ANDROID_ID 值。因此,在相同設備上運行但具有不同簽署密鑰的應用將不會再看到相同的 Android ID(即使對于同一用戶來說,也是如此)。
- 只要簽署密鑰相同(并且應用未在 OTA 之前安裝到某個版本的 O),ANDROID_ID 的值在軟件包卸載或重新安裝時就不會發生變化。
- 即使系統更新導致軟件包簽署密鑰發生變化,ANDROID_ID 的值也不會變化。
- 要借助一個簡單的標準系統實現應用獲利,請使用廣告 ID。廣告 ID 是 Google Play 服務針對廣告服務提供的唯一 ID,此 ID 可由用戶重置。
- 查詢 net.hostname 系統屬性返回的結果為空。
1.14、記錄未捕獲的異常
如果某個應用安裝的 Thread.UncaughtExceptionHandler 未移交給默認的 Thread.UncaughtExceptionHandler,則當出現未捕獲的異常時,系統不會終止應用。從 Android O 開始,在此情況下系統將記錄異常堆棧跟蹤情況;在之前的平臺版本中,系統不會記錄異常堆棧跟蹤情況。
我們建議,自定義 Thread.UncaughtExceptionHandler 實現始終移交給默認處理程序處理;遵循此建議的應用不受 Android O 此項變更的影響。
1.15、聯系人提供程序使用情況統計方法的變更
在之前版本的Android中,聯系人提供程序組件允許開發者獲取每個聯系人的使用情況數據。此使用情況數據揭示了與某個聯系人相關聯的每個電子郵件地址和每個電話號碼的信息,包括與該聯系人聯系的次數以及上次聯系該聯系人的時間。請求 READ_CONTACTS 權限的應用可以讀取此數據。
如果應用請求 READ_CONTACTS 權限,它們仍可以讀取此數據。從 Android O 開始,使用情況數據查詢會返回近似值,而不是精確值。不過,Android 系統內部仍然會保留精確值,因此,此變更不會影響 auto-complete API。
此行為變更會影響以下查詢參數:
- TIMES_CONTACTED
- TIMES_USED
- LAST_TIME_CONTACTED
- LAST_TIME_USED
1.16、集合的處理
現在,AbstractCollection.removeAll() 和 AbstractCollection.retainAll() 始終引發 NullPointerException;之前,當集合為空時不會引發 NullPointerException。此項變更使行為符合文檔要求。
1.17、Android 企業版
Android O 更改了企業應用(包括設備規范控制器 (DPC))的某些 API 和功能的行為。這些變更包括:
- 新增多種行為,幫助應用支持完全托管設備中的工作資料。
- 變更系統更新處理、應用驗證和身份驗證方式,以提高設備和系統的完整性。
- 改進用戶在配置、通知、“最近使用的應用”屏幕和 Always on VPN 方面的體驗。