Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

The method of Android10 adaptation

2025-01-18 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)05/31 Report--

Most people do not understand the knowledge points of this "Android10 adaptation method" article, so the editor summarizes the following content, detailed content, clear steps, and has a certain reference value. I hope you can get something after reading this article. Let's take a look at this "Android10 adaptation method" article.

Preparatory work

The old rule is to change the targetSdkVersion in our project to 29 first.

1.Scoped Storage (partitioned Storage) description

In versions prior to Android 10, we would apply for read and write access to the storage space when doing file operations. However, these permissions are completely abused, and the problem is that the storage space of the phone is filled with a large number of files of unknown functions, and it is not deleted after the app is uninstalled. To solve this problem, the concept of Scoped Storage was introduced in Android 10 to achieve better file management by adding external storage access restrictions.

First of all, define a concept, external storage and internal storage.

Internal storage: / data directory. Generally speaking, we use the getFilesDir () or getCacheDir () method to obtain the internal storage path of this application. Reading and writing files under this path do not need to apply for storage space read-write permission, and will be deleted automatically when the application is uninstalled.

External storage: / storage or / mnt directory. Generally, we use the path obtained by the getExternalStorageDirectory () method to access the file.

Because of different manufacturers and system versions, the above method does not have a fixed file path. Understanding the above concepts, then what we call external storage access restrictions can be considered to be for files under the getExternalStorageDirectory () path. The specific rules are shown in the following table:

The figure above divides the external storage space into three parts:

A specific directory (App-specific), accessed using the getExternalFilesDir () or getExternalCacheDir () method. No permissions are required and will be deleted automatically when the application is uninstalled.

Media files such as photos, video and audio. Using MediaStore access, READ_EXTERNAL_STORAGE permission is required to access media files from other applications.

Other directories, using the storage access framework SAF (Storage Access Framwork)

So even if you have read and write access to the storage space on Android 10, there is no guarantee that you can read and write files normally.

Adaptation

The simplest and most rude way is to add android:requestLegacyExternalStorage= "true" to the AndroidManifest.xml to request the use of the old storage mode.

But I don't recommend this method. Because this configuration will be invalidated in the next version of Android, external storage restrictions will be enforced. In fact, it was mandatory long before Android Q Beta 3, but it was not enforced in order to give developers the right time to adapt. So if you don't seize this time to adapt, then Android 11 will come out in the second half of this year. Direct flowering ~ ~

If you have already adapted to Android 10, here is a phenomenon to pay attention to:

If the application is installed through an upgrade, the previous storage mode (Legacy View) will also be used. New mode (Filtered View) can only be enabled by first installation or by uninstalling and reinstalling.

So when adapting, our judgment code is as follows:

/ / use Environment.isExternalStorageLegacy () to check the running mode of APP if (Build.VERSION.SDK_INT > = Build.VERSION_CODES.Q & &! Environment.isExternalStorageLegacy ()) {}

The advantage is that you can easily move the user's data to a specific directory of the application after the user has upgraded. Otherwise, you can only move through SAF, which will be very troublesome. If you want to move data, note that it only applies to Android 10, so now is a good time to adapt. Of course, if you don't need to migrate data, it's easier to adapt.

Let's talk about the recommended adaptation:

For the file operations involved in the application, modify your file path.

We used to use the Environment.getExternalStorageDirectory () method, but now we can use the getExternalFilesDir () method (including files such as downloaded installation packages). If it is a cache type file, you can put it under the getExternalCacheDir () path.

Or, using MediaStore, save the file to the corresponding media type (picture: MediaStore.Images, video: MediaStore.Video, audio: MediaStore.Audio), but only for multimedia files.

The following code saves the picture to a public directory and returns Uri:

Public static Uri createImageUri (Context context) {ContentValues values = new ContentValues (); / / optional values.put (MediaStore.Images.Media.DESCRIPTION, "This is an image"); values.put (MediaStore.Images.Media.DISPLAY_NAME, "Image.png"); values.put (MediaStore.Images.Media.MIME_TYPE, "image/png"); values.put (MediaStore.Images.Media.TITLE, "Image.png") when you need to specify file information Values.put (MediaStore.Images.Media.RELATIVE_PATH, "Pictures/test"); return context.getContentResolver (). Insert (MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);}

