Android7.0 has been released for more than a month, Android7.0 has brought some new features to users at the same time, but also brought new challenges to developers, these days I will apply to Android7.0, which also encountered a lot of problems and stepped on some pits, Here is my adaptation on Android7.0 on some of the experience to share with you, so that your application can run on Android7.0 a day earlier.

Permission to change

As Android gets more advanced, so does its privacy. From Android6.0’s introduction of dynamic Permissions to Android7.0’s “private directories are restricted access”, “StrictMode API policies”. These changes create new tasks for developers as well as a more secure operating system for users. How to adapt your APP to these changes instead of cash is the responsibility of every Android developer.

Access to directories is restricted

For a long time, iOS has done a good job of protecting access to directories and files, such as the iOS sandbox mechanism. However, Android’s protection in this respect is a little weak, in Android applications can read and write any directory and files in the phone’s storage, which also brings a lot of security issues. Now Android is trying to solve this problem.

In Order to improve the security of private files in Android7.0, application private directories for Android N or later will be restricted. For this permission change, developers need to be aware of the change:

How to cope: This change in permissions will mean that you can no longer access data stored on your phone through the File API, and some File browsers based on the File API will also be significantly affected. So far, this restriction isn’t fully enforced. Applications may still use the native API or File API to modify their private directory permissions. However, Android officials are strongly opposed to granting permission to private directories. You can see that rolling back access to private files is the future of Android.

  • Passing the file:// URI to other applications may prevent recipients from accessing the path. Therefore, trying to pass the file:// URI in Android7.0 triggers a FileUriExposedException.

Solution: You can solve this problem by using FileProvider.

Strategy: everyone can through ContentResolver openFileDescriptor () to access by DownloadManager open files.

Files are shared between applications

On Android7.0, the Android framework enforces StrictMode API policies to prohibit exposing file:// URI outside of your application. If an Intent with the file:// URI type leaves your app, the application fails with a FileUriExposedException, such as calling the system camera to take a photo, or crop a photo.

Solution: To share files between applications, send a URI of type Content :// URI and grant temporary access to the URI. The easiest way to do this is to use the FileProvider class. For more information about permissions and sharing files, see Sharing Files.

On Android7.0 call system camera to take photos, cropped photos

Call the system camera to take photos

Before Android7.0, if you wanted to call the system camera to take a photo, you could do so with the following code:

File file=new File(Environment.getExternalStorageDirectory(), "/temp/"+System.currentTimeMillis() + ".jpg"); if (! file.getParentFile().exists())file.getParentFile().mkdirs(); Uri imageUri = Uri.fromFile(file); Intent intent = new Intent(); intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE); PutExtra (mediastore. EXTRA_OUTPUT, imageUri); // Save the photo to the specified URI startActivityForResult(Intent,1006);Copy the code



Android7.0 photographs. PNG

On Android7.0, using the above method to call the system camera will raise the following exception:

android.os.FileUriExposedException: file:////storage/emulated/0/temp/1474956193735.jpg exposed beyond app through Intent.getData()
at android.os.StrictMode.onFileUriExposed(StrictMode.java:1799)
at android.net.Uri.checkFileUriExposed(Uri.java:2346)
at android.content.Intent.prepareToLeaveProcess(Intent.java:8933)
at android.content.Intent.prepareToLeaveProcess(Intent.java:8894)
at android.app.Instrumentation.execStartActivity(Instrumentation.java:1517)
at android.app.Activity.startActivityForResult(Activity.java:4223)
...
at android.app.Activity.startActivityForResult(Activity.java:4182)Copy the code



Android7.0 Photos flash back.png

This is due to StrictMode API implementation in Android7.0, but don’t worry, we can use FileProvider to solve this problem, now we will solve this problem step by step.

Using FileProvider

The steps to use FileProvider are as follows: Step 1: Register the provider in the manifest file


    
Copy the code

Exported: The required value must be false, and a security exception will be reported if it is true. GrantUriPermissions :true, granting temporary access to the URI.

Step 2: Specify the shared directory

