The coarse and fine location are considered dangerous permissions. These permissions have to be explicitly requested on Android 6 and up. Here's one way to go about it:
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
){//Can add more as per requirement
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION,Manifest.permission.ACCESS_COARSE_LOCATION},
123);
}
}
And for calling:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
checkPermission();
}
You can implement it anywhere. You can request it on the first launch, or whenever they're needed.
Nonetheless, always remember to check whether you have the permission before using it. The permission can be revoked at runtime as well, which would bypass any checks you have on startup.
Here's one way to do it:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
/*
This is called before initializing the map because the map needs permissions(the cause of the crash)
*/
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.M ) {
checkPermission();
}
// Re-check before enabling. You can add an else statement to warn the user about the lack of functionality if it's disabled.
// "or" is used instead of "and" as per the error. If it requires both, flip it over to &&. (I'm not sure, I haven't used GPS stuff before)
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED ||
ContextCompat.checkSelfPermission(this,Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED){
/*
* Create a new location client, using the enclosing class to handle
* callbacks.
*/
mLocationClient = new LocationClient(this, this, this);
// Create the LocationRequest object
mLocationRequest = LocationRequest.create();
// Use high accuracy
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
// Set the update interval to 5 seconds
mLocationRequest.setInterval(UPDATE_INTERVAL);
// Set the fastest update interval to 1 second
mLocationRequest.setFastestInterval(FASTEST_INTERVAL);
}
setContentView(R.layout.activity_main);
.
.
.
This is the way I recommend doing it. There are other ways to deal with permissions, but no matter what you pick, do make sure you check whether you have the permission before accessing an API dependent on dangerous permissions. The permissions can be withdrawn at runtime without triggering the destroy lifecycle events, and therefore bypass any checks you have on startup to make sure you have the permissions. Because of that, checking before you use APIs is extremely important.
There's also other ways to implement permission requesting. If you're looking for alternatives to this super basic startup check, here's some ideas:
- If you have a setup activity, add permission requesting to it.
- Don't request permissions at startup, but rather whenever they're needed
- Add a permission requesting activity to your startup flow, if the permission checks fail on startup
There's also more ways to go about this than I know if. I haven't touched Android in a couple years, and I'm far from familiar with all the ways to request permissions. See also the documentation for potentially more up to date advice.