Active los servicios de ubicación sin navegar a la página de configuración


121

En contra del enfoque tradicional de pedirle al usuario que vaya a la página de configuración y habilite los servicios de ubicación y vuelva de nuevo, he notado una forma más sencilla de hacer lo mismo en algunas de las aplicaciones más recientes.

Refiriéndose a la captura de pantalla a continuación, aparece un cuadro de diálogo para que el usuario habilite los servicios de ubicación con solo un clic y funciona en esas aplicaciones.

¿Cómo puedo lograr lo mismo?

ingrese la descripción de la imagen aquí


13
¿Pueden los votantes negativos dar la razón?
GAMA

3
Gracias por hacer esta pregunta. Votado a favor
Lokesh Pandey

@GAMA ¡Así es como funciona stackoverflow! La gente no necesita una razón para votar en contra. ¡Qué gran comunidad tan hostil y al mismo tiempo!

Respuestas:


150

Este cuadro de diálogo lo crea LocationSettingsRequest.Builder disponible en Google Play Services.

Necesita agregar una dependencia a su aplicación build.gradle:

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

Entonces puedes usar este ejemplo mínimo:

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

Puede encontrar el ejemplo completo aquí .


1
Lo siento, pero no entendí las dos primeras líneas:You need to add a dependency to your app build.gradle: compile 'com.google.android.gms:play-services:8.1.0'
GAMA

Puede encontrar más información sobre cómo configurar el servicio Google Play aquí
Mattia Maestrini

¿Dónde se encuentra build.gradle ?
GAMA

Dentro del directorio del módulo de tu aplicación. Por lo general, el nombre del directorio esapp
Mattia Maestrini

3
SettingsApi ahora está depricado.
Sagar Kacha

27

Siga los pasos que se mencionan a continuación

1) Cree un LocationRequestsegún su deseo

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

2) Crea unLocationSettingsRequest.Builder

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

3) Obtener LocationSettingsResponse Taskel uso siguiente código

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

Nota: LocationServices.SettingsApi está en desuso, así que use en su SettingsClientlugar.

4) Agregue un OnCompleteListenerpara obtener el resultado de la tarea. Cuando se Taskcomplete, el cliente puede verificar la configuración de ubicación mirando el código de estado del LocationSettingsResponseobjeto.

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

CASO 1: La LocationSettingsStatusCodes.RESOLUTION_REQUIRED ubicación no está habilitada, pero podemos pedirle al usuario que habilite la ubicación solicitándole que active la ubicación con el cuadro de diálogo (llamando startResolutionForResult).

Solicitud de configuración de ubicación de Google Map

CASO 2: LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE La configuración de ubicación no está satisfecha. Sin embargo, no tenemos forma de corregir la configuración, por lo que no mostraremos el cuadro de diálogo.

5) OnActivityResult podemos obtener la acción del usuario en el cuadro de diálogo de configuración de ubicación. RESULT_OK=> El usuario activó la ubicación. RESULT_CANCELLED- El usuario rechazó la solicitud de configuración de ubicación.


11

Funciona de forma similar a los mapas de Google

Agregar dependencia en el archivo build.gradle

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

esta o aquella

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

ingrese la descripción de la imagen aquí

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

}

2
SettingsApi ahora está depricada
Sagar Kacha

2
SettingsApi ahora está en desuso. Ahora use SettingsClient: developers.google.com/android/reference/com/google/android/gms/…
Rishabh Chandel

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

Declaración de variable

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

Abrir cuadro de diálogo usando el siguiente código

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

¡Gracias! Si usa este código en un fragmento, consulte stackoverflow.com/a/39579124/2914140 : en lugar de rae.startResolutionForResult(activity, REQUEST_CHECK_SETTINGS)llamar startIntentSenderForResult(rae.getResolution().getIntentSender(), REQUEST_CHECK_SETTINGS, null, 0, 0, 0, null), de lo contrario onActivityResult(), no se llamará.
CoolMind

@CoolMind Gracias puede ser útil para alguien que necesita esto para el fragmento
Ketan Ramani

