繁体   English   中英

应用程序因禁用设置的位置信息权限而崩溃

[英]App crashes on disabling location permission from settings

我有一个在后台连续运行以获取位置更新的服务类。 一切正常,但是当我从设置中禁用权限时,应用程序崩溃。 从设置中禁用位置权限后,我无法弄清楚为什么应用程序崩溃。 以下是我在logcat中获得的内容。

FATAL EXCEPTION: GoogleApiHandler
                 Process: com.android.myapp, PID: 7703
                 java.lang.SecurityException: Client must have ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission to perform any location operations.
                 at android.os.Parcel.readException(Parcel.java:1683)
                 at android.os.Parcel.readException(Parcel.java:1636)
                 at com.google.android.gms.internal.zzeu.zza(Unknown Source)
                 at com.google.android.gms.internal.zzcfa.zzif(Unknown Source)
                 at com.google.android.gms.internal.zzcfd.getLastLocation(Unknown Source)
                 at com.google.android.gms.internal.zzcfk.getLastLocation(Unknown Source)
                 at com.google.android.gms.location.zzg.zza(Unknown Source)
                 at com.google.android.gms.common.api.internal.zze.zza(Unknown Source)
                 at com.google.android.gms.common.api.internal.zzbo.zzb(Unknown Source)
                 at com.google.android.gms.common.api.internal.zzbo.zzaiw(Unknown Source)
                 at com.google.android.gms.common.api.internal.zzbo.onConnected(Unknown Source)
                 at com.google.android.gms.common.internal.zzac.onConnected(Unknown Source)
                 at com.google.android.gms.common.internal.zzn.zzakr(Unknown Source)
                 at com.google.android.gms.common.internal.zze.zzw(Unknown Source)
                 at com.google.android.gms.common.internal.zzi.zzaks(Unknown Source)
                 at com.google.android.gms.common.internal.zzh.handleMessage(Unknown Source)
                 at android.os.Handler.dispatchMessage(Handler.java:102)
                 at android.os.Looper.loop(Looper.java:154)
                 at android.os.HandlerThread.run(HandlerThread.java:61)

这是我的服务班级。 它始终在后台运行。

public class LocationService extends Service {


    ...
    ...
    ...

    @Override
    public void onCreate() {
        try {
            mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);

            mLocationCallback = new LocationCallback() {
                @Override
                public void onLocationResult(LocationResult locationResult) {
                    super.onLocationResult(locationResult);
                    onNewLocation(locationResult.getLastLocation());
                }
            };

            createLocationRequest();
            getLastLocation();
            requestLocationUpdates();
        }catch(Exception e){
            e.printStackTrace();
        }

    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i(TAG, "Service started");

        return START_STICKY;
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
    }


    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }


    @Override
    public void onDestroy() {
        Log.i(TAG, "Service destroy");
        Toast.makeText(getApplicationContext(), "Service Destroy", Toast.LENGTH_SHORT).show();
    }

    /**
     * Makes a request for location updates. Note that in this sample we merely log the
     * {@link SecurityException}.
     */
    public void requestLocationUpdates() {
        Log.i(TAG, "Requesting location updates");
        Utils.setRequestingLocationUpdates(this, true);
        try {

          mFusedLocationClient.requestLocationUpdates(mLocationRequest,
                mLocationCallback, Looper.myLooper());
        } catch (SecurityException unlikely) {
            Utils.setRequestingLocationUpdates(this, false);
            Log.e(TAG, "Lost location permission. Could not request updates. " + unlikely);
        }
    }

    /**
     * Removes location updates. Note that in this sample we merely log the
     * {@link SecurityException}.
     */
    public void removeLocationUpdates() {
        Log.i(TAG, "Removing location updates");
        try {

   mFusedLocationClient.removeLocationUpdates(mLocationCallback);
            Utils.setRequestingLocationUpdates(this, false);
            stopSelf();
        } catch (SecurityException unlikely) {
            Utils.setRequestingLocationUpdates(this, true);
            Log.e(TAG, "Lost location permission. Could not remove updates. " + unlikely);
        }
    }

    private void getLastLocation() {
        try {
            mFusedLocationClient.getLastLocation()
                .addOnCompleteListener(task -> {
                        if (task.isSuccessful() && task.getResult() != null) {
                            mLocation = task.getResult();
                        } else {
                            Log.w(TAG, "Failed to get location.");
                        }
                    });
        } catch (SecurityException unlikely) {
            Log.e(TAG, "Lost location permission." + unlikely);
        }
    }

    private void onNewLocation(Location location) {
        Log.i(TAG, "New location: " + location);

        mLocation = location;
        // Doing some operations using location data.
        mPreviousLocation = mLocation;
        System.gc();

    }

    /**
     * Sets the location request parameters.
     */
    private void createLocationRequest() {
        mLocationRequest = new LocationRequest();
        mLocationRequest.setInterval(UPDATE_INTERVAL_IN_MILLISECONDS);
        mLocationRequest
         .setFastestInterval(FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS);
        mLocationRequest
        .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
    }

    @Override
    public void onTaskRemoved(Intent rootIntent) {
        Log.i(TAG, "Service Task Removed");
        Toast.makeText(getApplicationContext(), "Service Task Removed", Toast.LENGTH_SHORT).show();
        startService(new Intent(getApplicationContext(), LocationService.class));
        super.onTaskRemoved(rootIntent);
    }
}

