ACCESS_FINE_LOCATION SecurityException尽管指定了清单文件中的权限

时间:2015-10-29 05:44:10

标签: android permissions android-6.0-marshmallow

我的应用正在尝试访问设备的位置,我在AndroidManifest.xml中包含以下内容:

<manifest 
    xmlns:android="http://schemas.android.com/apk/res/android" 
    package="com.app">
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

    <application>
        <meta-data android:name="com.google.android.gms.version" />
    </application>

</manifest>

我已按如下方式实施GoogleApiClient.ConnectionCallbacks以访问位置服务:

public class BackgroundLocationService implements
        GoogleApiClient.ConnectionCallbacks,
        GoogleApiClient.OnConnectionFailedListener {

    private static final String TAG = BackgroundLocationService.class.getSimpleName();

    private static GoogleApiClient googleApiClient;
    private static PendingIntent locationCallback;

    public static int LOCATION_INTERVAL = 10000;
    public static int FAST_INTERVAL = 5000;

    @Override
    public void onConnected(Bundle bundle) {
        Log.i(TAG, "Connected to Google API");

        LocationRequest request = new LocationRequest();
        request.setInterval(LOCATION_INTERVAL);
        request.setFastestInterval(FAST_INTERVAL);
        request.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);

        LocationServices.FusedLocationApi.requestLocationUpdates(googleApiClient, request, locationCallback);
    }

    @Override
    public void onConnectionSuspended(int i) {
        Log.i(TAG, Integer.toString(i));
    }

    @Override
    public void onConnectionFailed(ConnectionResult connectionResult) {
        Log.i(TAG, connectionResult.toString());
    }
}

当我触发位置服务调用时,抛出以下异常:

java.lang.SecurityException: Client must have ACCESS_FINE_LOCATION permission to request PRIORITY_HIGH_ACCURACY locations.
    at android.os.Parcel.readException(Parcel.java:1599)
    at android.os.Parcel.readException(Parcel.java:1552)
    at com.google.android.gms.location.internal.zzi$zza$zza.zza(Unknown Source)
    at com.google.android.gms.location.internal.zzk.zza(Unknown Source)
    at com.google.android.gms.location.internal.zzl.zza(Unknown Source)
    at com.google.android.gms.location.internal.zzd$7.zza(Unknown Source)
    at com.google.android.gms.location.internal.zzd$7.zza(Unknown Source)
    at com.google.android.gms.internal.zzlb$zza.zzb(Unknown Source)
    at com.google.android.gms.internal.zzlf.zza(Unknown Source)
    at com.google.android.gms.internal.zzlf.zzb(Unknown Source)
    at com.google.android.gms.internal.zzli.zzb(Unknown Source)
    at com.google.android.gms.location.internal.zzd.requestLocationUpdates(Unknown Source)
    at com.localz.spotzpush.sdk.service.BackgroundLocationService.onConnected(BackgroundLocationService.java:45)
    at com.google.android.gms.common.internal.zzk.zzh(Unknown Source)
    at com.google.android.gms.internal.zzlg.zznU(Unknown Source)
    at com.google.android.gms.internal.zzlg.onConnected(Unknown Source)
    at com.google.android.gms.internal.zzli$2.onConnected(Unknown Source)
    at com.google.android.gms.common.internal.zzj$zzg.zzpf(Unknown Source)
    at com.google.android.gms.common.internal.zzj$zza.zzc(Unknown Source)
    at com.google.android.gms.common.internal.zzj$zza.zzt(Unknown Source)
    at com.google.android.gms.common.internal.zzj$zzc.zzph(Unknown Source)
    at com.google.android.gms.common.internal.zzj$zzb.handleMessage(Unknown Source)
    at android.os.Handler.dispatchMessage(Handler.java:102)
    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)

我正在使用一个实际的设备来解决这个问题,并且一直在讨论抛出异常的原因。

4 个答案:

答案 0 :(得分:16)

问题是由Android 6.0的新功能引起的。

从Android 6.0(API级别23)开始,用户在应用运行时向应用授予权限,而不是在安装应用时授予权限。

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

为了解决未明确授予权限的问题,我已经设置了一个检查以包装位置服务调用(根据Google文档,略有修改)。

int permissionCheck = ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION);

if (permissionCheck == PackageManager.PERMISSION_GRANTED) {
    //Execute location service call if user has explicitly granted ACCESS_FINE_LOCATION..
}

Google文档还会逐步介绍如何请求所需的权限。

2016年10月12日更新

添加@ Siddharth的更新,为checkSelfPermission()

添加更有帮助的答案
//For this example, run the check onResume()
@Override
public void onResume() {

    if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
                != PackageManager.PERMISSION_GRANTED) {

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

            // 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.
            // PERMISSION_REQUEST_ACCESS_FINE_LOCATION can be any unique int
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, PERMISSION_REQUEST_ACCESS_FINE_LOCATION);
        }
    }
}

@Override
public void onRequestPermissionsResult(int requestCode,
                                       String permissions[], int[] grantResults) {
    switch (requestCode) {
        case PERMISSION_REQUEST_ACCESS_FINE_LOCATION: {
            // If request is cancelled, the result arrays are empty.
            if (grantResults.length > 0
                    && grantResults[0] == PackageManager.PERMISSION_GRANTED) {

                // permission was granted, yay! Do the
                // contacts-related task you need to do.

            } else {

                // permission denied, boo! Disable the
                // functionality that depends on this permission.
            }
            return;
        }

        // other 'case' lines to check for other
        // permissions this app might request
    }
}

答案 1 :(得分:2)

从Google文档中提取。似乎此线程上最常被接受的答案是缺少有关异步checkSelfPermission回调的一些重要信息。

请确认。如果没有,我会删除这个答案。

// Here, thisActivity is the current 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.
    }
}

@Override
public void onRequestPermissionsResult(int requestCode,
        String permissions[], int[] grantResults) {
    switch (requestCode) {
        case MY_PERMISSIONS_REQUEST_READ_CONTACTS: {
            // If request is cancelled, the result arrays are empty.
            if (grantResults.length > 0
                && grantResults[0] == PackageManager.PERMISSION_GRANTED) {

                // permission was granted, yay! Do the
                // contacts-related task you need to do.

            } else {

                // permission denied, boo! Disable the
                // functionality that depends on this permission.
            }
            return;
        }

        // other 'case' lines to check for other
        // permissions this app might request
    }
}

答案 2 :(得分:0)

LocationSource的默认建议并不一定要使用GPS来返回准确的位置。

如果我删除了清单文件中的权限"ACCESS_FINE_LOCATION",我会在尝试显示地图时立即崩溃

这是因为默认实现使用LocationClient LocationRequest.PRIORITY_HIGH_ACCURACY

当您仅请求GoogleMap.setMyLocationEnabled权限时,

ACCESS_COARSE_LOCATION,但切换为LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY

请参阅此Android: Google Maps location with low battery usage

答案 3 :(得分:0)

对于其他人在Manifest.permission.ACCESS_FINE_LOCATION错误中回答gyamana的错误。确保使用的是android.Manifest而不是my.app.package.Manifest。