android 8.0 對應的 sdk 版本 26
1. 通知欄
Android 8.0 引入了通知渠道,其允許您為要顯示的每種通知類型創建用戶可自定義的渠道。用戶界面將通知渠道稱之為通知類別。
針對 8.0 的應用,創建通知前需要創建渠道,創建通知時需要傳入 channelId,否則通知將不會顯示。示例代碼如下:
// 創建通知渠道 private void initNotificationChannel() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { CharSequence name = mContext.getString(R.string.app_name); NotificationChannel channel = new NotificationChannel(mChannelId, name, NotificationManager.IMPORTANCE_DEFAULT); mNotificationManager.createNotificationChannel(channel); } } // 創建通知傳入channelId NotificationCompat.Builder builder = new NotificationCompat.Builder(context, NotificationBarManager.getInstance().getChannelId());
2. 后台執行限制
如果針對 Android 8.0 的應用嘗試在不允許其創建后台服務的情況下使用 startService() 函數,則該函數將引發一個 IllegalStateException。
我們無法得知系統如何判斷是否允許應用創建后台服務,所以我們目前只能簡單 try-catch startService(),保證應用不會 crash,示例代碼:
Intent intent = new Intent(getApplicationContext(), InitializeService.class); intent.setAction(InitializeService.INITIALIZE_ACTION); intent.putExtra(InitializeService.EXTRA_APP_INITIALIZE, appInitialize); ServiceUtils.safeStartService(mApplication, intent); public static void safeStartService(Context context, Intent intent) { try { context.startService(intent); } catch (Throwable th) { DebugLog.i("service", "start service: " + intent.getComponent() + "error: " + th); ExceptionUtils.printExceptionTrace(th); } }
或者:
系統不允許后台應用創建后台服務, Android 8.0 引入了一種全新的方法,即 Context.startForegroundService(),以在前台啟動新服務.
將原來 startService方式啟動服務修改為 startForegroundService啟動服務
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
context.startForegroundService(checkIntent);
} else {
context.startService(checkIntent);
}
程序有通知的情況下:
在系統創建服務后,應用有五秒的時間來調用該服務的startForeground()方法以顯示新服務的用戶可見通知(如果應用在此時間限制內未調用 startForeground(),則系統將停止服務並聲明此應用為 ANR),在服務的onCreate()方法中調用startForeground()即可。
@Override
public void onCreate() {
super.onCreate();
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
createNotificationChannel();
Notification notification = new Notification.Builder(getApplicationContext(), channelID).build();
startForeground(1, notification);
}
}
3. 允許安裝未知來源應用
針對 8.0 的應用需要在 AndroidManifest.xml 中聲明 REQUEST_INSTALL_PACKAGES 權限,否則將無法進行應用內升級。
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
4. 主題的 Activity 設置屏幕方向
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> <item name="android:windowIsTranslucent">true</item> </style> <activity android:name=".MainActivity" android:screenOrientation="portrait" android:theme="@style/AppTheme"> </activity>
將會拋出以下異常:
java.lang.IllegalStateException: Only fullscreen opaque activities can request orientation大概意思是:只有不透明的全屏Activity可以自主設置界面方向即使滿足上述條件,該異常也並非一定會出現,為什么這么說,看下面兩種表現:
- targetSdk=26,滿足上述條件,API 26 手機沒問題,API 27 手機沒問題
- targetSdk=27,滿足上述條件,API 26 手機Crash,API 27 手機沒問題
有點摸不清 Google 的套路了……
可知,targetSdk=26 時,API 26 和 27 都沒有問題,所以這個坑暫時放在適配 API 27 時再填吧。
5. 桌面圖標適配
針對 8.0 的應用如果不適配桌面圖標,則應用圖標在 Launcher 中將會被添加白色背景:

適配方法:一起來學習Android 8.0系統的應用圖標適配吧
https://mp.weixin.qq.com/s/WxgHJ1stBjokPi6lTUd1Mg
適配后的效果:


