【Android版本更新帶來的權(quán)限管理問題】open failed: EACCES (Permission denied)

前言

最近在研究Android的音視頻播放暇务,我在Demo中連 Music 的存儲路徑都讀不出來带污,orz...
于是乎,大行百度宛琅,來學(xué)習(xí)一下Android的存儲,研究了各個Android版本下的權(quán)限管理臀晃。參考https://blog.csdn.net/w18756901575/article/details/52085157的讀取圖片示例開始觉渴,來了解一下 Android權(quán)限管理的發(fā)展史。
—— PS:我朋友說我學(xué)習(xí)搞錯了方向徽惋,認(rèn)證反思了一下案淋,的確如此。畢竟自己的主攻方向不在Android的界面開發(fā)上险绘,不能在這個上面花太多時間踢京。


示例源代碼

參考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;
    //調(diào)用系統(tǒng)相冊-選擇圖片
    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
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/btnImg"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:text="點擊選擇圖片"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.0" />
    

    <ImageView
        android:id="@+id/imgView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="200dp"
        android:scaleType="fitCenter"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"></ImageView>

</androidx.constraintlayout.widget.ConstraintLayout>

Android 版本 和 權(quán)限管理

加載上面的代碼,會發(fā)現(xiàn)無法提取圖片宦棺,主要是Android限制了你的權(quán)限瓣距。

Android 6.0之前 (API 23 以下)

靜態(tài)配置,僅需要在 AndroidManifest.xml 里進(jìn)行聲明
—— 我自己的環(huán)境 是 minSdkVersion 23 的版本代咸,這種方式肯定沒用

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

Android 10.0 (API 29 以下)

  1. AndroidManifest.xml 里進(jìn)行聲明
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"></uses-permission>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
  1. Activity 中動態(tài)聲明
    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;//獲取應(yīng)用的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是獲取當(dāng)前手機版本 Build.VERSION_CODES.M為6.0系統(tǒng)
            //如果系統(tǒng)>=6.0
            if (targetSdkVersion >= Build.VERSION_CODES.M) {
                //第 1 步: 檢查是否有相應(yīng)的權(quán)限
                boolean isAllGranted = checkPermissionAllGranted(permissionList);
                if (isAllGranted) {
                    //Log.e("err","所有權(quán)限已經(jīng)授權(quán)蹈丸!");
                    return;
                }
                // 一次請求多個權(quán)限, 如果其他有權(quán)限是已經(jīng)授予的將會自動忽略掉
                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;
    }

    //申請權(quán)限結(jié)果返回處理
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == 1) {
            boolean isAllGranted = true;
            // 判斷是否所有的權(quán)限都已經(jīng)授予了
            for (int grant : grantResults) {
                if (grant != PackageManager.PERMISSION_GRANTED) {
                    isAllGranted = false;
                    break;
                }
            }
            if (isAllGranted) {
                // 所有的權(quán)限都授予了
                Toast.makeText(MainActivity.this, "授權(quán)成功", Toast.LENGTH_LONG).show();
            } else {
                Toast.makeText(MainActivity.this, "授權(quán)失敗", Toast.LENGTH_LONG).show();
            }
        }
    }

親測有效

Android 10.0 及 以上

這里我就不深究了,不想花時間了呐芥;
主要就是 Android 10.0 對于權(quán)限管理的一些變更 巴拉巴拉的

--- build.gradle 中直接改 targetSdkVersion

不想勞神的辦法

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

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末逻杖,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子思瘟,更是在濱河造成了極大的恐慌荸百,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,386評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件滨攻,死亡現(xiàn)場離奇詭異够话,居然都是意外死亡,警方通過查閱死者的電腦和手機光绕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評論 3 394
  • 文/潘曉璐 我一進(jìn)店門女嘲,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人诞帐,你說我怎么就攤上這事澡为。” “怎么了景埃?”我有些...
    開封第一講書人閱讀 164,704評論 0 353
  • 文/不壞的土叔 我叫張陵媒至,是天一觀的道長。 經(jīng)常有香客問我谷徙,道長拒啰,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,702評論 1 294
  • 正文 為了忘掉前任完慧,我火速辦了婚禮谋旦,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己册着,他們只是感情好拴孤,可當(dāng)我...
    茶點故事閱讀 67,716評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著甲捏,像睡著了一般演熟。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上司顿,一...
    開封第一講書人閱讀 51,573評論 1 305
  • 那天芒粹,我揣著相機與錄音,去河邊找鬼大溜。 笑死化漆,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的钦奋。 我是一名探鬼主播座云,決...
    沈念sama閱讀 40,314評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼付材!你這毒婦竟也來了朦拖?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,230評論 0 276
  • 序言:老撾萬榮一對情侶失蹤伞租,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后限佩,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體葵诈,經(jīng)...
    沈念sama閱讀 45,680評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,873評論 3 336
  • 正文 我和宋清朗相戀三年祟同,在試婚紗的時候發(fā)現(xiàn)自己被綠了作喘。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,991評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡晕城,死狀恐怖泞坦,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情砖顷,我是刑警寧澤贰锁,帶...
    沈念sama閱讀 35,706評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站滤蝠,受9級特大地震影響豌熄,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜物咳,卻給世界環(huán)境...
    茶點故事閱讀 41,329評論 3 330
  • 文/蒙蒙 一锣险、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦芯肤、人聲如沸巷折。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,910評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽锻拘。三九已至,卻和暖如春掩幢,著一層夾襖步出監(jiān)牢的瞬間逊拍,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,038評論 1 270
  • 我被黑心中介騙來泰國打工际邻, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留芯丧,地道東北人。 一個月前我還...
    沈念sama閱讀 48,158評論 3 370
  • 正文 我出身青樓世曾,卻偏偏與公主長得像缨恒,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子轮听,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,941評論 2 355

推薦閱讀更多精彩內(nèi)容