The Android 11 adaptation has finally begun. Take notes for anyone who needs them.

1. Preparation

As usual, first change the targetSdkVersion in our project to 30. Or use compatibility debugging tools, which I’ll talk about later.

2. The storage mechanism is updated

Scoped Storage

The specific adaptation method is not much different from last year’s Android 10 adaptation guide.

Note, however, that the partitioned storage mechanism is enforced with targetSdkVersion >= 30. Before the AndroidManifest. Add android: XML requestLegacyExternalStorage = “true” way of adaptation has no effect.

One more change: Android 11 allows direct access to media files in shared storage via file paths using apis other than the MediaStore API. These include:

  • FileAPI.
  • Native libraries, for examplefopen().

This is good news if you haven’t adapted to Android 10 before. Android 10 in AndroidManifest. Add Android: XML requestLegacyExternalStorage = “true” to adaptation, Android using the File directly on 11 API access media files. Have to say, wait for the party to win?

However, direct access to media files in shared storage using the original file path redirects to the MediaStore API, which has a performance impact (random reads and writes are about twice as slow). Using the raw file path directly does not offer any advantage over using the MediaStore API, so it is strongly recommended to use the MediaStore API directly.

MANAGE_EXTERNAL_STORAGE

Of course, there is a simple and crude adaptation method, access to external storage management rights. If your application is a mobile phone manager or file manager that needs to access a large number of files, apply for the MANAGE_EXTERNAL_STORAGE permission to direct users to the system Settings page. The code is as follows:

<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
        tools:ignore="ScopedStorage" />
Copy the code
public static void checkStorageManagerPermission(Context context) {
    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && ! Environment.isExternalStorageManager()) { Intent intent =newIntent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(intent); }}Copy the code

Note that even if you have MANAGE_EXTERNAL_STORAGE permission, you cannot access files in the Android/data/ directory.

Domestic use should have no impact on the MANAGE_EXTERNAL_STORAGE permission. On Google Play, however, you need to explain why your existing SAF or MediaStore doesn’t meet your application’s needs. Therefore, I personally do not recommend that you apply for the MANAGE_EXTERNAL_STORAGE permission for ease of adaptation.

Other details of the changes can be found in the documentation: Storage mechanism Updates in Android 11.

New Android 11 features – Scoped Storage

Storage Access Framework (SAF) changes

Android 11 adds the following restrictions to SAF:

  • useACTION_OPEN_DOCUMENT_TREEACTION_OPEN_DOCUMENT, cannot be viewedAndroid/data/Android/obb/ Directory and all its subdirectories.
  • useACTION_OPEN_DOCUMENT_TREEUnable to authorize access to the root directory, Download folder.

REQUEST_INSTALL_PACKAGES

In adaptation 8.0, we need to apply for the “Install application from unknown source” permission before installing apK package. Generally speaking, the first step is to jump to the authorization page for the user to manually open, and then return to the APP for installation.

In Android 11, apps are killed when users enable the install app from unknown sources option. This behavior is related to forcing partitioned storage because applications with REQUEST_INSTALL_PACKAGES permission can access the Android/ OBB directories of other applications.

Fortunately, after the user grants permission, the app will be killed, but the installation page will still pop up.

I have not found a suitable way to handle this change. For details, see: Android 11 Feature adjustment: Installing apps from external sources requires a restart of the APP


The Android/data/ and Android/obb/ directories and all their subdirectories cannot be accessed by other applications. So you need to pay attention to whether the files stored in this can be accessed by other programs.

The EXTRA_OUTPUT file is in a private directory, so I can’t crop images correctly. Therefore, it needs to be adapted for Android 11:

String fileName = System.currentTimeMillis() + ".jpg";
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
    // Clipping can't access App's private directory, so it can be saved to the public directory
    ContentValues values = new ContentValues();
    values.put(MediaStore.Images.Media.DISPLAY_NAME, fileName);
    values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
    values.put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_PICTURES + "/Crop");
    Uri uri = this.getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
    intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
} else{... }Copy the code

Or save to the Android/ Media shared file directory so that the version does not need to be adapted.

String fileName = System.currentTimeMillis() + ".jpg";
File file = new File(this.getExternalMediaDirs()[0].getAbsolutePath() + File.separator + fileName);
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(file));
Copy the code

Of course, if you are your own implementation of the tailoring function, then not affected.

3. Change the permission

Single permission authorization

