您的位置:

Android存储权限详解

一、Android存储权限

Android存储权限是指应用程序可以访问设备存储空间和SD卡上的文件。

在Android系统中,将存储权限划分为:READ_EXTERNAL_STORAGEWRITE_EXTERNAL_STORAGE

READ_EXTERNAL_STORAGE是指访问设备存储空间和SD卡上的文件的权限;WRITE_EXTERNAL_STORAGE是指向设备存储空间和SD卡上写入文件的权限。

二、Android存储权限申请

在Android6.0及以上版本中,应用程序需要在运行时动态获取权限,否则将无法获取存储空间和SD卡上的文件。在申请权限前,需要先检查权限是否已经被授予,然后再申请权限。

以下是检查和申请SD卡权限的代码示例:

// 检查权限是否已经被授予
if (ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE)
        != PackageManager.PERMISSION_GRANTED) {
    // 申请权限
    ActivityCompat.requestPermissions(activity, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
            requestCode);
} else {
    // 已经授予权限,可以进行操作
}

三、Android存储权限授权

当应用程序发起存储空间或者SD卡上的文件读或写请求时,会弹出授权对话框,询问用户是否授权该操作。

在用户做出授权选择后,会回调函数onRequestPermissionsResult,可以在该函数中处理用户的授权选择。

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    switch (requestCode) {
        case REQUEST_CODE_STORAGE:
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // 用户已经授予权限,可以进行操作
            } else {
                // 用户拒绝授权,无法进行操作
                Toast.makeText(MainActivity.this, "无法获取存储权限,操作无法完成", Toast.LENGTH_LONG).show();
            }
            break;
    }
}

四、Android存储权限源码分析

在Android系统中,存储权限授权的具体实现是在PackageManagerService中,该类实现了应用程序管理服务,提供了应用程序安装、卸载、权限管理等功能。

存储权限的授权过程是通过该服务中的grantPermissionsLPw方法实现的。在该方法中,会先对应用程序的权限进行验证,然后再向用户发起授权请求。

private boolean grantPermissionsLPw(PackageParser.Package pkg, boolean replace, int userId,
            int[] gpFlags, String[] grantedPermissions, LongSparseArray permsState) {
    // 先验证权限是否合法
    final boolean allowedSig = checkPackageSignature(pkg);
    // ...
    // 获取对应权限后,向用户发起授权请求
    if (delta != 0) {
        int flags = ((delta & PackageManager.FLAG_PERMISSION_REQUESTED) != 0) ? 0
                : PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT;
        if (DEBUG_INSTALL) {
            Slog.d(TAG, "Auto-granting " + p.perm.info.getName() + " permission to default");
        }
        p.granted = true;
        IntArray userIds = p.userId == UserHandle.USER_ALL ? pkg.getIntArrayInstallDuring()
                : new IntArray();
        userIds.add(p.userId);
        if (!grantRuntimePermissionsLPw(pkg, p.perm, flags, allowedSig, userIds.toArray(),
                gpFlags, permsState)) {
            return false;
        }
        changed = true;
    }
    // ...
    return true;
}

  

五、Android获取存储权限

在获取存储权限前,需要先检查应用程序是否已经被授予了相应的权限。

以下是检查存储权限和获取存储权限的示例代码:

// 检查权限是否已经被授予
if (ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE)
        != PackageManager.PERMISSION_GRANTED) {
    // 申请权限
    ActivityCompat.requestPermissions(activity, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
            requestCode);
} else {
    // 已经授予权限,可以进行操作
}

// 获取存储权限
Intent intent = new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION);
Uri uri = Uri.fromParts("package", context.getApplicationContext().getPackageName(), null);
intent.setData(uri);
context.startActivity(intent);

六、Android 11 存储权限

在Android11及以上版本中,存储权限的授权方式发生了变化:

  • 应用程序不能访问外部存储中其他应用程序的存储空间。
  • 应用程序只能在应用自己的私有目录中创建文件,无法在外部存储中创建文件。
  • 应用程序需要在清单文件中声明访问外部存储空间的权限,否则不能获取外部存储权限。

以下是在Android11以上版本中获取存储权限的示例代码:

if (Environment.isExternalStorageManager()) {
    // 已经授予访问外部存储权限,可以进行操作
} else {
    Intent intent = new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION);
    Uri uri = Uri.fromParts("package", context.getApplicationContext().getPackageName(), null);
    intent.setData(uri);
    context.startActivity(intent);
}

七、Android 13 存储权限

在Android13中,存储权限的授权方式发生了进一步的变化:

  • 应用程序需要在清单文件中声明MANAGE_EXTERNAL_STORAGE权限才能申请访问外部存储空间的权限。
  • 如果应用程序未在清单文件中声明该权限,则无法使用申请访问外部存储空间的权限。

以下是在Android13版本中获取存储权限的示例代码:

// 检查是否授权访问外部存储空间
if (Environment.isExternalStorageManager()) {
    // 已经授权访问外部存储空间,可以进行操作
} else {
    Intent intent = new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION);
    Uri uri = Uri.fromParts("package", context.getApplicationContext().getPackageName(), null);
    intent.setData(uri);
    context.startActivity(intent);
}

八、Android存储数据的方法选取

在Android系统中,存储数据的方法有很多种,包括以下几种:

  • 文件系统:通过文件系统读写文件。
  • Shared Preferences:通过SharedPreferences保存数据。
  • SQLite数据库:通过SQLite数据库保存数据。
  • Content Providers:通过Content Providers共享数据。
  • 网络存储:通过网络存储数据。

根据实际需求,选取相应的数据存储方式。