Official document affixed first convention: developer.android.com/about/versi…

Set up the Android 12 SDK

To develop using the Android 12 API and test Android 12 behavior changes in your application, you need to set up the Android 12 SDK. Follow the instructions on this page to set up the Android 12 SDK in Android Studio and build and run your application on Android 12.

Obtain the Android Studio

The Android 12 SDK contains changes that are not compatible with older versions of Android Studio. In order to obtain the Android SDK 12 best development experience, please use the Android Studio Arctic Fox | 2020.3.1 or later.

Obtain the Android Studio

Installing the SDK

In Android Studio, you can install the Android 12 SDK as follows:

  1. Go to Tools > SDK Manager.
  2. On the SDK Platforms TAB, select Android 12.
  3. On the SDK Tools TAB, select Android SDK build-Tools 31.
  4. Click OK to install the SDK.

Update the build configuration of the application

To access the Android 12 API and test your application’s compatibility with Android 12, open the build.gradle or build.gradle. KTS file at the module level. And update compileSdkVersion and targetSdkVersion with Android 12 values:

android {
    compileSdkVersion 31

    defaultConfig {
        targetSdkVersion 31
    }
}
Copy the code

Note: If you are not ready to fully support Android 12, you can still use debugable apps, Android 12 devices and compatibility framework to perform application compatibility testing without changing the application compileSdkVersion or targetSdkVersion.

To learn what changes might affect you and how to test them in your application, see the following topics:

  • Behavior changes that affect all applications
  • Behavior changes that affect only apps targeted at Android 12

For a detailed look at the new apis and features available in Android 12, see Android 12 Features.

Security and Privacy Settings

Exporting More secure components android: Exported

<activity
    android:name=".TestActivity"
    android:exported="true">
    <intent-filter>
        ......
    </intent-filter>
</activity>
Copy the code

It mainly sets whether the activity, service, and receiver can be started by other application components. True means yes, false means no.

In general, if you use the intent – filter, are exported to true by default, cannot be exported set to false, so the activity is invoked, the system will be thrown ActivityNotFoundException exception;

On the other hand, if you do not have an intent-fileter and default to false, you should not set exported to true, which may be defined as a security vulnerability during security scans.

If your application component contains the LAUNCHER category, set Android :exported to true. In most other cases, set Android :exported to false.

Android 12 will not install the App if the declaration is not displayed. The error log is as follows:

Installation did not succeed. The application could not be installed: INSTALL_FAILED_VERIFICATION_FAILURE List of apks: [0] '... /build/outputs/apk/debug/app-debug.apk' Installation failed due to: 'null'Copy the code

At this point you may choose to go to AndroidManifest and manually modify it one by one, but what if your SDK or third-party library doesn’t support it? Or do you want to launch a package for a different target platform? The following Gradle script will save you some trouble:

Com. Android. Tools. Build: gradle: rule 3.4.3 the following version

