Android에 대한 READ_EXTERNAL_STORAGE 권한


84

사용자 장치의 미디어 파일 (음악)에 액세스하여 재생하려고합니다. 쉬운 "hello world"음악 플레이어 앱입니다.

나는 몇 가지 튜토리얼을 따랐고 기본적으로 동일한 코드를 제공합니다. 하지만 작동하지 않습니다. 계속 충돌하고 나에게 말합니다.

error.....
Caused by: java.lang.SecurityException: Permission Denial: reading com.android.providers.media.MediaProvider uri content://media/external/audio/media from pid=27696, uid=10059 requires android.permission.READ_EXTERNAL_STORAGE, or grantUriPermission()
....

이제 이것은 내 매니페스트 파일입니다.

<?xml version="1.0" encoding="utf-8"?>
<manifest
    xmlns:android="http://schemas.android.com/apk/res/android"
    package="slimsimapps.troff" >

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


<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/AppTheme" >
    <activity
        android:name=".MainActivity"
        android:label="@string/app_name" >
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
</application>
</manifest>

이것은 내 Java 방법입니다.

public void initialize() {
    ContentResolver contentResolver = getContentResolver();
    Uri uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
    Cursor cursor = contentResolver.query(uri, null, null, null, null);
    if (cursor == null) {
        // query failed, handle error.
    } else if (!cursor.moveToFirst()) {
        // no media on the device
    } else {
        do {
            addSongToXML(cursor);
        } while (cursor.moveToNext());
    }
}

나는 시도했다 :

이것을 매니페스트 파일의 다른 위치에 넣으려면 :

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

외부 저장소 읽기 권한에서 android : maxSdkVersion을 추가하려면 :

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

이것을 manifest / application / activity-tag에 넣으려면 :

android:exported=“true

javamethod에서 uri와 cursro 사이에 grantUriPremission을 넣으려면 다음을 수행하십시오.

grantUriPermission(null, uri, Intent.FLAG_GRANT_READ_URI_PERMISSION);

이를 사용하려면 충돌하지 않지만 커서는 null이됩니다.

uri = MediaStore.Audio.Media.getContentUri("EXTERNAL_CONTENT_URI”);

내부 콘텐츠 URI를 사용하려면 예상대로 작동하지만 셔터 소리, 배터리 부족 소리, 버튼 클릭 등과 같은 "OS 소리"만 제공합니다.

uri = MediaStore.Audio.Media.INTERNAL_CONTENT_URI;

제발 도와주세요, 이것은 제가 아는 어려운 문제는 아니지만, 그런 초보자처럼 느껴집니다!

나는 읽고 시도했다 (또는 내 문제에 적용되지 않는 것으로 간주) :

스택 추적 :

09-08 06:59:36.619    2009-2009/slimsimapps.troff D/AndroidRuntime﹕ Shutting down VM
    --------- beginning of crash
09-08 06:59:36.619    2009-2009/slimsimapps.troff E/AndroidRuntime﹕ FATAL EXCEPTION: main
    Process: slimsimapps.troff, PID: 2009
    java.lang.IllegalStateException: Could not execute method for android:onClick
            at android.view.View$DeclaredOnClickListener.onClick(View.java:4452)
            at android.view.View.performClick(View.java:5198)
            at android.view.View$PerformClick.run(View.java:21147)
            at android.os.Handler.handleCallback(Handler.java:739)
            at android.os.Handler.dispatchMessage(Handler.java:95)
            at android.os.Looper.loop(Looper.java:148)
            at android.app.ActivityThread.main(ActivityThread.java:5417)
            at java.lang.reflect.Method.invoke(Native Method)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
     Caused by: java.lang.reflect.InvocationTargetException
            at java.lang.reflect.Method.invoke(Native Method)
            at android.view.View$DeclaredOnClickListener.onClick(View.java:4447)
            at android.view.View.performClick(View.java:5198)
            at android.view.View$PerformClick.run(View.java:21147)
            at android.os.Handler.handleCallback(Handler.java:739)
            at android.os.Handler.dispatchMessage(Handler.java:95)
            at android.os.Looper.loop(Looper.java:148)
            at android.app.ActivityThread.main(ActivityThread.java:5417)
            at java.lang.reflect.Method.invoke(Native Method)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
     Caused by: java.lang.SecurityException: Permission Denial: reading com.android.providers.media.MediaProvider uri content://media/external/audio/media from pid=2009, uid=10059 requires android.permission.READ_EXTERNAL_STORAGE, or grantUriPermission()
            at android.os.Parcel.readException(Parcel.java:1599)
            at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:183)
            at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:135)
            at android.content.ContentProviderProxy.query(ContentProviderNative.java:421)
            at android.content.ContentResolver.query(ContentResolver.java:491)
            at android.content.ContentResolver.query(ContentResolver.java:434)
            at slimsimapps.troff.MainActivity.initialize(MainActivity.java:106)
            at slimsimapps.troff.MainActivity.InitializeExternal(MainActivity.java:80)
            at java.lang.reflect.Method.invoke(Native Method)
            at android.view.View$DeclaredOnClickListener.onClick(View.java:4447)
            at android.view.View.performClick(View.java:5198)
            at android.view.View$PerformClick.run(View.java:21147)
            at android.os.Handler.handleCallback(Handler.java:739)
            at android.os.Handler.dispatchMessage(Handler.java:95)
            at android.os.Looper.loop(Looper.java:148)
            at android.app.ActivityThread.main(ActivityThread.java:5417)
            at java.lang.reflect.Method.invoke(Native Method)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
    --------- beginning of system

