Let’s take a look at what Android 11 has changed and, most importantly, how it needs to be adapted. If targetVersion is not changed to 30, does it need to be adapted?

I will talk about it in two parts

  • Android 11 targeted version (targetSdkVersion>=30)

  • All apps adapt to Android 11 devices (regardless of targetSdkVersion, any app running on Android 11 devices will be affected)

Why say targetSdkVersion>=30 first? Generally speaking, in order to make us adapt to the new content in a longer time and ensure the stability of the application on the line, Google will put the content with big changes that need time to adapt into the corresponding application of the new targetSdkVersion. If you do not have the requirement of adapting targetSdkVersion30 for the time being, Also look at module 2 to see if it covers your application.

Adapter targetSdkVersion30

Changes to this module only take effect for targetSdkVersion 30 or above.

Partitioned storage forcibly executed

Access to external storage directories is limited to application-specific directories and specific types of media that have been created by the application.

Partition storage has been implemented in Android 10. Simply put, applications can only read and write files in sandbox environment, that is, the directory of their own application. Other media files can be accessed through MediaStore.

But with Android 10, Google has left one hand open for developers. In targetSdkVersion = 29 applications, set the android: requestLegacyExternalStorage = “true”, can not boot partition storage, file read before normal use. But targetSdkVersion = 30 is not available, forcibly enable partition storage.

Android, of course, as a human, or left a small hand for developers, if it is cover installation, can increase the Android: preserveLegacyExternalStorage = “true”, the temporary closure partition storage, good let developers to complete data migration work. Why temporary? Because as soon as you unload and reinstall it, it won’t work. Here’s what happens with partitioned storage

All cases

, listed to everyone, first on the code:

Fun saveFile () {if (checkPermission ()) {/ / getExternalStoragePublicDirectory was abandoned, Partition storage after opening were not allowed to access the val filePath = Environment. GetExternalStoragePublicDirectory (" "). The toString () + "/ test3. TXT" val fw = FileWriter(filePath) fw.write("hello world") fw.close() showToast(" File written successfully ")}}Copy the code

1) targetSdkVersion = 28, normal read and write after running. 2) targetSdkVersion = 29, do not delete the application, targetSdkVersion is changed from 28 to 29, overwrite the installation, normal read and write after running. 3) targetSdkVersion = 29, delete application, re-run, read and write error, program crash (open failed: EACCES (Permission denied)) 4) targetSdkVersion = 29, add the android: requestLegacyExternalStorage = “true” (not the partition storage), 5) targetSdkVersion = 30, do not delete the application, targetSdkVersion changed from 29 to 30, read and write error, program crash (open failed: EACCES (Permission denied)) 6) targetSdkVersion = 30 Increase the android: preserveLegacyExternalStorage = “true”, normal, speaking, reading and writing is not an error 7) targetSdkVersion = 30, delete the application, rerun, read/write error, the program crashes (open failed: EACCES (Permission denied))

Ok, so what should I change? There are three ways to access files:

1) App specific directories

Val file = file (context.filesdir, Filename) / / application exclusive external storage space val appSpecificExternalDir = File (context) getExternalFilesDir (), filename)Copy the code

2) Access public media directory files

val cursor = contentResolver.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, null, null, null, "${MediaStore.MediaColumns.DATE_ADDED} desc") if (cursor ! = null) { while (cursor.moveToNext()) { val id = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.MediaColumns._ID)) val uri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, id) println("image uri is $uri") } cursor.close() }Copy the code

SAF (Storage Access Framework)

val intent = Intent(Intent.ACTION_OPEN_DOCUMENT) intent.addCategory(Intent.CATEGORY_OPENABLE) intent.type = "image/*" startActivityForResult(intent, 100) @RequiresApi(Build.VERSION_CODES.KITKAT) override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) if (data == null || resultCode ! = Activity.RESULT_OK) return if (requestCode == 100) { val uri = data.data println("image uri is $uri") } }Copy the code

Speaking of which, some people may ask, then my app is a mobile phone manager, I have to clear the cache of other apps, there is a way! Android provides two intEnts:

  • Call ACTION_MANAGE_STORAGE Intent to check the available space.

  • Call ACTION_CLEAR_APP_CACHE intent to clear all caches.

