Android App兼容 10.0 系統

北京時間2019年3月14日Google正式對外發布Android Q Beta 1及預覽版SDK,這意味着安卓開發者們又即將迎來一年一度的新版本適配工作了。Android Q 爲開發者們帶來了許多新功能,如折疊屏增強項、新網絡連接 API、全新的媒體解碼器、攝像頭新功能、NNAPI 擴展、Vulkan 1.1 圖形支持 等等。

1.加權限

<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>
<uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE"/> 
<uses-permission android:name="android.permission.CAMERA" />         
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
 

2.修改編譯版本及目標版本

compileSdkVersion 29 (28+)

targetSdkVersion 29(28+)

 

3.選擇相冊圖片時出現權限問題

application標籤下添加

android:requestLegacyExternalStorage =“true”

4. 獲取文件夾路徑

String savePAth = Environment.getExternalStorageDirectory() + “/DownFile/”;

上面方法要換成下面的 否則獲取會失敗
String savePAth = getExternalCacheDir()+"/DownFile/";

 

5. Android Q 行爲變更:所有應用

官方文檔將這一部分內容獨立於Q 行爲變更:所有應用來介紹,是因爲這一部分內容龐大且重要,其中最大的更新就是用戶隱私權限變更。具體變更的權限如下:

權限 受影響應用 如何啓用(影響範圍)
存儲權限 訪問和共享外部存儲設備中的文件的應用 adb shell sm set-isolated-storage on(下文詳述)
定位權限 在後臺時請求訪問用戶位置信息的應用 這種權限策略在 Android Q 上始終處於啓用狀態
從後臺啓動 Activity 不需要用戶互動就啓動 Activity 的應用 關閉允許系統執行後臺活動開發者選項即可啓用限制
設備標識符(deviceId) 訪問設備序列號或 IMEI 的應用 在搭載 Android Q 的設備上安裝應用
無線掃描權限 使用 WLAN API 和 Bluetooth API 的應用 以 Android Q 爲目標平臺

從後臺啓動Activity權限和無線掃描權限兩種權限的變更影響較少 ,本文就不做介紹,詳細可以查看請查閱官方文檔:https://developer.android.com/preview/privacy/background-activity-starts
從後臺啓動Activity權限變更僅針對與用戶毫無交互就啓動一個Activity的情況,(比如微信登陸授權)。

本文將重點講述存儲權限,定位權限和設備標識符三種權限的變更與適配。

1.用戶存儲權限的變更

Android Q 在外部存儲設備中爲每個應用提供了一個“隔離存儲沙盒”(例如 /sdcard)。任何其他應用都無法直接訪問您應用的沙盒文件。由於文件是您應用的私有文件,因此您不再需要任何權限即可在外部存儲設備中訪問和保存自己的文件。此變更可讓您更輕鬆地保證用戶文件的隱私性,並有助於減少應用所需的權限數量。
谷歌官方推薦應用在沙盒內存儲文件的地址爲Context.getExternalFilesDir()下的文件夾。比如要存儲一張圖片,則應放在Context.getExternalFilesDir(Environment.DIRECTORY_PICTURES)中。

以下將按訪問的目標文件的地址介紹如何適配:

  1. 訪問自己文件:Q中用更精細的媒體特定權限替換並取消了 READ_EXTERNAL_STORAGE和 WRITE_EXTERNAL_STORAGE權限,並且無需特定權限,應用即可訪問自己沙盒中的文件。

  2. 訪問系統媒體文件:Q中引入了一個新定義媒體文件的共享集合,如果要訪問沙盒外的媒體共享文件,比如照片,音樂,視頻等,需要申請新的媒體權限:READ_MEDIA_IMAGES,READ_MEDIA_VIDEO,READ_MEDIA_AUDIO,申請方法同原來的存儲權限。

  3. 訪問系統下載文件:對於系統下載文件夾的訪問,暫時沒做限制,但是,要訪問其中其他應用的文件,必須允許用戶使用系統的文件選擇器應用來選擇文件。

  4. 訪問其他應用沙盒文件:如果你的應用需要使用其他應用在沙盒內創建的文件,請點擊使用其他應用的文件,本文不做介紹。

所以請判斷當應用運行在Q平臺上時,取消對READ_EXTERNAL_STORAGE和 WRITE_EXTERNAL_STORAGE兩個權限的申請。並替換爲新的媒體特定權限。

當滿足以下每個條件時,將開啓兼容模式,即不開啓Q設備中的存儲權限改動:

  1. 應用targetSDK<=P。
  2. 應用安裝在從 Android P 升級到 Android Q 的設備上。

當應用重新安裝(更新)時,不會重新開啓兼容模式,存儲權限改動將生效。
所以按官方文檔所說,無論targetSDK是否爲Q,必須對應用進行存儲權限改動的適配。
在測試中,當targetSDK<=P,在Q Beat1版上申請兩個舊權限時會自動改成申請三個新權限,不會影響應用正常使用,但當targetSDK==Q時,申請舊權限將失敗並影響應用正常使用。

