Отказ в разрешении: открытие провайдера com.android.providers.contacts.ContactsProvider2 от ProcessRecord в Android Studio

Я получаю эту ошибку, когда я пытаюсь прочитать контакты с телефона, и я включил READ_CONTACTS разрешение в файле манифеста. И странно, что в Eclipse все работало нормально, но когда я преобразовал свой проект в Gradle и запустил его в Android Studio, я получил эту ошибку.

logcat говорит:

Отказ в разрешении: открытие провайдера com.android.providers.contacts.ContactsProvider2 из ProcessRecord{302f069 29282:com.GP/u0a322} (pid=29282, uid=10322) требует android.permission.READ_CONTACTS или android.permission.WRITE_CONAC

вот код манифеста:

<uses-sdk
        android:minSdkVersion="14"
        android:targetSdkVersion="19" />

    <!-- Read Contacts from phone -->
    <uses-permission android:name="android.permission.read_contacts" />
    <uses-permission android:name="android.permission.read_phone_state" />
    <uses-permission android:name="android.permission.GET_TASKS" />
    <uses-permission android:name="android.permission.READ_CALL_LOG" />

7 ответов

Из-за обновления Marshmallow, запрашивающего разрешения во время выполнения, разрешение на чтение контакта не работает. Пример кода

import android.Manifest;
import android.content.ContentResolver;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.os.Build;
import android.provider.ContactsContract;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {
    // The ListView
    private ListView lstNames;

    // Request code for READ_CONTACTS. It can be any number > 0.
    private static final int PERMISSIONS_REQUEST_READ_CONTACTS = 100;

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

        // Find the list view
        this.lstNames = (ListView) findViewById(R.id.lstNames);

        // Read and show the contacts
        showContacts();
    }

    /**
     * Show the contacts in the ListView.
     */
    private void showContacts() {
        // Check the SDK version and whether the permission is already granted or not.
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && checkSelfPermission(Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) {
            requestPermissions(new String[]{Manifest.permission.READ_CONTACTS}, PERMISSIONS_REQUEST_READ_CONTACTS);
            //After this point you wait for callback in onRequestPermissionsResult(int, String[], int[]) overriden method
        } else {
            // Android version is lesser than 6.0 or the permission is already granted.
            List<String> contacts = getContactNames();
            ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, contacts);
            lstNames.setAdapter(adapter);
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions,
                                           int[] grantResults) {
        if (requestCode == PERMISSIONS_REQUEST_READ_CONTACTS) {
            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // Permission is granted
                showContacts();
            } else {
                Toast.makeText(this, "Until you grant the permission, we canot display the names", Toast.LENGTH_SHORT).show();
            }
        }
    }

    /**
     * Read the name of all the contacts.
     *
     * @return a list of names.
     */
    private List<String> getContactNames() {
        List<String> contacts = new ArrayList<>();
        // Get the ContentResolver
        ContentResolver cr = getContentResolver();
        // Get the Cursor of all the contacts
        Cursor cursor = cr.query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null);

        // Move the cursor to first. Also check whether the cursor is empty or not.
        if (cursor.moveToFirst()) {
            // Iterate through the cursor
            do {
                // Get the contacts name
                String name = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
                contacts.add(name);
            } while (cursor.moveToNext());
        }
        // Close the curosor
        cursor.close();

        return contacts;
    }
}

Образцы скриншотов: введите описание изображения здесь введите описание изображения здесь

Я получил следующий исходный код отсюда

Новая схема разрешений во время выполнения используется только в том случае, если targetSdkVersion приложения (указанный в манифесте) равен 23 или выше. Таким образом, один из способов избежать этой проблемы - сделать targetSdkVersion ниже 23. Смотрите описание здесь:

https://developer.android.com/guide/topics/security/permissions.html

Моя проблема заключалась в том, что я использовал эмулятор Marshmallow, и это внесло некоторые изменения в то, как мы запрашиваем разрешения у пользователя. Следовательно, он продолжал запрашивать разрешения даже после их добавления. http://developer.android.com/training/permissions/requesting.html

Google Play ограничивает использование разрешений с высокой степенью риска или конфиденциальных разрешений, включая группы разрешений для SMS или журнала вызовов. Короче говоря, даже если вы спросите разрешения во время выполнения, высока вероятность, что ваше приложение не будет разрешено в Google Play.

Однако вы можете подать заявку на исключение. Google Play рассмотрит запрос и предоставит исключения в каждом конкретном случае. Критерии исключения позволяет упомянуты здесь.

      import android.Manifest;
import android.content.ContentResolver;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.os.Build;
import android.provider.ContactsContract;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {
    // The ListView
    private ListView lstNames;

    // Request code for READ_CONTACTS. It can be any number > 0.
    private static final int PERMISSIONS_REQUEST_READ_CONTACTS = 100;

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

        // Find the list view
        this.lstNames = (ListView) findViewById(R.id.lstNames);

        // Read and show the contacts
        showContacts();
    }

    /**
     * Show the contacts in the ListView.
     */
    private void showContacts() {
        // Check the SDK version and whether the permission is already granted or not.
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && checkSelfPermission(Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) {
            requestPermissions(new String[]{Manifest.permission.READ_CONTACTS}, PERMISSIONS_REQUEST_READ_CONTACTS);
            //After this point you wait for callback in onRequestPermissionsResult(int, String[], int[]) overriden method
        } else {
            // Android version is lesser than 6.0 or the permission is already granted.
            List<String> contacts = getContactNames();
            ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, contacts);
            lstNames.setAdapter(adapter);
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions,
                                           int[] grantResults) {
        if (requestCode == PERMISSIONS_REQUEST_READ_CONTACTS) {
            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // Permission is granted
                showContacts();
            } else {
                Toast.makeText(this, "Until you grant the permission, we canot display the names", Toast.LENGTH_SHORT).show();
            }
        }
    }

    /**
     * Read the name of all the contacts.
     *
     * @return a list of names.
     */
    private List<String> getContactNames() {
        List<String> contacts = new ArrayList<>();
        // Get the ContentResolver
        ContentResolver cr = getContentResolver();
        // Get the Cursor of all the contacts
        Cursor cursor = cr.query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null);

        // Move the cursor to first. Also check whether the cursor is empty or not.
        if (cursor.moveToFirst()) {
            // Iterate through the cursor
            do {
                // Get the contacts name
                String name = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
                contacts.add(name);
            } while (cursor.moveToNext());
        }
        // Close the curosor
        cursor.close();

        return contacts;
    }
}

Согласно документации Google при запросе разрешения, при обращении с этим следует иметь в виду следующее.

Например, предположим, что вы указываете READ_CONTACTS и WRITE_CONTACTS в манифесте приложения.

Если вы запрашиваете READ_CONTACTS, и пользователь предоставляет разрешение, а затем вы запрашиваете WRITE_CONTACTS, система немедленно предоставляет вам это разрешение без взаимодействия с пользователем.

https://developer.android.com/training/permissions/requesting

Просто добавьте это в свой AndroidManifest.xml внутри <manifest>:

<uses-permission android:name="android.permission.READ_CONTACTS"/>
Другие вопросы по тегам