매니페스트 <uses-permission android : name = "android.permission.READ_EXTERNAL_STORAGE"/>에이 줄을 지정하지 않은 경우 이상한 오류가 표시됩니다. 다른 앱에서 보호하는 일부 파일을 읽으려고하십니까?
sunil sunny

어떤 API 수준에서 이것을 시도하고 있습니까?
샤프 에지

프로젝트 청소를 시도 했습니까? ?
sunil sunny

@sunilsunny 나는 보호되는 som 파일을 읽으려고하지 않습니다. 어쨌든 내가 아는 것이 아니라 단순한 미디어 플레이어입니다. 예, 정리를 시도했습니다. 컴퓨터를 다시 시작했습니다. 서명 된 APK를 생성하여 Google Play에 게시하고 테스터로 액세스하려고했습니다. 운이 없습니다 ....
Slim Sim

@날카로운 모서리 ; 내 AVD는 표준 Nexus 5, api 23입니다. 내 모듈 gradle은 다음과 같습니다. compileSdkVersion 23 buildToolsVersion "23.0.0"minSdkVersion 14 targetSdkVersion 23 그래서 23이라고 말할 것입니다.
Slim Sim

답변:


90

문제에 대한 두 가지 해결책이 있습니다. 빠른 방법은 targetApi를 22 (build.gradle 파일)로 낮추는 것입니다. 두 번째는 새롭고 멋진 권한 요청 모델을 사용하는 것입니다.

if (checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE)
        != PackageManager.PERMISSION_GRANTED) {

    // Should we show an explanation?
    if (shouldShowRequestPermissionRationale(
            Manifest.permission.READ_EXTERNAL_STORAGE)) {
        // Explain to the user why we need to read the contacts
    }

    requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
            MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE);

    // MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE is an
    // app-defined int constant that should be quite unique

    return;
}

Sniplet은 여기에서 찾을 수 있습니다 : https://developer.android.com/training/permissions/requesting.html

해결 방법 2 : 작동하지 않는 경우 다음을 시도하십시오.

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
    && ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
        REQUEST_PERMISSION);

return;

}

그리고 콜백에서

@Override
public void onRequestPermissionsResult(final int requestCode, @NonNull final String[] permissions, @NonNull final int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == REQUEST_PERMISSION) {
    if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
        // Permission granted.
    } else {
        // User refused to grant permission.
    }
}
}

그것은 댓글에서 나온 것입니다. 감사


1
네, 물론입니다! Google이 최신 Android로 도입 한 새로운 권한 모델! 감사합니다. 가능한 한 빨리 테스트하고 작동하면 올바르게 표시하겠습니다! (그리고 나는 이것이 잊혀 졌다고 생각하기 시작했습니다!)
Slim Sim

1
요청되는 권한은이어야합니다 READ_EXTERNAL_STORAGE. 이 답변같습니다 .
maclir

swap! = PackageManager.READ_EXTERNAL_STORAGE for! = PackageManager.PERMISSION_GRANTED
Renascienza

