AndroidQ of 10 Partition Storage Perfect Adaptation Method

  • 2021-11-14 07:02:36
  • OfStack

Preface

Recently, the adaptation of AndroidQ has been done. As of today, the adaptation of AndroidQ partition storage has been completed, and there are many pits during the period. At present, most of the posts on the Internet are an overview of the changes. The next few posts are a summary of the actual experience code of partition storage and the experience of filling pits. I hereby record 1 and provide help for everyone.

This article is mainly to AndroidQ (10) partition storage adaptation concrete realization

Key points:
Android Q file storage mechanism is modified to sandbox mode APP can only access files in its own directory and public media files For AndroidQ below, still use the old file storage method

It should be noted here that when adapting to AndroidQ, it should be compatible with the system version below Q, and use SDK_VERSION to distinguish

Background

Storage permissions

Android Q still uses READ_EXTERNAL_STORAGE and WRITE_EXTERNAL_STORAGE as storage-related runtime permissions, but even if these permissions are obtained, access to external storage is limited to files in its own directory and public inner body files.

External storage structure partition

Public catalogues: Downloads, Documents, Pictures, DCIM, Movies, Music, Ringtones, etc

Address:/storage/emulated/0/Downloads (Pictures), etc

Files in public directories will not be deleted following APP uninstall.

APP Private Directory

Address:/storage/emulated/0/Android/data/Package Names/files

The private directory holds the private files of app, which will be deleted with the uninstallation of App.

Adaptation guidance

Adding, deleting, modifying and checking files using ContentResolver in AndroidQ

1. Get (create) folders under your own directory

Get and create. If there is no corresponding folder in the mobile phone, the system will automatically generate it


// Create in its own directory apk Folder 
File apkFile = context.getExternalFilesDir("apk");

2. Create files in your own directory

Generate the path to be downloaded, read and write through the input and output stream


String apkFilePath = context.getExternalFilesDir("apk").getAbsolutePath();
File newFile = new File(apkFilePath + File.separator + "temp.apk");
OutputStream os = null;
try {
  os = new FileOutputStream(newFile);
  if (os != null) {
    os.write("file is created".getBytes(StandardCharsets.UTF_8));
    os.flush();
  }
} catch (IOException e) {
} finally {
  try {
    if (os != null) {
      os.close();
    }
  } catch (IOException e1) {
    
  }
}

3. Create folders under public directories

Write through MediaStore. insert


if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
  return null;
}
ContentResolver resolver = context.getContentResolver();
ContentValues values = new ContentValues();
values.put(MediaStore.Downloads.DISPLAY_NAME, fileName);
values.put(MediaStore.Downloads.DESCRIPTION, fileName);
// Set the file type 
values.put(MediaStore.Downloads.MIME_TYPE, "application/vnd.android.package-archive");
// Attention MediaStore.Downloads.RELATIVE_PATH Need targetVersion=29,
// Therefore, this method can only be used in Android10 Execute on the mobile phone of 
values.put(MediaStore.Downloads.RELATIVE_PATH, "Download" + File.separator + "apk");
Uri external = MediaStore.Downloads.EXTERNAL_CONTENT_URI;
Uri insertUri = resolver.insert(external, values);
return insertUri;

4. Create files under the specified folder in the public directory

Combined with the above code, we mainly create files or folders in the public directory to get the local path uri, and different Uri can be saved to different public directories. Next, you can write to the file by using the input and output stream

Important: file://type access files are not supported in AndroidQ, and can only be accessed through uri


ContentResolver resolver = context.getContentResolver();
Uri insertUri = resolver.insert(external, values);
if(insertUri == null) {
  return;
}
String mFilePath = insertUri.toString();
InputStream is = null;
OutputStream os = null;
try {
  os = resolver.openOutputStream(insertUri);
  if(os == null){
    return;
  }
  int read;
  File sourceFile = new File(sourcePath);
  if (sourceFile.exists()) { //  When the file exists 
    is = new FileInputStream(sourceFile); //  Read the original file 
    byte[] buffer = new byte[1024];
    while ((read = is.read(buffer)) != -1) {
      os.write(buffer, 0, read);
    }
  }
} catch (Exception e) {
  e.printStackTrace();
}finally {
  try {
    if (is != null) {
      is.close();
    }
    if (os != null) {
      os.close();
    }
  } catch (IOException e) {
    e.printStackTrace();
  }
}

5. Read files in public directory through MediaStore


ParcelFileDescriptor parcelFileDescriptor = null;
FileDescriptor fileDescriptor = null;
Bitmap tagBitmap = null;
try {
  parcelFileDescriptor = context.getContentResolver().openFileDescriptor(uri, "r");
      
  if (parcelFileDescriptor != null && parcelFileDescriptor.getFileDescriptor() != null) {
    fileDescriptor = parcelFileDescriptor.getFileDescriptor();
    // Conversion uri For bitmap Type 
    tagBitmap = BitmapFactory.decodeFileDescriptor(fileDescriptor);
  }
} catch (FileNotFoundException e) {
  e.printStackTrace();
} catch (IOException e) {
  e.printStackTrace();
} finally {
  try {
    if (parcelFileDescriptor != null) {
      parcelFileDescriptor.close();
    }
  } catch (IOException e) {
  }
}

6. Delete files using MediaStore


context.getContentResolver().delete(fileUri, null, null);

7. Permissions required by APP to access files through MediaStore

header 1 无权限 READ_EXTERNAL
Audio 可读写APP自己创建的文件,但不可直接使用路径访问 可以读其他APP创建的媒体类文件,删改操作需要用户授权
Image 可读写APP自己创建的文件,但不可直接使用路径访问 可以读其他APP创建的媒体类文件,删改操作需要用户授权
File 可读写APP自己创建的文件,但不可直接使用路径访问 不可读写其他APP创建的非媒体类文件
Downloads 可读写APP自己创建的文件,但不可直接使用路径访问 不可读写其他APP创建的非媒体类文件

Follow-up introduction of AndroidQ storage for specific functions, welcome to pay attention ~


Related articles: