Attiva i servizi di localizzazione senza accedere alla pagina delle impostazioni


121

Contro l'approccio tradizionale di chiedere all'utente di andare alla pagina delle impostazioni e abilitare i servizi di localizzazione e tornare di nuovo, ho notato un modo più semplice di fare lo stesso in alcune delle app più recenti.

Facendo riferimento allo screenshot sottostante, richiede una finestra di dialogo all'utente per abilitare i servizi di localizzazione con un solo clic e funziona in quelle app.

Come posso ottenere lo stesso risultato?

inserisci qui la descrizione dell'immagine


13
Gli elettori negativi possono fornire il motivo?
GAMA

3
Grazie per aver posto questa domanda. Up ha votato
Lokesh Pandey

@GAMA Ecco come funziona lo stackoverflow! Le persone non hanno bisogno di un motivo per votare a favore. Una comunità così ostile e grande allo stesso tempo!

Risposte:


150

Questa finestra di dialogo viene creata da LocationSettingsRequest.Builder disponibile in Google Play Services.

Devi aggiungere una dipendenza alla tua app build.gradle:

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

Quindi puoi usare questo esempio minimo:

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

Puoi trovare l'esempio completo qui .


1
Mi dispiace ma non ho capito le prime due righe:You need to add a dependency to your app build.gradle: compile 'com.google.android.gms:play-services:8.1.0'
GAMA

Puoi trovare maggiori informazioni su come configurare Google Play Service qui
Mattia Maestrini

dove si trova build.gradle ?
GAMA

All'interno della directory del modulo dell'applicazione. Di solito il nome della directory èapp
Mattia Maestrini

3
SettingsApi è ora deprecato.
Sagar Kacha

27

Segui i passaggi indicati di seguito

1) Crea un LocationRequestsecondo il tuo desiderio

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

2) Crea un fileLocationSettingsRequest.Builder

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

3) Ottieni LocationSettingsResponse Taskutilizzando il seguente codice

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

Nota: LocationServices.SettingsApi è deprecato quindi, usa SettingsClientinvece.

4) Aggiungere a OnCompleteListenerper ottenere il risultato dall'attività. Al Tasktermine, il client può controllare le impostazioni della posizione guardando il codice di stato LocationSettingsResponsedall'oggetto.

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 posizione non è abilitata ma, possiamo chiedere all'utente di abilitare la posizione chiedendogli di attivare la posizione con la finestra di dialogo (chiamando startResolutionForResult).

Richiesta di impostazioni di posizione di Google Map

CASO 2 LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE :: le impostazioni di posizione non sono soddisfatte. Tuttavia, non abbiamo modo di correggere le impostazioni, quindi non mostreremo la finestra di dialogo.

5) OnActivityResult possiamo ottenere l'azione dell'utente nella finestra di dialogo delle impostazioni della posizione. RESULT_OK=> L'utente ha attivato la posizione. RESULT_CANCELLED- L'utente ha rifiutato la richiesta di impostazione della posizione.


11

Funziona in modo simile a Google Maps

Aggiungi dipendenza nel file build.gradle

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

questo o quello

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

inserisci qui la descrizione dell'immagine

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 è ora deprecato
Sagar Kacha

2
SettingsApi è ora deprecato. Ora usa SettingsClient: developers.google.com/android/reference/com/google/android/gms/…
Rishabh Chandel

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

Dichiarazione di variabili

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

Apri la finestra di dialogo utilizzando il codice sottostante

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

Grazie! Se usi questo codice in frammento, vedi stackoverflow.com/a/39579124/2914140 : invece di rae.startResolutionForResult(activity, REQUEST_CHECK_SETTINGS)call startIntentSenderForResult(rae.getResolution().getIntentSender(), REQUEST_CHECK_SETTINGS, null, 0, 0, 0, null), altrimenti onActivityResult()non verrà chiamato.
CoolMind

@CoolMind Thanks può essere utile per qualcuno che ne ha bisogno per il frammento
Ketan Ramani

