Android 6.0 (Marshmallow) READ_CONTACTS 权限允许在权限被拒绝时读取联系人的姓名
Posted
技术标签:
【中文标题】Android 6.0 (Marshmallow) READ_CONTACTS 权限允许在权限被拒绝时读取联系人的姓名【英文标题】:Android 6.0 (Marshmallow) READ_CONTACTS permission allows to read Contact's name when permission is denied 【发布时间】:2016-06-05 00:05:47 【问题描述】:我想检查新的权限模型是如何工作的,所以在应用程序的设置中我禁用了Contacts
。然后我去应用程序并尝试阅读Contacts
并且......它有点工作:
try
Uri result = data.getData();
int contentIdx;
cursor = getContentResolver().query(result, null, null, null, null);
contentIdx = cursor.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER);
if(cursor.moveToFirst())
content = cursor.getInt(contentIdx);
if(content > 0)
contentIdx = cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME);
if(cursor.moveToFirst())
name = cursor.getString(contentIdx);
contentIdx = cursor.getColumnIndex(BaseColumns._ID);
if(cursor.moveToFirst())
content = cursor.getLong(contentIdx);
cursor = managedQuery(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, new String[] Phone.NUMBER , Data.CONTACT_ID + "=?", new String[] String.valueOf(content) , null);
if(cursor.moveToFirst())
number = cursor.getString(cursor.getColumnIndex(Phone.NUMBER));
catch (Exception e)
//SecurityException
我可以读取联系人姓名
当我尝试读取联系人号码时,SecurityException
被抛出
java.lang.SecurityException: Permission Denial: 从 pid=20123 读取 com.android.providers.contacts.HtcContactsProvider2 uri content://com.android.contacts/data/phones,uid=10593 需要 android.permission.READ_CONTACTS , 或 grantUriPermission()
为什么会这样?
相关资料:Contact data leakage via pick activities
【问题讨论】:
请注意,您没有使用谷歌的 ContactsContract,如您所见,我们看到您正在访问 com.android.providers.contacts.HtcContractsProvider,可能 HTC 存在验证权限问题。我的建议是检查 AOSP 设备,看看是否同样如此。如果它不是真的,那么这意味着它是 HTC 内部的权限泄漏问题。如果它们相同,则听起来像是 AOSP 问题。 它也在 Nexus 上重现。 【参考方案1】:Android marshmallow 有新的权限系统。 您需要在运行时请求权限。 http://developer.android.com/training/permissions/requesting.html.
例子:
@Override
public void onClick(View v)
switch (v.getId())
case R.id.tv_contact:
askForContactPermission();
break;
private void getContact()
Intent intent = new Intent(Intent.ACTION_PICK, ContactsContract.Contacts.CONTENT_URI);
startActivityForResult(intent, PICK_CONTACT);
public void askForContactPermission()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
if (ContextCompat.checkSelfPermission(getActivity(),Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED)
// Should we show an explanation?
if (ActivityCompat.shouldShowRequestPermissionRationale(getActivity(),
Manifest.permission.READ_CONTACTS))
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setTitle("Contacts access needed");
builder.setPositiveButton(android.R.string.ok, null);
builder.setMessage("please confirm Contacts access");//TODO put real question
builder.setOnDismissListener(new DialogInterface.OnDismissListener()
@TargetApi(Build.VERSION_CODES.M)
@Override
public void onDismiss(DialogInterface dialog)
requestPermissions(
new String[]
Manifest.permission.READ_CONTACTS
, PERMISSION_REQUEST_CONTACT);
);
builder.show();
// Show an expanation to the user *asynchronously* -- don't block
// this thread waiting for the user's response! After the user
// sees the explanation, try again to request the permission.
else
// No explanation needed, we can request the permission.
ActivityCompat.requestPermissions(getActivity(),
new String[]Manifest.permission.READ_CONTACTS,
PERMISSION_REQUEST_CONTACT);
// MY_PERMISSIONS_REQUEST_READ_CONTACTS is an
// app-defined int constant. The callback method gets the
// result of the request.
else
getContact();
else
getContact();
@Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults)
switch (requestCode)
case PERMISSION_REQUEST_CONTACT:
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED)
getContact();
// permission was granted, yay! Do the
// contacts-related task you need to do.
else
ToastMaster.showMessage(getActivity(),"No permission for contacts");
// permission denied, boo! Disable the
// functionality that depends on this permission.
return;
// other 'case' lines to check for other
// permissions this app might request
【讨论】:
// Show an expanation ...
注释后面应该加一些代码吗?
我可以用 HTML5 和 javascript 做这个吗??【参考方案2】:
@Override
public void onClick(View v)
switch (v.getId())
case R.id.button:
askForContactPermission();
break;
private void getContact()
Cursor phones = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,null,null, null);
while (phones.moveToNext())
String name=phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
String phoneNumber = phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
Toast.makeText(getApplicationContext(),name+" "+phoneNumber, Toast.LENGTH_LONG).show();
phones.close();
public void askForContactPermission()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
if (ContextCompat.checkSelfPermission(this,Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED)
// Should we show an explanation?
if (ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.READ_CONTACTS))
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Contacts access needed");
builder.setPositiveButton(android.R.string.ok, null);
builder.setMessage("please confirm Contacts access");//TODO put real question
builder.setOnDismissListener(new DialogInterface.OnDismissListener()
@TargetApi(Build.VERSION_CODES.M)
@Override
public void onDismiss(DialogInterface dialog)
requestPermissions(
new String[]
Manifest.permission.READ_CONTACTS
, PERMISSION_REQUEST_CONTACT);
);
builder.show();
// Show an expanation to the user *asynchronously* -- don't block
// this thread waiting for the user's response! After the user
// sees the explanation, try again to request the permission.
else
// No explanation needed, we can request the permission.
ActivityCompat.requestPermissions(this,
new String[]Manifest.permission.READ_CONTACTS,
PERMISSION_REQUEST_CONTACT);
// MY_PERMISSIONS_REQUEST_READ_CONTACTS is an
// app-defined int constant. The callback method gets the
// result of the request.
else
getContact();
else
getContact();
@Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults)
switch (requestCode)
case PERMISSION_REQUEST_CONTACT:
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED)
getContact();
// permission was granted, yay! Do the
// contacts-related task you need to do.
else
Toast.makeText(this, "No Permissions ", Toast.LENGTH_SHORT).show();
// permission denied, boo! Disable the
// functionality that depends on this permission.
return;
// other 'case' lines to check for other
// permissions this app might request
【讨论】:
总是去 "Toast.makeText(this, "No Permissions ", Toast.LENGTH_SHORT).show();"并且不要询问权限弹出窗口 我可以用 HTML5 和 javascript 做这个吗??以上是关于Android 6.0 (Marshmallow) READ_CONTACTS 权限允许在权限被拒绝时读取联系人的姓名的主要内容,如果未能解决你的问题,请参考以下文章
Android 6.0 (MarshMallow) 上的 HttpURLConnnection 请求失败
如何在 Android 6.0 Marshmallow 中访问相机?
如何以编程方式打开 Android 6.0 (Marshmallow) 上特定应用的权限屏幕?
Android 6.0 Marshmallow BLE 连接问题