To specify the shared directory we need to create an XML directory in the resource (RES) directory, and then create a resource file named “file_paths” (whatever the name is, as long as it matches the resource referenced by the provider registered in the manifest), as follows:



    
        
    
Copy the code
  • Represents the root directory: context.getfilesdir ()
  • On behalf of the root directory of the: Environment. External.getexternalstoragedirectory ()
  • Represents the root directory: getCacheDir()

Result: If you set path to “pictures”, you can share any file in the root directory and its subdirectories with other applications. It represents the root directory of pictures directory (eg: / storage/emulated / 0 / pictures), if you share pictures to other applications beyond the range of the file is not a directory.

Step 3: Use FileProvider

With that done, we are now ready to use FileProvider. Taking the system camera as an example, we need to modify the above photo taking code as follows:

File file=new File(Environment.getExternalStorageDirectory(), "/temp/"+System.currentTimeMillis() + ".jpg"); if (! file.getParentFile().exists())file.getParentFile().mkdirs(); Uri imageUri = FileProvider.getUriForFile(context, "com.jph.takephoto.fileprovider", file); Intent Intent = new Intent(); intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); Intent.setaction (mediastore.action_image_capture); intent.setAction(mediastore.action_image_capture); PutExtra (mediastore. EXTRA_OUTPUT, imageUri); // Save the photo to the specified URI startActivityForResult(Intent,1006);Copy the code

There are two major changes in the code above:

  1. Change the Uri scheme type of file to create a Uri of content type with the FileProvider.
  2. addedintent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);To apply temporary authorization to the file represented by the Uri to the target.

Result: The above code uses the FileProvider Uri getUriForFile (Context Context, String Authority, File File) static method to obtain the Uri. Authority parameters in this method is the android manifest file registration provider: authorities = “com. JPH. Takephoto. Fileprovider”. If you are familiar with Web servers such as Tomcat and IIS, you only know that Web servers support setting a virtual directory for Web content to ensure the security and efficiency of Web content. In fact, FileProvider also has some similarities and similarities.

Print the Uri obtained by the getUriForFile method as follows:

