Android 12 適配升級小結

????Android 12 發(fā)布已經(jīng)有 4 個月了,而且隨著各大市場對應用適配的要求逐漸提高,小菜也嘗試將一個歷史的應用簡單升級適配 Android 12

Android 12

????Android 12 對應 Build.VERSION_CODES.S,使用 Material You 打造的全新系統(tǒng)界面,富有表現(xiàn)力、活力和個性。使用重新設計的微件、AppSearch、游戲模式和新的編解碼器擴展您的應用。支持隱私信息中心和大致位置等新的保護功能。使用富媒體內(nèi)容插入功能、更簡便的模糊處理功能、經(jīng)過改進的原生調(diào)試功能等提高工作效率。

????Android 12 相對我們的歷史項目來說屬于較大版本的更新,在適配過程中遇到一系列問題,小菜簡單記錄整理一下。

SDK 版本號升級

????小菜首先對 SDK 版本號進行升級,之后對升級后的應用逐步進行適配更新;

當前版本

minSdkVersion = 17
targetSdkVersion = 28
compileSdkVersion = 28
buildToolsVersion = '28.0.3'

升級后版本

minSdkVersion = 17
targetSdkVersion = 31
compileSdkVersion = 31
buildToolsVersion = '31.0.0'

Q1: Gradle 不匹配

????升級 SDKsync 后遇到第一個 Gradle 不匹配問題;

Installed Build Tools revision 31.0.0 is corrupted. Remove and install again using the SDK Manager.

A1: 升級 Android 12 對應 Gradle 版本

????歷史版本 Gradle 對應版本是 3.3.3,升級到最新的 7.0.4

classpath 'com.android.tools.build:gradle:7.0.4'

Q2: distributionUrl 不匹配

Caused by: org.gradle.api.internal.plugins.PluginApplicationException: Failed to apply plugin [id 'com.android.internal.version-check']
    at com.android.build.gradle.BasePlugin.apply(BasePlugin.kt:33)
    at com.android.build.gradle.LibraryPlugin.apply(LibraryPlugin.kt:26)
    at build_21d4k8dpcp55f408j9ar3yifm.run(/Users/user/Documents/workspace/App/adlibrary/build.gradle:1)
Caused by: java.lang.RuntimeException: Minimum supported Gradle version is 7.0.2. Current version is 6.1.1. If using the gradle wrapper, try editing the distributionUrl in /Users/user/Documents/workspace/App/gradle/wrapper/gradle-wrapper.properties to gradle-7.0.2-all.zip
    at com.android.build.gradle.internal.plugins.VersionCheckPlugin.apply(VersionCheckPlugin.kt:59)
    at com.android.build.gradle.internal.plugins.VersionCheckPlugin.apply(VersionCheckPlugin.kt:33)
    ...

A2: 升級 Android 12 對應 distributionUrl Gradle 版本

????小菜將本地 gradle-wrapper.properties 中升級到與 classpath 一致的 7.0.2-all 即可;

distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-all.zip

Q3: Marven 倉庫不支持 Http

????小菜歷史項目中引入了很多公司內(nèi)部倉庫和部分非 Https 的線上庫,在 Gradle 升級后,Marven 倉庫建議使用 Https 安全的倉庫;

Could not resolve all dependencies for configuration ':classpath'.
   > Using insecure protocols with repositories, without explicit opt-in, is unsupported. Switch Maven repository 'maven(http://0.0.0.0:80/xxx/App)' to redirect to a secure protocol (like HTTPS) or allow insecure protocols. 
   See https://docs.gradle.org/7.0.2/dsl/org.gradle.api.artifacts.repositories.UrlArtifactRepository.html#org.gradle.api.artifacts.repositories.UrlArtifactRepository:allowInsecureProtocol for more details. 

A3: 升級 Https 線上庫或解決安全警告

????對于部分線上 Marven 倉庫可以更新至 Https,對于不可更新的庫可以通過添加 allowInsecureProtocol 屬性解決 Gradle 倉庫地址的不安全警告;

repositories {
    maven {
      url "http://0.0.0.0:80/xxx/App"
      allowInsecureProtocol = true
    }
}

Q4: compile 棄用

????小菜的歷史項目中有個別 Module 中未及時修改 compile(),而 Gradle 升級之后已完全棄用 compile()

A problem occurred evaluating project ':lib'.
> Could not find method compile() for arguments [directory 'libs'] on object of type
    org.gradle.api.internal.artifacts.dsl.dependencies.DefaultDependencyHandler.

A4: 更新為 api 或 implementation

????根據(jù)具體的業(yè)務需求將 compile() 更新為 api / implementation 即可;

api fileTree(dir: 'libs', include: ['*.jar'])

Q5: Android 工程依賴的 Java 版本過低

