打开位置服务而不导航到设置页面

与传统的提示用户进入设置页面并启用位置服务然后再次返回的方法不同,我注意到在一些最新的应用程序中有一种更简单的方法来做同样的事情。

参考下面的截图,它提示一个对话框给用户启用位置服务,只需点击一下,它就可以在这些应用程序中工作。

我怎样才能达到同样的效果呢?

enter image description here

104810 次浏览

Android M 6支持运行时权限。运行时权限只能在棉花糖上工作,在棉花糖之前它仍然按照旧的方式工作。

你可以在 Android 开发者官方视频中了解更多:

Https://www.youtube.com/watch?v=c8ludpvszdk

请求许可: http://developer.android.com/training/permissions/requesting.html

此对话框由可在 Google Play Services 中获得的 位置设置请求。生成器创建。

你需要给你的应用程序 build.gradle添加一个依赖项:

compile 'com.google.android.gms:play-services-location:10.0.1'

然后你可以用这个最小的例子:

private void displayLocationSettingsRequest(Context context) {
GoogleApiClient googleApiClient = new GoogleApiClient.Builder(context)
.addApi(LocationServices.API).build();
googleApiClient.connect();


LocationRequest locationRequest = LocationRequest.create();
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
locationRequest.setInterval(10000);
locationRequest.setFastestInterval(10000 / 2);


LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder().addLocationRequest(locationRequest);
builder.setAlwaysShow(true);


PendingResult<LocationSettingsResult> result = LocationServices.SettingsApi.checkLocationSettings(googleApiClient, builder.build());
result.setResultCallback(new ResultCallback<LocationSettingsResult>() {
@Override
public void onResult(LocationSettingsResult result) {
final Status status = result.getStatus();
switch (status.getStatusCode()) {
case LocationSettingsStatusCodes.SUCCESS:
Log.i(TAG, "All location settings are satisfied.");
break;
case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
Log.i(TAG, "Location settings are not satisfied. Show the user a dialog to upgrade location settings ");


try {
// Show the dialog by calling startResolutionForResult(), and check the result
// in onActivityResult().
status.startResolutionForResult(MainActivity.this, REQUEST_CHECK_SETTINGS);
} catch (IntentSender.SendIntentException e) {
Log.i(TAG, "PendingIntent unable to execute request.");
}
break;
case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
Log.i(TAG, "Location settings are inadequate, and cannot be fixed here. Dialog not created.");
break;
}
}
});
}

您可以找到完整的示例 给你

谢谢 Mattia Maestrini 的回答,我想用

compile 'com.google.android.gms:play-services-location:8.1.0'

这样可以防止你的应用程序包含不必要的库,并有助于保持你的方法计数低。

它的工作方式类似于谷歌地图

在 build.gradle 文件 中添加依赖项

compile 'com.google.android.gms:play-services:8.3.0'

这个或那个

compile 'com.google.android.gms:play-services-location:10.0.1'

enter image description here

import android.content.Context;
import android.content.IntentSender;
import android.location.LocationManager;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;


import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.PendingResult;
import com.google.android.gms.common.api.ResultCallback;
import com.google.android.gms.common.api.Status;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.location.LocationSettingsRequest;
import com.google.android.gms.location.LocationSettingsResult;
import com.google.android.gms.location.LocationSettingsStatusCodes;


import java.util.List;


public class LocationOnOff_Similar_To_Google_Maps extends AppCompatActivity {


protected static final String TAG = "LocationOnOff";


private GoogleApiClient googleApiClient;
final static int REQUEST_LOCATION = 199;


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);


this.setFinishOnTouchOutside(true);


// Todo Location Already on  ... start
final LocationManager manager = (LocationManager) LocationOnOff_Similar_To_Google_Maps.this.getSystemService(Context.LOCATION_SERVICE);
if (manager.isProviderEnabled(LocationManager.GPS_PROVIDER) && hasGPSDevice(LocationOnOff_Similar_To_Google_Maps.this)) {
Toast.makeText(LocationOnOff_Similar_To_Google_Maps.this,"Gps already enabled",Toast.LENGTH_SHORT).show();
finish();
}
// Todo Location Already on  ... end


if(!hasGPSDevice(LocationOnOff_Similar_To_Google_Maps.this)){
Toast.makeText(LocationOnOff_Similar_To_Google_Maps.this,"Gps not Supported",Toast.LENGTH_SHORT).show();
}