/ * * * modify Android for the construction of exported question * / Android. ApplicationVariants. All {variant - > the variant. The outputs. All {output - > output.processResources.doFirst { pm -> String manifestPath = output.processResources.manifestFile def manifestFile = new File(manifestPath) def xml = new XmlParser(false, Parse (manifestFile) def exportedTag = "android:exported" /// specify space def androidSpace = new groovy.xml.Namespace('http://schemas.android.com/apk/res/android', 'android') def nodes = xml.application[0].'*'.findall {// Select nodes to modify, No specified exported only need to increase it. The name () = = 'activity' | | it. The name () = = 'receiver' | | it. The name () = = 'service') && Attribute (androidSpace. Exported) == null} Default false nodes.each {def isMain = false it.each {if (it.name() == "intent-filter") {it.each {if (it.name() == "action") { if (it.attributes().get(androidSpace.name) == "android.intent.action.MAIN") { isMain = true println("...................... MAIN FOUND......................" ) } } } } } it.attributes().put(exportedTag, "${isMain}") } PrintWriter pw = new PrintWriter(manifestFile) pw.write(groovy.xml.XmlUtil.serialize(xml)) pw.close() } } }Copy the code

Com. Android. Tools. Build: gradle: 4.1.0 above

/ * * * modify Android for the construction of exported question * / Android. ApplicationVariants. All {variant - > the variant. The outputs. Each {output - > def processManifest = output.getProcessManifestProvider().get() processManifest.doLast { task -> def outputDir = task.multiApkManifestOutputDirectory File outputDirectory if (outputDir instanceof File) { outputDirectory = outputDir }  else { outputDirectory = outputDir.get().asFile } File manifestOutFile = file("$outputDirectory/AndroidManifest.xml") println("----------- ${manifestOutFile} ----------- ") if (manifestOutFile.exists() && manifestOutFile.canRead() && Manifestoutfile.canwrite ()) {def manifestFile = manifestOutFile // So you can't use androidSpace down here, I'm going to use nameTag def XML = new XmlParser(false, Parse (manifestFile) def exportedTag = "android:exported" def nameTag = "android:name" /// export space specified //def androidSpace = new groovy.xml.Namespace('http://schemas.android.com/apk/res/android', 'android') def nodes = xml.application[0].'*'.findall {// Select nodes to modify, Don't specify exported only need to add / / if exportedTag can't get to try it. The attribute (androidSpace. Exported) (it. The name () = = 'activity' | | it. The name () = = 'receiver' | | it. The name () = = 'service') && it. The attribute (exportedTag) = = null} / / / add exported, Default false nodes.each {def isMain = false it.each {if (it.name() == "intent-filter") {it.each {if (it.name() == "Action ") {// If the nameTag is not available try it.attribute(androidspace.name) if (it.attributes().get(nameTag) == "android.intent.action.MAIN") { isMain = true println("...................... MAIN FOUND......................" ) } } } } } it.attributes().put(exportedTag, "${isMain}") } PrintWriter pw = new PrintWriter(manifestFile) pw.write(groovy.xml.XmlUtil.serialize(xml)) pw.close() } } }}Copy the code

Gradle /android{} you can run this script directly in app/build.gradle/android{}, or you can run it in a separate gradle file and apply it. Retrieve all components that are not exported during the packaging process and dynamically configure them to be exported. It is important to note, there is a special, because the start Activity is need to be the Launcher opens by default, so “android. Intent. Action. The MAIN” need to be exported is set to true. (PS: Use the LAUNCHER category, intentionally using MAIN.)

If necessary, you can specify the default Settings for intent-filter. If the script of a version later than 4.1.0 is abnormal, you can manually configure the script in the Manifest of the current App. The script is mainly dynamically modified for third-party AAR dependencies during compilation

  • Why do I need to display declarations on Android 12android:exportedAttribute?

Because of the default value of the Android: Exported property, Twicca App had a security issue because another App did not have access to an SD card or network, Pictures or movies stored on an SD card can be uploaded to the social network on a Twicca user’s Twitter account via the Twicca App.

The code that causes the problem looks like this:

<activity android:configChanges="keyboard|keyboardHidden|orientation" android:name=".media.yfrog.YfrogUploadDialog" android:theme="@style/Vulnerable.Dialog" android:windowSoftInputMode="stateAlwaysHidden"> <intent-filter android:icon="@drawable/yfrog_icon" android:label="@string/YFROG"> <action android:name="jp.co.vulnerable.ACTION_UPLOAD"  /> <category android:name="android.intent.category.DEFAULT" /> <data android:mimeType="image/*" /> <data android:mimeType="video/*" /> </intent-filter> </activity>Copy the code

The Android :exported attribute is set to true by default because of intent-filter. This causes the above problem (uploading pictures or movies stored on the SD card to the Twicca user’s Twitter account via the Twicca App), and there are two solutions:

  • Solution 1: Addandroid:exported="false"attribute
<activity 
    android:exported="false"
    android:configChanges="keyboard|keyboardHidden|orientation"
    android:name=".media.yfrog.YfrogUploadDialog"
    android:theme="@style/VulnerableTheme.Dialog"
    android:windowSoftInputMode="stateAlwaysHidden" >    
</activity>
Copy the code
  • Scheme 2: Twicca App does not use Method 1, but checks whether the package name of the caller is the same as its own package name
public void onCreate(Bundle arg5) { super.onCreate(arg5); . ComponentName v0 = this.getCallingActivity(); if(v0 == null) { this.finish(); } else if(! jp.r246.twicca.equals(v0.getPackageName())) { this.finish(); } else { this.a = this.getIntent().getData(); if(this.a == null) { this.finish(); }... }}}Copy the code

This is also possible because it is impossible to have two applications with the same package name on a single device. For more information, visit Restrict Access to Sensitive Activities.

This is just one of the security holes in activity that can be exploited to do different things in different scenarios. Of course, service and receiver components are also the same, there are security problems.

Second, the PendingIntent

To create PendingIntent in Android 12, you need to display whether the declaration is mutable.

  • variablePendingIntent.FLAG_IMMUTABLE 
  • immutablePendingIntent.FLAG_MUTABLE 

If the application tries to create a PendingIntent object without setting any mutable flags, the system throws an IllegalArgumentException. The error log is as follows:

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.
Copy the code
  • Why do you need to display the variability of the specified PendingIntent on Android 12?

Before Adnroid 12, a PendingIntent is created by default. It is mutable, so other malicious applications may intercept, redirect, or modify the Intent. (But conditionally)

A PendingIntent is an Intent that can be used by another application. The application that receives the Intent can perform the action specified in the Intent with the same permissions and identity as the application that generated the Intent.

Therefore, you must be careful when creating pending intents. For security purposes, Google requires developers to specify the variability of pendingIntents themselves in Android 12.

For more information about PendingIntent security, check out Always Pass Explicit Intents to a PendingIntent.

Adb backup restrictions

Android developers should be aware of the adb backup command, which can backup application data. In Android 12, in order to protect private application data, any other system data exported from the device when the user runs adb backup does not contain the application data.

If you need adb backup to backup application data during testing and development, you can export application data by setting the android:debuggable to true in the AndroidManifest.

<application android:name=".App" android:debuggable="true" ...... />Copy the code

Note: Be sure to set the Android :debuggable to false before publishing the app.

Why is it limited on Android 12adb backupThe default behavior of the command

Because of this serious security problem, Google can add android:allowBackup attribute in the AndroidManifest to provide App data backup and recovery function, the default value is true, when you create an App, This property is added by default, as shown below.

<application android:name=".App" android:allowBackup="true" ...... />Copy the code

When android:allowBackup=”true”, users can use adb backup and adb restore commands to backup and restore the application data, i.e. install the same application on other android phones. Run the preceding command to restore user data.

To be on the safe side, make sure that the Android :allowBackup property is set to false in the distributed Apk to disable the backup and restore functionality of the application.

National level application letter of XX, at once the version allowBackup attribute value is true, by other reverse after developers use, the current version of this value has been modified to false, can be decompiled boys are interested in and have a look.

Android :allowBackup = “false

Attribute application@allowBackup value=(false) from AndroidManifest.xml:22:9-36
    is also present at [*****] AndroidManifest.xml:12:9-35 value=(true).
    Suggestion: add 'tools:replace="android:allowBackup"' to <application> element at AndroidManifest.xml:20:5-105:19 to override.
Copy the code

Tools :replace = “Android :allowBackup” tools:replace =” Android :allowBackup” tools:replace = “Android :allowBackup” Replace all with Android :allowBackup = “false”, keeping the configuration consistent with the current project.

If you want to know more about Backup, you can go here to juejin.cn/post/695533…

4. Security and privacy Settings

4.1. General location

With an App with TargetSDK 31, the user can request that the App only access approximate location information.

If the App requests ACCESS_COARSE_LOCATION but does not request ACCESS_FINE_LOCATION then there is no impact.

The App with TargetSDK 31 requests the ACCESS_FINE_LOCATION runtime permission and must also request the ACCESS_COARSE_LOCATION permission. When the App requests both permissions, the system Permissions dialog will provide the user with the following new options:

4.2, SameSite cookies

The SameSite attribute of a Cookie determines whether it can be sent with any request or only with same-site requests.

  • There is noSameSiteThe Cookie of the property is treated asSameSite=Lax.
  • withSameSite=NoneCookies must also be specifiedSecureProperties, which means they need a secure context and need to be sent over HTTPS.
  • Links between the HTTP and HTTPS versions of a site are now considered cross-site requests, so unless cookies are correctly marked asSameSite=None; SecureOtherwise, cookies will not be sent.

You can manually enable the SameSite behavior on the test device by switching webview-enable-modern-cookie-same-site in WebView devTools.

Five, the application of sleep

Android 12 expands on the automatic permission reset behavior introduced in Android 11.

If the App user with TargetSDK 31 does not open it for several months, the system will automatically reset all permissions granted and put the App to sleep.

The more you can consult: developer.android.com/topic/perfo…

Six, SplashScreen

Android 12 has added a new API for SplashScreen, which includes an action to enter the app at startup, an icon screen to display the app, and a transition effect to display the app itself.

It is roughly composed of the following four parts, which need to be noted:

  • Preferably a vector drawable object, of course it can be static or animated.
  • 2 is optional, which is the background of the icon.
  • As with adaptive ICONS, one third of the foreground is obscured (3).
  • 4 is the window background.

The splash screen animation mechanism consists of entering animation and exiting animation.

  • The entry animation consists of the system view to the splash screen, which is controlled by the system and not customizable.
  • The exit animation consists of an animation run that hides the splash screen. If you want to customize it, you can customize it through SplashScreenView.

Official data: developer.android.com/guide/topic… , here mainly introduces how to adapt and use the problem.

First, no matter what version of TargetSDK you have, SplashScreen will be added to all apps when you run them on Android 12 phones.

If you do nothing, the App Launcher icon becomes the SplashScreen icon, and the color specified in the windowBackground property of the theme becomes the background color of the SplashScreen. This startup effect occurs during cold and hot startup for all applications.

In fact, it doesn’t seem to be a problem.

About how to use SplashScreen migration and can refer to the official document in detail: developer.android.com/guide/topic…

Also check out Jetpack’s new member SplashScreen: creating a new App SplashScreen, which details how to use the official Jetpack library to adapt this effect to lower Target platforms.

What we would normally do is:

  • 1, upgrade,compileSdkVersion 31targetSdkVersion 31 & BuildToolsVersion '31.0.0'
  • 2. Add dependenciesImplementation "androidx. Core: the core - splashscreen: 1.0.0 - alpha02"
  • 3, increasevalues-v31The directory where the
  • 4, addstyles.xmlCorresponding topic, for example:
<resources> <style name="LaunchTheme" parent="Theme.SplashScreen"> <item name="windowSplashScreenBackground">@color/splashScreenBackground</item> <! --<item name="windowSplashScreenAnimatedIcon">@drawable/splash</item>--> <item name="windowSplashScreenAnimationDuration">500</item> <item name="postSplashScreenTheme">@style/AppTheme</item> </style> </resources> Copy the codeCopy the code
  • 5. Give your startActivityAdd this theme and use different themes for different directories to achieve the effect.

7. Notification Center

Android 12 has made it possible to fully customize the look and behavior of notifications. Previously, custom notifications could use the entire notification area and provide their own layout and style, but now it behaves differently.

With apps with TargetSDK 31, notifications containing custom content views will no longer use the full notification area; Instead, use system standard templates.

This template ensures that custom notifications look exactly like other notifications in all states, such as notification icon and expansion in the collapse state, and notification icon, application name, and collapse in the expansion state. With the Notification. DecoratedCustomViewStyle behavior are almost identical.

Viii. Android App Links Verification

Android App Links is a special type of DeepLink that allows the Web to open the corresponding App content directly within an Android App without requiring the user to select the App. To use it, perform the following steps:

How to use the accessible: developer.android.com/training/ap…

With the App TargetSDK 31, the system makes some adjustments to the verification method of Android App Links, which will improve the reliability of App Links.

If your App relies on Android App Links validation to open web Links in your App, make sure to use the correct format when adding an Intent filter for Android App Links validation. In particular, make sure these intent-filters contain the BROWSABLE category and support HTTPS schemes.

The Activity lifecycle

The root launcher activity no longer completes when the Back button is pressed

Android 12 changes the default way the system handles the launcher activity that is the root of its task when the Back button is pressed. In previous versions, the system completed these activities when the Back button was pressed. In Android 12, the system now moves the activity and its tasks to the background instead of completing the activity. When navigating out of an app using a home screen button or gesture, the new behavior is consistent with the current behavior.

Note: The system only applies the new behavior to the launcher activity that is the root of its task, that is, the activity that declares the intent filter with ACTION_MAIN and CATEGORY_LAUNCHER. For other activities, when the Back button is pressed, the system completes the activity as before.

For most apps, this change means that users who exit an app using the back button can recover the app from a warm state more quickly, rather than having to completely restart the app from a cold state.

It is recommended that you test your application against this change. If your application currently replaces onBackPressed() to handle the back navigation and complete the Activity, update your implementation to call super.onBackPressed() instead of completing the Activity. Calling super.onBackPressed() moves the activity and its tasks into the background when appropriate and provides a more consistent navigation experience for users across applications.

Also note that, in general, we recommend that you use the AndroidX Activity API to provide custom back navigation rather than replacing onBackPressed(). If no component blocking system presses the “back” button, the AndroidX Activity API automatically follows the appropriate system behavior.

Part of the article is reprinted from the following authors

Author: Love cat de Xiao Guo link: juejin.cn/post/703710… Author: DHL link: juejin.cn/post/704358… Source: Rare earth mining copyright belongs to the author. Commercial reprint please contact the author for authorization, non-commercial reprint please indicate the source.