1
@Renascienza, 네 말이 맞습니다. 누군가이 답변을 잘못된 방식으로 수정했습니다.
piotrpo

2
MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE 란 무엇입니까?
Solo

17

런타임에 권한을 요청해야합니다.

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
        && ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
    ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
            REQUEST_PERMISSION);
    dialog.dismiss();
    return;
}

그리고 아래 콜백에서 문제없이 스토리지에 액세스 할 수 있습니다.

@Override
public void onRequestPermissionsResult(final int requestCode, @NonNull final String[] permissions, @NonNull final int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if (requestCode == REQUEST_PERMISSION) {
        if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            // Permission granted.
        } else {
            // User refused to grant permission.
        }
    }
}

7

1 단계 : Android manifest.xml에 권한 추가

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

2 단계 : onCreate () 메서드

int permissionCheck = ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE);

    if (permissionCheck != PackageManager.PERMISSION_GRANTED) {
        ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, MY_PERMISSIONS_REQUEST_READ_MEDIA);
    } else {
        readDataExternal();
    }

3 단계 : onRequestPermissionsResult 메서드를 재정 의하여 콜백을 가져옵니다.

 @Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
    switch (requestCode) {
        case MY_PERMISSIONS_REQUEST_READ_MEDIA:
            if ((grantResults.length > 0) && (grantResults[0] == PackageManager.PERMISSION_GRANTED)) {
                readDataExternal();
            }
            break;

        default:
            break;
    }
}

참고 : readDataExternal ()은 외부 저장소에서 데이터를 가져 오는 메서드입니다.

감사.


1
여기에 필요한 권한을 잘못 배치했다고 생각합니다. is READ_EXTERNAL_STORAGE.
Renascienza 2016

4

나는 또한 비슷한 오류 로그가 있었고 여기에 내가 한 일이 있습니다.

  1. onCreate 메서드에서 권한 확인을위한 대화 상자를 요청합니다.

    ActivityCompat.requestPermissions(MainActivity.this,
    new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},1);
    
  2. 결과 확인 방법

    @Override
    public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
    switch (requestCode) {
        case 1: {
            // If request is cancelled, the result arrays are empty.
            if (grantResults.length > 0
                    && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // permission granted and now can proceed
             mymethod(); //a sample method called
    
            } else {
    
                // permission denied, boo! Disable the
                // functionality that depends on this permission.
                Toast.makeText(MainActivity.this, "Permission denied to read your External storage", Toast.LENGTH_SHORT).show();
            }
            return;
        }
        // add other cases for more permissions
        }
    }
    

런타임 권한 요청에 대한 공식 문서


1
나는 그것을 사용했고 완벽하게 모든 안드로이드 장치에서 작동합니까?
Mahdi Hraybi

1

문제가 해결 되었습니까? 타겟 SDK는 무엇입니까? 추가 시도 android;maxSDKVersion="21"<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />


22 (대신 23)에 AndroidManifest.xml에 만 최대 SDK 버전을 설정하여, 내가 코르도바를 사용하여 근무
조지 케이건

0

http://developer.android.com/reference/android/provider/MediaStore.Audio.AudioColumns.html

줄을 바꿔보세요 contentResolver.query

//change it to the columns you need
String[] columns = new String[]{MediaStore.Audio.AudioColumns.DATA}; 
Cursor cursor = contentResolver.query(uri, columns, null, null, null);

공개 정적 최종 문자열 MEDIA_CONTENT_CONTROL

미디어 소비의 개인 정보 보호로 인해 타사 응용 프로그램에서 사용할 수 없습니다.

http://developer.android.com/reference/android/Manifest.permission.html#MEDIA_CONTENT_CONTROL

<uses-permission android:name="android.permission.MEDIA_CONTENT_CONTROL"/>첫 번째 를 제거하고 다시 시도 하시겠습니까?


감사합니다. 제안을 시도했지만 같은 지점에서 충돌이 발생했습니다. Mac을 사용하고 있습니다. 문제가 될 수 있나요?
Slim Sim

업데이트되었습니다. 제거 <uses-permission android:name="android.permission.MEDIA_CONTENT_CONTROL"/>하고 시도 하시겠습니까? 허가 앱 요청이 허용되지 않는 때문에 이상한 행동을 만들 수 있습니다
데릭 봉을