Starting with Android 11, every time an app requests permission related to location information, microphone, or camera, the user-facing permission dialog box contains a once-only option. If the user selects this option in the dialog box, the system grants temporary single authorization to the application.

An application granted with a single permission can access data within a period of time, which depends on the application behavior and user operations:

  • When the application’s Activity is visible, the application can access related data.
  • If the user transfers the application to the background, the application can continue to access related data for a short period of time.
  • If you start a foreground service while your Activity is visible, and the user then moves your application to the background, your application can continue to access the relevant data until the foreground service is stopped.
  • If a user revokes a single authorization (for example, in system Settings), the application cannot access the data, whether or not you have started the foreground service. As with any permission, if the user revokes the application’s single authorization, the application process terminates.

The next time a user opens an application and a function in the application requests access to location information, microphone, or camera, the system prompts the user to grant permission again.

If you requested permission before the time limit, this change will have no effect on your application.

Request location permission

This section has been tweaked for Android 10, with the following rules:

Requesting ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION permission indicates that you have access to device location information in the foreground. In the request dialog box, if you select Always Allow, both the front and back ends can obtain location information. If you select Allow only when the application is in use, you only have the foreground permission.

In Android 11, the “always allow” option is removed from the request box. This means that by default you are not granted background access to device location information. If you attempt to request ACCESS_BACKGROUND_LOCATION permission at the same time as any other permission, the system will throw an exception and will not grant any of these permissions to the application.

The official adaptation suggestions and reasons are as follows:

It is recommended that the application perform incremental request for location permission, first requesting foreground location information access permission, and then requesting background location information access permission. Performing incremental requests provides users with greater control and transparency because they can better understand which functions in the application require access to background location information.

Two points can be summarized:

  • First request foreground location information access, then request background location information access.
  • Request access to background location information separately, not in conjunction with other permissions.

It’s also important to note how apps on different target platforms perform on Android 11:

  • Android 10 apps for target platforms will allow access to both front and back location information, but there will also be no “always allow” option.
  1. When there is no front and back location information permission:

  1. When you have access to the location information of the front desk:

  • Android 11 is the target platform
  1. If you do not have the location information permission of the foreground, you can only request the location information permission of the foreground:

  1. If you have the location information permission of the foreground, the system will jump to the following setting page when you request the location information of the background.

If always Allow is selected, the user has the permission to access the front and back location information. If the user rejects two application location access requests (such as a direct return), the subsequent requests for the same permission will be prompted with a message indicating that the request fails. (This is where we need to guide the user)

To explain “deny twice”, this is the visibility of the permissions dialog added on Android 11. Previously, we clicked “Ask no more” to deny permissions. Now there’s a go to system setting like the one above, and then hit the back button, which is also a denial of authorization. Of course, the user pressing the back button to close the permissions dialog does not count.

In summary, the difference with Android 10 is that the background permission request is separated, and the user “reject” condition is added, so that the application does not repeatedly request the user denied permission.

Package visibility

Package visibility is a new feature on Android 11 that improves system privacy security. Its function is to restrict the app from arbitrarily accessing information and installation status of other apps. Avoid security incidents such as phishing and user installation information leakage caused by viruses and spyware.

To obtain the list of automatically visible applications, run adb shell Dumpsys package queries to locate the forceQueryable part. Here are the results of the execution on vivo’s IQoo phone.

