<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Android 14 適配的那些事情

          共 9424字,需瀏覽 19分鐘

           ·

          2024-04-11 01:11

          7eae487e1b375fc8c286dfa088eb0409.webp

          作者:37 手游移動(dòng)客戶端團(tuán)隊(duì) 

          juejin.cn/post/7308434314777772042

          簡(jiǎn)介

          距離 Android 14 發(fā)布已經(jīng)有一段時(shí)間了,趁著這次機(jī)會(huì),了解和熟悉了 Android 14 更新的內(nèi)容,現(xiàn)在來(lái)和大家分享一下,大家喜歡的話可以點(diǎn)個(gè)贊多多支持一下,文章的內(nèi)容按照適配內(nèi)容的重要程度進(jìn)行排序。

          targetSdk 版本要求

          在 Android 14 上面,新增了一個(gè)要求,要求新安裝的應(yīng)用的 targetSdkVersion 需要大于等于 23(即 Android 6.0 及以上),如果小于這個(gè)值將無(wú)法在 Android 14 的設(shè)備上面安裝,此時(shí)大家心里可能有疑惑了,谷歌為什么要求那么做呢?我們來(lái)看看谷歌的原話是什么

          惡意軟件通常會(huì)以較舊的 API 級(jí)別為目標(biāo)平臺(tái), 以繞過(guò)在較新版本 Android 中引入的安全和隱私保護(hù)機(jī)制。例如,有些惡意軟件應(yīng)用使用 targetSdkVersion 22, 以避免受到 Android 6.0 Marshmallow(API 級(jí)別 23)在 2015 年引入的運(yùn)行時(shí)權(quán)限模型的約束。這項(xiàng) Android 14 變更使惡意軟件更難以規(guī)避安全和隱私權(quán)方面的改進(jìn)限制。

          從上面這段話不難看出來(lái)谷歌的用意,其實(shí)為了保障用戶的手機(jī)安全,如果用戶安裝應(yīng)用的 targetSdkVersion 版本過(guò)低,有一些惡意軟件會(huì)利用高系統(tǒng)會(huì)兼容舊軟件這一特性(漏洞),故意繞過(guò)系統(tǒng)的安全檢查,從而會(huì)導(dǎo)致 Android 高版本上面一些安全特性無(wú)法生效,沒有了系統(tǒng)的管束,這些惡意軟件可能就會(huì)肆意亂來(lái)。

          另外你如果想在 Android 14 系統(tǒng)上面,仍然要安裝 targetSdkVersion 小于 23 的應(yīng)用,可以通過(guò)以下 adb 命令來(lái)安裝 apk,這樣就能繞過(guò)系統(tǒng)的安裝限制。

                
                adb install --bypass-low-target-sdk-block xxx.apk

          前臺(tái)服務(wù)類型要求

          如果你的應(yīng)用 targetSdkVersion 升級(jí)到了 34(即 Android 14),并且在 Service 中調(diào)用了 startForeground 方法,那么就需要進(jìn)行適配了,否則系統(tǒng)會(huì)拋出 MissingForegroundServiceTypeException 異常,這是因?yàn)樵?Android 14 上面,要求應(yīng)用在開啟前臺(tái)服務(wù)的時(shí)候,需要注明這個(gè)前臺(tái)服務(wù)的用途,谷歌給我們列舉了以下幾種用途:

          用途 說(shuō)明 清單文件權(quán)限要求 運(yùn)行時(shí)要求
          攝像頭 繼續(xù)在后臺(tái)訪問相機(jī),例如支持多任務(wù)的視頻聊天應(yīng)用 FOREGROUND_SERVICE_CAMERA 請(qǐng)求 CAMERA 運(yùn)行時(shí)權(quán)限
          連接的設(shè)備 與需要藍(lán)牙、NFC、IR、USB 或網(wǎng)絡(luò)連接的外部設(shè)備進(jìn)行互動(dòng) FOREGROUND_SERVICE_CONNECTED_DEVICE 必須至少滿足以下其中一個(gè)條件:在清單中至少聲明以下其中一項(xiàng)權(quán)限:CHANGE_NETWORK_STATE CHANGE_WIFI_STATE CHANGE_WIFI_MULTICAST_STATE NFC TRANSMIT_IR 至少請(qǐng)求以下其中一項(xiàng)運(yùn)行時(shí)權(quán)限:BLUETOOTH_CONNECT BLUETOOTH_ADVERTISE BLUETOOTH_SCAN UWB_RANGING 調(diào)用 UsbManager.requestPermission()
          數(shù)據(jù)同步 數(shù)據(jù)傳輸操作,例如:數(shù)據(jù)上傳或下載 備份和恢復(fù)操作 導(dǎo)入或?qū)С霾僮?獲取數(shù)據(jù) 本地文件處理 通過(guò)網(wǎng)絡(luò)在設(shè)備和云端之間傳輸數(shù)據(jù) FOREGROUND_SERVICE_DATA_SYNC 無(wú)
          健康 為健身類別的應(yīng)用(例如鍛煉追蹤器)提供支持的所有長(zhǎng)時(shí)間運(yùn)行的用例 FOREGROUND_SERVICE_HEALTH 必須至少滿足以下其中一個(gè)條件:在清單中聲明 HIGH_SAMPLING_RATE_SENSORS 權(quán)限。至少請(qǐng)求以下其中一項(xiàng)運(yùn)行時(shí)權(quán)限:BODY_SENSORS ACTIVITY_RECOGNITION
          位置 需要位置信息使用權(quán)的長(zhǎng)時(shí)間運(yùn)行的用例, 例如導(dǎo)航和位置信息分享 FOREGROUND_SERVICE_LOCATION 至少請(qǐng)求以下其中一項(xiàng)運(yùn)行時(shí)權(quán)限:ACCESS_COARSE_LOCATION ACCESS_FINE_LOCATION
          媒體 在后臺(tái)繼續(xù)播放音頻或視頻。在 Android TV 上支持?jǐn)?shù)字視頻錄制 (DVR) 功能。 FOREGROUND_SERVICE_MEDIA_PLAYBACK
          媒體投影 使用 MediaProjection API 將內(nèi)容投影到非主要顯示屏或外部設(shè)備。這些內(nèi)容不必全都為媒體內(nèi)容。不包括 Cast SDK FOREGROUND_SERVICE_MEDIA_PROJECTION 調(diào)用 createScreenCaptureIntent() 方法。無(wú)
          麥克風(fēng) 在后臺(tái)繼續(xù)捕獲麥克風(fēng)內(nèi)容,例如錄音器或通信應(yīng)用 FOREGROUND_SERVICE_MICROPHONE 請(qǐng)求 RECORD_AUDIO 運(yùn)行時(shí)權(quán)限
          打電話 使用 ConnectionService API 繼續(xù)當(dāng)前通話 FOREGROUND_SERVICE_PHONE_CALL 在清單文件中聲明 MANAGE_OWN_CALLS 權(quán)限。
          消息服務(wù) 將短信從一臺(tái)設(shè)備轉(zhuǎn)移到另一臺(tái)設(shè)備。在用戶切換設(shè)備時(shí),幫助確保用戶消息任務(wù)的連續(xù)性 FOREGROUND_SERVICE_REMOTE_MESSAGING 無(wú)
          短期服務(wù) 快速完成不可中斷或推遲的關(guān)鍵工作。這種類型有一些獨(dú)特的特征:只能持續(xù)運(yùn)行一小段時(shí)間(大約 3 分鐘)。不支持粘性前臺(tái)服務(wù)。無(wú)法啟動(dòng)其他前臺(tái)服務(wù)。不需要類型專用權(quán)限,不過(guò)它仍需要 FOREGROUND_SERVICE 權(quán)限。正在運(yùn)行的前臺(tái)服務(wù)不能更改為 shortService 類型或從該類型更改為其他類型。 無(wú) 無(wú)
          特殊用途 涵蓋其他前臺(tái)服務(wù)類型未涵蓋的所有有效前臺(tái)服務(wù)用例。除了聲明 FOREGROUND_SERVICE_TYPE_SPECIAL_USE 前臺(tái)服務(wù)類型之外,開發(fā)者還應(yīng)在清單中聲明用例。為此,他們會(huì)在 `` 元素內(nèi)指定 <property> 元素。當(dāng)您在 Google Play 管理中心內(nèi)提交應(yīng)用時(shí),我們會(huì)審核這些值和相應(yīng)的用例。 FOREGROUND_SERVICE_SPECIAL_USE 無(wú)
          系統(tǒng)豁免 為系統(tǒng)應(yīng)用和特定系統(tǒng)集成預(yù)留, 使其能繼續(xù)使用前臺(tái)服務(wù)。如需使用此類型,應(yīng)用必須至少滿足以下條件之一:設(shè)備處于演示模式狀態(tài) 應(yīng)用是設(shè)備所有者 應(yīng)用是性能分析器所有者 屬于具有 ROLE_EMERGENCY 角色的安全應(yīng)用 屬于設(shè)備管理應(yīng)用 否則,聲明此類型會(huì)導(dǎo)致系統(tǒng)拋出 ForegroundServiceTypeNotAllowedException FOREGROUND_SERVICE_SYSTEM_EXEMPTED 無(wú)

          介紹完這幾種前臺(tái)服務(wù)類型,接下來(lái)介紹如何適配它,適配前臺(tái)服務(wù)類型的特性方式具體有兩種方式,一種是注冊(cè)清單屬性,另外一種是代碼動(dòng)態(tài)注冊(cè)

                
                <service
            android:name=".XxxService"
            android:foregroundServiceType="dataSync"
            android:exported="false">

          </service>
          java
          startForeground(xxx, xxx, ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC);

          另外附上前臺(tái)服務(wù)類型對(duì)應(yīng)的適配屬性

          用途 清單文件屬性值 Java 常量值
          攝像頭 camera ServiceInfo.FOREGROUND_SERVICE_TYPE_CAMERA
          連接的設(shè)備 connectedDevice ServiceInfo.FOREGROUND_SERVICE_TYPE_CONNECTED_DEVICE
          數(shù)據(jù)同步 dataSync ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC
          健康 health ServiceInfo.FOREGROUND_SERVICE_TYPE_HEALTH
          位置 location ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION
          媒體 mediaPlayback ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK
          媒體投影 mediaProjection ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION
          麥克風(fēng) microphone ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE
          打電話 phoneCall ServiceInfo.FOREGROUND_SERVICE_TYPE_PHONE_CALL
          消息服務(wù) remoteMessaging ServiceInfo.FOREGROUND_SERVICE_TYPE_REMOTE_MESSAGING
          短期服務(wù) shortService ServiceInfo.FOREGROUND_SERVICE_TYPE_SHORT_SERVICE
          特殊用途 specialUse ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE
          系統(tǒng)豁免 systemExempted ServiceInfo.FOREGROUND_SERVICE_TYPE_SYSTEM_EXEMPTED

          圖片和視頻的部分訪問權(quán)限

          谷歌在 API 33(Android 13)上面引入了 READ_MEDIA_IMAGESREAD_MEDIA_VIDEO 這兩個(gè)權(quán)限,目前針對(duì)這兩個(gè)權(quán)限在 Android 14 上面有新的變動(dòng),具體的變動(dòng)點(diǎn)就是新增了 READ_MEDIA_VISUAL_USER_SELECTED 權(quán)限,那么這個(gè)權(quán)限的作用是什么呢?我們都知道 READ_MEDIA_IMAGESREAD_MEDIA_VIDEO 是申請(qǐng)圖片和視頻權(quán)限的,但是這樣會(huì)有一個(gè)問題,當(dāng)?shù)谌綉?yīng)用申請(qǐng)到權(quán)限后,就擁有了手機(jī)相冊(cè)中所有照片和視頻的訪問權(quán)限,這是十分危險(xiǎn)的,也是非常不可控的,因?yàn)橛脩粢矡o(wú)法知道第三方應(yīng)用會(huì)干什么,所以谷歌在 API 34(Android 14)引入了這個(gè)權(quán)限,這樣用戶擁有了更多的選擇,可以將相冊(cè)中所有的圖片和視頻授予給第三方應(yīng)用,也可以將部分的圖片和視頻給第三方應(yīng)用。

          講完了這個(gè)特性的來(lái)龍去脈,那么接下來(lái)講講這個(gè)權(quán)限如何適配,如果你的應(yīng)用申請(qǐng)了 READ_MEDIA_IMAGES 或者 READ_MEDIA_VIDEO 權(quán)限,并且 targetSdkVersion 大于等于 33(Android 13),那么需要在申請(qǐng)權(quán)限時(shí)攜帶上 READ_MEDIA_VISUAL_USER_SELECTED 權(quán)限方能正常申請(qǐng),如果不攜帶上 READ_MEDIA_VISUAL_USER_SELECTED 權(quán)限就申請(qǐng) READ_MEDIA_IMAGES 或者 READ_MEDIA_VIDEO 權(quán)限,會(huì)彈出權(quán)限詢問對(duì)話框,但是如果用戶是選擇全部授予,那么 READ_MEDIA_IMAGES 或者 READ_MEDIA_VIDEO 權(quán)限狀態(tài)是已授予的狀態(tài),如果用戶是選擇部分授予,那么 READ_MEDIA_IMAGES 或者 READ_MEDIA_VIDEO 權(quán)限狀態(tài)是已拒絕的狀態(tài),假設(shè)此時(shí)有攜帶了 READ_MEDIA_VISUAL_USER_SELECTED 權(quán)限的情況下,那么 READ_MEDIA_VISUAL_USER_SELECTED 權(quán)限是已授予的狀態(tài)。

          看到這里,腦洞大的同學(xué)可能有想法了,那我不申請(qǐng) READ_MEDIA_IMAGES 或者 READ_MEDIA_VIDEO 權(quán)限,我就只申請(qǐng) READ_MEDIA_VISUAL_USER_SELECTED 權(quán)限行不行啊?答案也是不行的,我替大家試驗(yàn)過(guò)了,這個(gè)權(quán)限申請(qǐng)會(huì)在不會(huì)詢問用戶的情況下,被系統(tǒng)直接拒絕掉。

          另外需要的一點(diǎn)是 READ_MEDIA_VISUAL_USER_SELECTED 屬于危險(xiǎn)權(quán)限,除了在運(yùn)行時(shí)動(dòng)態(tài)申請(qǐng)外,還需要在清單文件中進(jìn)行注冊(cè)。

          registerReceiver 需要指定導(dǎo)出行為

          谷歌在 Android 12 (API 31)新增了四大組件需要指定 android:exported 屬性的特性,這次在 Android 13 上面做了一些變動(dòng),因?yàn)楣雀柚爸豢紤]到靜態(tài)注冊(cè)四大組件的情況,但是遺漏了一種情況,BroadcastReceiver 不僅可以靜態(tài)注冊(cè),還可以動(dòng)態(tài)注冊(cè),動(dòng)態(tài)注冊(cè)的廣播不需要額外在 AndroidManifest.xml 中再進(jìn)行靜態(tài)注冊(cè),所以這次谷歌將這個(gè)規(guī)則漏洞補(bǔ)上了,并且要求開發(fā)者在動(dòng)態(tài)注冊(cè)廣播的時(shí)候,能夠指定 BroadcastReceiver 是否能支持導(dǎo)出,由此來(lái)保護(hù)應(yīng)用免受安全漏洞的影響。

          到此,大家心中可能有一個(gè)疑惑,這里的支持導(dǎo)出是什么意思?有產(chǎn)生什么作用?可以先看一下谷歌官方的原話

          為了幫助提高運(yùn)行時(shí)接收器的安全性,Android 13 允許您指定您應(yīng)用中的特定廣播接收器是否應(yīng)被導(dǎo)出以及是否對(duì)設(shè)備上的其他應(yīng)用可見。如果導(dǎo)出廣播接收器,其他應(yīng)用將可以向您的應(yīng)用發(fā)送不受保護(hù)的廣播。此導(dǎo)出配置在以 Android 13 或更高版本為目標(biāo)平臺(tái)的應(yīng)用中可用,有助于防止一個(gè)主要的應(yīng)用漏洞來(lái)源。

          在以前的 Android 版本中,設(shè)備上的任何應(yīng)用都可以向動(dòng)態(tài)注冊(cè)的接收器發(fā)送不受保護(hù)的廣播,除非該接收器受簽名權(quán)限的保護(hù)。

          谷歌的解釋很明了,如果廣播支持導(dǎo)出,那么其他應(yīng)用可以通過(guò)發(fā)送這個(gè)廣播觸發(fā)我們應(yīng)用的邏輯,這可能會(huì)發(fā)生程序安全漏洞的問題。

          那么該如何適配這一特性呢?谷歌官方提供了一個(gè) registerReceiver(BroadcastReceiver receiver, IntentFilter filter, int flags) API,flags 參數(shù)傳入 Context.RECEIVER_EXPORTED(支持導(dǎo)出) 或 Context.RECEIVER_NOT_EXPORTED(不支持導(dǎo)出),具體的代碼適配代碼如下:

                
                String action = "xxxxxx";
          IntentFilter filter = new IntentFilter(action);
          if (VERSION.SDK_INT >= VERSION_CODES.TIRAMISU) {
              context.registerReceiver(new LocaleChangeReceiver(), filter, Context.RECEIVER_EXPORTED);
          else {
              context.registerReceiver(new LocaleChangeReceiver(), filter);
          }

          還有一種情況,不需要指定 flag 參數(shù),就是當(dāng)要注冊(cè)的廣播 action 隸屬系統(tǒng)的 action 時(shí)候,這個(gè)時(shí)候可以不需要指定導(dǎo)出行為。

          更安全的動(dòng)態(tài)代碼加載

          如果我們應(yīng)用有動(dòng)態(tài)加載代碼的需求,并且此時(shí) targetSdk 升級(jí)到了 API 34(即 Android 14),那么需要注意一個(gè)點(diǎn),動(dòng)態(tài)加載的文件(Jar、Dex、Apk 格式)需要設(shè)置成只讀的,具體案例的代碼如下:

                
                ini
          File jar = new File("xxxx.jar");
          try (FileOutputStream os = new FileOutputStream(jar)) {
          jar.setReadOnly();
          } catch (IOException e) { ... }
          PathClassLoader cl = new PathClassLoader(jar, parentClassLoader);

          至于谷歌這樣做的原因,我覺得十分簡(jiǎn)單,是為了程序的安全,防止有人搶先在動(dòng)態(tài)加載之前先把動(dòng)態(tài)文件替換了,那么會(huì)導(dǎo)致執(zhí)行到一些惡意的代碼,間接導(dǎo)致應(yīng)用被入侵或者篡改。

          另外需要注意的一個(gè)點(diǎn)的是,如果你的應(yīng)用 targetSdk 大于等于 API 34(即 Android 14),如果不去適配這一特性,那么運(yùn)行在 Android 14 的手機(jī)上面系統(tǒng)會(huì)拋出異常。

          屏幕截圖檢測(cè)

          Android 14 新增引入了屏幕截圖檢測(cè)的 API,方便開發(fā)者更好地檢測(cè)到用戶的操作,具體的使用案例如下:

          在清單文件中靜態(tài)注冊(cè)權(quán)限

                
                
                  <uses-permission android:name="android.permission.DETECT_SCREEN_CAPTURE" />
                  

          創(chuàng)建監(jiān)聽器對(duì)象

                
                final Activity.ScreenCaptureCallback screenCaptureCallback = new Activity.ScreenCaptureCallback() {

              @Override
              public void onScreenCaptured() {
                  // 監(jiān)聽到截圖了
              }
          };

          在合適的時(shí)機(jī)注冊(cè)監(jiān)聽

                
                public final class XxxActivity extends Activity {

              @Override
              protected void onStart() {
                  super.onStart();
                  registerScreenCaptureCallback(executor, screenCaptureCallback);
              }
          }

          需要注意的是,如果使用的是 adb 進(jìn)行的截圖,并不會(huì)觸發(fā) onScreenCaptured 監(jiān)聽方法。

          如果不想你的應(yīng)用能被系統(tǒng)截圖,可以考慮給當(dāng)前的 Window 窗口加上 WindowManager.LayoutParams.FLAG_SECURE 標(biāo)記位。

          最后表達(dá)一下我對(duì)這個(gè) API 看法,這個(gè) API 設(shè)計(jì)得不是很好,比如應(yīng)用想知道用戶是否截圖了,應(yīng)用可能需要知道的是,截圖文件的存放路徑,但是 onScreenCaptured 是一個(gè)空參函數(shù),也就意味著沒有攜帶任何參數(shù),如果要實(shí)現(xiàn)獲取截圖文件存放路徑的需求,可能還需要沿用之前的老方式,即使用 ContentObserver 監(jiān)聽媒體數(shù)據(jù)庫(kù)的變化,然后從幾個(gè)維度(文件時(shí)間維度、文件路徑維度、圖片尺寸維度)判斷新增的圖片是否為用戶的截圖,這種實(shí)現(xiàn)的方式相對(duì)是比較麻煩的,但是也無(wú)發(fā)現(xiàn)更好的實(shí)現(xiàn)方式。

          瀏覽 39
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  美女靠逼在线观看 | 亚州欧美日韩 | 美女高潮喷水影院 | 亚洲精品在线无码观看 | AV在线影音 |