Android所有版本的存储权限适配

Android各个版本存储权限适配 虽然 Android10 上面提出了外部存储分区的概念,不过之前的版本中,我们只要为应用添加了。1、AndroidManifest添加权限设置。3、拒绝权限时跳转详细设置页面。就可以像之前的方式一样访问手机的外部存储空间。2、请求所有文件管理权限。 阅读详情
AI摘要

本文介绍了在Android应用中,针对不同版本(从Android6.0到Android12)如何在Manifest文件中配置权限,以及如何在运行时请求READ_EXTERNAL_STORAGE和WRITE_EXTERNAL_STORAGE权限以在外部存储上写入文件,包括对MediaImages权限的处理和针对Android11/12的新规则。

             第一步:在Manifest文件添加如下权限

    <uses-permission android:name="android.permission.READ_MEDIA_IMAGES"/>
    <uses-permission android:name="android.permission.READ_MEDIA_AUDIO"/>
    <uses-permission android:name="android.permission.READ_MEDIA_VIDEO"/>
         <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.permission.READ_EXTERNAL_STORAGE"/>

         android:requestLegacyExternalStorage="true"
         第二步:定义以下常量
         private static final int REQUEST_CODE_FOR_READ_MEDIA_IMAGES_PERMISSION_FROM_ANDROID_13 = 0x00000003;
             private static final int REQUEST_CODE_FOR_WRITE_EXTERNAL_STORAGE_PERMISSION_FROM_ANDROID_10_TO_ANDROID_12 = 0x00000005;
             private static final int REQUEST_CODE_FOR_WRITE_EXTERNAL_STORAGE_PERMISSION_FOR_ANDROID_6_TO_ANDROID_9 = 0x00000006;
         第三步:在需要写入文件的地方编写以下代码
            java.io.OutputStream outputStream = null;
            java.lang.String errorMessage = "";
            java.lang.String fileName = "test_导出资料_" + java.lang.System.currentTimeMillis() + ".xls";
            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
                android.util.Log.d("debug", "设备系统的版本号是大于等于安卓6.0以上的版本,需要检查运行时的危险权限");
                if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) {
                    android.util.Log.d("debug", "设备系统的版本号是大于等于安卓10.0以上的版本,说明是只能用媒介存储写入文件和读取文件");
                    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.TIRAMISU) {
                        android.util.Log.d("debug", "设备系统的版本号是大于等于安卓13.0以上的版本,换成检查Media声音和Media视频和Media图片的权限");
                        int checkSelfPermissionResultForReadMediaImages = checkSelfPermission(android.Manifest.permission.READ_MEDIA_IMAGES);
                        android.util.Log.d("debug", "checkSelfPermissionResultForReadMediaImages->" + checkSelfPermissionResultForReadMediaImages);
                        if (checkSelfPermissionResultForReadMediaImages == android.content.pm.PackageManager.PERMISSION_GRANTED) {
                            android.util.Log.d("debug", "已经授予媒介图片的读取权限");
                            android.net.Uri uri = android.provider.MediaStore.Files.getContentUri("external");
                            android.content.ContentValues contentValues = new android.content.ContentValues();
                            contentValues.put(android.provider.MediaStore.MediaColumns.DISPLAY_NAME, fileName);
                            contentValues.put(android.provider.MediaStore.MediaColumns.MIME_TYPE, "application/x-xls");
                            android.content.ContentResolver contentResolver = getContentResolver();
                            android.net.Uri uriForInsertResult = contentResolver.insert(uri, contentValues);
                            try {
                                outputStream = contentResolver.openOutputStream(uriForInsertResult);
                            } catch (java.io.IOException ioException) {
                                ioException.printStackTrace();
                                errorMessage = ioException.getMessage();
                            }
                        } else {
                            errorMessage = "需要授予权限";
                            android.util.Log.d("debug", "没有授予媒介图片的读取权限");
                            android.util.Log.d("debug", "现在执行请求读取媒介图片的权限");
                            java.lang.String[] permission = new java.lang.String[1];
                            permission[0] = android.Manifest.permission.READ_MEDIA_IMAGES;
                            requestPermissions(permission, REQUEST_CODE_FOR_READ_MEDIA_IMAGES_PERMISSION_FROM_ANDROID_13);
                        }
                        int checkSelfPermissionResultForReadExternalStorage = checkSelfPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE);
                        int checkSelfPermissionResultForWriteExternalStorage = checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE);
                        android.util.Log.d("debug", "检测完读取媒介图片权限之后再检测外部存储读取权限看看->" + checkSelfPermissionResultForReadExternalStorage);
                        android.util.Log.d("debug", "检测完读取媒介图片权限之后再检测外部存储写入权限看看->" + checkSelfPermissionResultForWriteExternalStorage);
                    } else {
                        android.util.Log.d("debug", "设备系统的版本号介于10.0到12.0之间的,通过android.provider.MediaStore获取外部存储目录");
                        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R) {
                            android.util.Log.d("debug", "安卓11或者安卓12通过Environment的isExternalStorageManager方法检查是否有权限");
                            if (android.os.Environment.isExternalStorageManager()) {
                                android.util.Log.d("debug", "在安卓11或者安卓12中有读写文件的权限");
                                android.net.Uri uri = android.provider.MediaStore.Files.getContentUri("external");
                                android.content.ContentValues contentValues = new android.content.ContentValues();
                                contentValues.put(android.provider.MediaStore.MediaColumns.DISPLAY_NAME, fileName);
                                contentValues.put(android.provider.MediaStore.MediaColumns.MIME_TYPE, "application/x-xls");
                                android.content.ContentResolver contentResolver = getContentResolver();
                                android.net.Uri uriForInsertResult = contentResolver.insert(uri, contentValues);
                                try {
                                    outputStream = contentResolver.openOutputStream(uriForInsertResult);
                                } catch (java.io.IOException ioException) {
                                    ioException.printStackTrace();
                                    errorMessage = ioException.getMessage();
                                }
                            } else {
                                errorMessage = "需要授予权限";
                                android.util.Log.d("debug", "安卓11或者安卓12的逻辑请求权限");
                                try {
                                    Intent intent = new Intent(android.provider.Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION);
                                    intent.addCategory("android.intent.category.DEFAULT");
                                    intent.setData(android.net.Uri.parse(String.format("package:%s",getApplicationContext().getPackageName())));
                                    startActivityForResult(intent, REQUEST_CODE_FOR_WRITE_EXTERNAL_STORAGE_PERMISSION_FROM_ANDROID_10_TO_ANDROID_12);
                                } catch (Exception e) {
                                    e.printStackTrace();
                                    Intent intent = new Intent();
                                    intent.setAction(android.provider.Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION);
                                    startActivityForResult(intent, REQUEST_CODE_FOR_WRITE_EXTERNAL_STORAGE_PERMISSION_FROM_ANDROID_10_TO_ANDROID_12);
                                }
                            }
                        } else {
                            android.util.Log.d("debug", "在安卓10版本中沿用之前的检查方法");
                            int checkSelfPermissionResultForReadExternalStorage = androidx.core.app.ActivityCompat.checkSelfPermission(this, android.Manifest.permission.READ_EXTERNAL_STORAGE);
                            //int checkSelfPermissionResultForWriteExternalStorage = androidx.core.app.ActivityCompat.checkSelfPermission(this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE);
                            android.util.Log.d("debug", "checkSelfPermissionResultForReadExternalStorage->" + checkSelfPermissionResultForReadExternalStorage);
                            //android.util.Log.d("debug", "checkSelfPermissionResultForWriteExternalStorage->" + checkSelfPermissionResultForWriteExternalStorage);
                            //boolean isHavePermission = checkSelfPermissionResultForReadExternalStorage == android.content.pm.PackageManager.PERMISSION_GRANTED && checkSelfPermissionResultForWriteExternalStorage == android.content.pm.PackageManager.PERMISSION_GRANTED;
                            if (checkSelfPermissionResultForReadExternalStorage == android.content.pm.PackageManager.PERMISSION_GRANTED) {
                                android.util.Log.d("debug", "已经授予外部存储写入权限");
                                android.net.Uri uri = android.provider.MediaStore.Files.getContentUri("external");
                                android.content.ContentValues contentValues = new android.content.ContentValues();
                                contentValues.put(android.provider.MediaStore.MediaColumns.DISPLAY_NAME, fileName);
                                contentValues.put(android.provider.MediaStore.MediaColumns.MIME_TYPE, "application/x-xls");
                                android.content.ContentResolver contentResolver = getContentResolver();
                                android.net.Uri uriForInsertResult = contentResolver.insert(uri, contentValues);
                                try {
                                    outputStream = contentResolver.openOutputStream(uriForInsertResult);
                                } catch (java.io.IOException ioException) {
                                    ioException.printStackTrace();
                                    errorMessage = ioException.getMessage();
                                }
                            } else {
                                errorMessage = "需要授予权限";
                                android.util.Log.d("debug", "没有授予外部存储写入权限");
                                android.util.Log.d("debug", "现在执行请求外部存储写入的权限");
                                android.util.Log.d("debug", "安卓10的逻辑请求权限");
                                java.lang.String[] permission = new java.lang.String[2];
                                permission[0] = android.Manifest.permission.READ_EXTERNAL_STORAGE;
                                permission[1] = android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
                                requestPermissions(permission, REQUEST_CODE_FOR_WRITE_EXTERNAL_STORAGE_PERMISSION_FROM_ANDROID_10_TO_ANDROID_12);
                            }
                        }
                    }
                } else {
                    android.util.Log.d("debug", "设备系统的版本号是介于6.0到9.0之间,仍然是可以从Environment类的getExternalStorageDirectory方法获取外部存储目录的,但是前提是要检查运行时权限");
                    int checkSelfPermissionResultForWriteExternalStorage = checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE);
                    if (checkSelfPermissionResultForWriteExternalStorage == android.content.pm.PackageManager.PERMISSION_GRANTED) {
                        java.io.File externalStorageDirectory = android.os.Environment.getExternalStorageDirectory();
                        android.util.Log.d("debug", "安卓系统是在6.0到9.0之间的,通过Environment类获取到外部存储目录->" + externalStorageDirectory.getPath());
                        try {
                            outputStream = new java.io.FileOutputStream(externalStorageDirectory.getPath() + java.io.File.separator + fileName);
                        } catch (java.io.IOException ioException) {
                            ioException.printStackTrace();
                            errorMessage = ioException.getMessage();
                        }
                    } else {
                        errorMessage = "需要授予权限";
                        java.lang.String[] permission = new java.lang.String[1];
                        permission[0] = android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
                        requestPermissions(permission, REQUEST_CODE_FOR_WRITE_EXTERNAL_STORAGE_PERMISSION_FOR_ANDROID_6_TO_ANDROID_9);
                    }
                }
            } else {
                android.util.Log.d("debug", "设备系统的版本号小于6.0以下的版本,不需要检查运行时权限");
                java.io.File externalStorageDirectory = android.os.Environment.getExternalStorageDirectory();
                android.util.Log.d("debug", "直接通过Environment类的getExternalStorageDirectory()即可获取外部存储目录->" + externalStorageDirectory.getPath());
                try {
                    outputStream = new java.io.FileOutputStream(externalStorageDirectory.getPath() + java.io.File.separator + fileName);
                } catch (java.io.IOException ioException) {
                    ioException.printStackTrace();
                    errorMessage = ioException.getMessage();
                }
            }
            if (outputStream != null) {
                //file write
            } else {
                android.widget.Toast.makeText(this, errorMessage, android.widget.Toast.LENGTH_LONG).show();
            }


        第四步:权限请求回调函数
        @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == REQUEST_CODE_FOR_READ_MEDIA_IMAGES_PERMISSION_FROM_ANDROID_13) {
            if (grantResults.length > 0 && grantResults[0] == android.content.pm.PackageManager.PERMISSION_GRANTED) {
                if (permissions.length > 0) {
                    android.util.Log.d("debug", "打印授予的权限->" + permissions[0]);
                }
                java.lang.String fileName = "buyup_导出资料_" + java.lang.System.currentTimeMillis() + ".xls";
                java.lang.String errorMessage = "";
                java.io.OutputStream outputStream = null;
                android.util.Log.d("debug", "设备系统的版本号是大于等于安卓10.0以上的版本,说明是只能用媒介存储写入文件和读取文件");
                android.net.Uri uri = android.provider.MediaStore.Files.getContentUri("external");
                android.content.ContentValues contentValues = new android.content.ContentValues();
                contentValues.put(android.provider.MediaStore.MediaColumns.DISPLAY_NAME, fileName);
                contentValues.put(android.provider.MediaStore.MediaColumns.MIME_TYPE, "application/x-xls");
                android.content.ContentResolver contentResolver = getContentResolver();
                android.net.Uri uriForInsertResult = contentResolver.insert(uri, contentValues);
                try {
                    outputStream = contentResolver.openOutputStream(uriForInsertResult);
                } catch (java.io.IOException ioException) {
                    ioException.printStackTrace();
                    errorMessage = ioException.getMessage();
                }
                if (outputStream != null) {
                    //file write
                } else {
                    android.widget.Toast.makeText(this, errorMessage, android.widget.Toast.LENGTH_LONG).show();
                }
            } else {
                if (permissions.length > 0) {
                    java.lang.String permission0 = permissions[0];
                    android.util.Log.d("debug", "打印请求的权限->" + permission0);
                }
                android.util.Log.d("debug", "权限授予失败");
                android.widget.Toast.makeText(this, "权限授予失败", android.widget.Toast.LENGTH_LONG).show();
            }
        } else if (requestCode == REQUEST_CODE_FOR_WRITE_EXTERNAL_STORAGE_PERMISSION_FOR_ANDROID_6_TO_ANDROID_9) {
            if (grantResults.length > 0 && grantResults[0] == android.content.pm.PackageManager.PERMISSION_GRANTED) {
                if (permissions.length > 0) {
                    android.util.Log.d("debug", "来自安卓6.0到安卓9.9之间的请求权限,打印授予的权限->" + permissions[0]);
                }
                java.lang.String fileName = "buyup_导出资料_" + java.lang.System.currentTimeMillis() + ".xls";
                java.lang.String errorMessage = "";
                java.io.OutputStream outputStream = null;
                android.util.Log.d("debug", "设备系统的版本号是大于等于安卓6.0到安卓9.0之间的,通过用android.os.Environment类获取外部存储");
                java.io.File externalStorageDirectory = android.os.Environment.getExternalStorageDirectory();
                try {
                    outputStream = new java.io.FileOutputStream(externalStorageDirectory.getPath() + java.io.File.separator + fileName);
                } catch (java.io.IOException ioException) {
                    ioException.printStackTrace();
                    errorMessage = ioException.getMessage();
                }
                if (outputStream != null) {
                    //file write
                } else {
                    android.widget.Toast.makeText(this, errorMessage, android.widget.Toast.LENGTH_LONG).show();
                }
            } else {
                if (permissions.length > 0) {
                    android.util.Log.d("debug", "来自安卓6.0到安卓9.9之间的请求权限,打印拒绝的权限->" + permissions[0]);
                }
                android.util.Log.d("debug", "来自安卓6.0到安卓9.9之间的请求权限,权限授予失败");
                android.widget.Toast.makeText(this, "权限授予失败", android.widget.Toast.LENGTH_LONG).show();
            }
        } else if (requestCode == REQUEST_CODE_FOR_WRITE_EXTERNAL_STORAGE_PERMISSION_FROM_ANDROID_10_TO_ANDROID_12) {
            if (grantResults.length > 0 && grantResults[0] == android.content.pm.PackageManager.PERMISSION_GRANTED) {
                if (permissions.length > 0) {
                    android.util.Log.d("debug", "来自安卓10.0的版本,打印授予的权限->" + permissions[0]);
                    android.util.Log.d("debug", "来自安卓10.0的版本,打印授予的权限->" + permissions[1]);
                }
                java.lang.String fileName = "buyup_导出资料_" + java.lang.System.currentTimeMillis() + ".xls";
                java.lang.String errorMessage = "";
                java.io.OutputStream outputStream = null;
                android.net.Uri uri = android.provider.MediaStore.Files.getContentUri("external");
                android.content.ContentValues contentValues = new android.content.ContentValues();
                contentValues.put(android.provider.MediaStore.MediaColumns.DISPLAY_NAME, fileName);
                contentValues.put(android.provider.MediaStore.MediaColumns.MIME_TYPE, "application/x-xls");
                android.content.ContentResolver contentResolver = getContentResolver();
                android.net.Uri uriForInsertResult = contentResolver.insert(uri, contentValues);
                try {
                    outputStream = contentResolver.openOutputStream(uriForInsertResult);
                } catch (java.io.IOException ioException) {
                    ioException.printStackTrace();
                    errorMessage = ioException.getMessage();
                }
                if (outputStream != null) {
                    //file write
                } else {
                    android.widget.Toast.makeText(this, errorMessage, android.widget.Toast.LENGTH_LONG).show();
                }
            } else {
                if (permissions.length > 0) {
                    android.util.Log.d("debug", "来自安卓10.0的版本,打印拒绝的权限->" + permissions[0]);
                    android.util.Log.d("debug", "来自安卓10.0的版本,打印拒绝的权限->" + permissions[1]);
                }
                android.widget.Toast.makeText(this, "权限授予失败", android.widget.Toast.LENGTH_LONG).show();
            }
        }
    }


    第五步:针对安卓11或者安卓12版本的请求权限方法
    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == REQUEST_CODE_FOR_WRITE_EXTERNAL_STORAGE_PERMISSION_FROM_ANDROID_10_TO_ANDROID_12) {
            android.util.Log.d("debug", "在安卓11或者安卓12系统中引导到系统设置界面开启权限回来");
            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R) {
                if (android.os.Environment.isExternalStorageManager()) {
                    android.util.Log.d("debug", "已经授予外部存储写入权限");
                    java.io.OutputStream outputStream = null;
                    java.lang.String errorMessage = "";
                    java.lang.String fileName = "buyup_导出资料_" + java.lang.System.currentTimeMillis() + ".xls";
                    android.util.Log.d("debug", "设备系统的版本号是介于10.0到12.0之间的,通过android.provider.MediaStore获取外部存储目录");
                    android.net.Uri uri = android.provider.MediaStore.Files.getContentUri("external");
                    android.content.ContentValues contentValues = new android.content.ContentValues();
                    contentValues.put(android.provider.MediaStore.MediaColumns.DISPLAY_NAME, fileName);
                    contentValues.put(android.provider.MediaStore.MediaColumns.MIME_TYPE, "application/x-xls");
                    android.content.ContentResolver contentResolver = getContentResolver();
                    android.net.Uri uriForInsertResult = contentResolver.insert(uri, contentValues);
                    try {
                        outputStream = contentResolver.openOutputStream(uriForInsertResult);
                    } catch (java.io.IOException ioException) {
                        ioException.printStackTrace();
                        errorMessage = ioException.getMessage();
                    }
                    if (outputStream != null) {
                        //file write
                    } else {
                        android.widget.Toast.makeText(this, errorMessage, android.widget.Toast.LENGTH_LONG).show();
                    }
                } else {
                    android.widget.Toast.makeText(this, "需要授予权限才能导出文件!", android.widget.Toast.LENGTH_SHORT).show();
                }
            }
        }
    }

Android14新权限机制 在本文中,我们将了解 Android14 的新权限,该权限。这个新权限允许用户在我们的应用程序。 阅读详情

相关推荐

Android存储权限适配指南:版本演进与Scoped Storage实践

移动应用开发中,数据访问权限管理是跨版本兼容的核心挑战。随着Android系统隐私保护强化,从6.0动态权限、7.0 FileProvider到10.0分区存储(Scoped Storage),系统持续重新划分数据访问边界。理解各版本权限模型差异,是避免读写失败、崩溃和审核风险的关键。MediaStore与SAF(存储访问框架)成为访问公共目录的标准手段,而FileProvider则解决了跨应用文件共享的安全问题。通过对这些基础机制的原理剖析与工程实践,开发者可构建一套兼容6.0至14.0的存储适配方案,确

weixin_30313409的博客 1万+

Android 13 媒体权限适配指南

此外,从 PickVisualMedia 和 PickMultipleVisualMedia 的源码可以看到,Android 13 内置的图片选择器对应的是 MediaStore.ACTION_PICK_IMAGES 这个新增的 Intent,而如果当前设备不支持媒体选择器功能的话,就会改为通过调用 Intent.ACTION_OPEN_DOCUMENT 来选择媒体资源,这种情况下 PickMultipleVisualMedia 设定的数量上限自然也就失效了。Android 13。

