Android Oreo
Android 8.0 功能和 API
(1)、用戶體驗
通知:
在Android 8.0中,我們已重新設計通知,以便為管理通知行為和設置提供更輕松和更統一的方式。這些變更包括:
1、通知渠道:Android 8.0引入了通知渠道,其允許您為要顯示的每種通知類型創建用戶可自定義的渠道。用戶界面將通知渠道稱之為通知類別。
2、通知標志:Android 8.0引入了對在應用啟動器圖標上顯示通知標志的支持。通知標志可反映某個應用是否存在與其關聯、並且用戶尚未予以清除也未對其采取行動的通知。通知標志也稱為通知點。
3、休眠:用戶可以通知置於休眠狀態,以便稍后重新顯示它。重新顯示時通知的重要程度與首次顯示時相同,用用可以移除或更新已休眠的通知,但更新休眠的通知並不會使其重新顯示。
4、通知超時,現在,使用setTimeoutAfter()創建通知時您可以設置超時。您可以使用此函數指定一個持續時間,超過該持續時間后,通知應取消。如果需要,您可以再指定的超時持續時間之前取消通知。
5、通知設置:當您使用Notification.INTENT_CATEFORY_NOTIFICATION_PREFERENCES Intent從通知創建指向應用通知設置的鏈接時,您可以調用setSettingsText()來設置要顯示的文本。此系統可以提供以下Extra數據和Intent,用於過濾應用必須向用戶顯示的設置:EXTRA_CHANNEL_ID、NOTIFICATION_TAG和NOTIFICATION_ID.
6、通知清除:系統現在可區分通知是由用戶清楚,還是由應用移除。要查看清除通知的方式,您應實現NotificationListenerService類的新的onNotificationRemoved()函數。
7、背景顏色:您現在可以設置和啟用通知的背景顏色。只能在用戶必須一眼就能看到的持續任務的通知中使用此功能。例如,您可以為與駕車路線或正在進行的通話有關的通知設置背景顏色。您還可以使用Notification.Builder.setColor()設置所需的背景顏色。這樣做將允許您使用Notification.Builder.setColorized()啟用通知的背景顏色設置。
8、消息樣式:現在,使用MessagingStyle類的通知可在其折疊形式中顯示更多內容,對於與消息有關的通知,您應使用MessagingStyle類。您還可以使用新的addHistoricMessage()函數,通過向與消息相關的通知添加歷史消息為會話提供上下文。
自動填充框架:
帳號創建、登錄和信用卡交易需要時間並且容易出錯。在使用要求執行此類重復性任務的應用時,用戶很容易遭受挫折。
Android 8.0 通過引入自動填充框架,簡化了登錄和信用卡表單之類表單的填寫工作。在用戶選擇接受自動填充之后,新老應用都可使用自動填充框架。
您可以采取某些措施,優化您的應用使用此框架的方式。
畫中畫模式:
Android 8.0 允許以畫中畫 (PIP) 模式啟動操作組件。PIP 是一種特殊的多窗口模式,最常用於視頻播放。目前,PIP 模式可用於 Android TV,而 Android 8.0 則讓該功能可進一步用於其他 Android 設備。
當某個 Activity 處於 PIP 模式時,它會處於暫停狀態,但仍應繼續顯示內容。因此,您應確保您的應用在 onPause() 處理程序中進行處理時不會暫停播放。相反,您應在 onStop() 中暫停播放視頻,並在 onStart()中繼續播放。如需了解詳細信息,請參閱多窗口生命周期。
要指定您的 Activity 可以使用 PIP 模式,請在清單中將android:supportsPictureInPicture設置為true。(從Android 8.0開始,如果您打算在Android TV或其他Android設備上支持PIP模式,則無需將 android:resizeableActivity 設置為true;只有在您的Activity支持其他多窗口模式時,才需要設置android:resizeableActivity。)
API變更:Android8.0引入一種新的對象PictureInPictureParams,您可以將該對象傳遞給 PIP 函數來指定某個 Activity 在其處於 PIP 模式時的行為。此對象還指定了各種屬性,例如操作組件的首選縱橫比。
現在,在添加畫中畫中介紹的現有 PIP 函數可用於所有 Android 設備,而不僅限於 Android TV。此外,Android 8.0 還提供以下函數來支持 PIP 模式:
Activity.enterPictureInPictureMode(PictureInPictureParams args):將操作組件置於畫中畫模式。操作組件的縱橫比和其他配置設置均由 args指定。如果 args 中的任何字段為空,系統將使用您上次調用 Activity.setPictureInPictureParams() 時所設置的值。
● 指定的操作組件被置於屏幕的一角,屏幕剩余部分則被屏幕顯示的上一個操作組件填滿。進入 PIP 模式的 Activity 將進入暫停狀態,但仍保持已啟動狀態。如果用戶點按此 PIP 操作組件,系統將顯示一個菜單供用戶操作,而在操作組件處於 PIP 狀態期間,不會理會任何觸摸事件。
● Activity.setPictureInPictureParams():更新操作組件的 PIP 配置設置。如果操作組件目前處於 PIP 模式,則會更新此設置;如果操作組件的縱橫比發生變化,這非常有用。如果操作組件不處於 PIP 模式,則會使用這些配置設置,而不會考慮您調用的 enterPictureInPictureMode() 函數。
可下載字體:
Android 8.0 和 Android 支持庫 26 允許您從提供程序應用請求字體,而無需將字體綁定到 APK 中或讓 APK 下載字體。此功能可減小 APK 大小,提高應用安裝成功率,使多個應用可以共享同一種字體。
XML 中的字體:
Android 8.0 推出一項新功能,即 XML 中的字體,允許您使用字體作為資源。這意味着,不再需要以資產的形式捆綁字體。字體在 R 文件中編譯,並且作為一種資源,可自動用於系統。然后,您可以利用一種新的資源類型 font 來訪問這些字體。
在運行 API 版本 14 及更高版本的設備中,支持庫 26 對此功能提供完全支持。
自動調整 TextView 的大小:
Android 8.0 允許您根據 TextView 的大小自動設置文本展開或收縮的大小。這意味着,在不同屏幕上優化文本大小或者優化包含動態內容的文本大小比以往簡單多了
自適應圖標:
Android 8.0 引入自適應啟動器圖標。自適應圖標支持視覺效果,可在不同設備型號上顯示為各種不同的形狀。
顏色管理:
圖像應用的 Android 開發者現在可以利用支持廣色域彩色顯示的新設備。要顯示廣色域圖像,應用需要在其清單(每個操作組件)中啟用一個標志,並加載具有嵌入的廣域彩色配置文件(AdobeRGB、Pro Photo RGB、DCI-P3 等)的位圖。
WebView API:
Android 8.0 提供多種 API,幫助您管理在應用中顯示網頁內容的 WebView 對象。這些 API 可增強應用的穩定性和安全性,它們包括:
● Version API
● Google SafeBrowsing API
● Termination Handle API
● Renderer Importance API
固定快捷方式和小部件:
Android 8.0 引入了快捷方式和微件的應用內固定功能。在您的應用中,您可以根據用戶權限為支持的啟動器創建固定的快捷方式和小部件。
最大屏幕縱橫比:
以 Android 7.1(API 級別 25)或更低版本為目標平台的應用默認的最大屏幕縱橫比為 1.86。針對 Android 8.0 或更高版本的應用沒有默認的最大縱橫比。如果您的應用需要設置最大縱橫比,請使用定義您的操作組件的清單文件中的 maxAspectRatio 屬性。
多顯示器支持:
從 Android 8.0 開始,此平台為多顯示器提供增強的支持。如果 Activity 支持多窗口模式,並且在具有多顯示器的設備上運行,則用戶可以將 Activity 從一個顯示器移動到另一個顯示器。當應用啟動 Activity 時,此應用可指定 Activity 應在哪個顯示器上運行。
注:如果 Activity 支持多窗口模式,則 Android 8.0 將為該 Activity 自動啟用多顯示器支持。您應測試您的應用,確保它在多顯示器環境下可正常運行。
每次只有一個 Activity 可以處於繼續狀態,即使此應用具有多個顯示器。具有焦點的 Activity 將處於繼續狀態,所有其他可見的 Activity 均暫停,但不會停止。
當用戶將 Activity 從一個顯示器移動到另一個顯示器時,系統將調整 Activity 大小,並根據需要發起運行時變更。您的 Activity 可以自行處理配置變更,或允許系統銷毀包含該 Activity 的進程,並以新的尺寸重新創建它。
ActivityOptions 提供兩個新函數以支持多個顯示器:
指定 Activity 在啟動后應顯示在哪個顯示器上。
返回操作組件的當前啟動顯示器。
對 adb shell 進行了擴展,以支持多個顯示器。shell start 命令現在可用於啟動操作組件,並指定操作組件的目標顯示器:
adb shell start <activity_name> --display <display_id>
統一的布局外邊距和內邊距:
Android 8.0 讓您可以更輕松地指定 View 元素的對邊使用相同外邊距和內邊距的情形。具體來說,您現在可以在布局 XML 文件中使用以下屬性:
● layout_marginVertical,同時定義 layout_marginTop 和 layout_marginBottom。
● layout_marginHorizontal,同時定義 layout_marginLeft 和 layout_marginRight。
● paddingVertical,同時定義 paddingTop 和 paddingBottom。
● paddingHorizontal,同時定義 paddingLeft 和 paddingRight。
注:如果您自定義應用邏輯以支持不同語言和文化(包括文本方向),請記住,這些屬性不會影響 layout_marginStart、layout_marginEnd、paddingStart 或 paddingEnd 的值。您可以自行設置這些值和新的垂直與水平布局屬性來創建取決於文本方向的布局行為。
指針捕獲:
某些應用(例如游戲、遠程桌面和虛擬化客戶端)將大大受益於鼠標指針控制。指針捕獲是 Android 8.0 中的一項新功能,可以通過將所有鼠標事件傳遞到您的應用中焦點視圖的方式提供此類控制。
從 Android 8.0 開始,您的應用中的 View 可以請求指針捕獲並定義一個偵聽器來處理捕獲的指針事件。鼠標指針在此模式下將隱藏。如果不再需要鼠標信息,該視圖可以釋放指針捕獲。系統也可以在視圖丟失焦點時(例如,當用戶打開另一個應用時)釋放指針捕獲。
應用類別:
在適當的情況下,Android 8.0 允許每個應用聲明其所屬的類別。這些類別用於將應用呈現給用戶的用途或功能類似的應用歸類在一起,例如按流量消耗、電池消耗和存儲消耗將應用歸類。您可以在 <application> 清單標記中設置 android:appCategory 屬性,定義應用的類別。
Android TV 啟動器:
Android 8.0 添加了一種以內容為中心的全新 Android TV 主屏幕體驗,支持 Android TV 模擬器和 Nexus Player Android 8.0 設備映像。新的主屏幕在對應於頻道的行中組織視頻內容,這些頻道在系統上通過應用填充各個節目。應用可以發布多個頻道,用戶可以配置他們希望在主屏幕上看到哪些頻道。Android TV 也包含一個 Watch Next 行,此行根據用戶的觀看習慣從應用填充節目。應用也可以提供視頻預覽,這些預覽會在用戶聚焦到節目時自動播放。用於填充頻道和節目的 API 屬於 TvProvider API,這些 API 以 Android 支持庫模塊的形式隨 Android 8.0 分發。
AnimatorSet:
從 Android 8.0 開始,AnimatorSet API 現在支持尋道和倒播功能。尋道功能允許您將動畫的位置設置為指定的時間點處。如果您的應用包含可撤消的操作的動畫,倒播功能會很有用。現在,您不必定義兩組獨立的動畫,而只需反向播放同一組動畫。
(2)、系統
新的 StrictMode 檢測程序:
Android 8.0 添加了三個新的 StrictMode 檢測程序,幫助識別應用可能出現的錯誤:
● detectUnbufferedIo() 將檢測您的應用何時讀取或寫入未緩沖的數據,這可能極大影響性能。
● detectContentUriWithoutPermission() 將檢測您的應用在其外部啟動 Activity 時何時意外忘記向其他應用授予權限。
●detectUntaggedSockets() 將檢測您的應用何時使用網絡流量,而不使用 setThreadStatsTag(int) 將流量標記用於調試目的。
緩存數據:
Android 8.0 優化了緩存數據的導航和行為。現在,每個應用均獲得一定的磁盤空間配額,用於存儲 getCacheQuotaBytes(UUID) 返回的緩存數據。
當系統需要釋放磁盤空間時,將開始從超過配額最多的應用中刪除緩存文件。因此,如果將您的緩存數據量始終保持低於配額的水平,則在必須清除系統中的某些文件時,您的緩存文件將能堅持到最后。系統在決定刪除您的應用中的哪些緩存文件時,將首先考慮刪除最舊的文件(由修改時間確定)。
您還可以針對每個目錄啟用兩種新行為,以控制系統如何釋放緩存數據:
StorageManager.setCacheBehaviorAtomic() 可用於指示某個目錄及其所有內容應作為一個不可分割的整體進行刪除。
setCacheBehaviorTombstone(File, boolean) 可用於指示不應刪除某個目錄內的文件,而應將它們截斷到 0 字節長度,使空文件保持完好。
最后,在需要為大文件分配磁盤空間時,可考慮使用新的 allocateBytes(FileDescriptor, long) API,它將自動清除屬於其他應用的緩存文件(根據需要),以滿足您的請求。在確定設備是否有足夠的磁盤空間保存您的新數據時,請調用 getAllocatableBytes(UUID) 而不要使用 getUsableSpace(),因為前者會考慮系統要為您清除的任何緩存數據。
內容提供程序分頁:
我們已更新內容提供程序以支持加載大型數據集,每次加載一頁。例如,一個具有大量圖像的照片應用可查詢要在頁面中顯示的數據的子集。內容提供程序返回的每個結果頁面由一個Cursor對象表示。客戶端和提供程序必須實現分頁才能利用此功能。
內容刷新請求:
現在,ContentProvider 和 ContentResolver 類均包含 refresh() 函數,這樣,客戶端可以更輕松地知道所請求的信息是否為最新信息。
您可以擴展 ContentProvider 以添加自定義的內容刷新邏輯。請務必重寫 refresh() 函數,以返回 true,告知提供程序的客戶端您已嘗試自行刷新數據。
您的客戶端應用可通過調用另一個函數(又稱 refresh()),顯式請求已刷新的內容。在調用此函數時,傳入待刷新數據的 URI。
注:由於您可能通過網絡不斷請求數據,您應僅在有明顯跡象表明內容確已過時時才從客戶端調用 refresh()。執行此類內容刷新最常見的原因是響應滑動刷新手勢,該手勢顯式請求當前界面顯示最新內容。
JobScheduler 改進:
Android 8.0 引入了對 JobScheduler 的多項改進。由於您通常可以使用計划作業替代現在受限的后台服務或隱式廣播接收器,這些改進可以讓您的應用更輕松地符合新的后台執行限制。
JobScheduler 的更新包括:
● 您現在可以將工作隊列與計划作業關聯。要將一個工作項添加到作業的隊列中,請調用 JobScheduler.enqueue()。當作業運行時,它可以將待定工作從隊列中剝離並進行處理。這種功能可以處理之前需要啟動后台服務(尤其是實現 IntentService 的服務)的許多用例。
● 您現在可以通過調用 JobInfo.Builder.setClipData() 的方式將 ClipData 與作業關聯。利用此選項,您可以將 URI 權限授予與作業關聯,類似於這些權限傳遞到 Context.startService() 的方式。您也可以將 URI 權限授予用於工作隊列上的 intent。
● 計划作業現在支持多個新的約束條件:
JobInfo.isRequireStorageNotLow()
如果設備的可用存儲空間非常低,作業將不會運行。
JobInfo.isRequireBatteryNotLow()
如果電池電量等於或低於臨界閾值,作業將不會運行;臨界閾值是指設備顯示 Low battery warning 系統對話框的電量。
作業需要一個按流量計費的網絡連接,比如大多數移動數據網絡數據套餐。
自定義數據存儲:
Android 8.0 允許您為首選項提供自定義數據存儲,如果您的應用將首選項存儲在雲或本地數據庫中,或者如果首選項特定於某個設備,此功能會非常有用。
findViewById() 簽名變更:
現在,findViewById() 函數的全部實例均返回 <T extends View> T,而不是 View。此變更會帶來以下影響:
●例如,如果 someMethod(View) 和 someMethod(TextView) 均接受調用findViewById() 的結果,這可能導致現有代碼的返回類型不確定。
●在使用Java 8源語言時,這需要在返回類型不受限制時(例如,assertNotNull(findViewById(...)).someViewMethod()))顯式轉換為View。
● 重寫非最終的 findViewById() 函數(例如,Activity.findViewById())將需要更新其返回類型。
(3)、媒體增強功能
VolumeShaper:
有一個新的 VolumeShaper 類。您可以用它來執行簡短的自動音量轉換,例如淡入、淡出和交叉淡入淡出。
音頻焦點增強功能:
音頻應用通過請求和舍棄音頻焦點的方式在設備上共享音頻輸出。應用通過啟動或停止播放或者閃避音量的方式處理處於聚焦狀態的變更。有一個新的 AudioFocusRequest 類。對於此類,應用在處理音頻焦點變化時會使用新功能:自動閃避和延遲聚焦。
媒體指標:
新的 getMetrics() 函數將返回一個包含配置和性能信息的 PersistableBundle 對象,用一個包含屬性和值的地圖表示。為以下媒體類定義 getMetrics() 函數:
為每個實例單獨收集指標,並持續到實例的生命周期結束為止。如果沒有可用的指標,則此函數將返回 null。返回的實際指標取決於類。
MediaPlayer:
Android 8.0 為 MediaPlayer 類添加了多種新函數。這些函數可以從多個方面增強您的應用處理媒體播放的能力:
● 在搜索幀時進行精細控制。
● 播放受數字版權管理保護的材料的功能。
MediaPlayer 現在支持采樣級加密。
音頻錄制器:
● 音頻錄制器現在支持對流式傳輸有用的 MPEG2_TS 格式:
mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_2_TS);
● MediaMuxer 現在可以處理任意數量的音頻和視頻流,而不再僅限於一個音頻曲目和/或一個視頻曲目。使用 addTrack() 可混錄所需的任意數量的曲目。
● MediaMuxer 還可以添加一個或多個包含用戶定義的每幀信息的元數據曲目。元數據的格式由您的應用定義。僅對 MP4 容器支持元數據曲目。
元數據可以用於離線處理。例如,傳感器的陀螺儀信號可以用於執行視頻穩定操作。
在添加元數據曲目時,曲目的 MIME 格式必須以前綴“application/”開頭。除了數據不是來源於 MediaCodec 以外,寫入元數據的操作與寫入視頻/音頻數據相同。相反,應用將包含相關時間戳的 ByteBuffer 傳遞給 writeSampleData() 函數。時間戳必須和視頻及音頻曲目處於相同的時基。
生成的 MP4 文件使用 ISOBMFF 的 12.3.3.2 部分定義的 TextMetaDataSampleEntry,指示元數據的 MIME 格式。在使用 MediaExtractor 提取包含元數據曲目的文件時,元數據的 MIME 格式將提取到 MediaFormat 中。
音頻播放控制:
Android 8.0 允許您查詢和請求設備產生聲音的方式。對音頻播放的以下控制將讓您的服務更輕松地僅在有利的設備條件下產生聲音。
Google 智能助理的新音頻使用類型
AudioAttributes 類包含一種新的聲音類型,即 USAGE_ASSISTANT,對應於 Google 智能助理在設備上的回答。
設備音頻播放的變更
如果您希望自己的服務僅在特定的設備音頻配置處於活動狀態時開始產生聲音,您可以使用 AudioManager 類注冊一個 AudioManager.AudioPlaybackCallback 實例,后者的onPlaybackConfigChanged() 函數可以幫助您確定當前活動的音頻屬性集。
顯式請求音頻焦點
您的服務可以使用 requestAudioFocus() 函數提交一個更精細的設備級音頻焦點接收請求。傳入一個 AudioFocusRequest 對象,您可以使用 AudioFocusRequest.Builder 創建這個對象。在這個構建類中,您可以指定以下選項:
●您希望獲得的焦點類型,例如 AUDIOFOCUS_GAIN_TRANSIENT或 AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK。
● 當另一個音頻服務獲得設備焦點時,您的服務應以更安靜的方式繼續,還是完全暫停。
● 您的服務能否等待獲得焦點,直至設備就緒。
注:構建您的 AudioFocusRequest 實例時,如果您通過調用 setAcceptsDelayedFocusGain() 指示您的服務可以等待產生聲音,您也必須調用 setOnAudioFocusChangeListener(),以便您的服務了解它何時可以開始產生聲音。
(4)、安全性與隱私
權限:
Android 8.0 引入了多個與電話有關的新權限:
● ANSWER_PHONE_CALLS 允許您的應用通過編程方式接聽呼入電話。要在您的應用中處理呼入電話,您可以使用 acceptRingingCall() 函數。
● READ_PHONE_NUMBERS 權限允許您的應用讀取設備中存儲的電話號碼。
(5)、運行時和工具
平台優化:
Android 8.0 為平台引入了運行時優化和其他優化,這些優化將帶來多項性能改進。這些優化包括並發壓縮垃圾回收、更有效的內存利用和代碼區域。
它們可以加快啟動時間,並為 OS 和應用帶來更好的性能。
更新的 Java 支持:
Android 8.0 添加了對更多 OpenJDK Java API 的支持:
● OpenJDK 8 中的 java.time。
● OpenJDK 7 中的 java.nio.file 和 java.lang.invoke。
.....
Android 8.0 行為變更
(1)、針對所有 API 級別的應用
后台執行限制:
Android 8.0 為提高電池續航時間而引入的變更之一是,當您的應用進入已緩存狀態時,如果沒有活動的組件,系統將解除應用具有的所有喚醒鎖。
此外,為提高設備性能,系統會限制未在前台運行的應用的某些行為。具體而言:
● 現在,在后台運行的應用對后台服務的訪問受到限制。
● 應用無法使用其清單注冊大部分隱式廣播(即,並非專門針對此應用的廣播)。
默認情況下,這些限制僅適用於針對 O 的應用。不過,用戶可以從 Settings 屏幕為任意應用啟用這些限制,即使應用並不是以 O 為目標平台。
Android 8.0 還對特定函數做出了以下變更:
● 如果針對 Android 8.0 的應用嘗試在不允許其創建后台服務的情況下使用 startService() 函數,則該函數將引發一個 IllegalStateException。
● 新的 Context.startForegroundService() 函數將啟動一個前台服務。現在,即使應用在后台運行,系統也允許其調用 Context.startForegroundService()。不過,應用必須在創建服務后的五秒內調用該服務的 startForeground() 函數。
Android 后台位置限制:
為節約電池電量、保持良好的用戶體驗和確保系統健康運行,在運行 Android 8.0 的設備上使用后台應用時,降低了后台應用接收位置更新的頻率。此行為變更會影響包括 Google Play 服務在內的所有接收位置更新的應用。
此類變更會影響以下 API:
● Fused Location Provider (FLP)
● Geofencing
● GNSS Measurements
● Location Manager
● Wi-Fi Manager
為確保您的應用按預期方式運行,請完成以下步驟:
● 查看您的應用的邏輯,並確保您使用的是最新的位置 API。
● 測試您的應用是否在每個用例中都表現出預期行為。
● 考慮使用 Fused Location Provider (FLP) 或地理圍欄來處理依賴於用戶當前位置的用例。
應用快捷鍵:
Android 8.0 對應用快捷方式做出了以下變更:
● com.android.launcher.action.INSTALL_SHORTCUT 廣播不再會對您的應用有任何影響,因為它現在是私有的隱式廣播。相反,您應使用 ShortcutManager 類中的 requestPinShortcut() 函數創建應用快捷方式。
● 現在,ACTION_CREATE_SHORTCUT Intent 可以創建可使用 ShortcutManager 類進行管理的應用快捷方式。此 Intent 還可以創建不與 ShortcutManager 交互的舊版啟動器快捷方式。在以前,此 Intent 只能創建舊版啟動器快捷方式。
● 現在,使用requestPinShortcut()創建的快捷方式和在處理ACTION_CREATE_SHORTCUT Intent的操作組件中創建的快捷方式均已轉換為功能齊全的應用快捷方式。因此,應用現在可以使用ShortcutManager中的函數來更新這些快捷方式。
舊版快捷方式仍然保留了它們在舊版 Android 中的功能,但您必須在應用中手動將它們轉換成應用快捷方式。
提醒窗口:
如果應用使用 SYSTEM_ALERT_WINDOW 權限並且嘗試使用以下窗口類型之一來在其他應用和系統窗口上方顯示提醒窗口:
...那么,這些窗口將始終顯示在使用 TYPE_APPLICATION_OVERLAY 窗口類型的窗口下方。如果應用針對的是 Android 8.0,則應用會使用 TYPE_APPLICATION_OVERLAY 窗口類型來顯示提醒窗口
網頁表單自動填充:
現在,Android 自動填充框架提供對自動填充功能的內置支持,對於安裝到運行 Android 8.0 的設備上的應用,與 WebView 對象相關的下列函數已經發生變化:
● getSaveFormData() 函數現在返回 false。之前,此函數返回 true。
● 調用 setSaveFormData() 不再有任何效果。
● 調用 clearFormData() 不再有任何效果。
● hasFormData() 函數現在返回 false。之前,當表單包含數據時,此函數返回 true。
網絡連接和 HTTP(S) 連接:
Android 8.0 對網絡連接和 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 8.0 廢除了此權宜方法;系統對格式錯誤的 URI 會返回 null。
● Android 8.0 在實現 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 8.0 之前的版本,即使 send() 調用成功,后續的 recv() 調用也會引發 SocketException。為確保一致性,現在這兩個調用均會引發 SocketException。
● 在回退到 TCP Echo 協議之前,InetAddress.isReachable() 會嘗試執行 ICMP。
○ 對於某些屏蔽端口 7 (TCP Echo) 的主機(例如 google.com),如果它們接受 ICMP Echo 協議,現在也許能夠訪問它們。
○ 對於確實無法訪問的主機,此項變更意味着調用需要兩倍的時間才能返回結果。
安全性:
Android 8.0 包含以下與安全性有關的變更:
● 此平台不再支持 SSLv3。
● 在與未正確實現 TLS 協議版本協商的服務器建立 HTTPS 連接時,HttpsURLConnection 不再嘗試回退到之前的 TLS 協議版本並重試的權宜方法。
● Android 8.0 將使用安全計算 (SECCOMP) 過濾器來過濾所有應用。允許的系統調用列表僅限於通過 bionic 公開的系統調用。此外,還提供了其他幾個后向兼容的系統調用,但我們不建議使用這些系統調用。
● 現在,您的應用的 WebView 對象將在多進程模式下運行。網頁內容在獨立的進程中處理,此進程與包含應用的進程相隔離,以提高安全性。
● 您無法再假定 APK 駐留在名稱以-1或-2結尾的目錄中。應用應使用sourceDir獲取此目錄,而不能直接使用目錄格式。
● ......
隱私性:
Android 8.0 對平台做出了以下與隱私性有關的變更。
● 現在,平台改變了標識符的處理方式。
○ 對於在 OTA 之前安裝到某個版本 Android 8.0(API 級別 26)的應用,除非在 OTA 后卸載並重新安裝,否則 ANDROID_ID 的值將保持不變。要在 OTA 后在卸載期間保留值,開發者可以使用密鑰/值備份關聯舊值和新值。
○ 對於安裝在運行 Android 8.0 的設備上的應用,ANDROID_ID 的值現在將根據應用簽署密鑰和用戶確定作用域。應用簽署密鑰、用戶和設備的每個組合都具有唯一的 ANDROID_ID 值。因此,在相同設備上運行但具有不同簽署密鑰的應用將不會再看到相同的 Android ID(即使對於同一用戶來說,也是如此)。
○ 只要簽署密鑰相同(並且應用未在 OTA 之前安裝到某個版本的 O),ANDROID_ID 的值在軟件包卸載或重新安裝時就不會發生變化。
○ 即使系統更新導致軟件包簽署密鑰發生變化,ANDROID_ID 的值也不會變化。
要借助一個簡單的標准系統實現應用獲利,請使用廣告 ID。廣告 ID 是 Google Play 服務針對廣告服務提供的唯一 ID,此 ID 可由用戶重置。
● 查詢 net.hostname 系統屬性返回的結果為空。
記錄未捕獲的異常:
如果某個應用安裝的Thread.UncaughtExceptionHandler未移交給默認的Thread.Uncaught ExceptionHandler,則當出現未捕獲的異常時,系統不會終止應用。從Android 8.0開始,在此情況下系統將記錄異常堆棧跟蹤情況;在之前的平台版本中,系統不會記錄異常堆棧跟蹤情況。
我們建議,自定義 Thread.UncaughtExceptionHandler 實現始終移交給默認處理程序處理;遵循此建議的應用不受 Android 8.0 此項變更的影響。
集合的處理:
現在,AbstractCollection.removeAll()和AbstractCollection.retainAll()始終引發NullPointerException;之前,當集合為空時不會引發NullPointerException。此項變更使行為符合文檔要求。
Android 企業版:
Android 8.0 更改了企業應用(包括設備規范控制器 (DPC))的某些 API 和功能的行為。這些變更包括:
● 新增多種行為,幫助應用支持完全托管設備中的工作資料。
● 變更系統更新處理、應用驗證和身份驗證方式,以提高設備和系統的完整性。
● 改進用戶在配置、通知、“最近使用的應用”屏幕和 Always on VPN 方面的體驗。
● ......
(2)、針對Android 8.0 的應用
提醒窗口:
使用 SYSTEM_ALERT_WINDOW 權限的應用無法再使用以下窗口類型來在其他應用和系統窗口上方顯示提醒窗口:
相反,應用必須使用名為 TYPE_APPLICATION_OVERLAY 的新窗口類型。
使用 TYPE_APPLICATION_OVERLAY 窗口類型顯示應用的提醒窗口時,請記住新窗口類型的以下特性:
● 應用的提醒窗口始終顯示在狀態欄和輸入法等關鍵系統窗口的下面。
● 系統可以移動使用 TYPE_APPLICATION_OVERLAY 窗口類型的窗口或調整其大小,以改善屏幕顯示效果。
● 通過打開通知欄,用戶可以訪問設置來阻止應用顯示使用 TYPE_APPLICATION_OVERLAY 窗口類型顯示的提醒窗口。
內容變更通知:
Android 8.0 更改了 ContentResolver.notifyChange() 和 registerContentObserver(Uri, boolean, ContentObserver) 在針對 Android 8.0 的應用中的行為方式。
現在,這些 API 需要在所有 URI 中為頒發機構定義一個有效的 ContentProvider。使用相關權限定義一個有效的 ContentProvider 可幫助您的應用防范來自惡意應用的內容變更,並防止將可能的私密數據泄露給惡意應用。
安全性:
如果您的應用的網絡安全性配置選擇退出對明文流量的支持,那么您的應用的 WebView 對象無法通過 HTTP 訪問網站。每個 WebView 對象必須轉而使用 HTTPS。
權限:
在 Android 8.0 之前,如果應用在運行時請求權限並且被授予該權限,系統會錯誤地將屬於同一權限組並且在清單中注冊的其他權限也一起授予應用。
對於針對 Android 8.0 的應用,此行為已被糾正。系統只會授予應用明確請求的權限。然而,一旦用戶為應用授予某個權限,則所有后續對該權限組中權限的請求都將被自動批准。
例如,假設某個應用在其清單中列出READ_EXTERNAL_STORAGE和 WRITE_EXTERNAL_STORAGE。應用請求 READ_EXTERNAL_STORAGE,並且用戶授予了該權限。如果該應用針對的是 API 級別 24 或更低級別,系統還會同時授予 WRITE_EXTERNAL_STORAGE,因為該權限也屬於同一 STORAGE 權限組並且也在清單中注冊過。如果該應用針對的是 Android 8.0,則系統此時僅會授予 READ_EXTERNAL_STORAGE;不過,如果該應用后來又請求 WRITE_EXTERNAL_STORAGE,則系統會立即授予該權限,而不會提示用戶。
原生庫:
在針對 Android 8.0 的應用中,如果原生庫包含任何可寫且可執行的加載代碼段,則不會再加載原生庫。倘若某些應用的原生庫包含不正確的加載代碼段,則此變更可能會導致這些應用停止工作。這是一種安全加強措施。
與早期的開發者預覽版相同,Android 8.0 還有助於更輕松地發現所有與鏈接器有關的問題。鏈接器的變更綁定到應用的目標 API 級別。如果應用的目標 API 級別發生鏈接器變更,則該應用無法加載該庫。如果您的目標 API 級別低於發生鏈接器變更的 API 級別,則 logcat 會顯示一條警告消息。在預覽版期間,與鏈接器有關的問題不僅會顯示在 logcat 中,也會以 toast 的形式顯示。對於特定的 API 級別,警告可能會變成錯誤,此變更有助於提前發現此類問題
集合的處理:
在 Android 8.0 中,Collections.sort() 是在 List.sort() 的基礎上實現的。在 Android 7.x(API 級別 24 和 25)中,則恰恰相反。在過去,List.sort() 的默認實現會調用 Collections.sort()。
此項變更使 Collections.sort() 可以利用優化的 List.sort() 實現,但具有以下限制:
List.sort() 的實現不能調用 Collections.sort(),因為這會導致堆棧因無限遞歸而溢出。相反,如果您需要 List 實現的默認行為,應避免重寫 sort()。
如果父類以不適當的方法實現 sort() ,通常最好使用在 List.toArray()、Arrays.sort() 和 ListIterator.set() 的基礎上構建的實現重寫 List.sort()。例如:
@Override
public void sort(Comparator<? super E> c) {
Object[] elements = toArray();
Arrays.sort(elements, c);
ListIterator<E> iterator = (ListIterator<Object>) listIterator();
for (Object element : elements) {
iterator.next();
iterator.set((E) element);
}
}
在大多數情況下,您也可以使用根據 API 級別委托給其他默認實現的實現重寫 List.sort()。例如:
@Override
public void sort(Comparator<? super E> comparator) {
if (Build.VERSION.SDK_INT <= 25) {
Collections.sort(this);
} else {
super.sort(comparator);
}
}
如果您選擇后者只是因為您希望開發一種適用於所有 API 級別的 sort() 函數,可以考慮賦予其一個唯一的名稱,例如 sortCompat(),而不是重寫 sort()。
現在,Collections.sort() 只是對調用 sort() 的 List 實現進行的一項結構性修改。例如,在 Android 8.0 之前的平台版本中,如果通過調用 List.sort() 進行排序,則當迭代處理 ArrayList 以及在迭代過程中調用 sort() 時,會引發 ConcurrentModificationException。而 Collections.sort() 則不會引發異常。
此項變更使平台行為更加一致:現在,兩種方法都會引發 ConcurrentModificationException。
類加載行為:
Android 8.0 檢查確保類加載器在加載新類時不會違反運行時假設條件。不論類引用自 Java(來自 forName())、Dalvik 字節碼還是 JNI,都會執行這些檢查。平台不會攔截 Java 對 loadClass() 函數的直接調用,也不會檢查此類調用的結果。此行為不應影響運行良好的類加載器的正常運行。
平台將檢查類加載器返回的類描述符是否與預期的描述符一致。如果返回的描述符與預期不符,平台會引發 NoClassDefFoundError 錯誤,並在異常日志中存儲一條注明不一致之處的詳細錯誤消息。
平台還檢查請求的類描述符是否有效。此檢查捕獲間接加載諸如 GetFieldID() 等類的 JNI 調用,向這些類傳遞無效的描述符。例如,找不到包含 java/lang/String 簽名的字段,是因為此簽名無效;它應為 Ljava/lang/String;。
這與 JNI 對 FindClass() 的調用不同,其中 java/lang/String 是一個有效的完全限定名稱。
Android 8.0 不支持多個類加載器同時嘗試使用相同的 DexFile 對象來定義類。嘗試進行此操作,會導致 Android 運行時引發 InternalError 錯誤,同時顯示消息“Attempt to register dex file <filename> with multiple class loaders”。
DexFile API 現已棄用,強烈建議您改為使用此平台的類加載器之一,包括 PathClassLoader 或 BaseDexClassLoader。
注: 您可以創建多個引用文件系統中同一個 APK 或 JAR 文件容器的類加載器。這樣做通常不會占用大量內存:如果存儲而不壓縮容器中的 DEX 文件,平台可以對此類文件執行 mmap 操作,而不直接提取它們。但是,如果平台必須從容器中提取 DEX 文件,以這種方式引用 DEX 文件可能占用大量內存。
在 Android 中,所有類加載器都被視為支持並行運行。當多個線程爭用同一個類加載器加載相同的類時,第一個完成此操作的線程勝出,而操作結果將用於其他線程。無論類加載器是返回同一個類、返回不同的類還是引發異常,都將發生此行為。該平台靜默忽略此類異常。
注意: 在低於 Android 8.0 的平台版本中,違反這些假設條件可能導致多次定義同一個類、由於類混淆造成堆損壞和其他不良影響。