安卓各編譯版本差異匯總(安卓10.0收集...)

安卓版本適配信息匯總,最后更新于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-V7 RecyclerView-V7 CardView-V7等框架,在UI上突出的變化還有 SharedElementAnimation elevation等。

    • 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:移除了Apachehttp支持包,如有需要手動(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_LOCATIONACCESS_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)限名稱(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_READABLEMODE_WORLD_WRITEABLE,與此相似的還有SharedPreferenceDataBase。否則會(huì)拋出SecurityException

    • 4.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.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_PHONE TYPE_PRIORITY_PHONE TYPE_SYSTEM_ALERT TYPE_SYSTEM_OVERLAY TYPE_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


  • 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。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容