Android 6
Dynamic application of runtime permissions, here we recommend Guo Lin’s open source library:/guolindev/PermissionX
Android 7
On Android 7.0 system, it is prohibited to expose file:// URI to your application. If an Intent containing file file:// URI type leaves your application, the application fails and a FileUriExposedException exception occurs, such as calling the system camera to take a photo. To share files between applications, you can send a Uri of content:// URI type and grant temporary access to the URI using the FileProvider class.
The general steps to using FileProvider are as follows:
1. Create the xml directory under res, and create the file_paths.xml file under this directory, with the following content:
<?xml version="1.0" encoding="utf-8"?> <paths> <!-- Internal storage,Equivalent to,path:/data/data/Package name/filesTable of contents--> <files-path name="DocDir" path="/" /> <!-- Internal storage,Equivalent to,path:/data/data/Package name/cacheTable of contents--> <cache-path name="CacheDocDir" path="/" /> <!--External storage,Equivalent to,path:/storage/sdcard/Android/data/Package name/files--> <external-files-path name="ExtDocDir" path="/" /> <!--External storage,Equivalent to path:/storage/sdcard/Android/data/Package name/cache--> <external-cache-path name="ExtCacheDir" path="/" /> </paths>
2. Register the provider in manifest
<provider android:name="" android:authorities="" android:exported="false" android:grantUriPermissions="true"> <!--exported:To befalse,fortrueA security abnormality will be reported。grantUriPermissionsfortrue,Indicates grantURITemporary access permissions--> <meta-data android:name=".FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider>
3. Use FileProvider
val file = File( getExternalFilesDir(null), "/temp/" + () + ".jpg" ) if (!()) { () } //Create a content type Uri through FileProvider val imageUri = ( this, "", file ) val intent = Intent() // Indicates that the file represented by the Uri is temporarily authorized to the target application (Intent.FLAG_GRANT_READ_URI_PERMISSION) = MediaStore.ACTION_IMAGE_CAPTURE //Save the taken photos to a specific URI (MediaStore.EXTRA_OUTPUT, imageUri) startActivity(intent)
Android 8
Android 8.0 introduces notification channels, allowing the creation of user-customizable channels for each notification type to be displayed, and the user interface calls notification channels a notification category.
private fun createNotification() { if (.SDK_INT >= Build.VERSION_CODES.O) { val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager //If you want to group, groupId should be unique val groupId = "group1" val group = NotificationChannelGroup(groupId, "advertisement") (group) //channelId unique val channelId = "channel1" val notificationChannel = NotificationChannel( channelId, "promote information", NotificationManager.IMPORTANCE_DEFAULT ) //Add channels into groups, you must create a group before adding = groupId (notificationChannel) //Create notification val notification = (this, channelId) .setSmallIcon(.ic_launcher) .setLargeIcon((resources, .ic_launcher)) .setContentTitle("A new notice") .setContentText("Likes and follows") .setAutoCancel(true) .build() (1, notification) } }
After Android 8.0, background applications are not allowed to start background services. They need to specify as foreground service through startForegroundService(). The application has five seconds to call the service's startForeground() method to display visible notifications. If startForeground() is not called within this time limit, the system stops Service and declares that the application is ANR.
if (.SDK_INT >= Build.VERSION_CODES.O) { val intent = Intent(this, UncleService::) startForegroundService(intent) }
class UncleService : Service() { override fun onCreate() { () if (.SDK_INT >= Build.VERSION_CODES.O) { val manager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager val channel = NotificationChannel("channelId", "channelName", NotificationManager.IMPORTANCE_HIGH) (channel) val notification = (this, "channelId") .build() startForeground(1, notification) } } override fun onDestroy() { () stopForeground(true) } override fun onBind(p0: Intent?): IBinder? { return null } }
Don't forget to add permissions in manifest
<uses-permission android:name=".FOREGROUND_SERVICE"/>
Android 9
In network requests in Android 9, http requests are not allowed, https is required.
Solution:
Create a new xml directory under res, and then create a file named: network_config.xml
<?xml version="1.0" encoding="utf-8"?> <network-security-config> <base-config cleartextTrafficPermitted="true" /> </network-security-config>
Then configure the property under the Mainfests application tag
android:networkSecurityConfig="@xml/network_config"
This is a simple and crude method. For security and flexibility, we can specify http domain name, and use http when some domain names.
<?xml version="1.0" encoding="utf-8"?> <network-security-config> <domain-config cleartextTrafficPermitted="true"> <domain includeSubdomains="true"></domain> </domain-config> </network-security-config>
Android 10
Position permissions
Users can better control when the app can access the device location. When an application running on Android 10 requests location access, the user will be given an authorization prompt through a dialog box. At this time, there are two location access permissions: in use (foreground only) or always (foreground and backend)
Added permissions ACCESS_BACKGROUND_LOCATION
If your app is targeted at Android 10 and needs to access the user's location while running in the background, you must declare new permissions in the app's manifest file
<uses-permission android:name=".ACCESS_COARSE_LOCATION" /> <uses-permission android:name=".ACCESS_BACKGROUND_LOCATION" /> <uses-permission android:name=".ACCESS_FINE_LOCATION" />
Partition storage
On versions before Android 10, we will apply for read and write permissions of storage space when doing file operations. However, these permissions are completely abused, and the problem is that the mobile phone's storage space is filled with a large number of unknown files, and it is not deleted after the application is uninstalled. To solve this problem, the concept of partitioned storage was introduced in Android 10, enabling better file management by adding external storage access restrictions. But the application is not thorough, because we can add android:requestLegacyExternalStorage="true" to request the use of the old storage mode to make simple and rough adaptations. But I do not recommend this because Android 11 enforces the partition storage mechanism, and this configuration will be invalid, so I have to do the adaptation honestly. Let’s take a look at the adaptation of Android 11 below.
Android 11
There are two types of access that can be accessed without storage permissions. One is the app's own internal storage, and the other is the app's own external storage.
The difference between storage scope access is reflected in how to access files in directories other than that.
Enforce partition storage
The shared storage space stores pictures, videos, audio and other files. These resources are public and can be accessed by all apps. The shared storage space stores pictures, videos, audios, and downloaded files. How to distinguish these types when the app acquires or inserts files? MediaStore is needed at this time. For example, if you want to query the image files in the shared storage space:
val cursor = ( .EXTERNAL_CONTENT_URI, null, null, null, null )
.EXTERNAL_CONTENT_URI means specifying that the type of query file is an image and constructed as a Uri object. Uri implements Parcelable and can be passed between processes.
Since files cannot be accessed directly through paths, how can I access files through Uri? Uri can be obtained through MediaStore or SAF. However, it should be noted that although Uri can be directly constructed through the file path, Uri constructed in this way does not have permission to access files.
Now let's read a text file in the /sdcard/ directory. Since it does not belong to the file in the shared storage space and belongs to other directories, it cannot be obtained through MediaStore, but can only be obtained through SAF.
private fun openSAF() { val intent = Intent(Intent.ACTION_OPEN_DOCUMENT) (Intent.CATEGORY_OPENABLE) //Specify the file that selects the text type = "text/plain" startActivityForResult(intent, 1) } override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { (requestCode, resultCode, data) if (requestCode == 1 && data != null) { val uri = startRead(uri!!) } } private fun startRead(uri: Uri) { try { val inputStream = (uri) val readContent = ByteArray(1024) var len: Int do { len = inputStream!!.read(readContent) if (len != -1) { (tag, "file content:${String(readContent).substring(0, len)}") } } while (len != -1) } catch (e: Exception) { (tag, "Exception:${}") } }
From this we can see that files belonging to "other directories" need to be accessed through SAF. SAF returns to Uri, and the InputStream is constructed through Uri to read the file.
Next, let’s write the content into the file. You still need to get Uri through SAF and construct the output stream after getting Uri.
private fun writeForUri(uri: Uri) { try { val outputStream = (uri) val content = "my name is Uncle Xing" outputStream?.write(()) outputStream?.flush() outputStream?.close() } catch (e: Exception) { (tag, "Exception:${}") } }
The advantage of SAF is that the system provides a file selector. The caller only needs to specify the file type to be read and written, such as text type, picture type, video type, etc. The selector will filter out the corresponding files for selection, which is simple to use.
Location permissions
Android 10 requests ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION means that you have permission to access device location information in the foreground. You can also see the Always Allowed option in the request box. In Android 11, the Always Allowed option is cancelled, and the background will not be granted permission to access device location information by default. Android 11 extracts the background device location information to obtain the background device location information through ACCESS_BACKGROUND_LOCATION permission. One thing to note is that other permissions cannot be requested while requesting ACCESS_BACKGROUND_LOCATION, otherwise the system will throw an exception. The official suggestion is to first request the front-end location information access permission, and then request the back-end location information access permission.
This is the article about the compatibility adaptation method for different versions of Android. For more related Android compatibility adaptation content, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!