6. 隱式廣播
由於 Android 8.0 引入了新的廣播接收器限制,因此您應該移除所有為隱式廣播 Intent 注冊的廣播接收器。將它們留在原位並不會在構建時或運行時令應用失效,但當應用運行在 Android 8.0 上時它們不起任何作用。
顯式廣播 Intent(只有您的應用可以響應的 Intent)在 Android 8.0 上仍以相同方式工作。
這個新增限制有一些例外情況。如需查看在以 Android 8.0 為目標平台的應用中仍然有效的隱式廣播的列表,請參閱隱式廣播例外。
developer.android.com/about/versi…
我對隱式廣播的理解:
未指定廣播接收器類名,通過 Action 發送。如有不妥,還請指教。
需要檢查應用靜態注冊的隱式廣播,需要改為動態注冊。
7. 網絡連接和 HTTP(S) 連接
Android 8.0 對網絡連接和 HTTP(S) 連接行為做出了以下變更:
無正文的 OPTIONS 請求具有 Content-Length: 0 標頭。之前,這些請求沒有 Content-Length 標頭。
HttpURLConnection 在包含斜線的主機或頒發機構名稱后面附加一條斜線,使包含空路徑的網址規范化。例如,它將 example.com 轉化為 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 協議,現在也許能夠訪問它們。 對於確實無法訪問的主機,此項變更意味着調用需要兩倍的時間才能返回結果。
developer.android.com/about/versi…
這點應用一般無需適配
8. 視圖焦點
可點擊的 View 對象現在默認也可以成為焦點。如果您希望 View 對象可點擊但不可成為焦點,請在包含 View 的布局 XML 文件中將 android:focusable 屬性設置為 false,或者將 false 傳遞至應用界面邏輯中的 setFocusable()。
developer.android.com/about/versi…
這點基本無需適配
9. 權限
在 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,則系統會立即授予該權限,而不會提示用戶。
developer.android.com/about/versi…
考拉中的權限都是按需申請的,不需要修改。
10. Tinker
特別是在Android N之后,由於混合編譯的inline策略修改,對於市面上的各種方案都不太容易解決。而Tinker熱補丁方案不僅支持類、So以及資源的替換,它還是2.X-8.X(1.9.0以上支持8.X)的全平台支持。
經測試,Tinker在8.0上功能正常。
11、懸浮窗要使用類型TYPE_APPLICATION_OVERLAY,原來的類型TYPE_SYSTEM_ALERT從Android8.0開始被舍棄了。 設置懸浮窗類型的兼容代碼示例如下:
WindowManager.LayoutParams wmParams = new WindowManager.LayoutParams(); // 設置為TYPE_SYSTEM_ALERT類型,才能懸浮在其它頁面之上 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) { // 注意TYPE_SYSTEM_ALERT從Android8.0開始被舍棄了 wmParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT; } else { // 從Android8.0開始懸浮窗要使用TYPE_APPLICATION_OVERLAY wmParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; }
12、屬性動畫組合AnimatorSet增加了setCurrentPlayTime和reverse方法,從而允許倒過來播放屬性動畫組合。 setCurrentPlayTime和reverse方法的調用方式示例如下:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { animSet.setCurrentPlayTime(0); // 設置當前播放的時間點 animSet.reverse(); // 從動畫尾巴開始倒播至setCurrentPlayTime設置的時間點 }

App頁面從全屏模式切換到畫中畫模式,它的Activity生命周期也會經歷銷毀后重建的過程,如果開發者想保持App頁面不被重建,則需給該頁面的activity節點加上以下的屬性描述:
android:configChanges="srceenLayout|orientation"
對於視頻播放頁面,Activity代碼同樣不在onPause方法中暫停播放視頻,而應當在onStop方法中暫停播放,並在onStart方法中恢復播放視頻;
進入畫中畫模式:
轉載:https://juejin.im/post/5baa1c606fb9a05d396f16ea

隱式廣播例外
作為Android 8.0(API級別26)后台執行限制的一部分,針對API級別26或更高級別的應用程序無法再在其清單中為隱式廣播注冊廣播接收器。但是,目前有幾個廣播免於這些限制。無論應用程序所針對的API級別如何,應用程序都可以繼續為以下廣播注冊監聽器。
注意:即使這些隱式廣播仍然在后台工作,您應該避免為它們注冊偵聽器。-
ACTION_LOCKED_BOOT_COMPLETED
,ACTION_BOOT_COMPLETED
- 免除,因為這些廣播僅在首次啟動時發送一次,並且許多應用需要接收此廣播以安排作業,警報等。
-
ACTION_USER_INITIALIZE
,"android.intent.action.USER_ADDED"
,"android.intent.action.USER_REMOVED"
- 這些廣播受特權權限保護,因此大多數普通應用程序無論如何都無法接收它們。
-
"android.intent.action.TIME_SET"
,ACTION_TIMEZONE_CHANGED
,ACTION_NEXT_ALARM_CLOCK_CHANGED
- 時間應用可能需要接收這些廣播,以便在更改時間,時區或警報時更新警報。
-
ACTION_LOCALE_CHANGED
- 僅在語言環境發生變化時發送,這不常見。應用可能需要在區域設置更改時更新其數據。
-
ACTION_USB_ACCESSORY_ATTACHED
,ACTION_USB_ACCESSORY_DETACHED
,ACTION_USB_DEVICE_ATTACHED
,ACTION_USB_DEVICE_DETACHED
- 如果應用程序需要了解這些與USB相關的事件,目前還沒有一個很好的替代方案來注冊廣播。
-
ACTION_CONNECTION_STATE_CHANGED
,ACTION_CONNECTION_STATE_CHANGED
,ACTION_ACL_CONNECTED
,ACTION_ACL_DISCONNECTED
- 如果應用收到這些藍牙事件的廣播,則用戶體驗不太可能受到影響。
-
ACTION_CARRIER_CONFIG_CHANGED
,TelephonyIntents.ACTION_*_SUBSCRIPTION_CHANGED
,"TelephonyIntents.SECRET_CODE_ACTION"
,ACTION_PHONE_STATE_CHANGED
,ACTION_PHONE_ACCOUNT_REGISTERED
,ACTION_PHONE_ACCOUNT_UNREGISTERED
- OEM電話應用可能需要接收這些廣播。
-
LOGIN_ACCOUNTS_CHANGED_ACTION
- 某些應用需要了解登錄帳戶的更改,以便他們可以為新帳戶和已更改帳戶設置計划操作。
-
ACTION_ACCOUNT_REMOVED
-
刪除帳戶后,可以看到帳戶的應用會收到此廣播。如果這是應用程序需要執行的唯一帳戶更改,則強烈建議應用程序使用此廣播而不是棄用
LOGIN_ACCOUNTS_CHANGED_ACTION
。 -
ACTION_PACKAGE_DATA_CLEARED
- 僅在用戶明確清除“設置”中的數據時發送,因此廣播接收器不太可能顯着影響用戶體驗。
-
ACTION_PACKAGE_FULLY_REMOVED
-
某些應用可能需要在刪除其他包時更新其存儲的數據; 對於這些應用程序,沒有很好的替代方案來注冊此廣播。
注意:其他與包相關的廣播(例如
ACTION_PACKAGE_REPLACED
)不受新限制的豁免。這些廣播很常見,對豁免廣告有潛在的性能影響。 -
ACTION_NEW_OUTGOING_CALL
-
響應用戶撥打電話而采取措施的應用需要接收此廣播。
-
ACTION_DEVICE_OWNER_CHANGED
-
這種廣播不經常發送; 一些應用需要接收它,以便他們知道設備的安全狀態已經改變。
-
ACTION_EVENT_REMINDER
-
由日歷提供商發送,以向日歷應用發布活動提醒。由於日歷提供商不知道日歷應用程序是什么,因此該廣播必須是隱含的。
-
ACTION_MEDIA_MOUNTED
,ACTION_MEDIA_CHECKING
,ACTION_MEDIA_UNMOUNTED
,ACTION_MEDIA_EJECT
,ACTION_MEDIA_UNMOUNTABLE
,ACTION_MEDIA_REMOVED
,ACTION_MEDIA_BAD_REMOVAL
-
這些廣播是由於用戶與設備的物理交互(安裝或刪除存儲卷)或作為啟動初始化的一部分(因為可用卷已安裝)而發送的,因此它們不常見,通常由用戶控制。
-
SMS_RECEIVED_ACTION
,WAP_PUSH_RECEIVED_ACTION
-
SMS收件人應用程序依賴這些廣播。