Android7.0文件读写(获取拍照结果)笔记

由于随着Android版本越来越高,Android对用户隐私保护力度越来越大,从Android6.0引入动态权限控制(Runtime Permission)到Android7.0私有目录被限制访问,“StrictMode API政策”.由于之前Android版本中,是可以读取到手机存储中任何一个目录及文件,这带来很多安全问题.在Android7.0中为了提高私有文件的安全性.面向Android N或者更高版本将被限制访问.

  • 私有文件的文件权限不再放权给所有的应用,使用MODE_WORLD_READABLE或者MODE_WORLD_WRITEABLE进行操作触发SecurityException.这使得无法通过File API访问手机存储上的数据了,基于File API的一些文件浏览器也将受到很大影响.

  • 给其他应用传递file://URI类型的Uri,可能会导致接收者无法访问该路径,因为在Android7.0中传递file://URI会触发FileUriExposedException.可以通过FileProvider来解决.

  • DownloadManager不再按文件名分享私人存储的文件,COLUMN_LOCAL_FILENAME在Android7.0中标记为deprecate,旧版应用在访问COLUMN_LOCAL_FILENAME可能会出现无法访问的路径.面向Android N或者更高版本中应用尝试访问COLUMN_LOCAL_FILENAME时会触发SecurityException.但可以通过ContentResolver.openFileDescriptor()来访问DownloadManager公开的文件.

    • 清单文件配置provider
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="xxx">
    <application>
    <provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="${applicationId}.FileProvider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/rc_file_path" />
        </provider>
    </application>
    </manifest>

    res/xml/rc_file_path.xml

    <?xml version="1.0" encoding="utf-8"?>
    <paths>
    <external-path name="rc_external_path" path="."/>
    </paths>
    • 创建临时图片

      if (CommonUtils.checkSDCard()) {
              File stubFile = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + File.pathSeparator + CROP_FILE_NAME);
              return FileProvider.getUriForFile(activity, BuildConfig.APPLICATION_ID + ".FileProvider", stubFile);
              //return Uri.fromFile(Environment.getExternalStorageDirectory()).buildUpon().appendPath(CROP_FILE_NAME).build();Android7.0以前
          } else {
              File stubFile = new File(activity.getCacheDir().getAbsolutePath() + File.pathSeparator + CROP_FILE_NAME);
              return FileProvider.getUriForFile(activity, BuildConfig.APPLICATION_ID + ".FileProvider", stubFile);
              //return Uri.fromFile(activity.getCacheDir()).buildUpon().appendPath(CROP_FILE_NAME).build();Android7.0以前
          }
    • 启动相机

      try {
              //每次选择图片把之前的图片删除
              clearCropFile(buildUri(fragment._mActivity));
              LogUtils.d("feige", "buildUri-->" + buildUri(fragment._mActivity).getPath());
      
              Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
              intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);
              intent.putExtra(MediaStore.EXTRA_OUTPUT, buildUri(fragment._mActivity));
              intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
              if (!isIntentAvailable(fragment._mActivity, intent)) {
                  return;
              }
              fragment.startActivityForResult(intent, INTENT_TAKE);
          } catch (Exception e) {
              e.printStackTrace();
          }
<think>嗯,用户想解决Android Studio中的权限问题,这需要分步骤来处理。首先,我得回忆一下Android权限机制的变化,特别是6.0之后的运行时权限。用户可能已经知道需要在AndroidManifest.xml里声明权限,但可能还不清楚动态请求的部分。 根据引用[1],用户需要在清单文件里添加读写存储权限,但6.0以后还需要在运行时请求。所以第一步是确认用户是否添加了正确的静态声明。然后,检查是否需要动态请求,比如对于危险权限,比如存储、相机等,必须每次使用时都检查并请求。 然后,用户提到的拍照闪退问题,引用[3]里的StrictMode解决方法可能针对的是文件URI暴露的问题,特别是在Android 7.0以上需要使用FileProvider。这可能也是权限相关的问题,或者与URI策略有关,需要配置FileProvider。 另外,网络权限在引用[2]中提到只需要在清单中添加,因为网络权限属于普通权限,不需要动态请求。但用户可能混淆了不同类型的权限处理方式。 接下来,用户可能遇到的问题可能包括:权限未声明导致应用崩溃,或者权限被拒绝后的处理不当。需要指导用户如何检查权限是否已授予,使用ContextCompat.checkSelfPermission,然后请求权限,处理回调结果。 可能还需要提到,如果用户的目标API级别较高,比如Android 10以上,存储权限的作用域变更,可能需要使用作用域存储,这时候读写外部存储的行为会受限,需要考虑适配。 此外,用户可能没有正确处理权限拒绝的情况,应该提示用户为何需要该权限,并在onRequestPermissionsResult中处理拒绝的情况,可能引导用户去设置里手动开启。 总结一下,解决步骤应该是:1. 静态声明权限;2. 动态请求危险权限;3. 处理权限回调;4. 适配高版本系统的变化,如Scoped Storage和FileProvider。同时,要确保代码中没有因为权限问题导致的异常,比如文件访问或相机调用时的权限检查。</think>### Android Studio 权限问题解决步骤 Android 权限管理分为**静态声明**和**动态请求**两部分,具体解决步骤如下: #### 1. 静态权限声明 在 $AndroidManifest.xml$ 中添加所需权限(根据功能需求选择): ```xml <!-- 存储权限 --> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <!-- 网络权限 --> <uses-permission android:name="android.permission.INTERNET" /> <!-- 相机权限 --> <uses-permission android:name="android.permission.CAMERA" /> ``` *注:普通权限(如网络权限)仅需静态声明[^2],危险权限(如存储、相机)需额外动态申请[^1]。* --- #### 2. 动态权限请求(针对Android 6.0+) 对于危险权限,需在代码中动态请求: ```java // 检查权限是否已授予 if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { // 请求权限 ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CODE_STORAGE); } // 处理权限回调 @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == REQUEST_CODE_STORAGE) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { // 权限已授予 } else { // 权限被拒绝,提示用户 } } } ``` --- #### 3. 特殊问题处理 - **拍照闪退问题**: Android 7.0+ 限制直接使用文件路径,需通过 $FileProvider$ 共享文件,并添加以下代码临时禁用严格模式[^3]: ```java if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder(); StrictMode.setVmPolicy(builder.build()); } ``` - **高版本存储限制(Android 10+)**: 使用作用域存储(Scoped Storage),通过 $MediaStore$ API 访问文件,或添加以下属性兼容旧版本: ```xml <application ... android:requestLegacyExternalStorage="true"> ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值