The content: / / com. JPH. Takephoto. Fileprovider/camera_photos/temp / 1474960080319. JPG `.Copy the code

Where camerA_photos is the name of paths in file_paths.xml.

For the above specified path is the path = “”, so the content: / / com. The JPH. Takephoto. Fileprovider camera_photos/on behalf of the real path is the root directory, i.e., / storage/emulated / 0 /. The content: / / com. JPH. Takephoto. Fileprovider/camera_photos/temp / 1474960080319. JPG represents the true path: / storage/emulated / 0 / temp / 1474960080319. The JPG.

In addition, I recommend you to use the open source tool library TakePhoto. TakePhoto is an open source tool library to get photos (take photos or select from albums or files), crop images, and compress images on Android devices.

Cutting photos

Before Android7.0, you could crop photos by:

File file=new File(Environment.getExternalStorageDirectory(), "/temp/"+System.currentTimeMillis() + ".jpg"); if (! file.getParentFile().exists())file.getParentFile().mkdirs(); Uri outputUri = Uri.fromFile(file); Uri imageUri=Uri.fromFile(new File("/storage/emulated/0/temp/1474960080319.jpg")); Intent intent = new Intent("com.android.camera.action.CROP"); intent.setDataAndType(imageUri, "image/*"); intent.putExtra("crop", "true"); intent.putExtra("aspectX", 1); intent.putExtra("aspectY", 1); intent.putExtra("scale", true); intent.putExtra(MediaStore.EXTRA_OUTPUT, outputUri); intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString()); intent.putExtra("noFaceDetection", true); // no face detection startActivityForResult(intent,1008);Copy the code

And take pictures, the above code on Android7.0 will also cause the android OS. FileUriExposedException abnormalities, solution is the use of the above about FileProvider.

Then, change the above code to the following:

File file=new File(Environment.getExternalStorageDirectory(), "/temp/"+System.currentTimeMillis() + ".jpg"); if (! file.getParentFile().exists())file.getParentFile().mkdirs(); Uri outputUri = FileProvider.getUriForFile(context, "com.jph.takephoto.fileprovider",file); Uri imageUri=FileProvider.getUriForFile(context, "com.jph.takephoto.fileprovider", new File("/storage/emulated/0/temp/1474960080319.jpg"); / / create a content type Uri through FileProvider Intent Intent = new Intent (com. Android. Camera. The action. "CROP"); intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); intent.setDataAndType(imageUri, "image/*"); intent.putExtra("crop", "true"); intent.putExtra("aspectX", 1); intent.putExtra("aspectY", 1); intent.putExtra("scale", true); intent.putExtra(MediaStore.EXTRA_OUTPUT, outputUri); intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString()); intent.putExtra("noFaceDetection", true); // no face detection startActivityForResult(intent,1008);Copy the code

TakePhoto is an open source tool for getting photos (take photos or select from albums or files), cropping and compressing pictures on Android devices.

Battery and Memory

Android 6.0 (API level 23) introduced a low power consumption mode, and Android7.0 has further optimized the battery and memory to reduce the power consumption and memory footprint of Android applications. Some of the rule changes that result from these optimizations can affect how your application accesses system resources and how your system interacts with other applications through specific implicit intents. So developers need to pay special attention to these changes.

Low power consumption mode

In low-power mode, when the user device is unplugged, stationary and the screen is off, this mode delays CPU and network activity, thus extending battery life. Android7.0 further enhances the low-power mode by applying some CPU and network limits when the device is unplugged and the screen is off, but not necessarily at rest (for example, when the user is out with the handheld device in his pocket).

That said, Android7.0 will limit CPU and network usage when the phone’s screen is off.

The specific rules are as follows:

  1. When the device is charged and the screen has been off for a certain amount of time, the device enters low power mode and applies the first part of the restrictions: shutting down application network access, postponing jobs, and synchronizing.
  2. If the device has been stationary for a certain period of time after entering low power mode, the system applies the remaining low power mode limits to PowerManager.WakeLock, AlarmManager alarm, GPS, and Wi-Fi scanning. Whether partial or full low power mode limits are applied, the system wakes up the device to provide a short maintenance window during which the application can access the network and perform any delayed jobs/synchronizations.

The background to optimize

You may know that There are implicit broadcasts in Android that can be used for certain functions, such as automatically downloading updates when the mobile network becomes WiFi. However, these implicit broadcasts frequently start applications registered to listen for them in the background, which can lead to high power consumption. To alleviate this problem and improve device performance and user experience, three implicit broadcasts have been removed in Android 7.0 to help optimize memory usage and power consumption.

Android 7.0 applies the following optimizations:

  • Applications on Android 7.0 will not receive this messageCONNECTIVITY_ACTIONBroadcast, even if you set up notifications in the manifest file requesting acceptance of these events. However, applications running in the foreground that use BroadcastReceiver to request notifications can still listen for CONNECTIVITY_CHANGE in the main thread.
  • Applications cannot send or receive on Android 7.0ACTION_NEW_PICTUREACTION_NEW_VIDEOType of broadcast.

How to cope: The Android framework provides several solutions to mitigate the need for these implicit broadcasts. For example, the JobScheduler API provides a robust mechanism for scheduling network operations that are performed when specified conditions, such as connectivity to an unlimited traffic network, are met. You can even use the JobScheduler API to accommodate content provider changes.

In addition, if you want to know more about background optimization can refer to background optimization.

Mobile devices experience frequent connection changes, such as switching between Wi-Fi and mobile data. Currently, applications can monitor these changes by registering a receiver in the application manifest to listen for implicit CONNECTIVITY_ACTION broadcasts. Since many applications register to receive this broadcast, a single network switch causes all applications to wake up and process the broadcast simultaneously.

The above is my adaptation on Android7.0 on some of the experience, partners if you have problems can be left a message below.

The last

Now that I have come, please leave me a favor and encourage me to continue to create

If you like my articles, follow mineblogCome on, let’s be friends

Click here and follow:

GitHub: My open source project