A problem occurred evaluating project ':lib'.
> Failed to apply plugin 'com.android.internal.library'.
   > Android Gradle plugin requires Java 11 to run. You are currently using Java 1.8.
     You can try some of the following options:
       - changing the IDE settings.
       - changing the JAVA_HOME environment variable.
       - changing `org.gradle.java.home` in `gradle.properties`.

A5: 更新 Android 依賴版本為 jdk 11.0.13

????通過 AndroidStudio -> Preferences... -> Gradle 更新 jdk 版本即可;

Q6: AGCPluginTask 中 randomEncryptComponent 屬性不應使用 @Optional 進行注釋

????小菜的歷史項目中使用了 Huawei HMS 推送等,使用的 Marven 庫版本較低,與升級后的 Gradle 不兼容;

1: Task failed with an exception.
-----------
* What went wrong:
Execution failed for task ':push:processDebugManifest'.
> A failure occurred while executing com.android.build.gradle.tasks.ProcessLibraryManifest$ProcessLibWorkAction
   > Manifest merger failed with multiple errors, see logs

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
==============================================================================

2: Task failed with an exception.
-----------
* What went wrong:
A problem was found with the configuration of task ':app:processDebugAGCPlugin' (type 'AGCPluginTask').
  - Type 'com.huawei.agconnect.agcp.AGCPluginTask' property 'randomEncryptComponent' of type boolean shouldn't be annotated with @Optional.
    
    Reason: Properties of primitive type cannot be optional.
    
    Possible solutions:
      1. Remove the @Optional annotation.
      2. Use the java.lang.Boolean type instead.
    
    Please refer to https://docs.gradle.org/7.0.2/userguide/validation_problems.html#cannot_use_optional_on_primitive_types for more details about this problem.

A6: 升級華為 HMS 庫版本

classpath 'com.huawei.agconnect:agcp:1.5.2.300'

Q7: 使用 Intent 過濾器的 Service 需設置 exported 屬性

????此元素設置 Activity 是否可由其他應用的組件啟動 —“true”表示可以,“false”表示不可以。若為“false”,則 Activity 只能由同一應用的組件或使用同一用戶 ID 的不同應用啟動。
????如果您使用的是 Intent 過濾器,則不應將此元素設置為“false”。否則,在應用嘗試調(diào)用 Activity 時,系統(tǒng)會拋出 ActivityNotFoundException 異常。相反,您不應為其設置 Intent 過濾器,以免其他應用調(diào)用 Activity。

????如果沒有 Intent 過濾器,則此元素的默認值為“false”。如果您將元素設置為“true”,則任何知道其確切類名的應用均可訪問 Activity,但在系統(tǒng)嘗試匹配隱式 Intent 時,該 Activity 無法解析。

????此屬性并非是限制 Activity 向其他應用公開的唯一方式。您還可使用權限來限制哪些外部實體能夠調(diào)用 Activity

/.../src/main/AndroidManifest.xml Error:
    android:exported needs to be explicitly specified for <service>. Apps targeting Android 12 and higher are required to specify an explicit value for `android:exported` when the corresponding component has an intent filter defined. 
    See https://developer.android.com/guide/topics/manifest/activity-element#exported for details.
/.../src/main/AndroidManifest.xml Error:
    android:exported needs to be explicitly specified for <service>. Apps targeting Android 12 and higher are required to specify an explicit value for `android:exported` when the corresponding component has an intent filter defined. 
    See https://developer.android.com/guide/topics/manifest/activity-element#exported for details.

A7: 在所有 Module 中找到使用 Intent 過濾器的 Service 并按業(yè)務需求添加對應的 exported 屬性

<service
    android:name="com.xxx.app.push.OPushMessageService"
    android:permission="com.coloros.mcs.permission.SEND_MCS_MESSAGE"
    android:exported="true">
  <intent-filter>
    <action android:name="com.coloros.mcs.action.RECEIVE_MCS_MESSAGE" />
  </intent-filter>
</service>

Q8: 使用 Intent 過濾器的 Receiver 需設置 exported 屬性

/.../src/main/AndroidManifest.xml Error:
    android:exported needs to be explicitly specified for <receiver>. Apps targeting Android 12 and higher are required to specify an explicit value for `android:exported` when the corresponding component has an intent filter defined. See https://developer.android.com/guide/topics/manifest/activity-element#exported for details.
/.../src/main/AndroidManifest.xml Error:
    android:exported needs to be explicitly specified for <receiver>. Apps targeting Android 12 and higher are required to specify an explicit value for `android:exported` when the corresponding component has an intent filter defined. See https://developer.android.com/guide/topics/manifest/activity-element#exported for details.

A8: 在所有 Module 中找到使用 Intent 過濾器的 Receiver 并按業(yè)務需求添加對應的 exported 屬性

<receiver android:name="com.xxx.app.SystemReceiver"
    android:exported="false">
  <intent-filter>
    <action android:name="android.intent.action.BOOT_COMPLETED" />
    <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
    <action android:name="android.intent.action.USER_PRESENT" />
  </intent-filter>
  <intent-filter>
    <action android:name="android.intent.action.PACKAGE_REMOVED" />

    <data android:scheme="package" />
  </intent-filter>