我正在活动类中检查位置权限,并在用户接受权限后启动服务。 这样做没有问题,我什至可以从后台服务获取位置更新。 同时,当我尝试从设置中禁用权限时,应用崩溃。 这是我的MainActivity类,用于检查位置权限。

public class MainActivity extends AppCompatActivity{


@Override
protected void onResume() {
    super.onResume();
    checkAndEnableGps();
}

private void checkAndEnableGps() {
    try {
        new RxPermissions(this)
                .request(Manifest.permission.ACCESS_FINE_LOCATION)
                .subscribe(granted -> {
                    if (granted) {
                        if (!Utils.isServiceRunning(this, LocationService.class)) {
                            startService(new Intent(this, LocationService.class));
                        }
                        showSettingDialog();
                    } 
                });

    }catch (Exception e){
        e.printStackTrace();
    }
}

}

您收到有关用户拒绝的位置访问权限的错误,并且需要检查使用checkSelfPermission(context,Permission)方法授予的权限,这将返回权限授予状态,然后您可以请求用户进行权限访问。

if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
                == PackageManager.PERMISSION_GRANTED) {
    mMap.setMyLocationEnabled(true);
} else {
    // Show rationale and request permission.
}

然后,从您请求权限的上下文中使用“ onRequestPermissionsResult”回调,如果授予了权限,则启动位置服务。

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    if (requestCode == MY_LOCATION_REQUEST_CODE) {
      if (permissions.length == 1 &&
          permissions[0] == Manifest.permission.ACCESS_FINE_LOCATION &&
          grantResults[0] == PackageManager.PERMISSION_GRANTED) {
        mMap.setMyLocationEnabled(true);
    } else {
      // Permission was denied. Display an error message.
    }
}

请参阅https://developers.google.com/maps/documentation/android-api/location以获取文档。

您必须添加6 checkpermission以上的Checkpermission,例如棉花糖,如下所示,

public void checkPermission()
{
    if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED ||
                   ContextCompat.checkSelfPermission(this,Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED)
    {

            ActivityCompat.requestPermissions(this,
                    new String[]{Manifest.permission.ACCESS_FINE_LOCATION,Manifest.permission.ACCESS_COARSE_LOCATION},
                    123);
    }
}

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ) {
    checkPermission();
}

希望能帮助到你!

它需要这些权限,将其删除,因此当它尝试获取位置时会崩溃。

使用catch语句来处理异常,或者检查您是否具有权限,并在实际尝试获取位置之前先请求运行时

在运行服务之前,只需检查您是否有权限。

mContext.checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION ) == PackageManager.PERMISSION_GRANTED;

如果没有权限,则可以从FragmentActivity进行请求。

requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION }, 200 /*request code*/);

您可以在FragmentActivity类中获得用户响应,即PERMISSION_GRANTED

@Override
public void onRequestPermissionsResult(int permsRequestCode, @NonNull String[] permissions, @NonNull int[] grantResults){

    switch(permsRequestCode){

        case 200:    // notice the request code is the same as requested.

            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {

                startService();
            }
            else {
                // don't start service.
            }

            break;
    }
}

发生这种情况是因为自API版本6.0起,您需要在运行时检查权限。 并且,如果未授予权限,则您的应用应在执行与权限相关的任务之前要求授予权限。

在这里,访问用户位置所需的权限是ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION 因此,您需要检查是否授予用户授予的位置权限。

还有一件事,您正在位置服务类中。 这是一个问题-

您不能要求用户获得服务许可

但您可以通过调用checkSelfPermission()检查

为了使其更加美观,您应该在Activity / Fragment类中检查并请求权限,然后手动启动Service。

另一方面,您可以检查服务中的权限,如果未被用户接受,则显示通知,授予权限,然后启动服务。

您已在活动中检查权限:

因此,现在使用checkSelfPermission()来检查用户是否授予了权限。 如果没有,则显示带有PendingIntent的Notification并添加一些标志。 打开活动请求许可,然后通过以下方式启动服务:

startService(new Intent(YourActivity.this, YourService.class));

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM