Mobile Development 21 min read

Android 10 Migration Guide: AndroidX, Scoped Storage, Device ID, and Cleartext HTTP Adaptation

This guide details the migration of Android apps to Android 10, covering AndroidX migration, scoped storage adaptation, handling device identifiers, and clearing cleartext HTTP restrictions, with step‑by‑step instructions, code snippets, and best‑practice recommendations for mobile developers.

Ctrip Technology
Ctrip Technology
Ctrip Technology
Android 10 Migration Guide: AndroidX, Scoped Storage, Device ID, and Cleartext HTTP Adaptation

Google released Android 10 (API 29) in September 2019, introducing major changes such as AndroidX, scoped storage, restricted access to device identifiers, and cleartext HTTP limitations. This article shares the experience of adapting Ctrip’s travel app to Android 10 and provides practical guidance for other developers.

1. AndroidX

AndroidX replaces the legacy Android Support Library, offering the same functionality with a new package structure and independent versioning. Upgrading to AndroidX is recommended because the Support Library is no longer maintained, its packages have been redesigned for modularity, and AndroidX uses strict semantic versioning.

1.1 What is AndroidX

AndroidX is essentially the next generation of the Support Library, providing backward‑compatible APIs while encouraging developers to adopt newer components.

1.2 Why upgrade

Version 28.0.0 is the last Support Library release; all new features are in AndroidX.

Package restructuring promotes smaller libraries and reduces ecosystem fragmentation.

AndroidX packages are maintained separately and follow semantic versioning.

1.3 Migration steps

1.3.1 Environment preparation

Android Studio 3.2.0+

Gradle 4.6+

Update compileSdkVersion , targetSdkVersion and buildToolsVersion to 29:

android {
   compileSdkVersion 29
   buildToolsVersion "29.0.2"
   defaultConfig {
      targetSdkVersion 29
   }
   ...
}

Enable AndroidX and Jetifier in gradle.properties :

android.useAndroidX=true
android.enableJetifier=true

Replace Support Library dependencies with AndroidX equivalents:

implementation 'com.android.support:appcompat-v7:28.0.0' → implementation 'androidx.appcompat:appcompat:1.0.2'
implementation 'com.android.support:design:28.0.0' → implementation 'com.google.android.material:material:1.0.0'
implementation 'com.android.support.constraint:constraint-layout:1.1.3' → implementation 'androidx.constraintlayout:constraintlayout:1.1.3'

Update import statements, e.g. import android.support.v7.app.AppCompatActivity; becomes import androidx.appcompat.app.AppCompatActivity;

Run the built‑in migration tool (Refactor → Migrate to AndroidX) and manually fix any remaining issues.

2. Scoped Storage

From Android 10 onward, apps targetting API 29 are granted scoped storage by default, meaning they can only access their own private directories and specific media collections. Direct file‑path access to shared directories is prohibited.

2.1 Background

Scoped storage improves user privacy by sandboxing external files. Apps see only Context.getExternalFilesDir() and media collections via MediaStore.

2.2 New features overview

External storage is split into private and shared directories.

Private directory: /Android/data/ package (accessible via getExternalFilesDir() ).

Shared directory: public media folders such as DCIM, Pictures, Music, etc.

2.3 Affected APIs

File‑based APIs like File.createNewFile() , File.delete() , File.renameTo() , FileInputStream , FileOutputStream , and BitmapFactory.decodeFile() no longer work on shared storage.

2.4 Compatibility mode

If full adaptation is not ready, set android:requestLegacyExternalStorage="true" in the manifest (targetSdkVersion ≥ 29) and check the runtime flag:

// Returns true if the app runs in legacy mode
Environment.isExternalStorageLegacy();

2.5 Migration guidance

Create private directories with context.getExternalFilesDir("apk") .

Write files using standard streams.

For shared media, use MediaStore or the Storage Access Framework (SAF).

Example: creating a file in the shared Download/apk folder on Android Q:

ContentValues values = new ContentValues();
values.put(MediaStore.Downloads.DISPLAY_NAME, fileName);
values.put(MediaStore.Downloads.MIME_TYPE, "application/vnd.android.package-archive");
values.put(MediaStore.Downloads.RELATIVE_PATH, "Download/apk");
Uri uri = getContentResolver().insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI, values);
return uri;

Reading a shared image via MediaStore:

if (cursor != null && cursor.moveToFirst()) {
    do {
        int id = cursor.getInt(cursor.getColumnIndex(MediaStore.Images.Media._ID));
        Uri imageUri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, id);
        // use imageUri
    } while (cursor.moveToNext());
}

3. Device ID

Starting with Android 10, apps can no longer access hardware identifiers such as IMEI, MAC address, or serial number. Calls to Build.getSerial() , TelephonyManager.getImei() , etc., return null (targetSdk < 29) or throw SecurityException (targetSdk ≥ 29).

3.1 Work‑arounds for pre‑Android 10 devices

Declare the permission with android:maxSdkVersion="28" to keep it usable on older devices:

<uses-permission android:name="android.permission.READ_PHONE_STATE" android:maxSdkVersion="28"/>

3.2 MAC address randomization

Android 10 randomizes the MAC address for Wi‑Fi and Bluetooth, making the real MAC unavailable to apps.

3.3 Recommended identifiers

Use Settings.Secure.ANDROID_ID for a per‑device, per‑user identifier (reset on factory reset).

Integrate the MSA OAID SDK for a cross‑vendor identifier (OAID, AAID, VAID).

Example of obtaining OAID via the SDK:

public static void initMSASDK(Context context){
    int code = MdidSdkHelper.InitSdk(context, true, listener);
    // handle init result codes
}

static IIdentifierListener listener = new IIdentifierListener() {
    @Override
    public void OnSupport(boolean support, IdSupplier idSupplier) {
        if (support && idSupplier != null) {
            String oaid = idSupplier.getOAID();
            // use OAID as unique identifier
        }
    }
};

4. Cleartext HTTP Restriction

When targetSdkVersion > 28 , cleartext (HTTP) traffic is blocked by default, causing java.net.UnknownServiceException: CLEARTEXT communication not permitted .

Solutions

Add android:usesCleartextTraffic="true" to the <application> tag in the manifest.

Create a network security config XML (e.g., network_security_config.xml ) with cleartextTrafficPermitted="true" and reference it via android:networkSecurityConfig="@xml/network_config" .

Example manifest snippet:

<application
    android:usesCleartextTraffic="true"
    android:networkSecurityConfig="@xml/network_config">
    ...
</application>

Example network_security_config.xml :

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <base-config cleartextTrafficPermitted="true" />
</network-security-config>

5. Outlook

Google released an Android 11 preview in February 2020, adding 5G, foldable support, on‑device machine learning, and further privacy and security enhancements. The continued evolution of Android promises a larger market share and richer capabilities for developers.

References

AndroidX Overview

Android 10 Introduction

Android 11 Preview

Android Q Adaptation Guide

Android 10 Scoped Storage Practice

AndroidMobileDevelopmentAndroidXAndroid10CleartextHTTPDeviceIDScopedStorage
Ctrip Technology
Written by

Ctrip Technology

Official Ctrip Technology account, sharing and discussing growth.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.