【问题标题】:App crashes on disabling location permission from settings应用程序在从设置中禁用位置权限时崩溃
【发布时间】:2018-02-01 11:04:16
【问题描述】:

我有一个在后台持续运行以获取位置更新的服务类。一切都按预期工作,但是当我从设置中禁用权限时,应用程序崩溃。当我从设置中禁用位置权限时,我无法弄清楚为什么应用程序崩溃了。以下是我在 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();
    }
}

}

【问题讨论】:

  • 运行时在哪里查看位置权限?
  • 在启动定位服务之前,您应该检查您是否有定位权限
  • 权限检查未完成
  • 在声明后台服务之前,我正在我的主要活动类中检查位置权限。

标签: android geolocation location android-permissions


【解决方案1】:

您收到关于位置访问权限被用户拒绝的错误,您需要检查使用 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

【讨论】:

    【解决方案2】:

    您必须为 6 岁以上添加 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();
    }
    

    希望对你有帮助!

    【讨论】:

    • 我正在我的 MainActivity 中检查位置权限。
    • 在这种情况下,如果权限被用户撤销,您的进程将被终止,这取决于该关键权限。如果您正在处理活动,您应该去 onResume(),在那里您可以使用checkSelfPermission() 或调用上述方法检查权限。
    【解决方案3】:

    它需要这些权限,你删除它们,所以当它试图获取位置时它会崩溃。

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

    【讨论】:

      【解决方案4】:

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

      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;
          }
      }
      

      【讨论】:

        【解决方案5】:

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

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

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

        您不能向用户请求服务的许可

        但您可以致电checkSelfPermission()查看

        为了让它更好,你应该在 Activity/Fragment 类中检查并请求权限,然后手动启动服务。

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

        您已在一项活动中检查了权限:

        所以,现在使用 checkSelfPermission() 来检查用户是否授予权限。如果没有,则显示Notification with PendingIntent 添加一些标志。开启Activity请求权限,然后启动服务,

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

        【讨论】:

        • 我必须在哪里检查权限?在我访问 locationServer 的服务类中,我添加了 try/catch 以避免崩溃。但仍然崩溃。我认为服务类没有问题。
        • 根据您当前的代码,它将在服务的 onCreate() 内部,如果授予权限,它将运行整个 try-catch 块
        • 如果您检查我上面的服务类代码。我在 onCreate() 中使用了 try/catch。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2022-11-28
        • 1970-01-01
        • 2019-06-25
        • 2018-09-02
        • 2018-06-05
        • 1970-01-01
        • 2017-06-23
        相关资源
        最近更新 更多