Anyway, application data privatization is the trend, or early adaptation of partitioned storage.

All file access rights

Having said that, there are some applications that require access to all files, such as antivirus software and file managers. Don’t worry, there is a way! MANAGE_EXTERNAL_STORAGE. This permission is used to obtain administrative permission for all files.

<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" /> val intent = Intent() intent.action= ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION startActivity(intent) // Determine whether to obtain MANAGE_EXTERNAL_STORAGE permission:  val isHasStoragePermission= Environment.isExternalStorageManager()Copy the code

Phone number permission

Android 11 changes the phone-related permissions that your app uses to read phone numbers.

What exactly has changed? There are actually two apis:

  • The getLine1Number() method in the TelecomManager class

  • The getMsisdn() method in the TelecomManager class

The READ_PHONE_STATE permission is no longer available when using both apis. READ_PHONE_NUMBERS is required.

To be specific, change targetSdkVersion to 30 and run a program to get the phone number:

ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.READ_PHONE_STATE), 100)         
btn2.setOnClickListener {            
    val tm = this.applicationContext.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager            
    val phoneNumber = tm.line1Number            
    showToast(phoneNumber)        
} 
Copy the code

Collapse:

 java.lang.SecurityException: getLine1NumberForDisplay: Neither user 10151 nor current process has android.permission.READ_PHONE_STATE, android.permission.READ_SMS, or android.permission.READ_PHONE_NUMBERS 
Copy the code

As expected, the permission is registered in andmanifest.xml and the dynamic permission request is added:

<uses-permission android:name="android.permission.READ_PHONE_STATE" />    
<uses-permission android:name="android.permission.READ_PHONE_NUMBERS" />     
ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.READ_PHONE_STATE,Manifest.permission.READ_PHONE_NUMBERS), 100) 
Copy the code

There you go. If you only need to get phone numbers, you can also apply for READ_PHONE_NUMBERS only:

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

The custom message box view is masked

As of Android 11, the custom message box view has been deprecated. If your app is targeting Android 11, message boxes containing custom views will be masked when published from the background

You might wonder, what is a custom message box view? If I say “custom toast views” in English, it means a custom toast. Write a simple code:

Toast toast = new Toast(context);    
toast.setDuration(show_length);    
toast.setView(view);    
toast.show();
Copy the code

Oops oops, custom toast is out? This is what we use in our project! Don’t worry, custom toasts are no longer allowed to display in the background. Let’s say I write a toast 3 seconds later and then go into the background as soon as the app opens to see what happens:

Handler().postdelayed ({itoast.show (" Hello, I'm customizing toast")}, 3000) W/NotificationService: Blocking custom toast from package com.example.studynote due to package not in the foregroundCopy the code

Nothing, just a warning. So don’t worry too much. If you really need a background display, just use a toast.

Now you need the APK signature scheme V2

For applications that use Android 11 (API level 30) as the target platform and only use APK signature scheme V1, you must use APK signature scheme v2 or later to sign applications. Users cannot install or update applications signed only by APK signature scheme V1 on Android 11 devices.

If you change your targetSdkVersion to 30, you must add the v2 signature. Otherwise, it cannot be installed and updated.

Media Intents require the system’s default camera

Starting with Android 11, only pre-installed system camera apps can respond to the following intEnts:

android.media.action.VIDEO_CAPTURE

android.media.action.IMAGE_CAPTURE

android.media.action.IMAGE_CAPTURE_SECURE

That is, if I call the intent to invoke the camera and use the VIDEO_CAPTURE action, only the system camera will respond, and the third-party camera application will not.

Val intent = intent () intent. Action = android. The provider. The MediaStore. ACTION_IMAGE_CAPTURE startActivity (intent) / / can't arouse the third-party camera, Can only evoke the system cameraCopy the code

This is a bit of a blow to normal camera apps. The official advice is that if you want to use a particular third-party camera app to capture images or videos on its behalf, you can make the intent explicit by setting the package name or component for the intent.

5G 

Android 11 adds support for 5G in your apps

The new Android 11 also supports 5G-related features, including:

  • Check if you’re connected to a 5G network

  • Check per-traffic billing