if (!manager.isProviderEnabled(LocationManager.GPS_PROVIDER) && hasGPSDevice(LocationOnOff_Similar_To_Google_Maps.this)) {
Log.e("keshav","Gps already enabled");
Toast.makeText(LocationOnOff_Similar_To_Google_Maps.this,"Gps not enabled",Toast.LENGTH_SHORT).show();
enableLoc();
}else{
Log.e("keshav","Gps already enabled");
Toast.makeText(LocationOnOff_Similar_To_Google_Maps.this,"Gps already enabled",Toast.LENGTH_SHORT).show();
}
}




private boolean hasGPSDevice(Context context) {
final LocationManager mgr = (LocationManager) context
.getSystemService(Context.LOCATION_SERVICE);
if (mgr == null)
return false;
final List<String> providers = mgr.getAllProviders();
if (providers == null)
return false;
return providers.contains(LocationManager.GPS_PROVIDER);
}


private void enableLoc() {


if (googleApiClient == null) {
googleApiClient = new GoogleApiClient.Builder(LocationOnOff_Similar_To_Google_Maps.this)
.addApi(LocationServices.API)
.addConnectionCallbacks(new GoogleApiClient.ConnectionCallbacks() {
@Override
public void onConnected(Bundle bundle) {


}


@Override
public void onConnectionSuspended(int i) {
googleApiClient.connect();
}
})
.addOnConnectionFailedListener(new GoogleApiClient.OnConnectionFailedListener() {
@Override
public void onConnectionFailed(ConnectionResult connectionResult) {


Log.d("Location error","Location error " + connectionResult.getErrorCode());
}
}).build();
googleApiClient.connect();


LocationRequest locationRequest = LocationRequest.create();
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
locationRequest.setInterval(30 * 1000);
locationRequest.setFastestInterval(5 * 1000);
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder()
.addLocationRequest(locationRequest);


builder.setAlwaysShow(true);


PendingResult<LocationSettingsResult> result =
LocationServices.SettingsApi.checkLocationSettings(googleApiClient, builder.build());
result.setResultCallback(new ResultCallback<LocationSettingsResult>() {
@Override
public void onResult(LocationSettingsResult result) {
final Status status = result.getStatus();
switch (status.getStatusCode()) {
case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
try {
// Show the dialog by calling startResolutionForResult(),
// and check the result in onActivityResult().
status.startResolutionForResult(LocationOnOff_Similar_To_Google_Maps.this, REQUEST_LOCATION);


finish();
} catch (IntentSender.SendIntentException e) {
// Ignore the error.
}
break;
}
}
});
}
}


}

随着最近的棉花糖更新,即使当位置设置打开,您的应用程序将需要明确要求的权限。推荐的方法是显示应用程序的权限部分,用户可以在其中根据需要切换权限。执行此操作的代码片段如下:

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

if (this.checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {

final AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Location Permission");
builder.setMessage("The app needs location permissions. Please grant this permission to continue using the features of the app.");
builder.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, PERMISSION_REQUEST_COARSE_LOCATION);

}
});
builder.setNegativeButton(android.R.string.no, null);
builder.show();
}
} else {
// do programatically as show in the other answer
}

并重写 onRequestPermissionsResult方法,如下所示:

@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
switch (requestCode) {
case PERMISSION_REQUEST_COARSE_LOCATION: {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Log.d(TAG, "coarse location permission granted");
} else {
Intent intent = new Intent();
intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
Uri uri = Uri.fromParts("package", getPackageName(), null);
intent.setData(uri);
startActivity(intent);
}
}
}
}

另一种方法是,您还可以使用 设置阿比查询启用了哪些位置提供程序。如果没有启用,您可以提示一个对话框从应用程序中更改设置。

感谢 Mattia Maestrini

Xamarin 解决方案:

using Android.Gms.Common.Apis;
using Android.Gms.Location;


public const int REQUEST_CHECK_SETTINGS = 0x1;


private void DisplayLocationSettingsRequest()
{
var googleApiClient = new GoogleApiClient.Builder(this).AddApi(LocationServices.API).Build();
googleApiClient.Connect();


var locationRequest = LocationRequest.Create();
locationRequest.SetPriority(LocationRequest.PriorityHighAccuracy);
locationRequest.SetInterval(10000);
locationRequest.SetFastestInterval(10000 / 2);


var builder = new LocationSettingsRequest.Builder().AddLocationRequest(locationRequest);
builder.SetAlwaysShow(true);


var result = LocationServices.SettingsApi.CheckLocationSettings(googleApiClient, builder.Build());
result.SetResultCallback((LocationSettingsResult callback) =>
{
switch (callback.Status.StatusCode)
{
case LocationSettingsStatusCodes.Success:
{
DoStuffWithLocation();
break;
}
case LocationSettingsStatusCodes.ResolutionRequired:
{
try
{
// Show the dialog by calling startResolutionForResult(), and check the result
// in onActivityResult().
callback.Status.StartResolutionForResult(this, REQUEST_CHECK_SETTINGS);
}
catch (IntentSender.SendIntentException e)
{
}


break;
}
default:
{
// If all else fails, take the user to the android location settings
StartActivity(new Intent(Android.Provider.Settings.ActionLocationSourceSettings));
break;
}
}
});
}


