Quyền READ_EXTERNAL_STORAGE cho Android


84

Tôi đang cố gắng truy cập các tệp phương tiện (nhạc) trên thiết bị của người dùng để phát chúng; một ứng dụng chơi nhạc "xin chào thế giới" dễ dàng.

Tôi đã làm theo một số hướng dẫn và về cơ bản chúng cung cấp mã giống nhau. Nhưng nó sẽ không hoạt động; nó tiếp tục gặp sự cố và nói với tôi:

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()
....

Bây giờ, đây là tệp kê khai của tôi:

<?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>

Đây là phương pháp Java của tôi:

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());
    }
}

Tôi đã thử:

Để đặt điều này ở các vị trí khác nhau trong tệp kê khai:

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

Để thêm android: maxSdkVersion tại Đọc trước bộ nhớ ngoài:

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

Để đặt điều này vào tệp kê khai / ứng dụng / thẻ hoạt động:

android:exported=“true

Để đặt GrantUriPremission giữa uri và cursro trong javamethod:

grantUriPermission(null, uri, Intent.FLAG_GRANT_READ_URI_PERMISSION);

Để sử dụng điều này, nó sẽ không bị lỗi, nhưng con trỏ sẽ trở thành null:

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

Để sử dụng nội dung NỘI BỘ, tính năng này hoạt động như mong đợi, nhưng nó chỉ cung cấp "âm thanh hệ điều hành" như âm thanh cửa trập, âm thanh pin yếu, nhấp vào nút và như vậy:

uri = MediaStore.Audio.Media.INTERNAL_CONTENT_URI;

Xin giúp đỡ, đây không phải là một vấn đề khó khăn mà tôi biết, nhưng tôi cảm thấy như một người mới bắt đầu!

Tôi đã đọc và thử (hoặc coi chúng không áp dụng được cho vấn đề của tôi):

Dấu vết ngăn xếp:

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

Kỳ lạ là lỗi được hiển thị khi bạn chưa nhập dòng này trong tệp kê khai <use-allow android: name = "android.permission.READ_EXTERNAL_STORAGE" /> bạn đang cố đọc một số tệp được bảo vệ bởi một số ứng dụng khác?
trời nắng

Bạn đang thử cái này ở cấp độ api nào?
Sharp Edge

Bạn đã thử làm sạch dự án. ?
trời nắng

@sunilsunny Tôi không cố đọc các tệp som được bảo vệ, không phải là tôi biết, chỉ là một trình phát đa phương tiện đơn giản. Có, tôi đã cố gắng làm sạch nó, tôi đã cố gắng khởi động lại máy tính, tôi đã cố gắng tạo APK đã ký và xuất bản nó lên Google Play và truy cập nó với tư cách là người thử nghiệm, thật không may ....
Slim Sim

@Cạnh sắc nét ; AVD của tôi là tiêu chuẩn Nexus 5, api 23. Module gradle của tôi có: compileSdkVersion 23 buildToolsVersion "23.0.0" minSdkVersion 14 targetSdkVersion 23 Vì vậy, tôi sẽ nói 23.
Slim Sim

Câu trả lời:


90

Bạn có hai giải pháp cho vấn đề của mình. Cách nhanh nhất là giảm targetApi xuống 22 (tệp build.gradle). Thứ hai là sử dụng mô hình xin phép mới và tuyệt vời:

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 được tìm thấy tại đây: https://developer.android.com/training/permissions/requesting.html

Giải pháp 2: Nếu nó không hoạt động, hãy thử cách này:

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;

}

và sau đó gọi lại

@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.
    }
}
}

đó là từ các bình luận. cảm ơn


1
Phải, tất nhiên! Mô hình quyền mới mà Google đã giới thiệu với Android mới nhất! Cảm ơn bạn, tôi sẽ kiểm tra điều này sớm nhất có thể và đánh dấu nó chính xác nếu nó hoạt động! (và tôi đã bắt đầu nghĩ rằng đây đã bị lãng quên!)
Slim Sim

1
Quyền được yêu cầu phải được READ_EXTERNAL_STORAGE. Giống như trong câu trả lời này .
maclir

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

1
@Renascienza, vâng bạn nói đúng. Ai đó đã chỉnh sửa câu trả lời này theo cách sai.
piotrpo

2
MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE là gì?
Solo

17

Bạn phải yêu cầu quyền tại thời điểm chạy:

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;
}

Và trong cuộc gọi lại bên dưới, bạn có thể truy cập bộ nhớ mà không gặp sự cố.

@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

Bước 1: Thêm quyền trên tệp kê khai android.xml

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

Bước 2: phương thức 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();
    }

