Android 10-11适配外部存储方案

这篇具有很好参考价值的文章主要介绍了Android 10-11适配外部存储方案。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Android Api 29 对文件和文件夹进行了重大更改。不允许使用外部存储,如下方法:

Environment.getExternalStorageDirectory() = /mnt/sdcard  
Environment.getExternalStoragePublicDirectory(“test”) = /mnt/sdcard/test

Android 10-11适配外部存储方案,android,安卓10和11权限适配,XXPermission

只能使用内部存储

getExternalFilesDir(“test”) = /mnt/sdcard/Android/data/com.my.app/files/test
getExternalFilesDir(null) = /mnt/sdcard/Android/data/com.my.app/files

Android 10-11适配外部存储方案,android,安卓10和11权限适配,XXPermission

但谷歌官方给了一个后门,在AndroidManifest.xml文件中application节点中加上android:requestLegacyExternalStorage="true"属性才可以访问沙盒路径下的数据

Android 10-11适配外部存储方案,android,安卓10和11权限适配,XXPermission

原来的项目就要重新适配

Android 10-11适配外部存储方案,android,安卓10和11权限适配,XXPermission

Android开发:filePath放在哪个文件夹

Environment.getDataDirectory() = /data
Environment.getDownloadCacheDirectory() = /cache  
外部存储
Environment.getExternalStorageDirectory() = /mnt/sdcard  
Environment.getExternalStoragePublicDirectory(“test”) = /mnt/sdcard/test
Environment.getRootDirectory() = /system
getPackageCodePath() = /data/app/com.my.app-1.apk
getPackageResourcePath() = /data/app/com.my.app-1.apk
getCacheDir() = /data/data/com.my.app/cache
getDatabasePath(“test”) = /data/data/com.my.app/databases/test
getDir(“test”, Context.MODE_PRIVATE) = /data/data/com.my.app/app_test
getExternalCacheDir() = /mnt/sdcard/Android/data/com.my.app/cache
应用内部存储
getExternalFilesDir(“test”) = /mnt/sdcard/Android/data/com.my.app/files/test
getExternalFilesDir(null) = /mnt/sdcard/Android/data/com.my.app/files
getFilesDir() = /data/data/com.my.app/files

参考文章:

安卓Enviroment类的详解-CSDN博客

权限申请

11以上添加如下权限:

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />

代码动态申请

public final class PermissionActivity extends AppCompatActivity {
 
    private static final int REQUEST_CODE = 1024;
 
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestPermission();
    }
 
    private void requestPermission() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            // 先判断有没有权限
            if (Environment.isExternalStorageManager()) {
                writeFile();
            } else {
                Intent intent = new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION);
                intent.setData(Uri.parse("package:" + context.getPackageName()));
                startActivityForResult(intent, REQUEST_CODE);
            }
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            // 先判断有没有权限
            if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED &&
                    ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
                writeFile();
            } else {
                ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CODE);
            }
        } else {
            writeFile();
        }
    }
 
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == REQUEST_CODE) {
            if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED &&
                    ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
                writeFile();
            } else {
                ToastUtils.show("存储权限获取失败");
            }
        }
    }
 
    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == REQUEST_CODE && Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            if (Environment.isExternalStorageManager()) {
                writeFile();
            } else {
                ToastUtils.show("存储权限获取失败");
            }
        }
    }
 
    /**
     * 模拟文件写入
     */
    private void writeFile() {
        ToastUtils.show("写入文件成功");
    }
}

动态申请代码三方框架XXPermissions

XXPermissions.with(this)
        // 不适配 Android 11 可以这样写
        //.permission(Permission.Group.STORAGE)
        // 适配 Android 11 需要这样写,这里无需再写 Permission.Group.STORAGE
        .permission(Permission.MANAGE_EXTERNAL_STORAGE)
        .request(new OnPermissionCallback() {
 
            @Override
            public void onGranted(List<String> permissions, boolean all) {
                if (all) {
                    toast("获取存储权限成功");
                }
            }
 
            @Override
            public void onDenied(List<String> permissions, boolean never) {
                if (never) {
                    toast("被永久拒绝授权,请手动授予存储权限");
                    // 如果是被永久拒绝就跳转到应用权限系统设置页面
                    XXPermissions.startPermissionActivity(MainActivity.this, permissions);
                } else {
                    toast("获取存储权限失败");
                }
            }
        });