@CoolMind, è possibile utilizzare qualcosa di simile startIntentSenderForResultnel metodo openGpsEnableSetting()?
Aliton Oliveira,

@AlitonOliveira, potresti descriverla in dettaglio? Nel codice openGpsEnableSetting()si avvia semplicemente una finestra di dialogo per abilitare le impostazioni GPS. Dopo che finisce, onActivityResult()viene chiamato con requestCode == REQUEST_ENABLE_GPS.
CoolMind

onActivityResult()viene chiamato da Activity e mi chiedevo se sia possibile restituire il risultato in modo Fragmentsimile startIntentSenderForResult.
Aliton Oliveira,

8

Grazie a Mattia Maestrini +1

Soluzione 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:

Questo non funzionerà con Huawei o altri dispositivi su cui non sono installati i servizi di Google.


La sua non funziona!! Puoi condividere il codice completo
Omkar

Sto provando a chiamare il metodo DisplayLocationSettingsRequest () dal metodo OnCreate di Android Activity. Ma sfortunatamente non sono in grado di visualizzare il popup di richiesta di impostazione della posizione che attiva la posizione. Puoi aiutarmi per favore.
Omkar

@Omkar, hai installato Xamarin.GooglePlayServices.Location tramite Nuget? Hai incluso le due righe sopra using android.Gms.Common.Apis; using Android.Gms.Location;? Dopo aver chiamato LocationServices.SettingsApi.CheckLocationSettings, ricevi una richiamata entro result.SetResultCallback(? Posiziona un punto di interruzione in ciascuno di questi e controlla cosa sta facendo il codice
Pierre

Sì, ho aggiunto tutti i prerequisiti. E ho ricevuto il risultato come Id = 1, Status = WaitingForActivation, Method = (null). Ma questo tempo di attesa è infinito poiché aspettato da molto tempo e non ha ricevuto alcun risultato.
Omkar

4

Android Marshmallow 6 supporta l'autorizzazione di runtime. Le autorizzazioni di runtime funzionano solo su Marshmallow e su pre-Marshmallow funziona ancora alla vecchia maniera.

Puoi saperne di più in questo video ufficiale dello sviluppatore Android:

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

E per richiedere l'autorizzazione: http://developer.android.com/training/permissions/requesting.html


Le API Marshmallow sono disponibili per scopi di sviluppo?
GAMA

quindi significa che il flusso di lavoro mostrato tramite screenshot può essere ottenuto solo Marshmallow e versioni successive?
GAMA

Sì, come indicato nella documentazione è il livello API 23, quindi funzionerà solo su Marshmallow e versioni successive.
Sharj

qualsiasi modo per ottenere lo stesso comportamento nella mia finestra di dialogo personalizzata
Srishti Roy

4

Grazie Mattia Maestrini per la risposta, vorrei aggiungerla utilizzando

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

sarebbe sufficiente. Ciò impedisce alla tua app di includere librerie non necessarie e aiuta a mantenere basso il conteggio dei metodi.


2

Soluzione Kotlin

Inserisci 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'

dopodiché crea questa funzione

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 il recente aggiornamento di Marshmallow, anche quando l'impostazione Posizione è attivata, l'app richiederà esplicitamente l'autorizzazione. Il modo consigliato per farlo è mostrare la sezione Autorizzazioni della tua app in cui l'utente può attivare o disattivare l'autorizzazione come richiesto. Lo snippet di codice per eseguire questa operazione è il seguente:

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 
}

E sovrascrivi il onRequestPermissionsResultmetodo come di seguito:

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

Un altro approccio è che puoi anche utilizzare SettingsApi per chiedere quali provider di posizione sono abilitati. Se nessuno è abilitato, puoi richiedere a una finestra di dialogo di modificare l'impostazione dall'interno dell'app.


1

Il modo più semplice che ho trovato durante la mia ricerca, è creare una classe Util per questo processo di richiesta di posizione e quindi chiamarlo per attivare il GPS per noi.

Per favore controlla questo blog! Raccontava l'intera storia.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.