chuyouyinghe的专栏 4739

Android 13存储权限适配:解决开关消失与全版本兼容方案

Android存储权限模型是应用访问设备文件系统的核心安全机制。其设计原理经历了从粗放管理到精细管控的演进,旨在保护用户隐私和数据安全。这一演进的技术价值在于通过分区存储和细化权限,限制应用对共享存储空间的随意访问,从而构建更安全的移动生态。在工程实践中,开发者常遇到因权限模型升级导致的适配问题,例如在Android 13及以上版本中,传统的READ_EXTERNAL_STORAGE权限被细化为READ_MEDIA_IMAGES等独立媒体权限,这直接导致了权限弹窗异常和“开关消失”现象。解决此类问题需要深入

weixin_34239592的博客 405

Android 14 媒体权限变化

在Android 14设备上与您的应用程序交互的用户现在可以在应用程序请求Android 13(API级别33)中引入的任何视觉媒体权限(READ_media_IMAGES或READ_media-VIDEO)时授予对其视觉媒体库(照片/视频)的部分访问权限。如果用户选择Select photos and videos(选择照片和视频),并且您的应用程序稍后再次请求READ_MEDIA_IMAGES或READ_MEDIA-VIDEO,系统将显示一个不同的对话框,让用户有机会访问其他照片和视频。

ziyunLLL的博客 8339

安卓应用版本更新完整实战:从下载到安装的全流程适配指南

在安卓开发中,应用版本更新是高频需求,但实现过程远比“下载APK再安装”复杂。从版本检查到APK下载,再到系统安装,每一步都涉及DownloadManager、OkHttp、FileProvider等组件的选型与适配。Android版本碎片化严重,从7.0到14.0,file://共享限制、安装未知应用权限、明文流量拦截、通知运行时权限等机制不断变化,稍有不慎就会导致更新失败。掌据版本更新闭环设计、接口字段定义、断点续传、MD5校验、前台服务等核心技术点,能够有效规避工程中的常见坑,提升用户体验。本文结合多

weixin_29276847的博客 316

安卓游戏资源集成:安全下载、存储管理与版本控制实践

游戏资源集成是移动应用开发中的关键技术环节,涉及文件下载、本地存储和版本管理等核心原理。在Android开发中,资源完整性校验通过MD5或SHA算法确保文件安全,而存储权限管理则需适配Android 10+的作用域存储机制。技术价值在于保障游戏资源的可靠性和安全性,避免运行时崩溃和安全漏洞。应用场景广泛覆盖第三方游戏集成、跨平台资源处理等需求,如波兰球之战等游戏的资源获取与集成。通过规范的版本控制策略和兼容性处理,能够有效管理依赖冲突,适配不同Android系统版本,确保游戏稳定运行。

weixin_34292402的博客 410

Unity安卓相机相册权限全版本适配:从运行时权限到作用域存储实战

在移动应用开发中,运行时权限管理是保障用户隐私与功能实现的核心机制。其原理在于系统将敏感权限(如相机、存储)的授予时机从安装时推迟到应用运行时,由用户动态控制。这一机制的技术价值在于平衡了应用功能需求与用户数据安全,是构建可信应用的基础。随着安卓系统迭代,权限模型持续演进,尤其在访问外部存储时,安卓11引入的作用域存储(Scoped Storage)规范,进一步收紧了文件访问范围,要求应用通过系统选择器或MediaStore API访问媒体文件,这直接影响了相机拍照与相册选图等常见场景的实现。对于使用Uni

weixin_30566111的博客 426

UniApp实现安卓通话录音全攻略:从权限申请到兼容性处理(附完整代码)

本文提供了在UniApp中实现安卓通话录音功能的完整解决方案。文章深入剖析了从安卓8到安卓13的权限演变与兼容性挑战,详细讲解了权限申请、电话状态监听、录音控制及文件存储等核心步骤,并针对高版本安卓提供了适配策略与备选方案,附有经过验证的完整代码,助力开发者高效集成通话录音功能。

nginx7reverse的博客 1168

在android X(安卓10版本)运行创建父文件夹失败,解决办法