2.用戶的定位權限的變更

爲了讓用戶更好地控制應用對位置信息的訪問權限,Android Q 引入了新的位置權限 ACCESS_BACKGROUND_LOCATION

與現有的 ACCESS_FINE_LOCATION和 ACCESS_COARSE_LOCATION權限不同,新權限僅會影響應用在後臺運行時對位置信息的訪問權。除非應用的某個 Activity 可見或應用正在運行前臺服務,否則應用將被視爲在後臺運行。

與iOS系統一樣,Q中也加入了後臺位置權限ACCESS_BACKGROUND_LOCATION,如果應用需要在後臺時也獲得用戶位置(比如滴滴),就需要動態申請ACCESS_BACKGROUND_LOCATION權限。

當然如果不需要的話,應用就無需任何改動,且谷歌會按照應用的targetSDK作出不同處理:
targetSDK <= P 應用如果請求了ACCESS_FINE_LOCATION或 ACCESS_COARSE_LOCATION權限,Q設備會自動幫你申請ACCESS_BACKGROUND_LOCATION權限。

3.設備唯一標識符的變更

從 Android Q 開始,應用必須具有 READ_PRIVILEGED_PHONE_STATE簽名權限才能訪問設備的不可重置標識符(包含 IMEI 和序列號)。
如果您的應用沒有該權限,但您仍嘗試查詢標識符的相關信息,會返回空值或報錯。
設備唯一標識符需要特別注意,原來的READ_PHONE_STATE權限已經不能獲得IMEI和序列。

如果想在Q設備上通過使用以下代碼獲取設備的ID

((TelephonyManager)getActivity().getSystemService(Context.TELEPHONY_SERVICE)).getDeviceId()
  • 1

則執行以上代碼會返回空值(targetSDK<=P)或者報錯(targetSDK==Q)。且官方所說的READ_PRIVILEGED_PHONE_STATE權限只提供給系統app,所以這個方法行不通了。

谷歌官方給予了設備唯一ID最佳做法,但是此方法給出的ID可變,可以按照具體需求具體解決。本文給出一個不變和基本不重複的UUID方法:

public static String getUUID() {
    String serial = null;
    String m_szDevIDShort = "35" +
        Build.BOARD.length() % 10 + Build.BRAND.length() % 10 +
        Build.CPU_ABI.length() % 10 + Build.DEVICE.length() % 10 +
        Build.DISPLAY.length() % 10 + Build.HOST.length() % 10 +
        Build.ID.length() % 10 + Build.MANUFACTURER.length() % 10 +
        Build.MODEL.length() % 10 + Build.PRODUCT.length() % 10 +
        Build.TAGS.length() % 10 + Build.TYPE.length() % 10 +
        Build.USER.length() % 10; //13 位

    try {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                serial = android.os.Build.getSerial();
            } else {
                serial = Build.SERIAL;
            }
            //API>=9 使用serial號
            return new UUID(m_szDevIDShort.hashCode(), serial.hashCode()).toString();
        } catch (Exception exception) {
            //serial需要一個初始化
            serial = "serial"; // 隨便一個初始化
      }
    //使用硬件信息拼湊出來的15位號碼
    return new UUID(m_szDevIDShort.hashCode(), serial.hashCode()).toString();
}

雖然由於唯一標識符權限的更改會導致android.os.Build.getSerial()返回unknown,但是由於m_szDevIDShort是由硬件信息拼出來的,所以仍然保證了UUID的唯一性和持久性。
測試輸出結果如下
在這裏插入圖片描述

經測試上述方法完全相同的手機有可能重複,網上還有其他方案比如androidID,但是androidID可能由於機型原因返回null,所以個人認爲兩種方法半斤八兩。設備ID的獲取一個版本比一個版本艱難,如果有好的方法歡迎指出。

4.關於minSDK警告

在 Android Q 中,當用戶首次運行以 Android 6.0(API 級別 23)以下的版本爲目標平臺的任何應用時,Android平臺會向用戶發出警告。

如果此應用要求用戶授予權限,則系統會先向用戶提供調整應用權限的機會,然後纔會允許此應用首次運行。


6. Android Q 行爲變更:以 Android Q 爲目標平臺的應用

非 SDK 接口限制

非SDK接口限制在Android P中就已提出,但是在Q中,被限制的接口的分類有較大變化。

非SDK接口介紹

爲了確保應用穩定性和兼容性,Android 平臺開始限制您的應用可在 Android 9(API 級別 28)中使用哪些非 SDK 接口。Android Q 包含更新後的受限非 SDK 接口列表(基於與 Android 開發者之間的協作以及最新的內部測試)。
非SDK接口限制就是某些SDK中的私用方法,如private方法,你通過Java反射等方法獲取並調用了,那麼這些調用將在target>=P或target>=Q的設備上被限制使用,當你使用了這些方法後,會報錯

