【Android版本更新带来的权限管理问题】open failed: EACCES (Permission denied)

前言

最近在研究Android的音视频播放,我在Demo中连 Music 的存储路径都读不出来,orz...
于是乎,大行百度,来学习一下Android的存储,研究了各个Android版本下的权限管理。参考https://blog.csdn.net/w18756901575/article/details/52085157的读取图片示例开始,来了解一下 Android权限管理的发展史。
—— PS:我朋友说我学习搞错了方向,认证反思了一下,的确如此。毕竟自己的主攻方向不在Android的界面开发上,不能在这个上面花太多时间。


示例源代码

参考https://blog.csdn.net/w18756901575/article/details/52085157
主要就是 MainActivity.java 和 activity_main.xml

  • MainActivity.java
package com.example.demopermission;

import androidx.appcompat.app.AppCompatActivity;

import android.app.Activity;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;

import java.io.File;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private Button mBtnImage;
    //调用系统相册-选择图片
    private static final int IMAGE = 1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mBtnImage = (Button) findViewById(R.id.btnImg);

        mBtnImage.setOnClickListener(this);


    }


    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.btnImg:
                /* 简单查看一下文件*/
                File f = new File(Environment.getExternalStorageDirectory() + "/Download");
                Log.d("MSG", "absolute path " + f.getAbsolutePath());
                Log.d("MSG", "is dir " + f.isDirectory());
                Log.d("MSG", "is canRead " + f.canRead());
                Log.d("MSG", "is canWrite " + f.canWrite());
                if ( f.listFiles() == null) {
                    Log.d("MSG", "f is null ");
                }
                else {
                    Log.d("MSG", "f is not null ");
                }

                Intent intent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
                startActivityForResult(intent, IMAGE);
                break;
            default:
                break;
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        switch (requestCode) {
            case IMAGE:
                if (resultCode == Activity.RESULT_OK && data != null) {
                    Uri selectedImage = data.getData();
                    String[] filePathColumns = {MediaStore.Images.Media.DATA};
                    Cursor c = getContentResolver().query(selectedImage, filePathColumns, null, null, null);
                    c.moveToFirst();
                    int columnIndex = c.getColumnIndex(filePathColumns[0]);
                    String imagePath = c.getString(columnIndex);
                    showImage(imagePath);
                    c.close();
                }
                break;
            default:
                break;
        }
    }

    //加载图片
    private void showImage(String path){
        Bitmap bm = BitmapFactory.decodeFile(path);
        ((ImageView)findViewById(R.id.imgView)).setImageBitmap(bm);
    }

}
  • activity_main.xml



    

Android 版本 和 权限管理

加载上面的代码,会发现无法提取图片,主要是Android限制了你的权限。

Android 6.0之前 (API 23 以下)

静态配置,仅需要在 AndroidManifest.xml 里进行声明
—— 我自己的环境 是 minSdkVersion 23 的版本,这种方式肯定没用

    
    

Android 10.0 (API 29 以下)

  1. AndroidManifest.xml 里进行声明
    
    
  1. Activity 中动态声明
    public void requestPermission()
    {

        String[] permissionList = {
                Manifest.permission.READ_EXTERNAL_STORAGE,
                Manifest.permission.WRITE_EXTERNAL_STORAGE
        };

        int targetSdkVersion = 0;
        try {
            final PackageInfo info = this.getPackageManager().getPackageInfo(this.getPackageName(), 0);
            targetSdkVersion = info.applicationInfo.targetSdkVersion;//获取应用的Target版本
            Log.d("targetSdkVersion: ", String.valueOf(targetSdkVersion));
        } catch (PackageManager.NameNotFoundException e) {
            Log.e("PackageInfo", "get targetSdkVersion failed.");
        }

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            //Build.VERSION.SDK_INT是获取当前手机版本 Build.VERSION_CODES.M为6.0系统
            //如果系统>=6.0
            if (targetSdkVersion >= Build.VERSION_CODES.M) {
                //第 1 步: 检查是否有相应的权限
                boolean isAllGranted = checkPermissionAllGranted(permissionList);
                if (isAllGranted) {
                    //Log.e("err","所有权限已经授权!");
                    return;
                }
                // 一次请求多个权限, 如果其他有权限是已经授予的将会自动忽略掉
                ActivityCompat.requestPermissions(this, permissionList, 1);
            }
        }
    }

    private boolean checkPermissionAllGranted(String[] permissions) {
        for (String permission : permissions) {
            if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
                return false;
            }
        }
        return true;
    }

    //申请权限结果返回处理
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == 1) {
            boolean isAllGranted = true;
            // 判断是否所有的权限都已经授予了
            for (int grant : grantResults) {
                if (grant != PackageManager.PERMISSION_GRANTED) {
                    isAllGranted = false;
                    break;
                }
            }
            if (isAllGranted) {
                // 所有的权限都授予了
                Toast.makeText(MainActivity.this, "授权成功", Toast.LENGTH_LONG).show();
            } else {
                Toast.makeText(MainActivity.this, "授权失败", Toast.LENGTH_LONG).show();
            }
        }
    }

亲测有效

Android 10.0 及 以上

这里我就不深究了,不想花时间了;
主要就是 Android 10.0 对于权限管理的一些变更 巴拉巴拉的

--- build.gradle 中直接改 targetSdkVersion

不想劳神的办法

    defaultConfig {
        applicationId "com.example.demopermission"
        minSdkVersion 23
        targetSdkVersion 28 ## 直接改
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

你可能感兴趣的:(【Android版本更新带来的权限管理问题】open failed: EACCES (Permission denied))