因爲各個應用市場要求,須要在 2019年5月1日 以前把 target 升級到 26。因此對本公司全網的 App 和可能影響到的相關 SDK 作一個升級。本文主要記錄這次升級的過程和解決的一些問題。html
其實升級 target 技術含量不是很高,可是由於涉及到庫(100 多個 SDK)和人員,依賴有點多,涉及到公司全部業務的 App, 並且改動的地方和細節也有多,很容易出現考慮不全,致使線上問題。android
主要過程爲如下幾步:git
由於公司的 App、組件、模塊都是基於 target 22 和 support 24 進行開發的,因此要看下官方文檔 releases/platforms 和 libraries/support-library 相關的文檔,從中找到影響點。咱們受影響主要有 2 個方面:github
由於第一個權限問題是比較廣泛的,因此應該有相關的開源項目支持,爲了效率,咱們就不重複製造輪子。參考各個比較流行的開源方案,作了一下對比:工具
相關庫 | 須要修改 Activity 或者 Fragment | 設置界面跳轉 | 備註 | star 數 |
---|---|---|---|---|
AndPermission | 不須要 | 有, 能夠參考 | 改動小 | 4911 |
Permissions4m | 須要 | 有,能夠參考 | 改動多 | 1594 |
RxPermissions | 須要,不支持 Application 請求傳入請求 | 無,須要本身實現 | 改動多 | 7911 |
FcPermissions | 須要,須要繼承 FcPermissionsCallbacks | 無,須要本身實現 | 改動多 | 406 |
EasyPermission | 須要 | 無 | 改動多 | 7526 |
PermissionHelper | 須要繼承 BasePermissionActivity | 無 | 改動多 | 1191 |
經過以上對比,咱們決定使用 AndPermission 的方案,由於這個對於咱們現有 App 的侵入是最少的,改動點比較少,並且支持 Appliction 傳入(其實當使用 Application 傳入時候,會有問題,後面再說)。測試
當時的考慮點是咱們公司不少 SDK 設計的時候是沒有 Activity 的引用。可是咱們的 SDK, 基本有個 Application 這個引用的,因此選擇了一個可以支持傳入 Applicaiton 就可以判斷權限回調的庫。爲何 AndPermission 可以支持呢?由於 AndPermission 在權限校驗的時候會啓動 PermissionActivity,而且加上了 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
,全部的權限請求都是在這個 PermissionActivity 處理,並且改動也比較少。優化
AndPermission 這個庫的動態權限請求具體過程大夥能夠看下 AndPermission 這個庫的源碼。使用方式以下:ui
從 API 調用來看是十分簡單好用的。而後我又仔細看了一下它的實現過程,發現了有些不符合咱們產品需求的地方:.net
這樣咱們就須要在 AndPermission 基礎上進行改造,作出適合本身的動態權限庫。咱們自定義了默認的 onDenied (申請權限失敗後的回調)。 這樣業務方就不須要關心失敗後怎麼提示了,只要關心成功後把以前的業務邏輯放到成功後這裏執行就行了。權限申請失敗提示框,用來啓動一個 Activity 來 show 這個 Dialog,這樣即便在前面傳入的是 Application 的 context 也是沒有問題了。對於屢次請求權限致使屢次彈框的問題,咱們在 AndPermission 的基礎上添加的請求隊列,只有上一個權限請求處理完成後,才進行下一次權限請求,這樣的話,即便用戶一次行爲的方法鏈過程當中有不少次請求也不會屢次彈框。 而後當我用隊列管理請求權限的時候,很怕某個權限阻塞了,或者出了未知異常,因此我對每次權限加入過程作了超時處理。以上幾點是對於本身業務場景的幾點考慮,進行的改造。插件
U51AndPermission SDK 已經生成了,那接下來就是怎麼集成到各個 SDK 和 App 中了。首先咱們要知道,咱們的 App 哪些地方有可能調用到了須要權限請求的 API。若是要人工去看效率實在是過低了。咱們有 100 多個庫,不可能把庫看完且不出錯。因此咱們使用了以前同事的一個插件去掃描相關的 API,用來定位到可能出現權限的類在哪裏,用的是哪一個庫。這樣就提升了準確率和效率。
這個是咱們插件須要搜索的 API
如下是部分搜索結果
按照這種方法,咱們本須要處理 100 多個類庫的,如今只有 20 個不到。一會兒少了 4 倍的工做量,並且相對準確。
不少 App 啓動的時候須要一些必選權限的,咱們的 App 也是同樣的,須要在 App 啓動的時候驗證一個必選權限。若是有必選權限,那麼提示用戶受權,若是不受權,那麼就不可以繼續使用咱們的產品了。因此進入 App 主要功能前,須要一個前置的攔截。考慮過 2 種方案:
方案1、在 Applicaiton 的 onCreate 方法中去申請必選權限,讓啓動 Activity 等待 Application 中權限申請好了,再用消息(EventBus) 通知 啓動 Activity 繼續走下去的流程
方案2、新建一個新的 啓動 Activity,在這個 Activity 中作申請權限,申請完後再去啓動以前老的啓動 Activity
和對接的業務方討論,他們選擇了第一種方案, 這麼作的緣由也是由於咱們不少 SDK 的初始化代碼在 Appliction 中,咱們必需要在初始化 SDK 以前就應該把必要權限拿到。若是選擇第二種,那麼咱們的初始化代碼須要移動到新的啓動 Activity 中,這樣改動風險有點高。
接入代碼以下:
對接完後有幾個咱們遇到的問題須要提下:
問題1、 由於在 App 啓動的時候,若是沒有必要權限,那麼就會有彈框讓用戶設置權限,這時候用戶點擊 "設置",就會跳轉到 App 設置權限頁面,當用戶受權回來的時候,有部分手機會出現黑屏。致使黑屏的緣由是 U51Permission 傳入進去的 context 是 Application。若是是 Activity 就不會黑屏。因此解決方法是使用 Activity 去請求權限,回調方式是使用 Application.registerActivityLifecycleCallbacks
,以下:
問題2、 由於咱們有些邏輯是放到先後臺切換的代碼裏面的,先後切換的主要用主要用到 Application.registerActivityLifecycleCallbacks
這個回調,根據 Activity 的生命週期統計來切換先後臺(先後臺的切換邏輯是使用統計 activity 的個數來實現的);因此 Application.registerActivityLifecycleCallbacks
這個操做應該是在 啓動 Activity 以前就應該被註冊。可是在申請必要權限的時候,我先啓動 Activity 後再去註冊這個 callback 的,因此致使啓動 Activity 不在計算範圍內,致使先後臺的調用邏輯不許確,業務邏輯處理時機不對的問題。後來咱們使用一個本身的 registerActivityLifecycleCallbacks
,命名 MyActivityLifecycleCallbacks
,在 Application 一開始啓動的時候就註冊了,而後把後面其餘須要註冊的地方放到 MyActivityLifecycleCallbacks
中,由它統一通知其餘須要先後臺的回調。
替換以前
替換以後
能夠看出來替換後改動代碼不多,並且全部的先後臺切換都會統一到本身的 MyActivityLifecycleCallbacks
裏面進行集中管理。
還有其餘相關問題,網上都可以找到,我就列舉一下,你們本身注意一下就行了:
android.os.FileUriExposedException
的異常,文件共享的限制和第 1 條同樣Sevices.startService
有些手機會奔潰,這個咱們的 App 以前就處理過了以上就是本次升級須要的修改點了,剩下的還有測試、灰度和正式上線。從整個適配過程來看,這個需求其實不是很難,可是從改動的點來講,溝通協調能力要求仍是很高的,會涉及到大部分客戶端開發、測試和產品。
對於改造升級大範圍的基礎庫,每一個環節儘可能多思考和團隊成員多討論,切記不要一我的悶頭就是幹。但也不要過多的擔憂,須要膽大心細,這樣才能把事情推動下去。好了,target 28 的適配也立刻要來了。