适配安卓X版本时,发现很多权限申请后无法达到应有的效果。 例如:申请了内存的读写权限,但是还是无法创建父文件夹。 查阅了一下开发文档: getExternalStorageDirectory()-在API级别29中不推荐使用此方法。为了提高用户隐私,不建议直接访问共享/外部存储设备。 当应用程序定位到Build.VERSION_CODES.Q时,此方法返回的路径不再可供应用程序直接访问。 通过迁移到Context#getExternalFilesDir(String),MediaStore或Intent#A

Kstar_Ming的博客 1482

Android系统 应用存储路径与权限

本文学习Android存储路径和权限,分为系统预装应用、特权系统应用、用户安装应用和平台签名应用。根据存储位置和权限级别各不相同。

我其实什么都不会 5811

从PWM到正弦波:RC低通滤波器的魔法转换之旅

本文详细介绍了如何利用RC低通滤波器将STM32F103生成的PWM信号转换为高质量正弦波的技术原理与实践方法。通过分析滤波器设计、参数计算、硬件实现及Proteus仿真验证,为嵌入式开发者提供了一套完整的PWM转正弦波解决方案,适用于电机控制、音频信号生成等多种应用场景。

jupi8的博客 380

Android各个版本存储权限适配与文件写入

【代码】Android各个版本存储权限适配与文件写入。

