Copyright notice: This article is originally published by the blogger, and shall not be reproduced without the permission of the bloggerCopy the code

One, foreword

This article mainly selects some common adaptations from the official documentation. If there are any flaws or need to be added, please point out in the comments section.

Two, version adaptation

1. Restrict HTTP network requests

In Android 9.0, HTTP (plaintext transmission) network requests are restricted. If HTTP requests continue to be used, the following exceptions will be displayed in the log:

java.net.UnknownServiceException: CLEARTEXT communication to xxx not permitted by network security policy
Copy the code

The methods of adaptation are as follows:

The first kind of

  • Create an XML file in the resource directory as a network security configuration file, for example, XML /network_security_config. XML, and fill the following contents in the file:

    <?xml version="1.0" encoding="utf-8"? >
    <network-security-config>
        <base-config cleartextTrafficPermitted="true" />
    </network-security-config>
    Copy the code
  • Configure in Androidmanifest.xml:

    <application
        .
        android:networkSecurityConfig="@xml/network_security_config">.</application>
    Copy the code

Second (AllenChiang)

  • Android 6.0 introduced whether to allow the network to use plaintext transmission configuration:

    <application android:usesCleartextTraffic=["true"|"false"] >
    Copy the code

    The default was true, but in Android 9.0 the default was changed to false, so manually setting the configuration to true resolves the problem of restricted plaintext transmission

2. Disable the Apache HTTP Client

The Apache HTTP Client class has been removed from Android 9.0, so our application or some third party library that uses these classes will throw an exception:

java.lang.NoClassDefFoundError: Failed resolution of: Lorg/apache/http/conn/scheme/SchemeRegistry;
Copy the code

To use the Apache HTTP Client, perform the following operations:

  • Add the following to androidmanifest.xml:

    <uses-library android:name="org.apache.http.legacy" android:required="false"/>
    Copy the code
  • Or package and reference the Apache HTTP Client-related classes directly in your application

3. Restrict calls to non-SDK interfaces

3.1 a brief introduction

For a long time, the official interface is divided into SDK interface and non-SDK interface. SDK interfaces are officially supported interfaces that developers can call directly without any restrictions. Generally speaking, SDK interfaces are recorded in the official interface index, and those that are not recorded are considered non-SDK interfaces, such as some methods that use the @hide annotation.

Traditionally, calls to non-SDK interfaces have been made using reflection or JNI indirect calls, but such calls can be prone to unknown errors if not handled properly. In order to improve user experience and reduce the risk of app crashes, Android 9.0 imposes restrictions on the non-SDK interfaces that can be used by apps. See the table below for specific restrictions:

In order for developers to transition to Android 9.0, non-SDK interfaces are classified into three categories: light-greylist, dark-greylist, and blacklist.

  • Light-greylist: For non-SDK interfaces in this list, no alternative SDK interface has been found, so developers can continue to access it (warning if targetSdkVersion is greater than or equal to 28).
  • Dark-greylist: When targetSdkVersion is less than 28, you can continue to use the interfaces in this list, but a warning will appear. When the value is greater than or equal to 28, these interfaces restrict access.
  • Blacklist: No matter what the targetSdkVersion is, as long as the application runs on Android 9.0, accessing the blacklist is restricted

3.2 How can I Test whether an Application Uses non-SDK interfaces

Tests can be performed in the following ways (see official documentation for details) :

  • Debug the app on an Android device 9.0 or later
  • Use StrictMode API for testing
  • Use the Veridex tool to scan the application

The third option is recommended, where the scan results list the details of the application’s calls to the interfaces in the three restricted lists.

4. Foreground service permission

In Android 9.0, applications must apply for FOREGROUND_SERVICE permission before using foreground services, or a SecurityException will be thrown.

The FOREGROUND_SERVICE permission is a common one, so you only need to register it in androidmanifest.xml and the system will automatically grant it:

<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
Copy the code

5. Enforce the FLAG_ACTIVITY_NEW_TASK requirement

Prior to Android 7.0 (API level 24), if you wanted to start an Activity from a non-activity context, you had to set the Intent flag to FLAG_ACTIVITY_NEW_TASK. Otherwise, the Activity would fail and the following exception would be thrown

android.util.AndroidRuntimeException: Calling startActivity() from outside of an Activity  context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?
Copy the code

However, this requirement was temporarily removed after the Android 7.0 update due to system issues, and developers can start activities normally without setting flags. In Android 9.0, the official fix for this issue requires a restart of enforcement, so developers need to be aware of this issue when adapting to Android 9.0.

6. Do not share the WebView data directory

In Android 9.0, to improve application stability and data integrity, applications can no longer share the same WebView data directory with multiple processes. Such data directories typically store cookies, HTTP caches, and other persistent and temporary storage related to web browsing.

If developers need in the process of how to use a WebView, you must first call WebView. SetDataDirectorySuffix () method for each process is used to store the WebView data directory. If multiple webViews need to share data, developers need to do it themselves via IPC.

In addition, if a developer wants to use WebView only in one process and wants to enforce this rule strictly, he can call the webView.disableWebView () method in another process so that the other process creating the WebView instance will throw an exception.

7. Other API modifications

7.1 Region. The Op

INTERSECT or Region.Op.DIFFERENCE will throw the following exception if you set a type other than Region.

 java.lang.IllegalArgumentException: Invalid Region.Op - only INTERSECT and DIFFERENCE are allowed
Copy the code

Op (@nonNULL RectF rect, @nonNULL region. Op Op) :

/**
 * Modify the current clip with the specified rectangle.
 *
 * @param rect The rect to intersect with the current clip
 * @param op How the clip is modified
 * @return true if the resulting clip is non-empty
 *
 * @deprecated Region.Op values other than {@link Region.Op#INTERSECT} and
 * {@link Region.Op#DIFFERENCE} have the ability to expand the clip. The canvas clipping APIs
 * are intended to only expand the clip as a result of a restore operation. This enables a view
 * parent to clip a canvas to clearly define the maximal drawing area of its children. The
 * recommended alternative calls are {@link #clipRect(RectF)} and {@link #clipOutRect(RectF)};
 *
 * As of API Level API level {@value Build.VERSION_CODES#P} only {@link Region.Op#INTERSECT} and
 * {@link Region.Op#DIFFERENCE} are valid Region.Op parameters.
 */
@Deprecated
public boolean clipRect(@NonNull RectF rect, @NonNull Region.Op op) {
    checkValidClipOp(op);
    return nClipRect(mNativeCanvasWrapper, rect.left, rect.top, rect.right, rect.bottom,
            op.nativeInt);
}

private static void checkValidClipOp(@NonNull Region.Op op) {
    if(sCompatiblityVersion >= Build.VERSION_CODES.P && op ! = Region.Op.INTERSECT && op ! = Region.Op.DIFFERENCE) {throw new IllegalArgumentException(
                "Invalid Region.Op - only INTERSECT and DIFFERENCE are allowed"); }}Copy the code

To solve this problem, you can use the following methods:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
    canvas.clipPath(path);
} else {
    canvas.clipPath(path, Region.Op.XOR);// REPLACE, UNION, etc
}
Copy the code

7.2 Build.SERIAL is deprecated

Before Android 9.0, developers could use build. SERIAL to get a device’s SERIAL number. Now that this method is deprecated, build. SERIAL will always be set to “UNKNOWN” to protect user privacy.

The adaptation is to first request the READ_PHONE_STATE permission and then call the build.getSerial () method.