protected override void OnActivityResult(int requestCode, Android.App.Result resultCode, Intent data)
{
switch (requestCode)
{
case REQUEST_CHECK_SETTINGS:
{
switch (resultCode)
{
case Android.App.Result.Ok:
{
DoStuffWithLocation();
break;
}
case Android.App.Result.Canceled:
{
//No location
break;
}
}
break;
}
}
}

注意:

这对华为或其它没有安装谷歌服务的设备不起作用。

按照下面提到的步骤操作

1) 按照你的意愿创建一个 LocationRequest

LocationRequest mLocationRequest = LocationRequest.create()
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
.setInterval(10 * 1000)
.setFastestInterval(1 * 1000);

2) 创建一个 LocationSettingsRequest.Builder

LocationSettingsRequest.Builder settingsBuilder = new LocationSettingsRequest.Builder()
.addLocationRequest(mLocationRequest);
settingsBuilder.setAlwaysShow(true);

3) 使用以下代码获取 LocationSettingsResponse Task

Task<LocationSettingsResponse> result = LocationServices.getSettingsClient(this)
.checkLocationSettings(settingsBuilder.build());

注意: LocationServices.SettingsApi不推荐使用,改为使用 SettingsClient

4) 添加一个 OnCompleteListener来获得 Task 的结果。当 Task完成时,客户端可以通过查看来自 LocationSettingsResponse对象的状态代码来检查位置设置。

result.addOnCompleteListener(new OnCompleteListener<LocationSettingsResponse>() {
@Override
public void onComplete(@NonNull Task<LocationSettingsResponse> task) {
try {
LocationSettingsResponse response =
task.getResult(ApiException.class);
} catch (ApiException ex) {
switch (ex.getStatusCode()) {
case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
try {
ResolvableApiException resolvableApiException =
(ResolvableApiException) ex;
resolvableApiException
.startResolutionForResult(MapsActivity.this,
LOCATION_SETTINGS_REQUEST);
} catch (IntentSender.SendIntentException e) {


}
break;
case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:


break;
}
}
}
});

情况1: LocationSettingsStatusCodes.RESOLUTION_REQUIRED: Location 没有启用,但是,我们可以通过对话框提示用户打开该位置(通过调用 startResolutionForResult)来要求用户启用该位置。

Google Map Location Settings Request

情况2: LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE: 位置设置不满足。但是,我们没有办法修复设置,所以我们不会显示对话框。

5) OnActivityResult我们可以在位置设置对话框中得到用户动作。用户打开位置。RESULT_CANCELLED-用户拒绝了位置设置请求。

implementation 'com.google.android.gms:play-services-location:16.0.0'

变量声明

private SettingsClient mSettingsClient;
private LocationSettingsRequest mLocationSettingsRequest;
private static final int REQUEST_CHECK_SETTINGS = 214;
private static final int REQUEST_ENABLE_GPS = 516;

使用以下代码打开对话框

LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder();
builder.addLocationRequest(new LocationRequest().setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY));
builder.setAlwaysShow(true);
mLocationSettingsRequest = builder.build();


mSettingsClient = LocationServices.getSettingsClient(YourActivity.this);


mSettingsClient
.checkLocationSettings(mLocationSettingsRequest)
.addOnSuccessListener(new OnSuccessListener<LocationSettingsResponse>() {
@Override
public void onSuccess(LocationSettingsResponse locationSettingsResponse) {
//Success Perform Task Here
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
int statusCode = ((ApiException) e).getStatusCode();
switch (statusCode) {
case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
try {
ResolvableApiException rae = (ResolvableApiException) e;
rae.startResolutionForResult(YourActivity.this, REQUEST_CHECK_SETTINGS);
} catch (IntentSender.SendIntentException sie) {
Log.e("GPS","Unable to execute request.");
}
break;
case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
Log.e("GPS","Location settings are inadequate, and cannot be fixed here. Fix in Settings.");
}
}
})
.addOnCanceledListener(new OnCanceledListener() {
@Override
public void onCanceled() {
Log.e("GPS","checkLocationSettings -> onCanceled");
}
});

OnActivityResult

@Override
public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);


if (requestCode == REQUEST_CHECK_SETTINGS) {
switch (resultCode) {
case Activity.RESULT_OK:
//Success Perform Task Here
break;
case Activity.RESULT_CANCELED:
Log.e("GPS","User denied to access location");
openGpsEnableSetting();
break;
}
} else if (requestCode == REQUEST_ENABLE_GPS) {
LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
boolean isGpsEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);


