安卓版本適配信息匯總,最后更新于2019年10月23日,持續(xù)收集中
-
1:安卓4.4 API-19
-
1.1:
READ_EXTERNAL_STORAGE讀取外置存儲(chǔ)權(quán)限強(qiáng)制檢查,此權(quán)限在低于4.4的版本默認(rèn)獲取。如果應(yīng)用只在內(nèi)部存儲(chǔ)數(shù)據(jù)或者如下特定目錄讀取/寫(xiě)入文件,則不需要WRITE_EXTERNAL_STORAGE或者READ_EXTERNAL_STORAGE權(quán)限。如果app沒(méi)有在別的地方讀寫(xiě)存儲(chǔ)但是minSdkVersion低于19,則可以在uses-permission標(biāo)簽內(nèi)加入android:maxSdkVersion適配:<uses-permission ... android:maxSdkVersion="18"/>。支持的文件位置如下:Context API 文件指向位置 備注 getExternalFilesDir(String)SD卡/Android/data/包名/String/ 非內(nèi)置存儲(chǔ) getExternalCacheDir()SD卡/Android/data/包名/cache/ 非內(nèi)置存儲(chǔ) getExternalMediaDirs()SD卡/Android/media/包名/ 非內(nèi)置存儲(chǔ) getDataDir()data/data/包名/ app內(nèi)置存儲(chǔ)根目錄 getDir(自定義dir,mode)data/data/包名/自定義dir/ 內(nèi)置存儲(chǔ)(api24開(kāi)始mode縮小限定范圍) getFilesDir()data/data/包名/files/ 內(nèi)置存儲(chǔ) getCacheDir()data/data/包名/cache/ 內(nèi)置存儲(chǔ) getPreferencesDir()data/data/包名/shared_prefs/ 內(nèi)置存儲(chǔ) getNoBackupFilesDir()data/data/包名/no_backup/ 內(nèi)置存儲(chǔ)(api21) getCodeCacheDir()data/data/包名/code_cache/ 內(nèi)置存儲(chǔ)(api21) getDatabasesDir()data/data/包名/databases/ 內(nèi)置存儲(chǔ)(api27) 1.2:應(yīng)用支持全屏模式,也就是常說(shuō)的 沉浸式
1.3:虛擬按鍵可隱藏,既然沉浸式底部導(dǎo)航欄跟著支持了,那就順路把相關(guān)控制API也暴露給開(kāi)發(fā)者
1.4:為了加強(qiáng)
WebView的功能,Google引入了Chromium內(nèi)核。但仍然還是存在 編輯的bug
-
-
2:安卓5.0 API-21
2.1:ART androidRunTime取代 Dalvik 成為平臺(tái)默認(rèn)設(shè)置,ART采用預(yù)先編譯技術(shù),改進(jìn)了垃圾回收機(jī)制與調(diào)試支持
2.2:
Material Design設(shè)計(jì)規(guī)范,編譯版本提升至至少21時(shí)才能方便使用Appcompat-V7RecyclerView-V7CardView-V7等框架,在UI上突出的變化還有SharedElementAnimationelevation等。2.3:提升用戶(hù)隱私的安全性,棄用
activityManager.getRecentTask()方法。對(duì)于向后兼容性,此方法仍會(huì)返回它的一小部分?jǐn)?shù)據(jù),包括應(yīng)用自己的任務(wù)和可能的一些其他非敏感任務(wù)(如首頁(yè))。如果你的應(yīng)用使用此方法檢索它自己的任務(wù),則改用getAppTasks檢索信息-
2.4:禁用隱式意圖啟動(dòng)服務(wù),運(yùn)行時(shí)會(huì)直接拋出
IllegalArgumentException異常Intent intent = new Intent();過(guò)時(shí)禁用 intent.setAction("com.example.myapplication"); startService(intent); 只能使用顯式意圖 Intent intent = new Intent("com.example.myapplication"); 2.5:
Notification模塊不支持設(shè)置了rgb通道的smallIcon,此bug 在后續(xù)版本已經(jīng)修復(fù),但是為了系統(tǒng)兼容性,建議開(kāi)發(fā)者在安卓5.0及以上設(shè)備上更換smallIcon以達(dá)到版本一致性2.6:WebView默認(rèn)會(huì)阻止混合內(nèi)容(https當(dāng)中不能加載http資源),要允許請(qǐng)調(diào)用
WebSettings#setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW)。
默認(rèn)阻止第三方 Cookie,要允許請(qǐng)調(diào)用CookieManager#setAcceptThirdPartyCookies(webView,true)。2.7:現(xiàn)在可以智能地選擇要繪制的 HTML 文檔部分。這個(gè)新的默認(rèn)行為有助于減少內(nèi)存占用和提升性能。如果您要一次渲染整個(gè)文檔,可通過(guò)調(diào)用
enableSlowWholeDocumentDraw()停用此優(yōu)化。2.8:自定義權(quán)限必須保證唯一,使用不同秘鑰簽名的應(yīng)用不能使用相同的自定義權(quán)限。如果用戶(hù)設(shè)備上存在一個(gè)應(yīng)用使用了相同的自定義權(quán)限,那么新的應(yīng)用將無(wú)法安裝
2.9:移除了對(duì)鎖定屏幕小部件的支持
2.10:新增
Intent.resolveActivity(*)對(duì)發(fā)起的意圖進(jìn)行設(shè)備匹配
-
3:安卓6.0 API-23
-
3.1:移除了
Apache的http支持包,如有需要手動(dòng)引入。android { useLibrary 'org.apache.http.legacy' } 3.2:廢棄:
FloatMath,Notification.setLastEventInfo()3.3:移除了對(duì)設(shè)備本地硬件標(biāo)識(shí)符的編程訪(fǎng)問(wèn)權(quán)。
WifiInfo.getMacAddress()方法和BluetoothAdapter.getAddress()方法現(xiàn)在會(huì)返回常量值02:00:00:00:00:00。如果需要通過(guò)藍(lán)牙和wifi掃描訪(fǎng)問(wèn)外部設(shè)備的硬件標(biāo)識(shí)符,應(yīng)用必須擁有ACCESS_FINE_LOCATION或ACCESS_COARSE_LOCATION權(quán)限。3.4:音頻管理器變更:不再支持通過(guò)
AudioManager類(lèi)直接設(shè)置音量或?qū)⑻囟ㄒ纛l流靜音。setStreamSolo()方法棄用,改為requestAudioFocus()方法。setStreamMute() 方法棄用,改為adjustStreamVolume()并傳入方向值ADJUST_MUTE/ ADJUST_UNMUTE。3.5:APK 驗(yàn)證更為嚴(yán)格。如果在清單中聲明的文件在 APK 中并不存在,該 APK 將被視為已損壞。移除任何內(nèi)容后必須重新簽署 APK。
-
3.6:運(yùn)行時(shí)權(quán)限管理,谷歌借鑒了蘋(píng)果 和國(guó)內(nèi)廠(chǎng)商的優(yōu)化經(jīng)驗(yàn),對(duì)應(yīng)用的權(quán)限不再一刀切,而是把相關(guān)權(quán)限分成了三組
- 特殊權(quán)限 每次冷啟動(dòng)APP都會(huì)重置狀態(tài),不建議應(yīng)用申請(qǐng)
權(quán)限名稱(chēng) 權(quán)限說(shuō)明 SYSTEM_ALERT_WINDOW設(shè)置懸浮窗,TYPE_SYSTEM_ALERT已失效 WRITE_SETTINGS修改系統(tǒng)設(shè)置 - 敏感權(quán)限 運(yùn)行時(shí)申請(qǐng),如果沒(méi)有適配會(huì)直接拋出異常,許可狀態(tài)會(huì)保存
權(quán)限組 權(quán)限名稱(chēng) 介紹 CALENDAR android.permission.READ_CALENDAR讀取系統(tǒng)日歷 android.permission.WRITE_CALENDAR寫(xiě)入系統(tǒng)日歷 CAMERA android.permission.CAMERA相機(jī)權(quán)限 CONTACTS android.permission.READ_CONTACTS讀取聯(lián)系人 android.permission.WRITE_CONTACTS寫(xiě)入聯(lián)系人 android.permission.GET_ACCOUNTS讀取賬號(hào) LOCATION android.permission.ACCESS_FINE_LOCATION獲取精準(zhǔn)位置 android.permission.ACCESS_COARSE_LOCATION獲取大概位置 MICROPHONE android.permission.RECORD_AUDIO錄音 PHONE android.permission.READ_PHONE_STATE獲取手機(jī)信息 android.permission.CALL_PHONE打電話(huà),不建議使用 android.permission.READ_CALL_LOG讀取通話(huà)記錄 android.permission.WRITE_CALL_LOG寫(xiě)入通話(huà)記錄 android.permission.PROCESS_OUTGOING_CALLS監(jiān)聽(tīng)、控制、取消呼出電話(huà)的權(quán)限 android.permission.USE_SIP使用sip(會(huì)話(huà)發(fā)起協(xié)議)網(wǎng)絡(luò)電話(huà) android.permission.ADD_VOICEMAIL添加系統(tǒng)中的語(yǔ)音郵件 SENSORS android.permission.BODY_SENSOR使用生命體征相關(guān)傳感器 SMS android.permission.SEND_SMS發(fā)送短信 android.permission.RECEIVE_SMS接收短信 android.permission.READ_SMS讀取短信 android.permission.RECEIVE_WAP_PUSH接收WapPush信息 android.permission.RECEIVE_MMS接收彩信 android.permission.READ_CELL_BROADCASTS不存在的權(quán)限 STORAGE android.permission.READ_EXTERNAL_STORAGE讀取存儲(chǔ) android.permission.WRITE_EXTERNAL_STORAGE寫(xiě)入存儲(chǔ) 運(yùn)行時(shí)權(quán)限共9組,同一組下如果有一個(gè)權(quán)限被允許,其它權(quán)限會(huì)自動(dòng)被允許。
開(kāi)發(fā)時(shí)應(yīng)減少申請(qǐng)權(quán)限的次數(shù),以避免交互被打斷。對(duì)于敏感權(quán)限可用intent來(lái)代替,讓其它應(yīng)用去處理
-
-
4:安卓7.0 API-24
4.1:應(yīng)用分屏,支持java8。通過(guò)
Context.getDir(name,mode)獲取存儲(chǔ)文件夾時(shí)不能再使用MODE_WORLD_READABLE和MODE_WORLD_WRITEABLE,與此相似的還有SharedPreference和DataBase。否則會(huì)拋出SecurityException4.2:
Notification.Builder通知消息可以通過(guò)setShowWhen()設(shè)置定時(shí)顯示4.3:刪除了三個(gè)常用隱式廣播 :
CONNECTIVITY_ACTION,ACTION_NEW_PICTURE,ACTION_NEW_VIDEO。因?yàn)檫@些廣播可能會(huì)一次喚醒多個(gè)應(yīng)用的后臺(tái)進(jìn)程,消耗內(nèi)存和電池4.4:優(yōu)化了
SurfaceView,使其在視頻播放和3D方面表現(xiàn)更優(yōu)于TextureView。4.5:APK signature scheme v2,android 7.0 新引入應(yīng)用簽名方案,它能提供更快的應(yīng)用安裝時(shí)間和更多針對(duì)未授權(quán) APK 文件更改的保護(hù)。
-
4.6:
StrictMode API政策禁止在您的應(yīng)用外部公開(kāi)file:// URI。如果啟動(dòng)一個(gè)包含文件 URI 的intent會(huì)拋出FileUriExposedException異常。受此影響的有拍照?qǐng)D片選擇,下載apk安裝等功能。要在應(yīng)用間共享文件,您應(yīng)發(fā)送一項(xiàng)content:// URI,并授予 URI 臨時(shí)訪(fǎng)問(wèn)權(quán)限。步驟如下:- 4.6.1:在AndroidManifest.xml中添加<provider>標(biāo)簽
<provider tools:replace="android:authorities"(如果使用的依賴(lài)module也存在provider則添加此tools) android:name="android.support.v4.content.FileProvider" android:authorities="替換為你的包名.fileProvider" android:grantUriPermissions="true" android:exported="false"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_provider_paths" /> </provider> - 4.6.2:在res/xml文件夾里面創(chuàng)建xml文件file_provider_paths.xml,文件名要和上方的
android:resource對(duì)應(yīng)值保持一致各個(gè)元素的定義可參考android.support.v4.content.FileProvider <?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <root-path name="root_path_name" path="test"/>"/" <files-path path="file_path_name" name="images"/>Context.getFilesDir() 示例位置 <cache-path name="cache_path_name" path="images" />Context.getCacheDir() <external-path name="external_path_name" path=" ." />Environment.getExternalStorageDirectory() <external-files-path name="external_file_path_name" path="images" />Context#getExternalFilesDir(String) <external-cache-path name="external_cache_path_name" path="images" /> <external-path name="external_path_name_01" path="Android/data/com.papa.auction/"/> <external-path name="external_path_name_02" path="."/> </paths>- 4.6.3:修改拍照intent示例:
Intent intentCamera = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); 判斷設(shè)備是否有應(yīng)用可以處理打開(kāi)相機(jī)intent if(intent.resolveActivity(context.getPackageManager()) != null){ Uri cameraUri; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); cameraUri = FileProvider.getUriForFile(context, context.getPackageName() + ".fileProvider", file); }else { cameraUri = Uri.fromFile(file); } intent.putExtra(MediaStore.EXTRA_OUTPUT, cameraUri); context.startActivityForResult(intent,requestCode); }- 4.6.4:修改安裝APK intent示例:
Intent installIntent = new Intent(Intent.ACTION_VIEW)); installIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 根據(jù)啟動(dòng)位置決定是否添加 Uri apkFileUri; if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N) { installIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); apkFileUri = FileProvider.getUriForFile(context, context.getPackageName() + ".fileProvider", apkFile); } else { apkFileUri = Uri.fromFile(apkFile); } installIntent.setDataAndType(apkFileUri, "application/vnd.android.package-archive"); context.startActivity(installIntent);
- 4.6.1:在AndroidManifest.xml中添加<provider>標(biāo)簽
-
4.7:加密庫(kù) Crypto廢棄 將密碼作為隨機(jī)數(shù)生成器的種子換算出密鑰 key這種做法已經(jīng)被認(rèn)定為是不安全的。相關(guān)的 Crypto provider 和 SHA1PRNG 算法同時(shí)廢棄掉了,并計(jì)劃在后續(xù)的 SDK 中完全移除相關(guān)的庫(kù),如下是官方給出的解決方案:
給出字符串的密碼 String password = "password"; 密鑰的比特位數(shù),注意這里是比特位數(shù) AES 支持 128、192 和 256 比特長(zhǎng)度的密鑰 int keyLength = 256; 鹽值的字節(jié)數(shù)組長(zhǎng)度,注意這里是字節(jié)數(shù)組的長(zhǎng)度 其長(zhǎng)度值需要和最終輸出的密鑰字節(jié)數(shù)組長(zhǎng)度一致 由于這里密鑰的長(zhǎng)度是 256 比特,則最終密鑰將以 256/8 = 32 位長(zhǎng)度的字節(jié)數(shù)組存在 所以鹽值的字節(jié)數(shù)組長(zhǎng)度也應(yīng)該是 32 int saltLength = 32; byte[] salt; 先獲取一個(gè)隨機(jī)的鹽值 你需要將此次生成的鹽值保存到磁盤(pán)上下次再?gòu)淖址畵Q算密鑰時(shí)傳入 如果鹽值不一致將導(dǎo)致?lián)Q算的密鑰值不同 保存密鑰的邏輯官方并沒(méi)寫(xiě),需要自行實(shí)現(xiàn) SecureRandom random = new SecureRandom(); byte[] salt = new byte[saltLength]; random.nextBytes(salt); 將密碼明文、鹽值等使用新的方法換算密鑰 int iterationCount = 1000; KeySpec keySpec = new PBEKeySpec(password.toCharArray(), salt,iterationCount, keyLength); SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1"); 到這里你就能拿到一個(gè)安全的密鑰了 byte[] keyBytes = keyFactory.generateSecret(keySpec).getEncoded(); SecretKey key = new SecretKeySpec(keyBytes, "AES");
-
5:安卓8.0 API-26 (8.1 API-27)
- 5.1:roundedIcon 自適應(yīng)圖標(biāo),在manifest文件中額外提供圓形應(yīng)用icon
<application android:name=".App" android:icon="@mipmap/ic_launcher" android:roundIcon="@mipmap/ic_launcher_round" ...... - 5.2:PHONE權(quán)限組新增兩個(gè)運(yùn)行時(shí)權(quán)限
-
ANSWER_PHONE_CALLS:允許接聽(tīng)呼入電話(huà)。在應(yīng)用中使用acceptRingingCall()函數(shù)處理呼入電話(huà)。 -
READ_PHONE_NUMBERS:允許應(yīng)用讀取設(shè)備中存儲(chǔ)的電話(huà)號(hào)碼。
-
- 5.3:安卓8.0中,Notification的通知渠道。用戶(hù)可以根據(jù)渠道來(lái)屏蔽一些不想要的通知
void setNotifyChannel(NotificationManager manager, NotificationCompat.Builder builder, String channeId, String channelName) { if (TextUtils.isEmpty(channeId)||TextUtils.isEmpty(channelName)){ L.e("NotifyCompat: ".concat("安卓8.0的通知兼容庫(kù)中 channeId 與 channelName 不能為empty")); } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { //第三個(gè)參數(shù)設(shè)置通知的優(yōu)先級(jí)別 NotificationChannel channel = new NotificationChannel(channeId, channelName, NotificationManager.IMPORTANCE_DEFAULT); channel.canBypassDnd();//是否可以繞過(guò)請(qǐng)勿打擾模式 channel.canShowBadge();//是否可以顯示icon角標(biāo) channel.enableLights(true);//是否顯示通知閃燈 channel.enableVibration(true);//收到小時(shí)時(shí)震動(dòng)提示 channel.setBypassDnd(true);//設(shè)置繞過(guò)免打擾 channel.setLockscreenVisibility(NotificationCompat.VISIBILITY_SECRET); channel.setLightColor(Color.RED);//設(shè)置閃光燈顏色 channel.getAudioAttributes();//獲取設(shè)置鈴聲設(shè)置 channel.setVibrationPattern(new long[]{100, 200, 100});//設(shè)置震動(dòng)模式 channel.shouldShowLights();//是否會(huì)閃光 if (manager != null) { manager.createNotificationChannel(channel); //manager 與channel關(guān)聯(lián) } if (builder != null) { builder.setChannelId(channeId);//Notification 與channel關(guān)聯(lián) } } } - 5.4:新增特殊權(quán)限:
android.permission.REQUEST_INSTALL_PACKAGES當(dāng)需要安裝未知來(lái)源應(yīng)用時(shí)使用,示例如下private void installAPK(){ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { boolean hasInstallPermission = getPackageManager().canRequestPackageInstalls(); if (hasInstallPermission) { 安裝應(yīng)用 } else { 提示用戶(hù)跳轉(zhuǎn)至“安裝未知應(yīng)用”權(quán)限界面,引導(dǎo)用戶(hù)開(kāi)啟權(quán)限 Uri selfPackageUri = Uri.parse("package:" + this.getPackageName()); Intent intent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES, selfPackageUri); startActivityForResult(intent, REQUEST_CODE_UNKNOWN_APP); } }else { 安裝應(yīng)用 } } - 5.6:SharedPreferences不能使用
MODE_WORLD_READABLE,請(qǐng)修改為MODE_PRIVATE - 5.6:新的廣播接收器限制導(dǎo)致靜態(tài)廣播無(wú)法正常接收,應(yīng)使用動(dòng)態(tài)廣播代替靜態(tài)廣播
- 5.7:
List.sort()的實(shí)現(xiàn)不能調(diào)用Collections.sort(),因?yàn)檫@會(huì)導(dǎo)致堆棧因無(wú)限遞歸而溢出 - 5.8:申請(qǐng)了
SYSTEM_ALERT_WINDOW權(quán)限的應(yīng)用需要在其他應(yīng)用和系統(tǒng)窗口上方顯示提醒窗口時(shí)只能使用TYPE_APPLICATION_OVERLAY類(lèi)型,之前的TYPE_PHONETYPE_PRIORITY_PHONETYPE_SYSTEM_ALERTTYPE_SYSTEM_OVERLAYTYPE_SYSTEM_ERROR不再生效。 - 5.9:在 Android 8.0 之前,如果應(yīng)用在運(yùn)行時(shí)請(qǐng)求權(quán)限并且被授予該權(quán)限,系統(tǒng)會(huì)將同一權(quán)限組且在Manifest中注冊(cè)的其他權(quán)限也一起授予應(yīng)用。此行為在8.0被糾正:系統(tǒng)只會(huì)授予應(yīng)用明確請(qǐng)求的權(quán)限。然而,一旦用戶(hù)為應(yīng)用授予某個(gè)權(quán)限,則所有后續(xù)對(duì)該權(quán)限組中權(quán)限的請(qǐng)求都將被自動(dòng)批準(zhǔn)。
- 5.10:
Only fullscreen opaque activities can request orientation,在Android 8.0上非全屏透明頁(yè)面不允許設(shè)置方向(8.1以上谷歌就修復(fù)去掉了這個(gè)限制)解決方案1:在manifest中去掉此Activity的
screenOrientation屬性
解決方案2:在此Activity的style里設(shè)置<item name="android:windowIsTranslucent">false</item>
解決方案3:使用Dialog/DialogFragment/Popwindow代替此Activity。
更多細(xì)節(jié)參閱:
https://developer.android.com/about/versions/oreo/android-8.0-changes#all-apps
https://developer.android.com/about/versions/oreo/android-8.1 - 5.1:roundedIcon 自適應(yīng)圖標(biāo),在manifest文件中額外提供圓形應(yīng)用icon
-
6:安卓9.0 API-28
-
6.1:限制明文流量的網(wǎng)絡(luò)請(qǐng)求,非加密的流量請(qǐng)求會(huì)被系統(tǒng)禁止掉
解決方案:在xml目錄新建文件network_security_config.xml<?xml version="1.0" encoding="utf-8"?> <network-security-config> <base-config cleartextTrafficPermitted="true" /> </network-security-config>在manifest清單文件application節(jié)點(diǎn)配置
android:networkSecurityConfig="@xml/network_security_config" 6.2:使用apacheHttp支持包時(shí)出現(xiàn)classNotFound 錯(cuò)誤,從 Android 9 開(kāi)始,Apache HTTP的支持內(nèi)容庫(kù)已從 bootclasspath 中移除,且默認(rèn)情況下應(yīng)用無(wú)法使用它。請(qǐng)?jiān)贛anifest文件的application節(jié)點(diǎn)中加入如下設(shè)置:
<uses-library android:name="org.apache.http.legacy" android:required="false" />-
6.3:
java.lang.IllegalArgumentException: Invalid Region.Op - only INTERSECT and DIFFERENCE are allowed
安卓9.0對(duì)canvas#clipPath()中的Region.Op做了限制只能使用INTERSECT或者DIFFERENCE。if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { canvas.clipPath(mPath); } else { canvas.clipPath(mPath, Region.Op.REPLACE); } 6.4:棄用 Bouncy Castle 加密。Android 9 棄用了幾個(gè)來(lái)自 Bouncy Castle 提供程序中的加密技術(shù),代之以由 Conscrypt 提供程序提供的加密技術(shù)。調(diào)用請(qǐng)求 Bouncy Castle 提供程序的 getInstance() 時(shí),會(huì)生成 NoSuchAlgorithmException 錯(cuò)誤。要解決這些錯(cuò)誤,請(qǐng)不要在 getInstance() 中指定提供程序(也就是請(qǐng)求默認(rèn)實(shí)現(xiàn))。
6.5:前臺(tái)服務(wù)權(quán)限。要使用前臺(tái)服務(wù)的應(yīng)用必須注冊(cè)普通權(quán)限 FOREGROUND_SERVICE。在未獲得此權(quán)限的情況下啟動(dòng)前臺(tái)服務(wù)將會(huì)引發(fā) SecurityException。
6.6:移除對(duì) Build.serial 的直接訪(fǎng)問(wèn)。使用Build.getSerial() 函數(shù)來(lái)替代 Build.serial獲取標(biāo)識(shí)符。應(yīng)用必須請(qǐng)求READ_PHONE_STATE 權(quán)限。
6.7:Detected problems with API 彈窗的解決:https://blog.csdn.net/codekxx/article/details/86507470#comments
更多細(xì)節(jié)參閱:https://developer.android.com/about/versions/pie
-
-
7:安卓10.0 API-29
- 7.1:TelephonyManager#getDeviceId(),需要申請(qǐng)READ_PRIVILEGED_PHONE_STATE權(quán)限,此權(quán)限只開(kāi)發(fā)給系統(tǒng)app,按照谷歌的建議如果不是做framework層app開(kāi)發(fā)就不要使用此api,普通app此處需要大量適配,因?yàn)槿街Ц额?lèi)統(tǒng)計(jì)類(lèi)支持包都會(huì)調(diào)用此api,如果不能全部更新就不要把target提升到29,否則會(huì)直接拋出SecurityException:
getDeviceId: The user 10104 does not meet the requirements to access device identifiers at android.os.Parcel.createException(Parcel.java:2071) at android.os.Parcel.readException(Parcel.java:2039) at android.os.Parcel.readException(Parcel.java:1987) at com.android.internal.telephony.ITelephony$Stub$Proxy.getDeviceId(ITelephony.java:10389)在安卓9.0時(shí)此方法已經(jīng)提示deprecated,建議開(kāi)發(fā)者用getImei()返回GSM網(wǎng)絡(luò)的IMEI,或者getMeid()返回CDMA網(wǎng)絡(luò)的MEID。
- 7.1:TelephonyManager#getDeviceId(),需要申請(qǐng)READ_PRIVILEGED_PHONE_STATE權(quán)限,此權(quán)限只開(kāi)發(fā)給系統(tǒng)app,按照谷歌的建議如果不是做framework層app開(kāi)發(fā)就不要使用此api,普通app此處需要大量適配,因?yàn)槿街Ц额?lèi)統(tǒng)計(jì)類(lèi)支持包都會(huì)調(diào)用此api,如果不能全部更新就不要把target提升到29,否則會(huì)直接拋出SecurityException: