Android 11 適配,看這篇就夠了!
BAT
作者:唯鹿
https://juejin.cn/post/6948211914455384072
1.準(zhǔn)備工作
老規(guī)矩,首先將我們項目中的 targetSdkVersion 改為 30。或者使用兼容性調(diào)試工具,后面我會說到。
2.存儲機制更新
Scoped Storage(分區(qū)存儲)
具體適配方法和去年的Android 10 適配攻略中的沒有太大區(qū)別。
https://weilu.blog.csdn.net/article/details/104513170
不過需要注意的是,應(yīng)用targetSdkVersion >= 30,強制執(zhí)行分區(qū)存儲機制。之前在AndroidManifest.xml中添加 android:requestLegacyExternalStorage="true"的適配方式已不起作用。
還有一個變化:Android 11 允許使用除 MediaStore API 之外的 API 通過文件路徑直接訪問共享存儲空間中的媒體文件。其中包括:
File API。
原生庫,例如 fopen()。
如果你之前沒有適配Android 10,這一點對你來說是個好消息。Android 10在AndroidManifest.xml中添加 android:requestLegacyExternalStorage="true"來適配,Android 11上直接使用File API訪問媒體文件。
不過,使用原始文件路徑直接訪問共享存儲空間中的媒體文件會重定向到 MediaStoreAPI,這次重定向會造成性能影響(隨機讀寫慢一倍左右)。而且直接使用原始文件路徑,并不會比使用 MediaStore API 有更多優(yōu)勢,因此官方強烈建議直接使用 MediaStore API。
MANAGE_EXTERNAL_STORAGE
當(dāng)然還有一種簡單粗暴的適配方法,獲取外部存儲管理權(quán)限。如果你的應(yīng)用是手機管家、文件管理器這類需要訪問大量文件的app,可以申請MANAGE_EXTERNAL_STORAGE權(quán)限,將用戶引導(dǎo)至系統(tǒng)設(shè)置頁面開啟。代碼如下:
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
tools:ignore="ScopedStorage" />
public static void checkStorageManagerPermission(Context context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R &&
!Environment.isExternalStorageManager()) {
Intent intent = new Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
}
需要注意的是即使你有了MANAGE_EXTERNAL_STORAGE權(quán)限,也無法訪問Android/data/ 目錄下的文件。
對于MANAGE_EXTERNAL_STORAGE權(quán)限,國內(nèi)使用應(yīng)該沒有什么影響。但是在Google Play上需要說明為什么已有的SAF或MediaStore不滿足你的應(yīng)用需求,審核通過才允許上架使用。所以一般情況下,我個人不推薦你為了適配簡單,直接申請使用MANAGE_EXTERNAL_STORAGE權(quán)限。
其他細節(jié)變更見文檔:Android 11 中的存儲機制更新。
https://developer.android.google.cn/about/versions/11/privacy/storage#scoped-storage
相關(guān)api變更及使用推薦郭霖大神的這篇:Android 11新特性,Scoped Storage又有了新花樣。
https://guolin.blog.csdn.net/article/details/113954552
存儲訪問框架 (SAF)變更
Android 11對SAF添加以下限制:
使用 ACTION_OPEN_DOCUMENT_TREE 或 ACTION_OPEN_DOCUMENT,無法瀏覽到Android/data/ 和 Android/obb/ 目錄及其所有子目錄。
使用 ACTION_OPEN_DOCUMENT_TREE無法授權(quán)訪問存儲根目錄、Download文件夾。
REQUEST_INSTALL_PACKAGES
在8.0的適配中,我們安裝apk包之前需要申請“安裝未知來源應(yīng)用”的權(quán)限。一般來說首次是跳轉(zhuǎn)到授權(quán)頁面讓用戶手動開啟,然后返回app進行安裝。
在Android 11中當(dāng)用戶開啟“安裝未知來源應(yīng)用”的權(quán)限,app就會被殺死。該行為與強制分區(qū)存儲有關(guān),因為持有 REQUEST_INSTALL_PACKAGES 權(quán)限的應(yīng)用可以訪問其他應(yīng)用的Android/obb 目錄。
好在用戶授予權(quán)限之后,雖然app會被殺死,但是安裝頁面依然會彈出。
目前對于這一變更我沒有發(fā)現(xiàn)可以適配處理的方式,詳細介紹見:Android 11特性調(diào)整:安裝外部來源應(yīng)用需要重啟APP。
https://news.51cto.com/art/202006/618118.htm
3.權(quán)限變化
單次權(quán)限授權(quán)
從 Android 11 開始,每當(dāng)應(yīng)用請求與位置信息、麥克風(fēng)或攝像頭相關(guān)的權(quán)限時,面向用戶的權(quán)限對話框會包含僅限這一次選項。如果用戶在對話框中選擇此選項,系統(tǒng)會向應(yīng)用授予臨時的單次授權(quán)。