项目地址:GitHub - getActivity/XXPermissions: Android 权限请求框架,已适配 Android 14

Android 10-11适配外部存储方案,android,安卓10和11权限适配,XXPermission

 // JitPack 远程仓库:https://jitpack.io
        maven { url 'https://jitpack.io' }
   // 权限请求框架:https://github.com/getActivity/XXPermissions
    implementation 'com.github.getActivity:XXPermissions:18.5

Android 10-11适配外部存储方案,android,安卓10和11权限适配,XXPermission

# 表示将第三方库迁移到 AndroidX
android.enableJetifier = true

<manifest>

    <application>

        <!-- 告知 XXPermissions 当前项目已经适配了分区存储特性 -->
        <meta-data
            android:name="ScopedStorage"
            android:value="true" />

    </application>

</manifest>文章来源地址https://www.toymoban.com/news/detail-742426.html

框架扩展

XXPermissions.with(this)
        // 申请单个权限
        .permission(Permission.RECORD_AUDIO)
        // 申请多个权限
        .permission(Permission.Group.CALENDAR)
        // 设置权限请求拦截器(局部设置)
        //.interceptor(new PermissionInterceptor())
        // 设置不触发错误检测机制(局部设置)
        //.unchecked()
        .request(new OnPermissionCallback() {

            @Override
            public void onGranted(@NonNull List<String> permissions, boolean allGranted) {
                if (!allGranted) {
                    toast("获取部分权限成功,但部分权限未正常授予");
                    return;
                }
                toast("获取录音和日历权限成功");
            }

            @Override
            public void onDenied(@NonNull List<String> permissions, boolean doNotAskAgain) {
                if (doNotAskAgain) {
                    toast("被永久拒绝授权,请手动授予录音和日历权限");
                    // 如果是被永久拒绝就跳转到应用权限系统设置页面
                    XXPermissions.startPermissionActivity(context, permissions);
                } else {
                    toast("获取录音和日历权限失败");
                }
            }
        });

其他API介绍

// 判断一个或多个权限是否全部授予了
XXPermissions.isGranted(Context context, String... permissions);

// 获取没有授予的权限
XXPermissions.getDenied(Context context, String... permissions);

// 判断某个权限是否为特殊权限
XXPermissions.isSpecial(String permission);

// 判断一个或多个权限是否被勾选了《不再询问》的选项(一定要在权限申请的回调方法中调用才有效果)
XXPermissions.isDoNotAskAgainPermissions(Activity activity, String... permissions);

// 跳转到应用权限设置页
XXPermissions.startPermissionActivity(Context context, String... permissions);
XXPermissions.startPermissionActivity(Activity activity, String... permissions);
XXPermissions.startPermissionActivity(Activity activity, String... permission, OnPermissionPageCallback callback);
XXPermissions.startPermissionActivity(Fragment fragment, String... permissions);
XXPermissions.startPermissionActivity(Fragment fragment, String... permissions, OnPermissionPageCallback callback);

// 设置不触发错误检测机制(全局设置)
XXPermissions.setCheckMode(false);
// 设置权限申请拦截器(全局设置)
XXPermissions.setInterceptor(new IPermissionInterceptor() {});