if (!isGpsEnabled) {
openGpsEnableSetting();
} else {
navigateToUser();
}
}
}


private void openGpsEnableSetting() {
Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivityForResult(intent, REQUEST_ENABLE_GPS);
}

Kotlin 溶液

加入 build.gradle(Module:app)

implementation 'com.google.android.gms:play-services-location:17.0.0'
implementation 'com.google.android.gms:play-services-maps:17.0.0'

然后创建这个函数

fun enablegps() {


val mLocationRequest = LocationRequest.create()
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
.setInterval(2000)
.setFastestInterval(1000)


val settingsBuilder = LocationSettingsRequest.Builder()
.addLocationRequest(mLocationRequest)
settingsBuilder.setAlwaysShow(true)


val result = LocationServices.getSettingsClient(this).checkLocationSettings(settingsBuilder.build())
result.addOnCompleteListener { task ->


//getting the status code from exception
try {
task.getResult(ApiException::class.java)
} catch (ex: ApiException) {


when (ex.statusCode) {


LocationSettingsStatusCodes.RESOLUTION_REQUIRED -> try {


Toast.makeText(this,"GPS IS OFF",Toast.LENGTH_SHORT).show()


// Show the dialog by calling startResolutionForResult(), and check the result
// in onActivityResult().
val resolvableApiException = ex as ResolvableApiException
resolvableApiException.startResolutionForResult(this,REQUEST_CHECK_SETTINGS
)
} catch (e: IntentSender.SendIntentException) {
Toast.makeText(this,"PendingIntent unable to execute request.",Toast.LENGTH_SHORT).show()


}


LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE -> {


Toast.makeText(
this,
"Something is wrong in your GPS",
Toast.LENGTH_SHORT
).show()


}




}
}






}




}

我在研究中发现的最简单的方法是为这个位置请求过程创建一个 Util 类,然后调用它为我们打开 GPS。

请看这个博客! 它讲述了整个故事。

如果希望在 Fragment中替换不推荐的 onActivityResultstartResolutionForResult,请参见 https://stackoverflow.com/a/65816646/2914140

val checkLocationSettings =
registerForActivityResult(ActivityResultContracts.StartIntentSenderForResult()) { result ->
if (result.resultCode == RESULT_OK) {
// GPS is turned on in system settings.
}
}


...


val intentSenderRequest = IntentSenderRequest.Builder(resolvable.resolution).build()
checkLocationSettings.launch(intentSenderRequest)
 private void openDeviceLocationRequest() {
if (!locationPermissionGranted)
return;


LocationRequest locationRequest = LocationRequest.create();
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder()
.addLocationRequest(locationRequest);
builder.setAlwaysShow(true); //this is the key ingredient


Task<LocationSettingsResponse> result =
LocationServices.getSettingsClient(this).checkLocationSettings(builder.build());
result.addOnCompleteListener(task -> {
try {
LocationSettingsResponse response = task.getResult(ApiException.class);
// All location settings are satisfied. The client can initialize location
// requests here.
if(lastKnownLocation == null)
getDeviceLocation();


} catch (ApiException exception) {
switch (exception.getStatusCode()) {
case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
// Location settings are not satisfied. But could be fixed by showing the
// user a dialog.
try {
// Cast to a resolvable exception.
ResolvableApiException resolvable = (ResolvableApiException) exception;
// Show the dialog by calling startResolutionForResult(),
// and check the result in onActivityResult().
resolvable.startResolutionForResult(
MapAddressActivity.this,
REQUEST_CHECK_SETTINGS);
} catch (IntentSender.SendIntentException e) {
// Ignore the error.
} catch (ClassCastException e) {
// Ignore, should be an impossible error.
}
break;
case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
// Location settings are not satisfied. However, we have no way to fix the
// settings so we won't show the dialog.
break;
}
}
});
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate( savedInstanceState );
setContentView( R.layout.activity_main );


LocationManager manager = (LocationManager) getSystemService( Context.LOCATION_SERVICE );
if (!manager.isProviderEnabled( LocationManager.GPS_PROVIDER )) {
buildAlertMessageNoGps();
}
}
private void buildAlertMessageNoGps() {
final AlertDialog.Builder builder = new AlertDialog.Builder( this );
builder.setMessage( "Your GPS seems to be disabled, do you want to enable it?" )
.setCancelable( false )
.setPositiveButton( "Yes", (dialog, id) -> startActivity( new Intent( android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS ) ) )
.setNegativeButton( "No", (dialog, id) -> dialog.cancel() );
final AlertDialog alert = builder.create();
alert.show();
}