덕분에, 나는 그 권한을 제거하려하지만 ... 같은 오류와 같은 지점에 충돌
슬림 심

0

아래 코드를 사용하여 sdcard의 모든 음악 파일을 찾을 수 있는지 확인하십시오.

public class MainActivity extends Activity{

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_animations);
    getAllSongsFromSDCARD();

}

public void getAllSongsFromSDCARD() {
    String[] STAR = { "*" };
    Cursor cursor;
    Uri allsongsuri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
    String selection = MediaStore.Audio.Media.IS_MUSIC + " != 0";

    cursor = managedQuery(allsongsuri, STAR, selection, null, null);

    if (cursor != null) {
        if (cursor.moveToFirst()) {
            do {
                String song_name = cursor
                        .getString(cursor
                                .getColumnIndex(MediaStore.Audio.Media.DISPLAY_NAME));
                int song_id = cursor.getInt(cursor
                        .getColumnIndex(MediaStore.Audio.Media._ID));

                String fullpath = cursor.getString(cursor
                        .getColumnIndex(MediaStore.Audio.Media.DATA));

                String album_name = cursor.getString(cursor
                        .getColumnIndex(MediaStore.Audio.Media.ALBUM));
                int album_id = cursor.getInt(cursor
                        .getColumnIndex(MediaStore.Audio.Media.ALBUM_ID));

                String artist_name = cursor.getString(cursor
                        .getColumnIndex(MediaStore.Audio.Media.ARTIST));
                int artist_id = cursor.getInt(cursor
                        .getColumnIndex(MediaStore.Audio.Media.ARTIST_ID));
                System.out.println("sonng name"+fullpath);
            } while (cursor.moveToNext());

        }
        cursor.close();
    }
}


}

또한 아래와 같이 AndroidManifest.xml 파일에 다음 줄을 추가했습니다.

<uses-sdk
    android:minSdkVersion="16"
    android:targetSdkVersion="17" />

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

감사합니다. 이전에 비슷한 것을 시도했지만 코드를 시도했는데 이전과 동일한 오류 인 "cursor = managedQuery (allsongsuri, STAR, selection, null, null);"에서 충돌이 발생합니다. 그건 그렇고; managedQuery는 더 이상 사용되지 않지만 입력 매개 변수가 동일한 "contentResolver.query"로 변경하면 여전히 충돌이 발생합니다 ...
Slim Sim

안녕하세요 저는 위의 코드를 사용하여 모든 sdcadr 노래를 얻을 수 있습니다. Android 버전 4.2.2 기기 및 버전 5.0.2에서도 가능합니다. 당신은 노력하고 있습니다. 어떤 오류는 안드로이드 버전으로 설명해주십시오있어
라잔 Bhavsar

스택 추적으로 질문을 업데이트했으며 도움이되기를 바랍니다. Android 버전이란 무엇을 의미합니까? (나는 apk 23을 사용하고 있습니다)
Slim Sim

Ok 전체 소스 코드를 제공하고 다시 확인하십시오.
Rajan Bhavsar 2015 년

직접 테스트하려면 여기에서 zip을 다운로드하십시오. drive.google.com/open?id=0B2AV8VRk9HUeVzFXSWVRZU9TRUk 실행할 때 왼쪽 초기화 버튼을 눌러 크 래치를 생성합니다.
Slim Sim

0

모든 답변 외에도. 이 주석과 함께 적용 할 minsdk를 지정할 수도 있습니다.

@TargetApi(_apiLevel_)

내 minsdk가 18 인 경우에도이 요청을 수락하기 위해 이것을 사용했습니다.이 방법은 장치가 "_apilevel_"이상을 대상으로 할 때만 메서드가 실행된다는 것입니다. 내 방법은 다음과 같습니다.

    @TargetApi(23)
void solicitarPermisos(){

    if (ContextCompat.checkSelfPermission(this,permiso)
            != PackageManager.PERMISSION_GRANTED) {

        // Should we show an explanation?
        if (shouldShowRequestPermissionRationale(
                Manifest.permission.READ_EXTERNAL_STORAGE)) {
            // Explain to the user why we need to read the contacts
        }

        requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
                1);

        // MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE is an
        // app-defined int constant that should be quite unique

        return;
    }

}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.