Bước 3: ghi đè phương thức onRequestPermissionsResult để nhận lại cuộc gọi

 @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;
    }
}

Lưu ý: readDataExternal () là phương thức lấy dữ liệu từ bộ nhớ ngoài.

Cảm ơn.


1
Tôi nghĩ rằng bạn đã đặt nhầm quyền cần thiết ở đây: là READ_EXTERNAL_STORAGE.
Renascienza,

4

Tôi cũng có một nhật ký lỗi tương tự và đây là những gì tôi đã làm-

  1. Trong phương thức onCreate, chúng tôi yêu cầu một Hộp thoại để kiểm tra quyền

    ActivityCompat.requestPermissions(MainActivity.this,
    new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},1);
    
  2. Phương pháp kiểm tra kết quả

    @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
        }
    }
    

Tài liệu chính thức để yêu cầu quyền thời gian chạy


1
Tôi đã sử dụng nó và nó hoạt động hoàn hảo. Nó hoạt động trên tất cả các thiết bị Android?
Mahdi Hraybi

1

Vấn đề của bạn đã được giải quyết chưa? SDK mục tiêu của bạn là gì? Thử thêm android;maxSDKVersion="21"vào<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />


Làm việc cho tôi bằng cách sử dụng Cordova, bằng cách chỉ đặt phiên bản SDK tối đa trong AndroidManifest.xml thành 22 (thay vì 23)
George Kagan

0

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

Hãy thử thay đổi dòng 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);

Chuỗi cuối cùng tĩnh công khai MEDIA_CONTENT_CONTROL

Không dành cho các ứng dụng của bên thứ ba do tính riêng tư của việc sử dụng phương tiện

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

thử xóa cái <uses-permission android:name="android.permission.MEDIA_CONTENT_CONTROL"/>đầu tiên và thử lại?


Cảm ơn, tôi đã thử đề xuất của bạn nhưng nó bị lỗi ở cùng một chỗ ... Tôi đang sử dụng máy Mac, đó có thể là vấn đề?
Slim Sim

đã cập nhật, hãy thử gỡ bỏ <uses-permission android:name="android.permission.MEDIA_CONTENT_CONTROL"/>và thử? Nó có thể tạo ra hành vi kỳ lạ bởi vì yêu cầu ứng dụng của bạn cho một phép không được phép
Derek Fung

cảm ơn, tôi đã cố gắng xóa quyền đó, nhưng nó bị lỗi tại cùng một điểm với cùng một lỗi ...
Slim Sim

0

Vui lòng kiểm tra mã bên dưới để sử dụng mã đó Bạn có thể tìm thấy tất cả các Tệp nhạc từ 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();
    }
}


}

Tôi cũng đã thêm dòng sau vào tệp AndroidManifest.xml như bên dưới:

<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" />

Cảm ơn, tôi đã thử một cái gì đó tương tự trước đây, nhưng tôi đã thử mã của bạn và nó bị lỗi trên "cursor = ManagedQuery (allsongsuri, STAR, selection, null, null);", lỗi giống như trước đây. Nhân tiện; managedQuery bị phản đối, nhưng nó vẫn bị treo nếu tôi thay đổi nó để "contentResolver.query", trong đó có các thông số đầu vào như nhau ...
Slim Sim

Xin chào, tôi có thể tải Tất cả bài hát sdcadr bằng cách sử dụng mã trên. với Thiết bị Android Phiên bản 4.2.2 và cũng có thể với Phiên bản 5.0.2. Trong đó Bạn đang cố gắng. Lỗi gì bạn đã xin mô tả với Android Version
Rajan Bhavsar

Tôi đã cập nhật câu hỏi với dấu vết ngăn xếp, hy vọng rằng sẽ hữu ích. Ý bạn là gì với Phiên bản Android? (Tôi đang sử dụng apk 23)
Slim Sim

Ok Hãy để tôi cung cấp mã nguồn đầy đủ và kiểm tra lại.
Rajan Bhavsar

nếu bạn muốn tự mình kiểm tra, hãy tải xuống zip tại đây: drive.google.com/open?id=0B2AV8VRk9HUeVzFXSWVRZU9TRUk khi bạn chạy nó, hãy nhấn nút khởi tạo bên trái, để tạo crach.
Slim Sim

0

Ngoài tất cả các câu trả lời. Bạn cũng có thể chỉ định minsdk để áp dụng với chú thích này

@TargetApi(_apiLevel_)

Tôi đã sử dụng điều này để chấp nhận yêu cầu này ngay cả khi minsdk của tôi là 18. Điều nó làm là phương thức chỉ chạy khi thiết bị nhắm mục tiêu "_apilevel_" trở lên. Đây là phương pháp của tôi:

    @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;
    }

}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.