Queries: system apps queryable: false forceQueryable: [com.android.BBKCrontab,com.vivo.fingerprint,com.vivo.epm,com.vivo.abe,com.vivo.fingerprintengineer,com.vivo.contentcatc her,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.v ivo.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,co m.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.datastatu snotification,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 ......Copy the code

You can see that they are all system application package names, so our tripartite applications are not visible by default. Most of the changes affect features like shared payments that need to interact with other apps. Here’s a simple example:


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(a) {
    Intent intent = new Intent();
    intent.setClassName("com.tencent.mm"."com.tencent.mm.ui.tools.ShareImgUI");
	Log.d("hasActivity:", hasActivity(this, intent) + "");
}
Copy the code

The hasActivity method uses queryIntentActivities to determine whether the page exists. However, in targetSdkVersion >= 30, these three parties are not visible by default. So it always returns false. Similar methods getInstalledPackages and getPackageInfo are also subject to restrictions.

To solve this problem, add the queries element to androidmanifest.xml and add the package names that need to be visible.

<manifest package="com.example.app">
    <queries>
        <package android:name="com.tencent.mm" /><- Specifies the wechat package name</queries>.</manifest>
Copy the code

I also used the following package names for adaptation, which we can add as needed:

<queries>
    <! - weibo -- -- >
    <package android:name="com.sina.weibo" />
    <! -- QQ -->
    <package android:name="com.tencent.mobileqq" />
    <! -- Alipay -->
    <package android:name="com.eg.android.AlipayGphone" /> 
    <! -- AlipayHK -->
    <package android:name="hk.alipay.wallet" />
</queries>
Copy the code

In addition to adding the package name directly, we can add it as an intent or 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>
Copy the code

For details, see Managing Package Visibility

Of course, there is also a crude way to apply for permissions QUERY_ALL_PACKAGES directly. If your app needs to be available on Google Play, you might want to pay attention to the policy. To respect user privacy, it is recommended that our application be adapted with the minimum package visibility required to function properly.

It is important to note that the startActivity method we use everyday is not affected by the system package visibility behavior, even if hasActivity is false. If we make a hasActivity-like judgment before making a jump, it will be affected.

To use the queries element, you need Android Gradle version 4.1 or later. This element is not compatible with older versions of the plugin.

Front Desk Service Type

In Android 10, you need to add the location service type in the corresponding service to access the location information in the foreground service.

Similarly, in Android 11, camera or microphone service types need to be added in the corresponding service to access the camera or microphone in the foreground service.

<manifest>.<service 
       android:name="MyService"
       android:foregroundServiceType="microphone|camera" />
</manifest>
Copy the code

This restriction change prevents the application from starting the service in the background to access the camera and microphone. If necessary, only the front desk can enable the front desk service. Unless:

  • Services are started by system components.
  • The service is started through the application widget.
  • The service is started by interacting with notifications.
  • A service isPendingIntentStarted, which is sent from another visible application.
  • The service is started by an application, which is a DPC and runs in device owner mode.
  • The service is provided by oneVoiceInteractionServiceThe application starts.
  • The service consists of one withSTART_ACTIVITIES_FROM_BACKGROUNDPermission to start the application.

Automatic permission reset

If the app is targeted at Android 11 or higher and has not been used for several months, the system protects user data by automatically resetting the run-time sensitive permissions that the user has granted to the app. As shown below:

Note in the figure above that there is a switch to enable automatic reset. If our application has special needs, we can instruct the user to turn it off. Example code is as follows:

public void checkAutoRevokePermission(Context context) {
	// Check whether it is enabled
    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && ! context.getPackageManager().isAutoRevokeWhitelisted()) {// Jump to Settings page
        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); }}Copy the code

SYSTEM_ALERT_WINDOW permissions

I did not use this part in the adaptation, and directly copied the document:

In Android 11, the system automatically grants the SYSTEM_ALERT_WINDOW permission to certain types of applications upon request:

  • The system automatically grants this permission to all applications that have ROLE_CALL_SCREENING and request SYSTEM_ALERT_WINDOW. If an application loses ROLE_CALL_SCREENING, it loses this permission.

  • This permission is automatically granted to all applications requesting SYSTEM_ALERT_WINDOW by MediaProjection unless the user has explicitly refused to grant it to the application. This permission is lost when the application stops capturing the screen. This use case is primarily used for live game applications.

Instead of sending ACTION_MANAGE_OVERLAY_PERMISSION to obtain SYSTEM_ALERT_WINDOW permission, these applications simply request SYSTEM_ALERT_WINDOW directly.

MANAGE_OVERLAY_PERMISSION Intent always directs the user to the system permission screen

Starting with Android 11, ACTION_MANAGE_OVERLAY_PERMISSION Intent always directs the user to the top-level Settings screen, where the user can grant or revoke the application’s SYSTEM_ALERT_WINDOW permission. Any package: data in the intent is ignored.

On earlier versions of Android, ACTION_MANAGE_OVERLAY_PERMISSION Intent can specify a package that directs the user to an application-specific screen to manage permissions. Starting with Android 11, this feature will no longer be supported. Instead, users must first choose which applications to grant or revoke. This change protects users by making permissions more purposeful.

Read the phone number

If you get the phone number using the getLine1Number method in TelecomManager, or the getMsisdn method in TelephonyManager. Add READ_PHONE_NUMBERS to Android 11. The use of other methods is not restricted.