到了这里,关于Android 10-11适配外部存储方案的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Android外部存储与内部存储详解

    内部储存(内部存储的文件夹其他应用和用户无法直接访问,可以用于存放敏感数据。app进行数据清理或卸载可以清理外部存储和内部存储下的所有文件目录, 不需要读写权限 ) getFilesDir() /data/data/包名/files 或者 /data/user/0/包名/files getCacheDir() /data/data/包名/cache 或者 /data/u

    2024年04月09日
    浏览(60)
  • Android所有版本的存储权限适配

                 第一步:在Manifest文件添加如下权限          uses-permission android:name=\\\"android.permission.WRITE_EXTERNAL_STORAGE\\\" android:maxSdkVersion=\\\"28\\\" tools:ignore=\\\"ScopedStorage\\\"/              uses-permission android:name=\\\"android.permission.MANAGE_EXTERNAL_STORAGE\\\"/          uses-permission android:name=\\\"android.p

    2024年01月17日
    浏览(35)
  • Android11 适配

    将build.gradle的目标版本targetSdkVersion修改为30(Android 11) Android11的改变改变主要影响以Adnroid11 为目标版本的应用(targetSdkVersion=30才有影响),和所有应用在Android11设备上适配改动(无论targetSdkVersion是多少,只要在Android11设备上运行的应用都有影响) 分区存储,将公共区域划

    2024年02月04日
    浏览(34)
  • Android将Uri转为路径字符串(适配安卓全版本)并使用第三方应用打开文件(适配Android7.0+)

    做这个功能时在网上找了无数篇例子,有些方法是有问题的,故自己写一篇完整实现的总结,作备忘也作案例。顺便说一句,Android对存储权限的给予真的越来越严格 目录 1.Uri转为路径String以获得文件名  2.获取文件后缀名 3.通过后缀名获取文件MIME类型  4.设置Intent的Uri与权限

    2024年02月19日
    浏览(43)
  • Android内部存储与外部存储(私有目录与公共目录)图文详解

        目录 一、存储空间概述 二、存储空间的划分 1、存储划分 2、内部存储 2.1 内部存储概述 2.2 内部存储 - 私有目录 3. 外部存储 3.1 外部存储概述 3.2 外部存储 - 私有目录 3.3 外部存储 - 公共目录 三、内部存储与外部存储比较 1、横向对比 2、目录结构 3、存储分类 四、总结

    2024年02月11日
    浏览(40)
  • Android 11 来袭,一起来看看怎么适配

    我的公众号 程序员徐公 ,四年中大厂工作经验,回复 黑马 ,领取 Android 学习视频一份,回复 徐公666 ,可以获得我精心整理的简历模板,带你走近大厂。 作者:唯鹿 来源:https://juejin.cn/post/6948211914455384072 终于开始了Android 11的适配工作。记录一下,供需要的人参考。 老规矩,

    2024年02月07日
    浏览(78)
  • 【Android 10 适配】隐私权限变更

    更详细内容请参考 Android 10 中的隐私权变更 Android 10(API 级别 29)引入了多项功能和行为变更,旨在更好地保护用户的隐私。这些变更让用户更清楚地了解并更好地控制自己的数据及为应用提供的权能。 下面是 Android 10 中与 隐私权限 相关的主要变更。 默认情况下,以 Andr

    2024年01月22日
    浏览(59)
  • Android实现App内自动升级,适配了安卓7、8及以上版本

            应用发布后,要实现灰度升级控制,如果只依赖各家应用市场是不够的,还需要自己在应用中控制升级逻辑。并且每家应用市场上新审核也是一件很麻烦的事情,尤其像至简网格这样的应用,甚至没在应用市场上架,更不可能依赖它们了。所以必须要在应用中实现自

    2024年02月10日
    浏览(70)
  • Android 操作系统日历完成提醒功能 附带开关闹钟 适配高版本安卓

    如果想要一个稳定且不用担心生命周期的提醒方式,可以试试利用系统日历去完成任务的提醒或某个活动的预约。 项目仓库地址在文末 环境 Java 11 Android sdk 30 Gredle 7.1 测试机型 mi 8(安卓 9) mi10 pro(安卓11) huawei m8(安卓7) 日历操作表 ​ 其实完成这个功能本质是对安卓原

    2024年02月03日
    浏览(47)
  • Android之屏幕适配方案

    在说明适配方案之前,我们需要对如下几个概念有所了解:屏幕尺寸,屏幕分辨率,屏幕像素密度。 屏幕尺寸 屏幕尺寸指屏幕的对角线的物理长度,单位是英寸,1英寸=2.54厘米。 比如常见的屏幕尺寸:5.0、5.99、6.0等等 屏幕分辨率 屏幕分辨率是指手机在横向、纵向上的像素

    2024年02月03日
    浏览(48)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包