android gradle权威指南pdf_干货 | 携程 Android 10适配踩坑指南
作者簡介
?曙光,攜程資深軟件工程師,負責市場營銷相關研發及管理工作。2019 年 9 月 3 日,Google 發布了 Android 10 正式版。Android 10 聚焦移動創新、安全隱私和數字健康三大主題,全面打造最佳用戶體驗。背景
目前攜程旅行線上最新版本已適配到Android 10(API =29),由于從API=26升級到API=29,跨度較大,我們提前對相關適配進行了調研,希望其中一些經驗能對其他開發者有一定的幫助。在Android 10 版本中,官方的改動較大,相應的開發者適配成本還是很高的。基于前期調研,我們主要基于以下幾方面進行Android 10的適配:Android X
分區存儲
設備ID
明文HTTP限制
一、AndroidX
AndroidX 對原始 Android Support庫進行了重大改進,后者現在已不再維護。AndroidX 軟件包完全取代了支持庫,不僅提供同等的功能,而且提供了新的庫。1.1 什么是AndroidXAndroid系統在剛剛面世的時候,可能連它的設計者也沒有想到它會如此成功。隨著Android系統版本不斷地迭代更新,每個版本中都會加入很多新的API進去,但是新增的API在老版系統中并不存在,因此這就出現了一個向下兼容的問題。于是Android團隊推出了一個鼎鼎大名的Android Support Library,用于提供向下兼容的功能。比如我們熟知的support-v4庫,appcompat-v7庫都是屬于Android Support Library的。4在這里指的是Android API版本號,對應的系統版本是1.6。support-v4的意思就是這個庫中提供的API會向下兼容到Android 1.6系統。類似地,appcompat-v7指的是將庫中提供的API向下兼容至API 7,也就是Android 2.1系統。隨著時間的推移,Android1.6、2.1系統早已被淘汰了,現在Android官方支持的最低系統版本已經是4.0.1,對應的API版本號是15。support-v4、appcompat-v7庫也不再支持那么久遠的系統了,但是它們的名字卻一直保留了下來,雖然它們現在的實際作用已經對不上當初命名的原因了。Android團隊也意識到這種命名已經非常不合適了,于是對這些API的架構進行了一次重新的劃分,推出了AndroidX。因此,AndroidX本質上其實就是對Android Support Library進行的一次升級。1.2 為什么要升級AndroidX版本 28.0.0 是Android Support 庫的最后一個版本。官方將不再發布 android.support 庫版本。所有新功能都將在 AndroidX命名空間中開發。
長遠來看。AndroidX重新設計了包結構,旨在鼓勵庫的小型化,支持庫和架構組件包的名字進行了簡化。而且這也是減輕Android生態系統碎片化的有效方式。
與Android Support庫不同,AndroidX軟件包是單獨維護和更新的。這些AndroidX包使用嚴格的語義版本控制,從版本1.0.0開始,您可以單獨更新項目中的AndroidX庫。
1.3 適配步驟
1.3.1 環境準備
AndroidStudio 3.2.0+
gradle:gradle-4.6+
android.useAndroidX=true 表示當前項目啟用 AndroidX;
android.enableJetifier=true 表示將依賴包也遷移到AndroidX 。如果取值為 false ,表示不遷移依賴包到AndroidX,但在使用依賴包中的內容時可能會出現問題,如果你的項目中沒有使用任何三方依賴,此項可以設置為 false。
1.3.3 修改項目中的build.gradle依賴庫
implementation 'com.android.support:appcompat-v7:28.0.0'→ implementation 'androidx.appcompat:appcompat:1.0.2'implementation 'com.android.support:design:28.0.0'→implementation 'com.google.android.material:material:1.0.0'implementation 'com.android.support.constraint:constraint-layout:1.1.3'→ implementation 'androidx.constraintlayout:constraintlayout:1.1.3'映射關系:https://developer.android.com/jetpack/androidx/migrate/artifact-mappings
1.3.4 修改支持庫類
將原來import的android.**包刪除,重新import新的androidx.**包;import android.support.v7.app.AppCompatActivity; →import androidx.appcompat.app.AppCompatActivity;1.3.5 遷移
官方遷移指南:https://developer.android.com/jetpack/androidx/migrate#migrate在 AndroidStudio 3.2 或更高版本(截圖中 AndroidStudio 為 3.5 版本)中執行如下操作:菜單>Refactor > Migrate to AndroidX(如果遷移失敗,就需要重復上面1,2,3,4步手動去修改遷移)注意:
使用AS遷移工具并不能完全修改完畢,需要手動修改
support包名涉及到資源修改,切記檢查資源中的類路徑
二、分區存儲
2.1 背景介紹為了更好的保護用戶數據并限制設備冗余文件增加,以 Android 10(API 級別 29)及更高版本為目標平臺的應用在默認情況下被賦予了對外部存儲設備的分區訪問權限(即分區存儲), 對外部存儲文件訪問方式重新設計,便于用戶更好的管理外部存儲文件。應用只能看到本應用專有的目錄(通過 Context.getExternalFilesDir() 訪問)以及特定類型的媒體。除非您的應用需要訪問存放在應用的專有目錄以及 MediaStore 之外的文件,否則最好使用分區存儲。要點:
Android Q文件存儲機制修改成了沙盒模式
APP只能訪問自己目錄下的文件和公共媒體文件
Android Q版本以下機型,還是使用老的文件存儲方式
Android Q及以上版本機型,所有應用均需要分區存儲, 所以應用需要提前確保支持分區存儲
2.2 新特性概覽
2.2.1 外部存儲
外部存儲被分為應用私有目錄以及共享目錄兩個部分:應用私有目錄:存儲應用私有數據,外部存儲應用私有目錄對應Android/data/packagename,內部存儲應用私有目錄對應data/data/packagename;
共享目錄:存儲其他應用可訪問文件, 包含媒體文件、文檔文件以及其他文件,對應設備DCIM、Pictures、Alarms, Music, Notifications,Podcasts, Ringtones、Movies、Download等目錄
1)私有目錄
應用私有目錄文件訪問方式與之前Android版本一致,可以通過File path獲取資源。2)共享目錄
共享目錄文件需要通過MediaStore API或者Storage Access Framework方式訪問。MediaStore API在共享目錄指定目錄下創建文件或者訪問應用自己創建文件,不需要申請存儲權限
MediaStore API訪問其他應用在共享目錄創建的媒體文件(圖片、音頻、視頻), 需要申請存儲權限,未申請存儲權限,通過ContentResolver查詢不到文件Uri,即使通過其他方式獲取到文件Uri,讀取或創建文件會拋出異常;
MediaStore API不能夠訪問其他應用創建的非媒體文件(pdf、office、doc、txt等), 只能夠通過Storage Access Framework方式訪問;
2.3 受影響的變更
2.3.1 圖片位置信息
一些圖片會包含位置信息,因為位置對于用戶屬于敏感信息, Android 10應用在分區存儲模式下圖片位置信息默認獲取不到,應用通過以下兩項設置可以獲取圖片位置信息:在manifest中申請ACCESS_MEDIA_LOCATION
調用MediaStore setRequireOriginal(Uri uri)接口更新圖片Uri
2.3.2?訪問數據
MediaStore.Files應用分區存儲模式下,MediaStore.Files 集合只能夠獲取媒體文件信息(圖片、音頻、視頻), 獲取不到非media(pdf、office、doc、txt等)文件。2.3.3 File Path路徑訪問受影響接口
開啟分區存儲新特性, Andrioid 10不能夠通過File Path路徑直接訪問共享目錄下資源,以下接口通過File 路徑操作文件資源,功能會受到影響,應用需要使用MediaStore或者SAF方式訪問。類名稱受影響的接口| File | createNewFile() |
| delete() | |
| renameTo(File dest) | |
| mkdir() | |
| mkdirs() | |
| FileInputStream | FileInputStream(File file) |
| FileInputStream(String name) | |
| FileOutputStream | FileOutputStream(String name) |
| FileOutputStream(String name, boolean append) | |
| FileOutputStream(File file) | |
| FileOutputStream(File file, boolean append) | |
| BitmapFactory | decodeFile(String pathName) |
| decodeFile(String pathName, Options opts) |
2.3.4 存儲特性Android版本差異概覽
存儲位置路徑版本存儲權限| 內部存儲 | data/data/packagename | 所有 | 否 | getFilesDir()、getCacheDir() | |
| 外部存儲 | 私有目錄 | Android/data/packagename | 4.4以上 | getExternalFilesDir()、getExternalCacheDir()、SAF | |
| 共享目錄 | DCIM、Pictures、Alarms, Music, Notifications,Podcasts, Ringtones、Movies、Download | <10 | 是 | Environment.getExternalStorageDirectory() | |
| 否 | SAF | ||||
| >=10 | 是 | 訪問其他應用media文件 -->MediaStore API | |||
| 訪問其他應用創建的非media文件 --> SAF | |||||
| 否 | 訪問自己應用創建的文件 -->MediaStore API | ||||
| SAF | |||||
2.4 兼容模式
應用未完成外部存儲適配工作,可以臨時以兼容模式運行, 兼容模式下應用申請存儲權限,即可擁有外部存儲完整目錄訪問權限,通過Android10之前文件訪問方式運行,以下兩種方法設置應用以兼容模式運行。2.4.1 AndroidManifest中申明
tagretSDK 大于等于Android 10(API level 29), 在manifest中設置requestLegacyExternalStorage屬性為true。......2.4.2、判斷兼容模式接口
//返回值//true : 應用以兼容模式運行//false:應用以分區存儲特性運行Environment.isExternalStorageLegacy();備注:應用已完成存儲適配工作且已打開分區存儲開關,如果當前應用以兼容模式運行,覆蓋安裝后應用仍然會以兼容模式運行,卸載重新安裝應用才會以分區存儲模式運行2.5 適配方案
2.5.1 方案概覽
分區存儲適配包含文件遷移以及文件訪問兼容性適配兩個部分:1)文件遷移
文件遷移是將應用共享目錄文件遷移到應用私有目錄或者Android10要求的media集合目錄。針對只有應用自己訪問并且應用卸載后允許刪除的文件,需要遷移文件到應用私有目錄文件,可以通過File path方式訪問文件資源,降低適配成本。
允許其他應用訪問,并且應用卸載后不允許刪除的文件,文件需要存儲在共享目錄,應用可以選擇是否進行目錄整改,將文件遷移到Android10要求的media集合目錄。
2)文件訪問兼容性
共享目錄文件不能夠通過File path方式讀取,需要使用MediaStore API或者Storage Access Framework框架進行訪問。2.5.2 適配指導
AndroidQ中使用ContentResolver進行文件的增刪改查。1)獲取(創建)私有目錄下的文件夾
//在自身目錄下創建apk文件夾File apkFile = context.getExternalFilesDir("apk");2)創建私有目錄文件
生成需要下載的路徑,通過輸入輸出流讀取寫入String apkFilePath = context.getExternalFilesDir("apk").getAbsolutePath();File newFile = new File(apkFilePath + File.separator + "demo.apk");OutputStream os = null;try { os = new FileOutputStream(newFile); if (os != null) { os.write("file is created".getBytes(StandardCharsets.UTF_8)); os.flush(); }} catch (IOException e) {} finally { try { if (os != null) { os.close(); }catch (IOException e1) { }}3)創建共享目錄文件夾
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { ContentResolver resolver = context.getContentResolver(); ContentValues values = new ContentValues(); values.put(MediaStore.Downloads.DISPLAY_NAME, fileName); values.put(MediaStore.Downloads.DESCRIPTION, fileName); //設置文件類型 values.put(MediaStore.Downloads.MIME_TYPE, "application/vnd.android.package-archive"); //注意MediaStore.Downloads.RELATIVE_PATH需要targetVersion=29, //故該方法只可在Android10的手機上執行 values.put(MediaStore.Downloads.RELATIVE_PATH, "Download" + File.separator + "apk"); Uri external = MediaStore.Downloads.EXTERNAL_CONTENT_URI; Uri insertUri = resolver.insert(external, values); return insertUri;}else{ ...}4)在共享目錄指定文件夾下創建文件
主要是在公共目錄下創建文件或文件夾拿到本地路徑uri,不同的Uri,可以保存到不同的公共目錄中。接下來使用輸入輸出流就可以寫入文件。重點:AndroidQ中不支持file://類型訪問文件,只能通過uri方式訪問。/** * 創建圖片地址uri,用于保存拍照后的照片 Android 10以后使用這種方法 */private Uri createImageUri() { String status = Environment.getExternalStorageState(); // 判斷是否有SD卡,優先使用SD卡存儲,當沒有SD卡時使用手機存儲 if (status.equals(Environment.MEDIA_MOUNTED)) { return getContext().getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, new ContentValues()); } else { return getContext().getContentResolver().insert(MediaStore.Images.Media.INTERNAL_CONTENT_URI, new ContentValues()); }}5)通過MediaStore API讀取公共目錄下的文件
if (cursor != null && cursor.moveToFirst()) { do { ... int _id = cursor.getInt(cursor.getColumnIndex(MediaStore.Images.Media._ID)); Uri imageUri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, _id); ... } while (!cursor.isLast() && cursor.moveToNext());} else {...}// 通過uri獲取bitmappublic Bitmap getBitmapFromUri(Context context, Uri uri) { ParcelFileDescriptor parcelFileDescriptor = null; FileDescriptor fileDescriptor = null; Bitmap bitmap = null; try { parcelFileDescriptor = context.getContentResolver().openFileDescriptor(uri, "r"); if (parcelFileDescriptor != null && parcelFileDescriptor.getFileDescriptor() != null) { fileDescriptor = parcelFileDescriptor.getFileDescriptor(); //轉換uri為bitmap類型 bitmap = BitmapFactory.decodeFileDescriptor(fileDescriptor); } } catch (Exception e) { e.printStackTrace(); }finally { try { if (parcelFileDescriptor != null) { parcelFileDescriptor.close(); }catch (IOException e) { } } return bitmap;}6)使用MediaStore刪除文件context.getContentResolver().delete(fileUri, null, null);三、設備ID
從Android 10開始已經無法完全標識一個設備,曾經用mac地址、IMEI等設備信息標識設備的方法,從Android 10開始統統失效。而且無論你的APP是否適配過Android 10。3.1 IMEI等設備信息
從Android10開始普通應用不再允許請求權限android.permission.READ_PHONE_STATE。而且,無論你的App是否適配過Android Q(既targetSdkVersion是否大于等于29),均無法再獲取到設備IMEI等設備信息。受影響的API:Build.getSerial();TelephonyManager.getImei();TelephonyManager.getMeid()TelephonyManager.getDeviceId();TelephonyManager.getSubscriberId();TelephonyManager.getSimSerialNumber();targetSdkVersion<29 的應用,其在獲取設備ID時,會直接返回null
targetSdkVersion>=29 的應用,其在獲取設備ID時,會直接拋出異常SecurityException
3.3 如何標識設備唯一性
3.3.1 Google解決方案:如果您的應用有追蹤非登錄用戶的需求,可用ANDROID_ID來標識設備。
ANDROID_ID生成規則:簽名+設備信息+設備用戶
ANDROID_ID重置規則:設備恢復出廠設置時,ANDROID_ID將被重置
3.3.2 信通院統一SDK(OAID)
統一標識依據電信終端產業協會(TAF)、移動安全聯盟(MSA)聯合推 出的團體標準《移動智能終端補充設備標識規范》開發,移動智能終端補充設備標識體系統一調用 SDK 集成設備廠商提供的接口,并獲得主流設備廠商的授權。移動安全聯盟(MSA)組織中國信息通信研究院(以下簡稱“中國信通院”)與終端生產企業、互聯網企業共同研究制定了“移動智能終端補充設備標識體系”,定義了移動智能終端補充設備標識體系的體系架構、功能要求、接口要求以及安全要求,使設備生產企業統一開發接口,為移動應用開發者提供統一調用方式,方便移動應用接入,降低維護成本。1)SDK獲取
MSA 統一 SDK 下載地址:移動安全聯盟官網,http://www.msa-alliance.cn/2)接入方式
解壓miit_mdid_sdk_v1.0.13.rar,
把 miit_mdid_1.0.13.aar 拷貝到項目中,并設置依賴。
將 supplierconfig.json 拷貝到項目 assets 目錄下,并修改里邊對應 內容,特別是需要設置 appid 的部分。需要設置 appid 的部分需要去對應的廠 商的應用商店里注冊自己的 app。
在初始化方法中調用JLibrary.InitEntry
實例化MSA SDK
通過以上方法獲取到OAID等設備標識之后,即可作為唯一標識使用。
四、明文HTTP限制
當SDK版本大于API 28時,默認限制了HTTP請求,并出現相關日志“java.net.UnknownServiceException: CLEARTEXT communication to xxx not permitted by network security policy“。該問題有兩種解決方案:
1)在AndroidManifest.xml中Application節點添加如下代碼
2)在res目錄新建xml目錄,已建的跳過 在xml目錄新建一個xml文件network_security_config.xml,然后在AndroidManifest.xml中Application添加如下節點代碼。
android:networkSecurityConfig="@xml/network_config"network_config.xml(命名隨機)<?xml version="1.0" encoding="utf-8"?>五、展望
2020年2月20號,Google提前發布了Android 11預覽版,通過 5G、折疊屏、內置機器學習等新技術,照亮了移動設備的未來。Android 11 依然致力于讓用戶暢享最新科技,并始終確保將安全和隱私放在首位,幫助用戶管理敏感數據和文件的訪問權限。此外還對平臺的關鍵區域做出了強化,以保持操作系統的彈性和安全性。對于像Android這樣的開放性OS來說,占有的市場份額越大,整個Android生態系統的發展會越好。隨著Android對于碎片化的整理、用戶隱私和安全性的重視、5G和機器學習等新技術的引入,已逐步抓住快速增長的中產階級用戶,未來的市場份額增長量將是不可預估的。?參考文檔:
1、AndroidX 概覽https://developer.android.google.cn/jetpack/androidx2、Android 10介紹https://developer.android.com/about/versions/103、Android 11預覽版介紹https://developer.android.com/preview4、Android Q Adaptation Guidehttps://chinesefoodstudio.com/index.php/2019/11/21/android-q-adaptation-guide/5、Android 10分區存儲介紹及百度APP適配實踐https://segmentfault.com/a/1190000021760036【推薦搜索】如果你有寫博客的好習慣歡迎投稿點個在看,小生感恩??總結
以上是生活随笔為你收集整理的android gradle权威指南pdf_干货 | 携程 Android 10适配踩坑指南的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python while-Python天
- 下一篇: 一阶rc电路时间常数_波形产生电路中的R