Background location information access permission

  • Starting from Android 10 devices, you need to request the background location permission (ACCESS_BACKGROUND_LOCATION) and select Allow all the time (always Allow) to obtain the background location permission. The background permission management is strengthened again on Android 11, which is mainly reflected in the system dialog box. The dialog box no longer prompts “Always Allow”, but provides the setting entrance of location permission. You need to select “always Allow” on the setting page to obtain the background location permission.

  • On devices equipped with Android 11 system, when targetVersion is less than 11, the foreground and background location permission can be applied together, and the dialog box provides a text description, indicating that the user location information needs to be obtained at any time. Enter the Settings and select always allow. However, with targetVersion 30, you must apply for background location permissions separately, and not out of order after obtaining foreground permissions. And there is no hint, the developer needs to design their own hint style.

It may be a bit convoluted, but here are a few examples:

1) For Android 10 devices, apply for foreground and background location permissions (any targetSdkVersion):

requestPermissions(arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_BACKGROUND_LOCATION), 100).Copy the code

2) Android 11 device, targetSdkVersion<=29(Android 10),

requestPermissions(arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_BACKGROUND_LOCATION), 100).Copy the code

3) Android 11 device, targetSdkVersion=30(Android 11)

requestPermissions(arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_BACKGROUND_LOCATION), 100).Copy the code

Executive nonresponse

4) Android 11 device, targetSdkVersion=30(Android 11), apply foreground location permission first, then apply background location permission:

requestPermissions(arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION), 100) and then execute requestPermissions (arrayOf (Manifest) permission) ACCESS_BACKGROUND_LOCATION), 100).Copy the code

So how do you fit in?

  • In the targetSdkVersion<30 case, if you already have the foreground and background location permissions, don’t worry, there is nothing to adapt.

  • TargetSdkVersion >30, you need to apply for the foreground and background location permission separately, and explain and guide the background location permission application, of course, in order to better serve users.

Package visibility

In Android 11, if you want to obtain the information of other applications, such as package name, name, etc., you cannot directly obtain the information. You must add the

element in the list file to tell the system which application information you want to obtain or which kind of application.

In Android 11, you can only query information about your own application and system application, but not about other applications. How do? Add the

element in two ways:

1) Add package names to the element

<manifest package="com.example.game"> <queries> <package android:name="com.example.store" /> <package android:name="com.example.services" /> </queries> ... </manifest>Copy the code

2) Add a fixed filter intent to the element

<manifest package="com.example.game">    <queries>        <intent>            <action android:name="android.intent.action.SEND" />            <data android:mimeType="image/jpeg" />        </intent>    </queries></manifest>
Copy the code

Some people may still wonder, what if my app is a browser or device manager? I’m gonna get all the package names, right? Rest assured, Android 11 also introduces QUERY_ALL_PACKAGES permissions, which can be added to the manifest file.

Document access restrictions

To give developers time to test, the following changes related to the Storage Access Framework (SAF) will only take effect if the app is targeted at Android 11.

Storage Access Framework (SAF) can be used to Access public directories. However, some directories and files cannot be accessed by Android 11 again. Details are as follows:

The following directories can no longer be requested using ACTION_OPEN_DOCUMENT_TREE Intent:

  • Root directory of the internal storage volume.

  • The root directory of each SD card volume that the device manufacturer considers reliable, whether the card is an analog or removable card. A reliable volume is one that an application can access successfully in most cases.

  • The Download directory.

You can no longer use ACTION_OPEN_DOCUMENT_TREE or ACTION_OPEN_DOCUMENT Intent actions to request the user to select a separate file from the following directory:

  • The Android/data/ directory and all its subdirectories.

  • The Android/obb/ directory and all its subdirectories.

Restrict read access to the APN database

11 for the application of the target platform for Android now. Must be able to Manifest the permission. WRITE_APN_SETTINGS privileges, to read or access phone provider APN database. If you try to access the APN database without this permission, a security exception is generated.

Automatic reset permission