單次權(quán)限授權(quán)的應(yīng)用可以在一段時間內(nèi)訪問相關(guān)數(shù)據(jù),具體時間取決于應(yīng)用的行為和用戶的操作:
當(dāng)應(yīng)用的 Activity 可見時,應(yīng)用可以訪問相關(guān)數(shù)據(jù)。
如果用戶將應(yīng)用轉(zhuǎn)為后臺運行,應(yīng)用可以在短時間內(nèi)繼續(xù)訪問相關(guān)數(shù)據(jù)。
如果您在 Activity 可見時啟動了一項前臺服務(wù),并且用戶隨后將您的應(yīng)用轉(zhuǎn)到后臺,那么您的應(yīng)用可以繼續(xù)訪問相關(guān)數(shù)據(jù),直到該前臺服務(wù)停止。
如果用戶撤消單次授權(quán)(例如在系統(tǒng)設(shè)置中撤消),無論您是否啟動了前臺服務(wù),應(yīng)用都無法訪問相關(guān)數(shù)據(jù)。與任何權(quán)限一樣,如果用戶撤消了應(yīng)用的單次授權(quán),應(yīng)用進程就會終止。
當(dāng)用戶下次打開應(yīng)用并且應(yīng)用中的某項功能請求訪問位置信息、麥克風(fēng)或攝像頭時,系統(tǒng)會再次提示用戶授予權(quán)限。
如果你之前就是使用權(quán)限時才請求相關(guān)權(quán)限,那么這一變更對于你的應(yīng)用沒有影響。
請求位置權(quán)限
這部分在Android 10的適配有過調(diào)整,當(dāng)時規(guī)則如下:
請求ACCESS_FINE_LOCATION或 ACCESS_COARSE_LOCATION權(quán)限表示在前臺時擁有訪問設(shè)備位置信息的權(quán)限。在請求彈框中,選擇“始終允許”表示前后臺都可以獲取位置信息,選擇“僅在應(yīng)用使用過程中允許”只表示擁有前臺的權(quán)限。
在Android 11中,請求彈框中取消了“始終允許”這一選項。也就是說默認不會授予你后臺訪問設(shè)備位置信息的權(quán)限。如果嘗試請求ACCESS_BACKGROUND_LOCATION權(quán)限的同時請求任何其他權(quán)限,系統(tǒng)會拋出異常,不會向應(yīng)用授予其中的任一權(quán)限。
官方給出的適配建議及原因如下:
建議應(yīng)用對位置權(quán)限執(zhí)行遞增請求,先請求前臺位置信息訪問權(quán)限,再請求后臺位置信息訪問權(quán)限。執(zhí)行遞增請求可以為用戶提供更大的控制權(quán)和透明度,因為他們可以更好地了解應(yīng)用中的哪些功能需要后臺位置信息訪問權(quán)限。
總結(jié)一下得出兩點:
1,先請求前臺位置信息訪問權(quán)限,再請求后臺位置信息訪問權(quán)限。
2,單獨請求后臺位置信息訪問權(quán)限,不要與其他權(quán)限一同請求。
這里還需要注意不同目標(biāo)平臺應(yīng)用在Android 11上的表現(xiàn):
Android 10 為目標(biāo)平臺的應(yīng)用 允許同時訪問前后臺的位置信息權(quán)限,但同樣不會有“始終允許”這一選項。
1,沒有前后臺的位置信息權(quán)限時:

2,有前臺的位置信息權(quán)限時:

Android 11 為目標(biāo)平臺的應(yīng)用
1,沒有前后臺的位置信息權(quán)限時,只能先請求前臺的位置信息權(quán)限。

2,有前臺的位置信息權(quán)限,請求后臺的位置信息時系統(tǒng)會跳轉(zhuǎn)到下面的設(shè)置頁面。

選擇“始終允許”表示具有前后臺位置信息訪問權(quán)限,如果用戶拒絕兩次應(yīng)用定位訪問請求(直接返回等),后面請求相同權(quán)限都會被直接提示請求失敗。(這里就需要我們給用戶以引導(dǎo)了)
這里解釋一下“拒絕兩次”,這是Android 11 上添加的權(quán)限對話框的可見性,以前我們點擊了“不再詢問”表示拒絕授權(quán)。現(xiàn)在還包含類似上面這種轉(zhuǎn)到系統(tǒng)設(shè)置,然后點返回按鈕,也算是拒絕授權(quán)。當(dāng)然,用戶按返回按鈕關(guān)閉權(quán)限對話框,此操作不算。
總結(jié)一下,與Android 10的區(qū)別就是將后臺權(quán)限的申請分離了出來,增加了用戶“拒絕”的條件,避免了應(yīng)用重復(fù)請求用戶已拒絕的權(quán)限。
軟件包可見性
軟件包可見性是Android 11上提升系統(tǒng)隱私安全性的一個新特性。它的作用是限制app隨意獲取其他app的信息和安裝狀態(tài)。避免病毒軟件、間諜軟件利用,引發(fā)網(wǎng)絡(luò)釣魚、用戶安裝信息泄露等安全事件。
獲取自動可見應(yīng)用的列表,可以執(zhí)行命令adb shell dumpsys package queries,找到 forceQueryable 部分。下面是在vivo iqoo手機的執(zhí)行結(jié)果。
Queries:
system apps queryable: false
forceQueryable:
[com.android.BBKCrontab,com.vivo.fingerprint,com.vivo.epm,com.vivo.abe,com.vivo.fingerprintengineer,com.vivo.contentcatcher,com.vivo.floatingball,com.vivo.agent,com.vivo.nightpearl,android,com.wapi.wapicertmanage,com.vivo.vms,co
m.android.providers.settings,com.vivo.upslide,com.vivo.assistant,com.vivo.vivokaraoke,com.vivo.fingerprintui,com.android.wallpaperbackup,com.bbk.facewake,com.vivo.faceunlock,com.vivo.doubleinstance,com.vivo.audiofx,com.iqoo.powersav
ing,com.bbk.SuperPowerSave,com.vivo.vibrator4d,com.vivo.smartunlock,com.vivo.globalanimation,com.vivo.appfilter,com.vivo.voicewakeup,com.vivo.minscreen,com.android.bbklog,com.mobile.cos.iroaming,com.vivo.networkstate,com.vivo.daemon
Service,com.vivo.smartshot,com.vivo.vtouch,com.android.networkstack.tethering.inprocess,com.android.localtransport,com.vivo.pem,com.vivo.wifiengineermode,com.android.server.telecom,com.vivo.gamecube,com.vivo.aiengine,com.vivo.multin
lp,com.vivo.smartmultiwindow,com.vivo.permissionmanager,com.qti.diagservices,com.vivo.bsptest,com.qti.snapdragon.qdcm_ff,com.vivo.dr,com.vivo.sps,com.android.dynsystem,com.vivo.setupwizard,com.vivo.gamewatch,com.android.keychain,com
.vivo.faceui,com.android.networkstack.inprocess,com.android.location.fused,com.android.inputdevices,com.android.settings,com.iqoo.engineermode,com.vivo.fuelsummary]
[com.qualcomm.uimremoteserver,com.vivo.devicereg,com.qti.qualcomm.deviceinfo,com.volte.config,com.android.mms.service,com.android.ons,com.qualcomm.qcrilmsgtunnel,com.vivo.sim.contacts,com.qualcomm.qti.uimGbaApp,com.qualcomm.qti.
modemtestmode,com.android.stk,com.android.vendors.bridge.softsim,com.qualcomm.uimremoteclient,com.qti.qualcomm.datastatusnotification,com.qualcomm.qti.uim,com.android.phone,com.qualcomm.qti.dynamicddsservice,com.qualcomm.qti.telepho
nyservice,com.android.cellbroadcastservice,com.android.providers.telephony,com.qti.dpmserviceapp,com.android.incallui]
[com.android.vivo.tws.vivotws,com.android.bluetooth]
com.android.nfc
com.android.se
com.android.networkstack.permissionconfig
com.android.shell
com.android.providers.media.module
com.android.wifi.resources.overlay.common
com.android.theme.icon_pack.filled.themepicker
com.android.theme.icon_pack.circular.themepicker
com.android.server.telecom.overlay.common
......
可以看到都是系統(tǒng)應(yīng)用包名,所以我們的三方應(yīng)用默認是不可見的。此項變更影響比較多的是分享支付一類需要與其他應(yīng)用交互的功能。下面舉一個簡單的例子:
private static boolean hasActivity(Context context, Intent intent) {
PackageManager packageManager = context.getPackageManager();
return packageManager.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY).size() > 0;
}
public void test() {
Intent intent = new Intent();
intent.setClassName("com.tencent.mm", "com.tencent.mm.ui.tools.ShareImgUI");
Log.d("hasActivity:", hasActivity(this, intent) + "");
}
hasActivity方法中通過queryIntentActivities來判斷此頁面是否存在。但是在targetSdkVersion >= 30中,這些三方默認都是不可見的。所以都會返回false。類似方法getInstalledPackages、getPackageInfo也受到相應(yīng)的限制。
解決方法很簡單,在AndroidManifest.xml 中添加queries元素,里面添加需要可見的應(yīng)用包名。
<manifest package="com.example.app">
<queries>
<package android:name="com.tencent.mm" /> <- 指定微信包名
</queries>
...
</manifest>
我在適配中用到的還有下面的包名,我們可以按需添加:
<queries>
<!-- 微博 -->
<package android:name="com.sina.weibo" />
<!-- QQ -->
<package android:name="com.tencent.mobileqq" />
<!-- 支付寶 -->
<package android:name="com.eg.android.AlipayGphone" />
<!-- AlipayHK -->
<package android:name="hk.alipay.wallet" />
</queries>
除了直接添加包名的方式外,我們可以按intent和provider來添加:
<manifest package="com.example.app">
<queries>
<intent>
<action android:name="android.intent.action.SEND" />
<data android:mimeType="image/jpeg" />
</intent>
<provider android:authorities="com.example.settings.files" />
</queries>
...
</manifest>
具體的規(guī)則參見:管理軟件包可見性。
https://developer.android.google.cn/training/basics/intents/package-visibility#intent-signature
當(dāng)然,還有一種簡單粗暴的方式,可以直接申請權(quán)限QUERY_ALL_PACKAGES。如果你的應(yīng)用需要上架Google Play,那么可能要注意相關(guān)政策。為了尊重用戶隱私,建議我們的應(yīng)用按正常工作所需的最小軟件包可見性來適配。
有一點需要說明一下,我們?nèi)粘J褂玫?/span>startActivity 方法不受系統(tǒng)軟件包可見性行為的影響,即使hasActivity為false,一樣可以跳轉(zhuǎn)。如果我們在做跳轉(zhuǎn)前,進行類似hasActivity的判斷,那么會受影響。
最后需要注意的是,使用queries元素需要Android Gradle 插件版本是 4.1及以上,因為舊版本的插件并不兼容此元素,出現(xiàn)合并 manifest 的錯誤。
前臺服務(wù)類型
Android 10中,在前臺服務(wù)訪問位置信息,需要在對應(yīng)的service中添加 location 服務(wù)類型。
同樣的,Android 11中,在前臺服務(wù)訪問攝像頭或麥克風(fēng),需要在對應(yīng)的service中添加camera或microphone 服務(wù)類型。
<manifest>
...
<service
android:name="MyService"
android:foregroundServiceType="microphone|camera" />
</manifest>
這一限制的變更,使得程序無法在后臺啟動服務(wù)訪問攝像頭和麥克風(fēng)。如需使用,只能是前臺開啟前臺服務(wù)。除非有如下情況:
服務(wù)由系統(tǒng)組件啟動。
服務(wù)是通過應(yīng)用小部件啟動。
服務(wù)是通過與通知交互啟動的。
服務(wù)是PendingIntent啟動的,它是從另一個可見的應(yīng)用程序發(fā)送過來的。
服務(wù)由一個應(yīng)用程序啟動,該應(yīng)用是一個DPC,且在設(shè)備所有者模式下運行。
服務(wù)由一個提供VoiceInteractionService的應(yīng)用啟動。
服務(wù)由一個具有START_ACTIVITIES_FROM_BACKGROUND權(quán)限的應(yīng)用啟動。
權(quán)限自動重置
如果應(yīng)用以 Android 11 或更高版本為目標(biāo)平臺并且數(shù)月未使用,系統(tǒng)會通過自動重置用戶已授予應(yīng)用的運行時敏感權(quán)限來保護用戶數(shù)據(jù)。如下圖所示:

注意上圖中有一個啟動自動重置的開關(guān)。如果我們的應(yīng)用有特殊需要,可以引導(dǎo)用戶關(guān)閉它。示例代碼如下:
public void checkAutoRevokePermission(Context context) {
// 判斷是否開啟
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R &&
!context.getPackageManager().isAutoRevokeWhitelisted()) {
// 跳轉(zhuǎn)設(shè)置頁
Intent intent = new Intent(Intent.ACTION_AUTO_REVOKE_PERMISSIONS);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setData(Uri.fromParts("package", context.getPackageName(), null));
context.startActivity(intent);
}
}
SYSTEM_ALERT_WINDOW權(quán)限
這部分我在適配中沒有用到,直接照搬文檔:
在 Android 11 中,系統(tǒng)會根據(jù)請求自動向某些類型的應(yīng)用授予 SYSTEM_ALERT_WINDOW 權(quán)限:
系統(tǒng)會自動向具有 ROLE_CALL_SCREENING 且請求 SYSTEM_ALERT_WINDOW 的所有應(yīng)用授予該權(quán)限。如果應(yīng)用失去 ROLE_CALL_SCREENING,就會失去該權(quán)限。
系統(tǒng)會自動向通過 MediaProjection 截取屏幕且請求 SYSTEM_ALERT_WINDOW 的所有應(yīng)用授予該權(quán)限,除非用戶已明確拒絕向應(yīng)用授予該權(quán)限。當(dāng)應(yīng)用停止截取屏幕時,就會失去該權(quán)限。此用例主要用于游戲直播應(yīng)用。
這些應(yīng)用無需發(fā)送 ACTION_MANAGE_OVERLAY_PERMISSION 以獲取 SYSTEM_ALERT_WINDOW 權(quán)限,它們只需直接請求 SYSTEM_ALERT_WINDOW 即可。
MANAGE_OVERLAY_PERMISSION intent 始終會將用戶轉(zhuǎn)至系統(tǒng)權(quán)限屏幕。
從 Android 11 開始,ACTION_MANAGE_OVERLAY_PERMISSION intent 始終會將用戶轉(zhuǎn)至頂級設(shè)置屏幕,用戶可在其中授予或撤消應(yīng)用的 SYSTEM_ALERT_WINDOW 權(quán)限。intent 中的任何 package: 數(shù)據(jù)都會被忽略。
在更低版本的 Android 中,ACTION_MANAGE_OVERLAY_PERMISSION intent 可以指定一個軟件包,它會將用戶轉(zhuǎn)至應(yīng)用專用屏幕以管理權(quán)限。從 Android 11 開始將不再支持此功能,而是必須由用戶先選擇要授予或撤消哪些應(yīng)用的權(quán)限。此變更可以讓權(quán)限的授予更有目的性,從而達到保護用戶的目的。
讀取手機號
如果你是通過TelecomManager的getLine1Number方法,或TelephonyManager的getMsisdn方法獲取電話號碼。那么在Android 11中需要增加READ_PHONE_NUMBERS權(quán)限。使用其他方法不受限。
<manifest>
<!-- 如果應(yīng)用僅在 Android 10及更低版本中使用該權(quán)限,可以添加 maxSdkVersion="29" -->
<uses-permission android:name="android.permission.READ_PHONE_STATE"
android:maxSdkVersion="29" />
<uses-permission android:name="android.permission.READ_PHONE_NUMBERS" />
</manifest>
4.其他行為變更
自定義view的Toast
Android 11 為目標(biāo)平臺的應(yīng)用,從后臺發(fā)送自定義view的Toast消息系統(tǒng)會進行屏蔽。前臺使用不受影響。Toast相應(yīng)的setView 和 getView也已經(jīng)廢棄不建議使用。
如果要在后臺使用,推薦使用默認的toast或Snackbar替代。
APK簽名
Android 11 為目標(biāo)平臺的應(yīng)用,僅通過v1 簽名的應(yīng)用無法在Android 11的設(shè)備上安裝或更新。必須使用v2或更高版本進行簽名。
同時Android 11 添加了對 APK 簽名方案 v4 的支持。
https://developer.android.google.cn/studio/command-line/apksigner?hl=zh_cn#v4-signing-enabled
AsyncTask
AsyncTask在Android 11已經(jīng)不建議使用,建議遷移至kotlin的協(xié)程。
此外Handler未指定Looper的構(gòu)造方法也已不建議使用。
建議明確指定Looper:
private Handler handler = new Handler(Looper.myLooper());
// 或
private Handler handler = new Handler(Looper.getMainLooper());
5.新增工具
兼容性調(diào)試工具
以往我們做適配的時候,需要先將我們項目中的 targetSdkVersion 修改為對應(yīng)版本。這就導(dǎo)致你適配過程中有可能受到其他變更的影響,而這個新增的兼容性調(diào)試工具可以讓你在不升級targetSdkVersion的情況下,針對每項變更逐個開啟適配。
使用方法:
開發(fā)者選項中找到應(yīng)用兼容性變更選項。
點擊進入找到你需要調(diào)試的應(yīng)用。
在變更列表中,找到想要開啟或關(guān)閉的變更,然后點擊相應(yīng)的開關(guān)。

