Android Location runtime permissions

2019-08-22 09:54发布

问题:

I know that this type of questions occurs very often on stack overflow. I have looked at many posts with similar questions, read the official documentation but finally I anyway cannot understand how do the runtime permissions work in android.

Firstly I get the following error:

Call requires permissions which may be rejected by user

When I generate the code that Android Studio suggests, I get this:

    if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
        // TODO: Consider calling
        //    ActivityCompat#requestPermissions
        // here to request the missing permissions, and then overriding
        //   public void onRequestPermissionsResult(int requestCode, String[] permissions,
        //                                          int[] grantResults)
        // to handle the case where the user grants the permission. See the documentation
        // for ActivityCompat#requestPermissions for more details.
        return;
    }

My first question is: if I want to use only fine location, do I have anyway to check the Coarse Location permissions also?

What should I do next? What should I include in the brackets of the generated code? How and where do I request the permissions?

Here is the part of my code where I must include permissions (the mLastLocation line):

    private void displayLocation() {

    mLastLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);

    if (mLastLocation != null) {
        double latitude = mLastLocation.getLatitude();
        double longitude = mLastLocation.getLongitude();

        lblLocation.setText(latitude + ", " + longitude);

    } else {

        lblLocation.setText("(Couldn't get the location. Make sure location is enabled on the device)");
    }
}

Permission defined in AndroidManifest:

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

Thank you very much!

回答1:

Fine Location :

The Fine location provides better and accurate locations.It gives permission for using both GPS_PROVIDER and NETWORK_PROVIDER

Coarse Location :

The Coarse location provides less accurate locations.It gives permission for using both NETWORK_PROVIDER only for determining the position.

Context:

Context allows access to application-specific resources and classes, as well as up-calls for application-level operations such as launching activities, broadcasting and receiving intents, etc.

You can Enable Permission Using the below class

UtilityLocation.Java

public class UtilityLocation {
    public static final int MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE = 123;

    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
    public static boolean checkPermission(final Context context)
    {
        int currentAPIVersion = Build.VERSION.SDK_INT;
        if(currentAPIVersion>= Build.VERSION_CODES.M)
        {
            if (ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
                if (ActivityCompat.shouldShowRequestPermissionRationale((Activity) context, Manifest.permission.ACCESS_FINE_LOCATION)) {
                    AlertDialog.Builder alertBuilder = new AlertDialog.Builder(context);
                    alertBuilder.setCancelable(true);
                    alertBuilder.setTitle("Permission necessary");
                    alertBuilder.setMessage("Camera permission is necessary");
                    alertBuilder.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
                        @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
                        public void onClick(DialogInterface dialog, int which) {
                            ActivityCompat.requestPermissions((Activity) context, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE);
                        }
                    });
                    AlertDialog alert = alertBuilder.create();
                    alert.show();

                } else {
                    ActivityCompat.requestPermissions((Activity) context, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE);
                }
                return false;
            } else {
                return true;
            }
        } else {
            return true;
        }
    }
}

MainActivity.Java

Check whether Permission is Enabled or Not

Private Context mContext;
mContext=MainActivty.this;

    if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                // only for gingerbread and newer versions
                boolean resultLocation = UtilityLocation.checkPermission(mContext);
                if (resultLocation) {
       //Allow Permission and Call your Location Activity.
             }
            } else {
      //Call your Location Activity
          }
        }


回答2:

if I want to use only fine location, do I have anyway to check the Coarse Location permissions also?

No. Please understand that IDE quick-fixes are templates without a lot of smarts.

What should I include in the brackets of the generated code? How and where do I request the permissions?

Well, that is explained in the generated code comment. In that block, call ActivityCompat.requestPermissions() to request your permission(s). You will then get called in onRequestPermissionsResult() after the user has granted or denied the permission(s).

Then, you would call your displayLocation() method in two places:

  • An else block of the if that was code-generated for you

  • In onRequestPermissionsResult(), if the user granted the permission

This sample app demonstrates requesting permissions and handling Play Services integration as part of finding the device's location.

Also, with regards to your displayLocation() method, do not assume that getLastLocation() will always return a location. Even though the providers may be enabled, the device may not be presently tracking its location.