Access to media resources: scenarios such as image selectors. You cannot use File directly, you should use Uri instead. Otherwise, the error is as follows:

Java.io.FileNotFoundException: open failed: EACCES (Permission denied)

For example, when I used the picture selector in the adaptation project, I first modified Glide to display the picture by loading File. Change to the way Uri is loaded, otherwise the picture will not be displayed.

MediaStore is still used to obtain Uri:

String id = cursor.getString (cursor.getColumnIndexOrThrow (MediaStore.Images.Media._ID)); Uri uri = Uri.withAppendedPath (MediaStore.Images.Media.EXTERNAL_CONTENT_URI, id)

Secondly, in order not to affect the logic of returning File when selecting a picture before (because it is usually uploading File, not uploading Uri directly), I saved the final selected file into getExternalFilesDir (). The main code is as follows:

File imgFile = this.getExternalFilesDir ("image"); if (! imgFile.exists ()) {imgFile.mkdir ();} try {File file = new File (imgFile.getAbsolutePath () + File.separator + System.currentTimeMillis () + ".jpg"); / / use the openInputStream (uri) method to get the byte input stream InputStream fileInputStream = getContentResolver (). OpenInputStream (uri); FileOutputStream fileOutputStream = new FileOutputStream (file); byte [] buffer = new byte [1024] Int byteRead; while (- 1! = (byteRead = fileInputStream.read (buffer) {fileOutputStream.write (buffer, 0, byteRead);} fileInputStream.close (); fileOutputStream.flush (); fileOutputStream.close (); / / New file available path file.getAbsolutePath ()} catch (Exception e) {e.printStackTrace ();}

If you want to get the location information in the picture, you need to apply for ACCESS_MEDIA_LOCATION permission and use MediaStore.setRequireOriginal () to get it. Here is the official sample code:

Uri photoUri = Uri.withAppendedPath (MediaStore.Images.Media.EXTERNAL_CONTENT_URI, cursor.getString (idColumnIndex)); final double [] latLong; / / get location information from the ExifInterface class photoUri = MediaStore.setRequireOriginal (photoUri); InputStream stream = getContentResolver (). OpenInputStream (photoUri); if (stream! = null) {ExifInterface exifInterface = new ExifInterface (stream); double [] returnedLatLong = exifInterface.getLatLong () / / If lat/long is null, fall back to the coordinates (0,0). LatLong = returnedLatLong! = null? ReturnedLatLong: new double [2]; / / Don't reuse the stream associated with the instance of "ExifInterface". Stream.close ();} else {/ / Failed to load the stream, so return the coordinates (0,0). LatLong = new double [2];}

In this way, a picture selector is basically adapted.

Supplement

After the application is uninstalled, the data in the App-specific directory will be deleted. If it is stated in the AndroidManifest.xml: android:hasFragileUserData= "true" users can choose whether to keep it or not.

For the use of SAF, you can check out the SAF playbook I wrote earlier, so I won't expand on it here.

Finally, here is a video about Scoped Storage, which is recommended to watch:

two。 Permission change

Since 6.0, there will be changes in permissions every time, and this time is no exception. (a preview of Android 11 was released a few days ago, and there seems to be a change in permissions. One-time permission is coming)

1. Permission is required to access device location information when running in the background

Android 10 introduces ACCESS_BACKGROUND_LOCATION permissions (dangerous permissions).

This permission allows the application to access the location in the background. If you request this permission, you must also request ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION permissions. Only requesting this permission has no effect.

On Android 10 devices, if your application's targetSdkVersion

< 29,则在请求 ACCESS_FINE_LOCATION 或 ACCESS_COARSE_LOCATION 权限时,系统会自动同时请求 ACCESS_BACKGROUND_LOCATION 。在请求弹框中,选择"始终允许"表示同意后台获取位置信息,选择"仅在应用使用过程中允许"或"拒绝"选项表示拒绝授权。 如果你的应用的 targetSdkVersion >

= 29, the request for ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION permission means that you have the right to access the device location information at the foreground. In the request pop-up box, selecting "always allow" means that both the foreground and background can obtain the location information, and selecting "allow only during application use" only means that you have the permission of the foreground.

In fact, officials do not recommend you to apply for backend access, because the result is nothing more than asking for one more permission, so what's the point of this like a change? Applying for too many permissions will also cause disgust among users. So the official recommendation is to use the front desk service.

To achieve, get the location information in the foreground service.

First add android:foregroundServiceType= "location" to the corresponding service in the listing:

...

Check if you have access to the front desk before starting the front desk service:

Boolean permissionApproved = ActivityCompat.checkSelfPermission (this, Manifest.permission.ACCESS_COARSE_LOCATION) = = PackageManager.PERMISSION_GRANTED; if (permissionApproved) {/ / start the foreground service} else {/ / request foreground access location permission}

In this way, the location information can be obtained in Service.

two。 API for some phones, Bluetooth, and WLAN requires precise location permission

The following lists that you must have ACCESS_FINE_LOCATION permissions in Android 10 to use classes and methods:

Telephone

TelephonyManager

GetCellLocation ()

GetAllCellInfo ()

RequestNetworkScan ()

RequestCellInfoUpdate ()

GetAvailableNetworks ()

GetServiceState ()

TelephonyScanManager

RequestNetworkScan ()

TelephonyScanManager.NetworkScanCallback

OnResults ()

PhoneStateListener

OnCellLocationChanged ()

OnCellInfoChanged ()

OnServiceStateChanged ()

WLAN

WifiManager

StartScan ()

GetScanResults ()

GetConnectionInfo ()

GetConfiguredNetworks ()

WifiAwareManager

WifiP2pManager

WifiRttManager

Bluetooth

BluetoothAdapter

StartDiscovery ()

StartLeScan ()

BluetoothAdapter.LeScanCallback

BluetoothLeScanner

StartScan ()

We can check whether it is used in the adaptation project and deal with it in time according to the specific classes and methods provided above.

3.ACCESS_MEDIA_LOCATION

Android 10 added permissions, which have been mentioned above, so I won't repeat them.

4.PROCESS_OUTGOING_CALLS

This permission has been deprecated on Android 10.

3. Restrictions on launching Activity in the background

The simple explanation is that Activity cannot be started when the application is in the background. For example, clicking on an application will go to the launch page or advertising page, and there will usually be a delay of a few seconds before jumping to the home page. If you step back backstage during this period, you will not be able to see the jump process. In previous versions, the page was forced to pop up to the foreground.

Since it is a restriction, then there must be unrestricted cases. There are mainly the following points:

Applications have visible windows, such as foreground Activity.

Apply the Activity that already exists in the return stack of the foreground task.

Applies the Activity that already exists in the return stack of an existing task on Recents. Recents is our task management list.

The application receives a PendingIntent notification from the system.

The application receives the system broadcast in which it should launch the interface. Examples include ACTION_NEW_OUTGOING_CALL and SECRET_CODE_ACTION. The application can start Activity a few seconds after the broadcast is sent.

The user has granted SYSTEM_ALERT_WINDOW permission to the application, or turn on the switch on the background pop-up page on the application permissions page.

Because this behavior change applies to all applications running on Android 10, the most obvious problem caused by this limitation is that some applications cannot jump properly when clicking on push messages (caused by specific implementation problems). Therefore, to solve this kind of problem, we can take the way of PendingIntent and use the setContentIntent method when sending notifications.

Of course, you can also apply for appropriate permissions or whitelist:

However, the method of applying for a whitelist is limited by various mobile phone manufacturers, which is very troublesome. It would be better to guide the user to turn on the permissions manually.

For full-screen intent, pay attention to setting the highest priority and adding the USE_FULL_SCREEN_INTENT permission, which is a normal permission. For example, when Wechat makes a voice or video call, the pop-up answer page uses this function.

Intent fullScreenIntent = new Intent (this, CallActivity.class); PendingIntent fullScreenPendingIntent = PendingIntent.getActivity (this, 0, fullScreenIntent, PendingIntent.FLAG_UPDATE_CURRENT); NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder (this, CHANNEL_ID) .setSmallIcon (R.drawable.notification_icon) .setContentTitle ("Incoming call") .setContentText ("(919) 555-1234") .setPriority (NotificationCompat.PRIORITY_HIGH) / /

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report