Android O 適配詳細指南

前言

最近 Google 爸爸對 Google Play 上架的應用提出了目標 API 等級要求html

從 2018 年 8 月 1 日起,全部向 Google Play 首次提交的新應用都必須針對 Android 8.0 (API 等級 26) 開發; 2018 年 11 月 1 日起,全部 Google Play 的現有應用更新一樣必須針對 Android 8.0。java

Google Play 目標 API 等級(targetSdkVersion)重要變動要求android

同時,國內的華爲、360、應用寶也要求開發者適配 Android P,不然應用將被不推薦、隱藏甚至下架(華爲),能夠看出國內應用市場對於推進應用適配新 API 的決心,雖然沒有強制要求適配,但也算國內應用市場的一大進步,相信很快就會有其餘應用市場跟進。git

爲保障華爲用戶的使用體驗,華爲應用市場已在7月份啓動Android P版本應用適配檢測工做,針對未作適配的應用開發者陸續進行郵件通知。 請您對應用適配這一環節加以重視,並於2018年10月底前完成Android P版本適配工做並自檢經過。針對未適配或在Android P版本體驗欠佳的應用,華爲應用市場將在Android P版本機型上採起下架、不推薦更新或屏蔽策略,可能會對您的推廣、用戶口碑及品牌產生影響。github

華爲公告 360公告 應用寶公告安全

意義

咱們都知道每次 Android 版本的更新都會新增一大波優化功能,好比 Android M 上引入了運行時權限,Android N 上帶來了 Doze 模式,Android O 上的後臺執行限制bash

總的來講,新版本會讓咱們的 Android 設備更流暢,更省電,隱私性更好。服務器

應用也能夠利用新版本的特性以提高用戶體驗,如 Android M 引入可指定通知欄顏色,以實現徹底沉浸式體驗。網絡

因此固然要適配新版本啦架構

新版本新增了不少優化,但同時對 APP 的限制也更多,好比在新版本上應用保活愈來愈困難,應用沒法在後臺作一些偷偷摸摸的事情,有些應用提供商確定不樂意啦,所以國內不少應用對 Android API 適配的積極性不高。

如今各大應用市場聯合起來催促開發者適配 Android API,這種狀況很定會慢慢有所改觀,國內的 Android 應用生態也會愈來愈良好。

正文

扯了這麼多,說到底,仍是想說爲了國內的 Android 應用生態,你們趕忙適配起來新版本吧

俗話說,不能一口吃個胖子,所以咱們先從 Android O 適配器來,也能達到 Google 爸爸的要求

下面是考拉 APP 適配 Android O 的記錄

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());
複製代碼

developer.android.com/about/versi…

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);
    }
}
複製代碼

developer.android.com/about/versi…

3. 容許安裝未知來源應用

針對 8.0 的應用須要在 AndroidManifest.xml 中聲明 REQUEST_INSTALL_PACKAGES 權限,不然將沒法進行應用內升級。

<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
複製代碼

4. 主題的 Activity 設置屏幕方向

針對 8.0 的應用,設置了透明主題的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系統的應用圖標適配吧

適配後的效果:

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)的全平臺支持。

github.com/Tencent/tin…

經測試,Tinker在8.0上功能正常。

總結

隨着 Android 版本的不斷迭代,Android 系統的體驗已經愈來愈好了。

Android 系統的絢爛多彩離不開廣大的 Android 開發者,咱們做爲開發者,咱們應該儘快適配 Android 新版本,讓咱們的應用擁有最好的體驗。

本篇介紹了 Android O 的適配要點,若有不足,還請指教

下一篇將會介紹 Android P 的適配,敬請期待

參考:

Android 綠色應用公約 統一推送聯盟

遷移自個人簡書 2018.09.19

相關文章
相關標籤/搜索