尝试从Android联系人URI读取时出现java.lang.SecurityException

9

我正在尝试从ContactsContract URI读取联系人姓名、电话号码和电子邮件地址,但是当我尝试运行程序时却出现了SecurityException。我已经在AndroidManifest.xml文件中设置了权限:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="edu.smumn.cs394"
      android:versionCode="1"
      android:versionName="1.0">
    <uses-sdk android:minSdkVersion="8" />
    **<uses-permission android:name="android.pemission.READ_CONTACTS"/>**
    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <activity android:name=".ReadPhoneNumbers"
                  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>`

以下是应用程序代码:
 @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.contact_list);       
        ContentResolver resolver = getContentResolver();
        Cursor c = resolver.query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null);
 //[...] Work through data here`

在最后一行(resolver.query())出现了安全异常:

`03-08 07:41:40.812: ERROR/AndroidRuntime(416): FATAL EXCEPTION: main
03-08 07:41:40.812: ERROR/AndroidRuntime(416): java.lang.RuntimeException: Unable to start activity ComponentInfo{edu.smumn.cs394/edu.smumn.cs394.ReadPhoneNumbers}: java.lang.SecurityException: Permission Denial: reading com.android.providers.contacts.ContactsProvider2 uri content://com.android.contacts/contacts from pid=416, uid=10037 requires android.permission.READ_CONTACTS
[...]
03-08 07:41:40.812: ERROR/AndroidRuntime(416): Caused by: java.lang.SecurityException: Permission Denial: reading com.android.providers.contacts.ContactsProvider2 uri content://com.android.contacts/contacts from pid=416, uid=10037 requires android.permission.READ_CONTACTS
[...]
03-08 07:41:40.812: ERROR/AndroidRuntime(416):     at edu.smumn.cs394.ReadPhoneNumbers.onCreate(ReadPhoneNumbers.java:30)

我肯定是漏掉了什么,但我还没搞清楚是什么。


你的 AndroidManifest.xml 文件中有一个语法错误。在第 <uses-permission android:name="android.pemission.READ_CONTACTS"/> 行中,android.permission 的拼写错误,没有 R,应该是 "permission" 而不是 "pemission"。 - technik
5个回答

17

在运行时请求权限

从Android 6.0(API级别 23)开始,用户授权应用程序的权限是应用程序运行时而不是安装应用程序时完成。

如果您需要添加的权限未列在常规权限下,则需要处理“运行时权限”。 运行时权限是在应用程序运行时根据需要请求的权限。 这些权限将向用户显示对话框,类似于以下对话框:

enter image description here

添加“运行时权限”的第一步是将其添加到AndroidManifest中:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.codepath.androidpermissionsdemo" >

    <uses-permission android:name="android.permission.READ_CONTACTS" />
    ...
</manifest>

接下来,您需要启动权限请求并处理结果。以下代码展示了如何在 Activity 上下文中执行此操作,但从 Fragment 中也可以执行。

// MainActivity.java
public class MainActivity extends AppCompatActivity {

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

        // In an actual app, you'd want to request a permission when the user performs an action
        // that requires that permission.
        getPermissionToReadUserContacts();
    }

    // Identifier for the permission request
    private static final int READ_CONTACTS_PERMISSIONS_REQUEST = 1;

    // Called when the user is performing an action which requires the app to read the
    // user's contacts
    public void getPermissionToReadUserContacts() {
        // 1) Use the support library version ContextCompat.checkSelfPermission(...) to avoid
        // checking the build version since Context.checkSelfPermission(...) is only available
        // in Marshmallow
        // 2) Always check for permission (even if permission has already been granted)
        // since the user can revoke permissions at any time through Settings
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS)
                != PackageManager.PERMISSION_GRANTED) {

            // The permission is NOT already granted.
            // Check if the user has been asked about this permission already and denied
            // it. If so, we want to give more explanation about why the permission is needed.
            if (shouldShowRequestPermissionRationale(
                    Manifest.permission.READ_CONTACTS)) {
                // Show our own UI to explain to the user why we need to read the contacts
                // before actually requesting the permission and showing the default UI
            }

            // Fire off an async request to actually get the permission
            // This will show the standard permission request dialog UI
            requestPermissions(new String[]{Manifest.permission.READ_CONTACTS},
                    READ_CONTACTS_PERMISSIONS_REQUEST);
        }
    }

    // Callback with the request from calling requestPermissions(...)
    @Override
    public void onRequestPermissionsResult(int requestCode,
                                           @NonNull String permissions[],
                                           @NonNull int[] grantResults) {
        // Make sure it's our original READ_CONTACTS request
        if (requestCode == READ_CONTACTS_PERMISSIONS_REQUEST) {
            if (grantResults.length == 1 &&
                    grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                Toast.makeText(this, "Read Contacts permission granted", Toast.LENGTH_SHORT).show();
            } else {
                Toast.makeText(this, "Read Contacts permission denied", Toast.LENGTH_SHORT).show();
            }
        } else {
            super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        }
    }
}

9
请确保将它添加到应用标签之外。在Ubuntu上使用Eclipse开发针对2.3.3目标平台时,日志文件中出现的权限失败提示表明我需要这行代码来处理类似的问题。直到我将*uses-permission...READ_CONTACTS*移到应用标签之外,才让事情开始正常运作。

+1:我在Windows 7系统上(针对API v10到v19)也遇到了这种情况。我使用GUI添加了权限,并将其应用于<application>标签内。我将其替换为<uses-permission>标签。 - Dexter

6

你好,Steven。调试日志跟踪告诉你需要 android.permission.READ_CONTACTS 权限。

所以,尝试编辑 Manifest.xml 文件并添加另一个权限,看看是否能正确读取。

同时,请检查这行代码是否有问题:**

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

dan


5
使用API 23时,权限<uses-permission android:name="android.permission.READ_CONTACTS"/>不起作用,请将模拟器的API级别更改为API 22(棒棒糖)或更低版本。

3
那么什么是替代方案? - NicoJuicy
5
降级API不应该是解决方案!! - Shumin
另一种选择是按照文档中所示,为API 23+编写明确的请求权限代码。为了避免做这么繁琐的工作,我还不得不将我的SDK的目标版本降级到22。 - zozelfelfo
我虽然使用的是API 22,但仍然遇到了相同的问题。请问有解决方案吗? - JPerk

2
如果设备运行的是Android 6.0或更高版本,且您的应用程序的目标SDK为23或更高版本:应用程序必须在清单中列出需要的权限,并在应用程序运行时请求每个危险权限。用户可以授予或拒绝每个权限,即使用户拒绝权限请求,应用程序仍然可以继续以有限的功能运行。
示例:
 //thisActivity is the running activity


if (ContextCompat.checkSelfPermission(thisActivity,
                Manifest.permission.READ_CONTACTS)
                != PackageManager.PERMISSION_GRANTED) {

            // Should we show an explanation?
            if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity,
                    Manifest.permission.READ_CONTACTS)) {

                // 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(thisActivity,
                        new String[]{Manifest.permission.READ_CONTACTS},
                        MY_PERMISSIONS_REQUEST_READ_CONTACTS);

                // MY_PERMISSIONS_REQUEST_READ_CONTACTS is an
                // app-defined int constant. The callback method gets the
                // result of the request.
            }
        }

http://developer.android.com/training/permissions/requesting.html


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接