sig321的专栏 433

LVDS系列11:Xilinx Ultrascale系可编程输入延迟(一)

按照IDELAYCTRL的参考时钟频率可以准确计算获取到,如200M参考时钟抽头分辨率为78ps,Ultrascale系列相对于7系列架构大改,体现便是U/U+系列的抽头增加到512个,同时每个抽头的分辨率就无法像7系列那样能得到一个准确的值,是一个波动的范围值,抽头分辨率随着工艺温度电压的变化而变化。EN_VTC:电压温度补偿开启的使用信号,COUNT模式下不能使用,必须保持为0,TIME模式下需要使用,在延迟工作时要启用温度电压补偿,在修改抽头值时需要关闭温度电压补偿,修改完后启用;

weixin_38828382的博客 1941

Android 17权限适配挑战与XXPermissions框架深度解析

在Android应用开发中,权限管理始终是开发者面临的核心技术难题。随着Android系统从6.0的运行时权限模型演进到Android 17的精细化权限控制,权限适配的复杂度呈指数级增长。XXPermissions作为目前唯一全面适配Android 17的权限请求框架,为开发者提供了从Android 4.0到Android 17的全版本兼容解决方案,解决了多版本系统适配、特殊权限处理、厂商定制化等

gitblog_00191的博客 6643

详解ReID的各部分组成及Trick——基于FastReID

这一系列博客将基于京东开源的FastReID进行扩充,详细介绍了ReID的各个组成部分,一些有用的Trick,评价指标,常用数据集等,详细内容见下方的链接,总结不易,如有理解不正确之处,麻烦各位批评指正。 一、FastReID的中的baseline文件配置 二、Training strategy 三、Pre-processing 四、Backbone 五、Aggregation 六、Head 七、Loss 八、Distance Metric 九、Post-processing 十、Evaluation 十一

藏晖的博客 9164

深度学习batch、batch_size、epoch、iteration以及小样本中episode、support set、query set关系

训练整个数据集是epoch、把数据集分为多少小块就是batch,每个小块(batch)多少个数据就是batch_size,整个数据集需要训练多少轮是iteration

qq_42740834的博客 1610

Android 5.0 ~ 14访问Android/data(obb)目录的方法

众所周知,安卓每次出新版本的时候都会收紧权限,存储权限也不例外。虽说官方的意思是为了保护隐私安全,但这些改动着实令开发者和用户感到头疼,尤其是Android/data、Android/obb目录的访问。毕竟用户更难操作,开发者也要费力适配。那么今天就来探索下怎么适配这些变更点吧。

gjc91126的博客 5万+

保姆级教程:用OpenCV和MediaPipe在Python里实现实时手势识别(附完整代码)