<manifest>
    <! MaxSdkVersion ="29" --> maxSdkVersion="29" -->
    <uses-permission android:name="android.permission.READ_PHONE_STATE"
                     android:maxSdkVersion="29" />
    <uses-permission android:name="android.permission.READ_PHONE_NUMBERS" />
</manifest>
Copy the code

4. Other behavior changes

Customize the Toast of the view

Android 11 is an application on the target platform. The system will block the Toast message of a custom view sent from the background. Front desk use is not affected. The setView and getView corresponding to Toast have been abandoned and are not recommended to be used.

For background use, it is recommended to use the default toast or Snackbar instead.

APK signature

Android 11 is an application on the target platform. An application signed only by V1 cannot be installed or updated on an Android 11 device. You must use version V2 or later for signature.

Android 11 also added support for THE APK signature scheme V4.

AsyncTask

AsyncTask is not recommended for Android 11 and is recommended to be migrated to Kotlin’s coroutine.

In additionHandlerIs not specifiedLooperThe constructor is also not recommended.

It is recommended to specify Looper explicitly:

private Handler handler = new Handler(Looper.myLooper());
/ / or
private Handler handler = new Handler(Looper.getMainLooper());
Copy the code

Status bar height

If targetSdkVersion is 30, the height of the status bar is 0. If targetSdkVersion is less than 30, the height of the status bar is 0. So use WindowMetrics to adapt:

public static int getStatusBarHeight(Context context) {

 	if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
        WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        WindowMetrics windowMetrics = wm.getCurrentWindowMetrics();
        WindowInsets windowInsets = windowMetrics.getWindowInsets();
        Insets insets = windowInsets.getInsetsIgnoringVisibility(WindowInsets.Type.navigationBars() | WindowInsets.Type.displayCutout());
        returninsets.top; }... }Copy the code

WindowMetrics is a new class in Android 11 that can be used to get window boundaries, as well as navigation heights.

5. Add tools

Compatibility Debugging Tool

In the past, when we made adaptation, we need to change the targetSdkVersion in our project to the corresponding version. As a result, your adaptation process may be affected by other changes, and this new compatibility debugging tool allows you to enable adaptation on a case-by-case basis without updating targetSdkVersion.

Usage:

  • Find the application Compatibility change option in developer options.
  • Click in to find the app you need to debug
  • In the change list, find the change you want to turn on or off, and click the switch.

The first line up hereDEFAULT_SCOPED_STORAGEPartitioned storage is enabled. These constants are described in the following table:Android 11 Change list.

For details about how to use the compatibility debugging tool, see: Compatibility Framework Tool, which is limited to space.

Wireless debugging

A wireless debugging feature has been added to Android 11’s developer options. Similar to the function of connecting bluetooth headset, it can be used for daily development and debugging without USB cable. (Unlike previous Android WIFI ADB, this is real wireless, haha)

Usage:

  • Find wireless Debugging in developer options and turn it on.
  • For the first time, click “Match device with Matching code”.
  • runadb pair ipaddr:portThen enter the matching code to connect.

Matters needing attention:

  • Keep your computer and phone on the same network.
  • The version of Platform Tools must be larger than 30.0. You can useadb --versionLook at it.

However, after my own experience, I feel that the connection is not very stable. I don’t know whether it is the problem of AS or the phone. It also disconnects after locking the screen, which is not a very good experience… Look forward to further optimizations.


This article is a bit too much. To summarize, Android 11 has a lot of changes in permissions, but if you follow best practices for requesting permissions, there is little additional adaptation.

Finally, for single authorization, visibility of permissions dialog boxes, SYSTEM_ALERT_WINDOW permissions, and installing APK, these changes will take effect on Android 11, regardless of whether you are an Android 11 adapter. As for other changes and apis (camera, 5G, waterfall screen, keyboard, etc.), I haven’t come across them yet, so they are not listed. If you need them, you can click the official document link at the end of this article.

At the time of writing this blog, I have found only bilibili on my phone that has been adapted to Android 11. Most are stuck at 28, 29, and even 26 (the minimum fit for Android 8.0 in China).

So I’ve attached a guide for Android 9 and 10 that I wrote earlier:

  • Android 9.0 Adaptation Guide
  • Android 10 Adaptation Guide

You may not be able to use this for a while, but you can’t live without it. Like collection is not too much ~~

reference

  • Android 11 official documentation
  • The storage mechanism in Android 11 has been updated
  • Wechat development platform – Android 11 system strategy update
  • OPPO – Android 11 Application compatibility and Adaptation Guide