上面第一行DEFAULT_SCOPED_STORAGE就是啟用分區(qū)儲存,這些常量詳細的含義見:Android 11 變更列表。
https://developer.android.google.cn/about/versions/11/reference/compat-framework-changes
對于兼容性調(diào)試工具詳細的使用方法見:兼容性框架工具,這里限于篇幅就不展開說了。
無線調(diào)試
Android 11的開發(fā)者選項中添加了一個無線調(diào)試的功能。類似于連接藍牙耳機功能,可以無需USB連接線進行日常開發(fā)調(diào)試工作。(區(qū)別于以前的Android WIFI ADB,這個是真無線,哈哈)

使用方法:
開發(fā)者選項中找到無線調(diào)試并打開。
首次配對需點擊“使用配對碼配對設(shè)備”。
運行 adb pair ipaddr:port后輸入配對碼進行連接。
注意事項:

保持電腦和手機在一個網(wǎng)絡(luò)。
Platform Tools 版本需大于30.0。可使用adb --version查看。
不過我自己體驗下來,感覺連接不是很穩(wěn)定,不知是AS的問題還是手機問題。同時鎖屏后也會斷開連接,體驗不是很好。。。期待后續(xù)的優(yōu)化吧。
6.總結(jié)
本篇內(nèi)容有點多。總結(jié)一下,Android 11在權(quán)限上的變更比較多,但如果你一直遵守申請權(quán)限相關(guān)的最佳做法,那么基本上不需要額外的適配工作。
https://developer.android.google.cn/privacy/best-practices#permissions
最后強調(diào)一下,對于單次授權(quán),權(quán)限對話框的可見性,SYSTEM_ALERT_WINDOW 權(quán)限,安裝apk這些變更只要在Android 11上就會生效,不論你是否適配Android 11。對于其他變更和API(相機、5G、瀑布屏、鍵盤等),因為我暫時沒有遇到,也就沒有列出,有需要的可以點擊文末的官方文檔鏈接查看。
截止發(fā)這篇博客時,我手機上只發(fā)現(xiàn)嗶哩嗶哩已經(jīng)適配了Android 11。大多數(shù)停留在28、29,更有甚者還在26(Android 8.0 國內(nèi)上架的最低適配標(biāo)準(zhǔn))。
所以我順便附上之前寫的Android 9、10的適配攻略:
Android 9.0 適配指南
https://blog.csdn.net/qq_17766199/article/details/98336225?spm=1001.2014.3001.5501
Android 10 適配攻略
https://blog.csdn.net/qq_17766199/article/details/104513170?spm=1001.2014.3001.5501
推薦閱讀
? 耗時2年,Android進階三部曲第三部《Android進階指北》出版!
? 『BATcoder』做了多年安卓還沒編譯過源碼?一個視頻帶你玩轉(zhuǎn)!
BATcoder技術(shù)群,讓一部分人先進大廠
大家好,我是劉望舒,騰訊云最具價值專家TVP,著有暢銷書《Android進階之光》《Android進階解密》《Android進階指北》,蟬聯(lián)四屆電子工業(yè)出版社年度優(yōu)秀作者,谷歌開發(fā)者社區(qū)特邀講師,百度百科收錄的技術(shù)專家。
前華為面試官,現(xiàn)大廠技術(shù)負責(zé)人。
想要加入 BATcoder技術(shù)群,公號回復(fù)BAT 即可。
為了防止失聯(lián),歡迎關(guān)注我的小號
微信改了推送機制,真愛請星標(biāo)本公號??