</receiver>

Q9: 使用 Intent 過濾器的 Activity 需設置 exported 屬性

/.../src/main/AndroidManifest.xml Error:
    android:exported needs to be explicitly specified for <activity>. Apps targeting Android 12 and higher are required to specify an explicit value for `android:exported` when the corresponding component has an intent filter defined. See https://developer.android.com/guide/topics/manifest/activity-element#exported for details.
/.../src/main/AndroidManifest.xml Error:
    android:exported needs to be explicitly specified for <activity>. Apps targeting Android 12 and higher are required to specify an explicit value for `android:exported` when the corresponding component has an intent filter defined. See https://developer.android.com/guide/topics/manifest/activity-element#exported for details.

A9: 在所有 Module 中找到使用 Intent 過濾器的 Activity 并按業(yè)務需求添加對應的 exported 屬性

<activity
    android:name=".xxx.app.TestActivity"
    android:exported="false"
    android:theme="@style/Theme.notAnimation">
  <intent-filter>
    <action android:name="com.sogou.novel.reader.setting.clean" />

    <category android:name="android.intent.category.DEFAULT" />
  </intent-filter>
</activity>

Q10: PendingIntent 需聲明可變性

????在 Android 12 中創(chuàng)建 PendingIntent 的時候,需要顯示的聲明是否可變,請分別使用 PendingIntent.FLAG_MUTABLEPendingIntent.FLAG_IMMUTABLE 標志,如果您的應用試圖在不設置任何可變標志的情況下創(chuàng)建 PendingIntent 對象,系統(tǒng)會拋出 IllegalArgumentException 異常;

PACKAGE_NAME: Targeting S+ (version 10000 and above) requires that one of \
FLAG_IMMUTABLE or FLAG_MUTABLE be specified when creating a PendingIntent.

Strongly consider using FLAG_IMMUTABLE, only use FLAG_MUTABLE if \
some functionality depends on the PendingIntent being mutable, e.g. if \
it needs to be used with inline replies or bubbles.

A10: 根據(jù)業(yè)務設置 PendingIntent 可變性

????PendingIntent 是一個可以給另一個應用程序使用的 IntentPendingIntent 接收待處理意圖的應用程序可以使用與產(chǎn)生待處理意圖的應用程序相同的權限和身份執(zhí)行待處理意圖中指定的操作;

????在 Adnroid 12 之前,默認創(chuàng)建一個 PendingIntent 它是可變的,因此其他惡意應用程序可能會攔截,重定向或修改此 Intent

PendingIntent pendingIntent = PendingIntent.getBroadcast(getContext().getApplicationContext(), type, intent, PendingIntent.FLAG_IMMUTABLE);
            

W11: 避免使用 flatDirs 提醒

????Gradle 升級之后,提示避免使用 flatDir 提醒,因該方式不支持任何元數(shù)據(jù)方式;

Using flatDir should be avoided because it doesn't support any meta-data formats.
Using flatDir2 should be avoided because it doesn't support any meta-data formats.

A11: 使用 jniLibs.srcDirs 方式引入 libs 庫

????Gradle 升級之后使用 jniLibs.srcDirs 方式替代 flatDirlibs 庫引入,并更新 aar 引入方式;

當前版本

repositories {
    flatDir {
        dirs 'libs'
    }
}

implementation(name: 'test_name', ext: 'aar')

升級后版本

android {
    sourceSets {
        main {
            jniLibs.srcDirs = ['libs']
        }
    }
}

implementation (files("libs/test_name.aar"))

W12: dexOptions 棄用提醒

DSL element 'dexOptions' is obsolete and should be removed.
It will be removed in version 8.0 of the Android Gradle plugin.
Using it has no effect, and the AndroidGradle plugin optimizes dexing automatically.

A12: Gradle 升級后 dexOptions 已棄用,刪除即可

dexOptions {
    preDexLibraries = true
}

Tips:

????小菜在測試過程中,明明代碼中所有涉及 intent-filter 過濾器的 Activity / Service / Receiver 都已經(jīng)設置了 exported 屬性,但依舊提示使用 Intent 過濾器的 XX 需設置 exported 屬性;其原因在于引入了各類三方 SDK,在引入的各類三方庫中可以存在對應的未設置 exported 屬性的 Activity / Service / Receiver,單獨設置處理一下即可;


????Android 12 的初步升級到此位置,還有很多特有的屬性,小菜會在后續(xù)的適配中進行完善;如有錯誤,請多多指導!

阿策小和尚

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,533評論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,055評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,365評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,561評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,346評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 54,889評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,978評論 3 439
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,118評論 0 286
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,637評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 40,558評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,739評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,246評論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 43,980評論 3 346
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,362評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,619評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,347評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,702評論 2 370

推薦閱讀更多精彩內(nèi)容