@CoolMind, ¿es posible usar algo similar a startIntentSenderForResulten el método openGpsEnableSetting()?
Aliton Oliveira

@AlitonOliveira, ¿podrías describirlo en detalle? En el código openGpsEnableSetting()simplemente se inicia un diálogo para habilitar la configuración del GPS. Una vez finalizado, onActivityResult()se llama con requestCode == REQUEST_ENABLE_GPS.
CoolMind

onActivityResult()se llama desde Activity y me preguntaba si es posible devolver el resultado a un me Fragmentgusta startIntentSenderForResult.
Aliton Oliveira

8

Gracias a Mattia Maestrini +1

Solución de 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;
            }
    }
}

NOTA:

Esto no funcionará con Huawei u otros dispositivos que no tengan los servicios de Google instalados.


¡¡No funciona!! ¿Puede compartir el código completo
Omkar

Estoy tratando de llamar al método DisplayLocationSettingsRequest () desde el método OnCreate de la actividad de Android. Pero, lamentablemente, no puedo ver la ventana emergente de solicitud de configuración de ubicación que activa Ubicación. ¿Puedes ayudarme?
Omkar

@Omkar, ¿instaló Xamarin.GooglePlayServices.Location a través de Nuget? ¿Incluiste las dos líneas de arriba using android.Gms.Common.Apis; using Android.Gms.Location;? Después de llamar LocationServices.SettingsApi.CheckLocationSettings, ¿recibe una devolución de llamada dentro result.SetResultCallback(? Coloque un punto de interrupción en cada uno de ellos y verifique lo que está haciendo el código
Pierre

Sí, agregué todos los requisitos previos. Y recibí el resultado como Id = 1, Status = WaitingForActivation, Method = (nulo). Pero este tiempo de espera es infinito, ya que se esperó durante mucho tiempo y no recibió ningún resultado.
Omkar

4

Android Marshmallow 6 admite permisos de tiempo de ejecución. Los permisos de tiempo de ejecución solo funcionan en Marshmallow y en versiones anteriores a Marshmallow todavía funcionan de la manera anterior.

Puede obtener más información al respecto en este video oficial para desarrolladores de Android:

https://www.youtube.com/watch?v=C8lUdPVSzDk

Y solicitando permiso: http://developer.android.com/training/permissions/requesting.html


¿La API de Marshmallow está disponible para fines de desarrollo?
GAMA

Entonces, ¿eso significa que el flujo de trabajo que se muestra a través de la captura de pantalla solo se puede lograr con Marshmallow y versiones posteriores?
GAMA

Sí, como se indica en la documentación, es de nivel de API 23, por lo que solo funcionará en Marshmallow y versiones posteriores.
Sharj

cualquier forma de lograr el mismo comportamiento en mi propio diálogo personalizado
Srishti Roy

4

Gracias Mattia Maestrini por la respuesta, me gustaría agregar eso usando

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

bastaría. Esto evita que su aplicación incluya bibliotecas innecesarias y ayuda a mantener un número bajo de métodos.


2

Solución de Kotlin

Añadir 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'

después de eso crea esta función

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()

                }


            }
        }



    }


}

1

Con la actualización reciente de Marshmallow, incluso cuando la configuración de Ubicación está activada, su aplicación requerirá pedir permiso explícitamente. La forma recomendada de hacer esto es mostrar la sección Permisos de su aplicación en la que el usuario puede alternar el permiso según sea necesario. El fragmento de código para hacer esto es el siguiente:

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 
}

Y anule el onRequestPermissionsResultmétodo de la siguiente manera:

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

Otro enfoque es que también puede usar SettingsApi para consultar qué proveedores de ubicación están habilitados. Si ninguno está habilitado, puede abrir un cuadro de diálogo para cambiar la configuración desde la aplicación.


1

La forma más sencilla que encontré mientras investigaba es crear una clase Util para este proceso de solicitud de ubicación y luego llamarla para que encienda el GPS.

¡Por favor revisa este blog! Contó toda la historia.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.