前言
一年一年過的太快了咆畏,還記得兩年前寫了 Android 11(R) 的適配文章,這一轉(zhuǎn)眼都13(T)了吴裤,這樣算下去幾年后26個字母就用完了旧找,到時候也不知道 Google 會如何進行命名??。
下面咱們來看看 Android 13 都有哪些更新麦牺,并來看看開發(fā)者應該如何進行適配吧钮蛛!
隱私及權(quán)限相關(guān)
通知的運行時權(quán)限
在之前版本中我們應用如果需要彈通知的話只需要通過 NotificationManager
即可直接進行彈出鞭缭,不需要任何權(quán)限,之前我一直覺得 Google 官方這一點做的不好魏颓,通知這么重要竟然不需要用戶同意就可以直接彈出岭辣,當然你可以在設置中進行手動關(guān)閉,但這對于大多數(shù)人來說比較困難甸饱。然后在 Android 13(T-33)中終于引入了新的運行時權(quán)限——通知權(quán)限:POST_NOTIFICATIONS
沦童。
但是如果用戶拒絕通知權(quán)限,他們?nèi)詴谇芭_服務 (FGS) 任務管理器中看到與這些前臺服務相關(guān)的通知叹话,但不會在抽屜式通知欄中看到這些通知偷遗。
這個更改對許多應用都有關(guān)系,只要你的應用會彈通知驼壶,那么如果要適配 Android 13 的話就都需要進行適配鹦肿,當然適配方法很簡單,再按照別的運行時權(quán)限適配下新的通知權(quán)限即可辅柴。
檢查應用能否發(fā)送通知
如果想要確認用戶是否已啟用通知箩溃,可以調(diào)用 NotificationManager.areNotificationsEnabled()
來進行判斷。
附近 Wi-Fi 設備的新運行時權(quán)限
在以前的 Android 版本中碌嘀,需要 ACCESS_FINE_LOCATION
權(quán)限涣旨,應用才能完成與熱點相關(guān)的多個常見 Wi-Fi 用例、Wi-Fi 直連股冗、Wi-Fi RTT 等霹陡。
由于用戶很難將位置信息權(quán)限與 Wi-Fi 功能相關(guān)聯(lián),因此 Android 13(T-33)在 NEARBY_DEVICES
權(quán)限組中引入了新的運行時權(quán)限止状,適用于管理設備與附近 Wi-Fi 接入點連接情況的應用烹棉。此權(quán)限 (NEARBY_WIFI_DEVICES
) 可滿足這些 Wi-Fi 用例。
只要應用不通過 Wi-Fi API 推導物理位置怯疤,那么在 Android 13 或更高版本為目標平臺并使用 Wi-Fi API 的時候就可以請求 NEARBY_WIFI_DEVICES
而不是 ACCESS_FINE_LOCATION
浆洗。
細化的媒體權(quán)限
如果要將應用升級為 Android 13 ,必須請求一個或多個新權(quán)限集峦,Android 13 中將媒體權(quán)限細分為了圖片伏社、視頻和音頻文件,而不是之前的 READ_EXTERNAL_STORAGE
和 WRITE_EXTERNAL_STORAGE
權(quán)限塔淤。請求的權(quán)限集取決于應用需要訪問的媒體類型摘昌,如下圖所示:
[圖片上傳失敗...(image-4133e6-1657527105953)]
注意:如果應用只需要訪問圖片、照片和視頻高蜂,應該考慮使用照片選擇器(下面會介紹)聪黎,而不是聲明 READ_MEDIA_IMAGES
和 READ_MEDIA_VIDEO
權(quán)限,還有备恤,申請了最新的三個權(quán)限的話應用就無需再聲明 WRITE_EXTERNAL_STORAGE
權(quán)限了稿饰。
下面來看下在 AndroidManifest.xml 中應該如何進行修改:
<manifest ...>
<!-- Android 13 -->
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
<!-- Required to maintain app compatibility. -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
android:maxSdkVersion="32" />
<application ...>
...
</application>
</manifest>
精確鬧鐘的新權(quán)限
如果升級到 Android 13 锦秒,可以使用自動授予應用的 USE_EXACT_ALARM
權(quán)限。不過湘纵,一般是系統(tǒng)應用才可以使用脂崔,因為即將推出的 Google Play 政策會阻止應用使用 USE_EXACT_ALARM
權(quán)限滤淳,除非應用為日歷或者時鐘這樣的系統(tǒng)應用(國內(nèi)另說)梧喷。
如果應用設置了精確鬧鐘,但又不是系統(tǒng)日歷或時鐘的話脖咐,還是繼續(xù)聲明 SCHEDULE_EXACT_ALARM
權(quán)限铺敌,并要為用戶拒絕授予應用相應訪問權(quán)限的情況做好準備。
開發(fā)者可降級權(quán)限
從 Android 13 開始屁擅,應用可以撤消先前由系統(tǒng)或用戶授予的運行時權(quán)限偿凭。開發(fā)者可以:
- 撤消未使用的權(quán)限。
- 遵循權(quán)限最佳做法派歌,從而提高用戶信任度弯囊。可以向用戶顯示一個對話框胶果,其中會顯示應用主動撤消的權(quán)限匾嘱。
如需撤消特定運行時權(quán)限,請將該權(quán)限的名稱傳入 revokeSelfPermissionOnKill()
早抠。如需同時撤消一組運行時權(quán)限霎烙,請將這組權(quán)限的名稱傳入 revokeSelfPermissionsOnKill()
。撤消是異步發(fā)生的蕊连,會終止與應用的 UID 相關(guān)聯(lián)的所有進程悬垃。
為了使系統(tǒng)撤消權(quán)限,必須終止與應用關(guān)聯(lián)的所有進程甘苍。當調(diào)用該 API 時尝蠕,系統(tǒng)會確定何時可以安全終止這些進程。通常载庭,系統(tǒng)會等待應用有較長時間在后臺運行趟佃,而不是在前臺運行時。
但如果為了立即撤消權(quán)限昧捷,那么就需要手動終止所有相關(guān)進程闲昭,但用戶體驗嘛,讓產(chǎn)品自己取舍吧靡挥。
后臺使用身體傳感器新的權(quán)限
Android 13 中引入了“在使用時”訪問身體傳感器(例如心率笙瑟、體溫和血氧飽和度)的概念咨油,如果要升級為 Android 13,并且在后臺運行時需要訪問身體傳感器信息笆豁,那么除了現(xiàn)有的 BODY_SENSORS
權(quán)限外,還必須聲明新的 BODY_SENSORS_BACKGROUND
權(quán)限锯七。
如何申請運行時權(quán)限
想了下這塊還是寫的詳細一些吧。Android 從 Android 6(M-23) 開始引入了運行時權(quán)限這個概念(所有權(quán)限列表),但是剛出來的時候編寫比較費勁舷手,于是乎就出現(xiàn)了一堆三方的權(quán)限庫以簡便申請權(quán)限的流程,這里就不一一進行列舉了劲绪,相信大家也都知道或使用過男窟,但現(xiàn)在官方對申請權(quán)限這塊的代碼進行了重寫,使用起來并不比那些三方庫復雜贾富,甚至更加簡單歉眷,下面來看下使用方法吧:
申請單個權(quán)限
val requestPermissionLauncher =
registerForActivityResult(
ActivityResultContracts.RequestPermission()
) { isGranted: Boolean ->
if (isGranted) {
// 同意
} else {
// 拒絕
}
}
when {
ContextCompat.checkSelfPermission(
this,
Manifest.permission.CAMERA
) == PackageManager.PERMISSION_GRANTED -> {
// 當前擁有這個權(quán)限
}
shouldShowRequestPermissionRationale(Manifest.permission.CAMERA) -> {
// 告訴用戶為啥要申請這個權(quán)限
}
else -> {
// 申請權(quán)限
requestPermissionLauncher.launch(
Manifest.permission.CAMERA
)
}
}
代碼比較容易理解,官方新封裝的權(quán)限申請代碼還是挺好的颤枪,無需咱們再自己處理 onRequestPermissionsResult 中的回調(diào)信息汗捡。
申請多個權(quán)限
val requestPermissionsLauncher =
registerForActivityResult(
ActivityResultContracts.RequestMultiplePermissions()
) {
it.forEach { (name, success) ->
if (success) {
// 同意
} else {
// 拒絕
}
}
}
when {
// ...
// 這塊和上面基本一致
else -> {
// 申請多個權(quán)限,數(shù)組展示
requestPermissionsLauncher.launch(
arrayOf(Manifest.permission.CAMERA)
)
}
}
這塊和上面申請單個權(quán)限的使用方法基本一致畏纲,只是將單個權(quán)限改為了多個權(quán)限扇住。
剪貼板中隱藏敏感內(nèi)容
從 Android 13 開始,將內(nèi)容添加到剪貼板時盗胀,系統(tǒng)會顯示標準視覺確認界面艘蹋。新確認界面會執(zhí)行以下操作:
- 確認內(nèi)容已成功復制。
- 提供所復制內(nèi)容的預覽读整。
在 Android 12L(32)及更低版本中簿训,用戶經(jīng)常不確定他們是否成功復制了內(nèi)容或者復制了什么內(nèi)容。
此功能可將應用在用戶復制內(nèi)容后顯示的各種通知標準化米间,并讓用戶可以更好地控制剪貼板强品。
如果應用允許用戶將敏感內(nèi)容(例如密碼或信用卡信息)復制到剪貼板,則必須在調(diào)用 ClipboardManager.setPrimaryClip()
之前向 ClipData 的 ClipDescription
添加一個標志屈糊。添加此標志可阻止敏感內(nèi)容出現(xiàn)在內(nèi)容預覽中的榛。
val clipboardManager = getSystemService(CLIPBOARD_SERVICE) as ClipboardManager
// When your app targets API level 33 or higher
clipData.apply {
description.extras = PersistableBundle().apply {
putBoolean(ClipDescription.EXTRA_IS_SENSITIVE, true)
}
}
// If your app targets a lower API level
clipData.apply {
description.extras = PersistableBundle().apply {
putBoolean("android.content.extra.IS_SENSITIVE", true)
}
}
預測性返回手勢
這個功能怎么說呢,蘋果已經(jīng)有的功能逻锐,由于現(xiàn)在 Android 13 還沒有正式版夫晌,這個功能還不能進行測試,先來看看官方給的樣子吧:
[圖片上傳失敗...(image-4f70bb-1657527105954)]
是不是和蘋果的很像昧诱。晓淀。。盏档。
如需選擇啟用預測性返回手勢凶掰,請在 AndroidManifest.xml
的 <application>
標記中將 android:enableOnBackInvokedCallback
標志設置為 true
。
<application
...
android:enableOnBackInvokedCallback="true"
... >
...
</application>
enableOnBackInvokedCallback
默認值為 false
,表示停用預測性返回手勢懦窘。
照片選擇器
Android 13(T-33)支持新的照片選擇器工具前翎。此工具為用戶提供了一種安全的內(nèi)置媒體文件選擇方式,讓其無需向應用授予對整個媒體庫的訪問權(quán)限畅涂。
[圖片上傳失敗...(image-c154ad-1657527105954)]
照片選擇器提供了一個可瀏覽港华、可搜索的界面,其中按日期(從最近到最早)順序向用戶呈現(xiàn)其媒體庫中的文件午衰×⒁耍可以指定用戶只能看到照片或只能看到視頻,并且默認情況下苇经,允許的媒體選擇量上限設置為 1赘理。
定義分享限制
應用可以聲明 android.provider.extra.PICK_IMAGES_MAX
的值宦言,該值表示在向用戶顯示時照片選擇器中顯示的媒體文件數(shù)量上限扇单。
需要注意的是:如果選擇的上限為 1 張,照片選擇器會以半屏模式打開奠旺。
選擇單張照片或單個視頻
先來看看如何選擇單張照片吧:
val intent = Intent(MediaStore.ACTION_PICK_IMAGES)
// 用戶可以選擇一張照片或一個視頻蜘澜。
startActivityForResult(intent, PHOTO_PICKER_REQUEST_CODE)
選擇多張照片或多個視頻
如果應用的用例需要用戶選擇多張照片或多個視頻,可以使用 EXTRA_PICK_IMAGES_MAX
extra 指定照片選擇器中應顯示照片的數(shù)量上限响疚,如以下代碼段中所示:
// 最大選擇數(shù)量
val maxNumPhotosAndVideos = 10
val intent = Intent(MediaStore.ACTION_PICK_IMAGES)
intent.putExtra(MediaStore.EXTRA_PICK_IMAGES_MAX, maxNumPhotosAndVideos)
startActivityForResult(intent, PHOTO_PICKER_MULTI_SELECT_REQUEST_CODE)
請注意鄙信,可指定為文件數(shù)量上限的最大數(shù)字存在平臺限制。如需訪問此限制忿晕,請調(diào)用 MediaStore.getPickImagesMaxLimit()
装诡。
處理照片選擇器結(jié)果
照片選擇器啟動后,使用新的 ACTION_PICK_IMAGES
intent 來處理結(jié)果践盼。該選擇器會返回一組 URI:
// 處理來自照片選擇器的回調(diào)鸦采。
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode != Activity.RESULT_OK) return
when (requestCode) {
REQUEST_PHOTO_PICKER_SINGLE_SELECT -> {
// 獲取單個選擇的照片選擇器響應
val currentUri: Uri = data.data
// 處理照片或視頻的URI.
return
}
REQUEST_PHOTO_PICKER_MULTI_SELECT -> {
// Get photo picker response for multi select.
var i = 0
while (i < data.clipData!!.itemCount) {
val uri = data.clipData.getItemAt[i]
// 處理照片或視頻的URI.
}
return
默認情況下,照片選擇器會既顯示照片又顯示視頻咕幻。咱們可以在 setType() 方法中設置 MIME 類型渔伯,以便按“僅顯示照片”或“僅顯示視頻”進行過濾。來看看代碼如何實現(xiàn)吧:
val intent = Intent(MediaStore.ACTION_PICK_IMAGES)
// 只顯示視頻
intent.type = "video/*"
startActivityForResult(intent, PHOTO_PICKER_VIDEO_SINGLE_SELECT_REQUEST_CODE)
// 只顯示圖片
// images only - intent.type = "images/*"
上面代碼中將只顯示視頻或者圖片的 type 都寫了下肄程,大家可以按需進行使用锣吼。
應用內(nèi)語言選擇器
Android 13 在手機設置中新增了一個集中設置選項,用于設置各應用語言偏好設定蓝厌。如果你的應用支持多種語言玄叠,官方強烈建議我們在應用的清單中聲明 android:localeConfig
屬性,這樣用戶就可以在同一位置像更改其他應用的語言設置一樣更改應用的語言設置拓提。
此外读恃,當前使用自定義應用內(nèi)語言選擇器的應用應改用適用于各應用語言偏好設定功能的新 API。使用這些新 API 有助于確保用戶無論是繼續(xù)通過應用內(nèi)語言選擇器選擇語言,還是通過手機設置選擇語言狐粱,都能以其首選語言查看應用舀寓。當然,如果不支持多種語言的應用將不受這些變更的影響肌蜻。
如何使用
-
創(chuàng)建一個名為
res/xml/locales_config.xml
的文件互墓,并指定您的應用的語言,如下所示:<?xml version="1.0" encoding="utf-8"?> <locale-config xmlns:android="http://schemas.android.com/apk/res/android"> <locale android:name="zh"/> <locale android:name="en"/> </locale-config>
-
在清單中蒋搜,添加一行指向這個新文件的代碼:
<manifest ... <application ... android:localeConfig="@xml/locales_config"> </application> </manifest>
如何在設置中進行設置
用戶可以通過新的系統(tǒng)設置為每個應用選擇首選語言篡撵。他們可以通過以下兩種方式訪問這些設置:
-
通過系統(tǒng)設置訪問
設置 > 系統(tǒng) > 語言和輸入法 > 應用語言 >(選擇一款應用)
-
通過應用設置訪問
設置 > 應用 >(選擇一款應用)> 語言
處理應用內(nèi)語言選擇器
如需設置用戶的首選語言,需要讓用戶在語言選擇器中選擇語言區(qū)域豆挽,然后在系統(tǒng)中設置該值:
val appLocale: LocaleListCompat = LocaleListCompat.forLanguageTags("xx-YY")
// 注意:需要在主線程上調(diào)用它育谬,因為它可能需要Activity.restart()
AppCompatDelegate.setApplicationLocales(appLocale)
如需支持搭載 Android 12(S-32)及更低版本的設備,請在應用的 AppLocalesMetadataHolderService
服務的清單條目中將 autoStoreLocales
值設置為 true
并將 android:enabled
設置為 false
帮哈,以指示 AndroidX 處理語言區(qū)域存儲空間膛檀,如以下代碼段所示:
<application
...
<service
android:name="androidx.appcompat.app.AppLocalesMetadataHolderService"
android:enabled="false"
android:exported="false">
<meta-data
android:name="autoStoreLocales"
android:value="true" />
</service>
...
</application>
請注意,將 autoStoreLocales
值設為 true
會導致主線程上出現(xiàn)阻塞讀取娘侍,并可能會導致 StrictMode
diskRead
和 diskWrite
違規(guī)行為咖刃。
帶主題的應用圖標
這個功能其實官方已經(jīng)宣傳了挺久了,從 Android 13 起憾筏,用戶可以選擇啟用帶主題的應用圖標嚎杨。借助此功能,用戶可以調(diào)節(jié)受支持的 Android 啟動器中應用圖標的色調(diào)氧腰,以繼承所選壁紙和其他主題的配色枫浙。
如需支持此功能,必須提供自適應圖標和單色應用圖標兩種古拴,并通過 AndroidManifest.xml 中的 <adaptive-icon>
元素指向該單色應用圖標箩帚。如果用戶啟用了帶主題的應用圖標,而啟動器支持此功能斤富,則系統(tǒng)將使用用戶選擇的壁紙和主題來確定色調(diào)顏色膏潮,然后該顏色將應用于單色應用圖標。
在以下任何情況下满力,主屏幕都不會顯示帶主題的應用圖標焕参,而是顯示自適應或標準應用圖標:
- 如果用戶未啟用帶主題的應用圖標
- 如果應用不提供單色應用圖標
- 如果啟動器不支持帶主題的應用圖標
單色應用圖標
- 應是一個
VectorDrawable
也就是矢量圖。 - 徽標適合 108 x 108 dp 容器中的 44 x 44 dp 的區(qū)域內(nèi)油额。如果需要更大尺寸的徽標叠纷,最大可以為 72 x 72 dp。(這里所說的徽標就是圖標中代表應用的樣子潦嘶,類似于支付寶的“支”字)涩嚣。
- 官方建議使用平面徽標,但如果徽標是三維的,可以使用 Alpha 漸變來實現(xiàn)航厚。
下面是官方單色應用圖標的圖片展示:
[圖片上傳失敗...(image-ed3d3e-1657527105954)]
如何使用
將 monochrome android:drawable
屬性添加到 <adaptive-icon>
元素中顷歌。例如,在 res/mipmap-anydpi-v26/ic_launcher.xml
中:
<adaptive-icon >
<background android:drawable="..." />
<foreground android:drawable="..." />
<monochrome android:drawable="@drawable/myicon" />
</adaptive-icon>
然后在 AndroidManifest.xml 中幔睬,使用 android:icon
定義圖標:
<application
…
android:icon="@mipmap/ic_launcher"
…>
</application>
注意:如果清單中同時包含
android:roundIcon
和android:icon
眯漩,必須移除對android:roundIcon
的引用,或者在由android:roundIcon
屬性定義的可繪制對象中提供單色圖標麻顶。
小結(jié)
其實 Android 13 中更新的內(nèi)容遠不止這些赦抖,比如在 Android 13 中優(yōu)化了 TextView 的 hyphenation 、還增加了彩色的矢量字體辅肾、還增加了 Receiver 的安全性等等队萤,我只是挑選了一些和普通開發(fā)者相關(guān)的更新來簡單描述了下。
在這里做個記錄矫钓,能幫助到大家最好要尔,看到這里麻煩點點贊關(guān)注下,感激不盡7莺埂S纭蝴簇!
就這樣杯活。