If the app is targeted at Android 11 and has not been used for several months, the system protects the user’s data by automatically resetting the run-time sensitive permissions that the user has granted to the app. This action is the same as if the user views the permissions in the system Settings and changes the application’s access level to deny. If the application has followed best practices for requesting permissions at run time, you do not need to make any changes to the application. This is because when users interact with features in your application, you should verify that the relevant features have the required permissions.

The official instructions are clear, and as long as the application follows best practices for requesting permissions at run time, which is to determine every time a permission needs to be invoked, then there should be no problem.

What if you need to turn this feature off? With the user to Settings page closed, you can call an Intent containing settings. ACTION_APPLICATION_DETAILS_SETTINGS action to direct the user to the page applied in system Settings.

How do I check if auto reset is disabled? Call the PackageManager’s isAutoRevokeWhitelisted() method. If this method returns true, the system does not automatically reset application permissions.

Front Desk Service Type

Starting with Android 9, apps are limited to foreground access to the camera and microphone. To further protect users, Android 11 changes the way foreground services access data related to cameras and microphones. If your application targets The Android 11 platform and accesses these types of data in a foreground service, you need to add the new Camera and MICROPHONE types to the foregroundServiceType property declared by the foreground service.

For example, if applying a foreground service requires access to location information, camera, and microphone, add:

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

For Android 11 phones

The changes in this module are for all project changes that exist on Android 11 phones and are not related to targetSdkVersion.

Data access audit

To make the process by which apps and their dependencies access users’ private data more transparent, Android 11 has introduced data access auditing. With insights from this process, you can better identify and correct potential for unexpected data access.

What are the categories of user private data? This function provides a listener that can listen for dangerous permission calls. Mainly involves is AppOpsManager OnOpNotedCallback. Any access to private data (dangerous permissions) will be called back to us, either from the app itself or from code in the dependent libraries or SDK.

This function is suitable for large projects or projects that use more SDKS to make the private data management of their applications more transparent and standardized, otherwise the use and management of private data is not comprehensive and convenient. And you can also use add attribution for permissions, which is a tag, to indicate where the permissions are being used. It’s easy to know where private data is being used during callbacks.

OnOpNotedCallback has three callback methods:

  • OnNoted normally calls back to this method

  • OnAsyncNoted () is called if the data access does not occur during an application call to the API, such as some listener callbacks.

  • OnSelfNoted In rare cases, onSelfNoted() is called if an application passes its own UID to noteOp().

Finally, you can see the permission code: Android :coarse_location and attribution shareLocation

A single license

In 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.

In simple terms, when applying for permission related to location information, microphone or camera, the system will automatically provide a single authorization option, which can be obtained only once. Then the next time the user opens the app, the system will prompt the user to grant permission again. This effect should not be big, as long as we use every time to judge the authority, not to apply for.

Application usage statistics

To better protect users, Android 11 stores app usage statistics for each user in a credential encrypted storage space.

This involves UsageStatsManager, the Android service that provides statistics on app usage. This service allows you to obtain application usage statistics, component state change event statistics, and hardware configuration information statistics for a specified time interval.

QueryAndAggregateUsageStats method, for example, you can get use statistical data within the specified time interval, in packages called merge keys for data.

But on Android 11 devices, sorry, you can’t use this information freely. The data is accessible only if the isUserUnlocked() method returns true. That is, the following two situations:

  • The user unlocks the device for the first time after the system starts

  • Users switch to their own accounts on the device

The JobScheduler API calls restrict debugging

JobScheduler Is a task scheduler that can perform tasks when the device is idle. In Android 11 if you set it to Debug mode (the debuggable list property is set to true), JobScheduler API calls that exceed the rate limit will return RESULT_FAILURE. What’s the use of this? This should help us find some performance issues, so if you’re interested, try it out for yourself.

By the way, Jetpack component WorkManager also uses JobScheduler. If you are not familiar with it, JobScheduler is a system service started by the SystemServer process, so it has such a large authority.

Non-sdk interface restrictions

Android 11 includes an updated list of restricted non-SDK interfaces (based on collaboration with Android developers and recent internal testing). Before we restrict the use of non-SDK interfaces, we try to ensure that we provide exposed alternatives as much as possible.

As usual, Android 11 will also restrict some interfaces, including the gray list and white list, to see the list of non-SDK interfaces.