獲取方法 報錯信息
Dalvik instruction referencing a field NoSuchFieldError thrown
Dalvik instruction referencing a method NoSuchMethodError thrown
Reflection via Class.getDeclaredField() or Class.getField() NoSuchFieldException thrown
Reflection via Class.getDeclaredMethod(), Class.getMethod() NoSuchMethodException thrown
Reflection via Class.getDeclaredFields(), Class.getFields() Non-SDK members not in results
Reflection via Class.getDeclaredMethods(), Class.getMethods() Non-SDK members not in results
JNI via env->GetFieldID() NULL returned,NoSuchFieldError thrown
JNI via env->GetMethodID() NULL returned,NoSuchMethodError thrown

非SDK接口查找

如果您不確定自己的應用是否使用了非 SDK 接口,則可以測試該應用進行確認。當你調用了非SDK接口時,會有類似Accessing hidden XXX的日誌:

Accessing hidden field Landroid/os/Message;->flags:I (light greylist, JNI)
  • 1

但是一個大項目到底哪裏使用了這些方法,靠review代碼和看日誌肯定是不現實的,谷歌官方也提供了官方檢查器veridex用來檢測一個apk中哪裏使用了非SDK接口。veridex下載: https://android.googlesource.com/platform/prebuilts/runtime/+/master/appcompat
其中有windows,linux和mac版本,對應下載即可。下載解壓後命令行cd到veridex目錄下使用./appcompat.sh --dex-file=Q.apk即可自動掃描。Q.apk爲包的絕對路徑,如果包與veridex在相同目錄下直接輸入包文件名即可。掃描結果分爲兩部分,一部分爲被調用的非SDK接口的位置,另一部分爲非SDK接口數量統計。

非SDK接口適配

如果您的應用依賴於非 SDK 接口,則應該開始計劃遷移到 SDK 替代方案。如果您無法爲應用中的某項功能找到使用非 SDK 接口的替代方案,則應該請求新的公共 API。

官方要求targetSDK>=P的應用不使用這些方法,並尋找其他的公共API去替代這些非SDK接口,如果找不到,則可以向谷歌申請,請求一個新的公共API: https://developer.android.com/distribute/best-practices/develop/restrictions-non-sdk-interfaces#feature-request

項目中使用非SDK接口大概率有以下兩種情況:

  1. 在自定義View的過程中爲了方便,使用反射修改某個參數。
  2. 三方SDK中使用了非SDK接口(這種情況比較多)。

第一種是好解決的,畢竟是我們自己寫的代碼。第二種就頭疼了,只能更新到最新的三方SDK版本,或者提工單、換庫(也是整個適配過程中工作量最龐大的部分)。


7. Android項目升級遇到的問題

模擬器X86,項目中SO庫爲v7

  • 找到so庫源代碼,編譯成x86
  • 如果so庫只是某個功能點使用,對APP整體沒大影響,就可以屏蔽特定so庫功能或略過測試
  • 如果so庫是項目核心庫必須加載,也可使用騰訊雲測,上面有谷歌親兒子Q版本。騰訊雲測有adb遠程連接調試功能(我沒成功過)。adb連不上也沒關係,直接安裝就行,雲測上也可以直接看日誌。
  • 至於inter的houdini我嘗試研究過,理論上能安裝在x86模擬器上讓它編譯v7的so庫,但是由於關於houdini的介紹比較少也比較舊,建議大家時間不充裕的話就別研究了。

Requires development platform Q but this is a release platform.

由於目前Q是preview版,所以targetSDK==Q 的應用只能在Q設備上跑。

INSTALL_FAILED_INVALID_APK: Failed to extract native libraries, res=-2

這個錯誤是由於打包壓縮so庫時造成的,具體原因可見:https://issuetracker.google.com/issues/37045367
在AndroidManifest.xml的application節點下加入android:extractNativeLibs="true"
可能有人加了上面代碼還是不行,在app/build.gradle中的defaultConfig節點下加入

packagingOptions{ 
      doNotStrip "/armeabi/.so" doNotStrip "/armeabi-v7a/.so" doNotStrip "/x86/.so" }
  • 1
  • 2

Didn’t find class “org.apache.http.client.methods.HttpPost"

在AndroidManifest.xml的application節點下加入

<uses-library android:name="org.apache.http.legacy" android:required="false"/>
  • 1

如果你的項目沒有適配過android O或P,那麼你需要注意

android O的讀取已安裝應用權限(對應用內自動更新有影響)
android P的默認禁止訪問http的API

 

 

本文的參考文檔:

Android Q Beta開發者文檔鏈接::https://developer.android.com/preview

Android Q Beta鏡像下載鏈接:https://developer.android.com/preview/download

Android Q Beta 發佈 blog:https://android-developers.googleblog.com/2019/03/introducing-android-q-beta.html

非SDK接口:https://juejin.im/post/5afe50eef265da0b70262463
 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章