Отказ в разрешении: открытие провайдера 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"/>