本文提供了一份详细的Python教程,教你如何使用OpenCV和MediaPipe实现实时手势识别系统。从环境配置、手部关键点检测到手势分类算法,逐步讲解如何构建高精度手势识别应用,适用于智能家居控制、PPT操作等场景。教程包含完整代码示例和性能优化技巧,特别适合计算机视觉初学者和开发者实践。

weixin_28677005的博客 327

从三星手机拉不起权限弹窗说起:一份给Android开发者的多品牌、多系统版本存储适配自查清单

本文深入探讨了Android开发中多品牌、多系统版本的存储权限适配问题,特别针对三星、小米等厂商的ROM定制行为提供了详细解决方案。通过构建测试矩阵、诊断权限状态和实施分级降级策略,帮助开发者有效应对存储权限的兼容性挑战,提升应用稳定性。

weixin_30564785的博客 244

2025资源从哪里来!

研究网络通信中的安全问题,如VLAN划分、路由协议(静态、动态如OSPF、BGP)、NAT转换、AAA认证、访问控制列表(ACL)等。‌Wi-Fi安全设置‌、‌密码破解原理‌(仅用于合法测试或教育目的)、‌常见Web安全问题‌如SQL注入、XSS跨站脚本攻击等的防范措施。在这个网站你可以找到你对应的专业-对应的路线-对应的资源-对应的百度网盘里面全是免费的资源------------------惊喜不?‌防火墙配置与策略‌、‌入侵检测与防御系统(IDS/IPS)‌、‌端口扫描与漏洞扫描技术‌等。

qq_56248592的博客 1902

脉冲变压器电感选型参数,结构原理,工艺与注意问题总结

脉冲变压器电感简称脉冲变压器,是一种特殊类型的变压器,主要用于处理脉冲信号。它的主要特性是能够在短时间内承受高电压和大电流。脉冲变压器主要用于开关电源、脉冲功率放大、雷达脉冲调制等领域。本文对脉冲变压器的工作原理,结构特点,工艺流程,选型参数及设计注意事项进行总结。

fydar的博客 1342

Android各版本适配(6-14)

从Android 4.4一直开发到现在,每次版本更新都有不同的内容需要适配。这里总结一下常见的适配方案,以便于查找。

scliaowen的博客 4038

CodeX 登录报错 os error 10013?一键修复 CodeX 无法登录问题(亲测有效)

CodeX 登录时报 os error 10013?本文提供快速修复方案,实测有效,彻底解决登录报错:登录失败:failed to start login server: 以一种访问权限不允许的方式做了一个访问套接字的尝试。 (os error 10013)的问题💡

XiaoqiangClub的博客 2924

ncmppGui安卓版部署指南:解决Android高版本系统兼容性问题

ncmppGui是一款使用C++编写的极速ncm转换GUI工具,专为音乐爱好者打造。本指南将详细介绍如何在Android高版本系统中部署ncmppGui,解决常见的兼容性问题,让你轻松体验无损音乐转换的便捷。 ## 一、准备工作:环境配置与依赖检查 在开始部署前,请确保你的开发环境满足以下要求: - **Android Studio版本**:建议使用Arctic Fox或更高版本 - **G

gitblog_01149的博客 955

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

Android版本适配

一个好的APP最好支持90%设备,这篇文章记录开发过程中遇到的相对重要以及常用的版本适配方案,希望对读者有所帮助。

wucomi的博客 1024

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

Android11系统应用兼容适配

一、背景 客户使用了安卓11系统手机,发现应用安装闪退,于是分析,发现需要做升级适配。 二、遇到问题 应用中之前有提供一个手机唯一标识的功能,是通过调用安卓系统接口TelephoneManager 来获取IMEI的,然后再新的系统版本上发现此接口无法获取该信息, 才知道原来安卓也和苹果一样,对于这种信息不再提供给外部三方应用,个人猜测也是基于用户隐私安全考虑,市场上这么多三方应用,如果都通过该系统接口获取到唯一标识,多个三方应用之间再共享数据,则可以将每台手机的用户从各个维度进行用户画像,真的.

yangwubolwg的博客 5462
上一篇: Android开发中各种目录
下一篇: 如何通过pg_dump命令导出Postgresql数据库的表结构
JianfeiMa
博客等级 码龄10年 61粉丝 131原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值