要求用户打开位置

Posted

技术标签:

【中文标题】要求用户打开位置【英文标题】:Ask user to turn on Location 【发布时间】:2017-08-25 14:43:47 【问题描述】:

如何提示用户开启位置


该应用应该使用用户的当前位置过滤位置列表。如果用户关闭了Location服务,应用应该提示用户要求打开Location

例如 Trip Advisor 应用程序会这样做:

( 不确定我是否可以在这里发布其他应用程序的屏幕截图,但如果我不应该这样做,请说出来。并为全尺寸的图像道歉,试图让它们变小,但没有'不喜欢...

在第一张图片中,您可以看到我关闭了位置服务。在打开 Trip Advisor 应用程序并点击 现在靠近我 选项后,我会收到第二张图片提示,要求我转身关于位置服务。点击按钮后,会出现一个对话框,以便我可以允许或禁止打开Location服务。如果我点击 OKLocation 服务会在设备上打开,并且应用会使用它。

我怎样才能做到这一点?

【问题讨论】:

developers.google.com/android/reference/com/google/android/gms/… 【参考方案1】:

找到了我想要的解决方案。


要求

NugetXamarin.GooglePlayServices.Location


代码

Int64
    interval = 1000 * 60 * 1,
    fastestInterval = 1000 * 50;

try 
    GoogleApiClient
        googleApiClient = new GoogleApiClient.Builder( this )
            .AddApi( LocationServices.API )
            .Build();

    googleApiClient.Connect();

    LocationRequest
        locationRequest = LocationRequest.Create()
            .SetPriority( LocationRequest.PriorityBalancedPowerAccuracy )
            .SetInterval( interval )
            .SetFastestInterval( fastestInterval );

    LocationSettingsRequest.Builder
        locationSettingsRequestBuilder = new LocationSettingsRequest.Builder()
            .AddLocationRequest( locationRequest );

    locationSettingsRequestBuilder.SetAlwaysShow( false );

    LocationSettingsResult
        locationSettingsResult = await LocationServices.SettingsApi.CheckLocationSettingsAsync(
            googleApiClient, locationSettingsRequestBuilder.Build() );

    if( locationSettingsResult.Status.StatusCode == LocationSettingsStatusCodes.ResolutionRequired ) 
        locationSettingsResult.Status.StartResolutionForResult( this, 0 );
    
 catch( Exception exception ) 
    // Log exception

使用此代码,如果 locationSettingsResult.Status.StatusCodeLocationSettingsStatusCodes.ResolutionRequired ( 6 ) 这意味着 - 可能 - Location 已关闭,尽管我发现了一种情况当设备关闭该选项时,它没有返回值。开机关机后就可以了,可能是设备的bug,也可能不是。

【讨论】:

但是我能问一下如何在按下 ok 时得到结果吗?我需要在那里编写一些代码。 只想回答我上面的问题。仍然是 OnActivityResult :)【参考方案2】:

假设你在一个名为 LocationActivity 的 Activity 中做所有这些事情。为此,您需要实现一些回调。下面是带有 cmets 的代码,因此您可以轻松了解哪个方法执行什么操作以及何时调用。

记住在应用清单文件中添加权限:

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

活动代码:

import android.app.Activity;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentSender;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.support.v13.app.ActivityCompat;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentActivity;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GoogleApiAvailability;
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;

public class LocationActivity extends FragmentActivity implements GoogleApiClient.ConnectionCallbacks,
        GoogleApiClient.OnConnectionFailedListener 

    // Unique tag for the error dialog fragment
    private static final String DIALOG_ERROR = "dialog_error";
    // Bool to track whether the app is already resolving an error
    private boolean mResolvingError = false;
    // Request code to use when launching the resolution activity
    private static final int REQUEST_RESOLVE_ERROR = 555;

    int ACCESS_FINE_LOCATION_CODE = 3310;
    int ACCESS_COARSE_LOCATION_CODE = 3410;
    private GoogleApiClient mGoogleApiClient;

    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        // Build Google API Client for Location related work
        buildGoogleApiClient();
    


    // When user first come to this activity we try to connect Google services for location and map related work
    protected synchronized void buildGoogleApiClient() 
        mGoogleApiClient = new GoogleApiClient.Builder(this)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .addApi(LocationServices.API)
                .build();
    


    // Google Api Client is connected
    @Override
    public void onConnected(Bundle bundle) 
        if (mGoogleApiClient.isConnected()) 
            //if connected successfully show user the settings dialog to enable location from settings services
            // If location services are enabled then get Location directly
            // Else show options for enable or disable location services
            settingsrequest();
        
    


    // This is the method that will be called if user has disabled the location services in the device settings
    // This will show a dialog asking user to enable location services or not
    // If user tap on "Yes" it will directly enable the services without taking user to the device settings
    // If user tap "No" it will just Finish the current Activity
    public void settingsrequest() 
        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); //this is the key ingredient

        PendingResult<LocationSettingsResult> result = LocationServices.SettingsApi.checkLocationSettings(mGoogleApiClient, builder.build());
        result.setResultCallback(new ResultCallback<LocationSettingsResult>() 
            @Override
            public void onResult(LocationSettingsResult result) 
                final Status status = result.getStatus();
                switch (status.getStatusCode()) 
                    case LocationSettingsStatusCodes.SUCCESS:
                        if (mGoogleApiClient.isConnected()) 

                            // check if the device has OS Marshmellow or greater than
                            if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1) 
                                if (ActivityCompat.checkSelfPermission(LocationActivity.this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(LocationActivity.this, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) 
                                    ActivityCompat.requestPermissions(LocationActivity.this, new String[]android.Manifest.permission.ACCESS_FINE_LOCATION, ACCESS_FINE_LOCATION_CODE);
                                 else 
                                    // get Location
                                
                             else 
                                // get Location
                            

                        
                        break;
                    case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
                        // Location settings are not satisfied. But could be fixed by showing the user
                        // a dialog.
                        try 
                            // Show the dialog by calling startResolutionForResult(),
                            // and check the result in onActivityResult().
                            status.startResolutionForResult(LocationActivity.this, REQUEST_RESOLVE_ERROR);
                         catch (IntentSender.SendIntentException e) 
                            // Ignore the 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;
                
            
        );
    


    // This method is called only on devices having installed Android version >= M (Marshmellow)
    // This method is just to show the user options for allow or deny location services at runtime
    @Override
    public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) 
        switch (requestCode) 
            case 3310: 

                if (grantResults.length > 0) 

                    for (int i = 0, len = permissions.length; i < len; i++) 

                        if (grantResults[i] == PackageManager.PERMISSION_DENIED) 
                            // Show the user a dialog why you need location
                         else if (grantResults[i] == PackageManager.PERMISSION_GRANTED) 
                            // get Location
                         else 
                            this.finish();
                        
                    
                
                return;
            
        
    


    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) 
        if (requestCode == REQUEST_RESOLVE_ERROR) 
            mResolvingError = false;
            switch (resultCode) 
                case Activity.RESULT_OK:
                    // get location method
                    break;
                case Activity.RESULT_CANCELED:
                    this.finish();
                    break;
            
        
    


    @Override
    public void onConnectionSuspended(int i) 
    


    // When there is an error connecting Google Services
    @Override
    public void onConnectionFailed(ConnectionResult result) 
        if (mResolvingError) 
            // Already attempting to resolve an error.
            return;
         else if (result.hasResolution()) 
            try 
                mResolvingError = true;
                result.startResolutionForResult(this, REQUEST_RESOLVE_ERROR);
             catch (IntentSender.SendIntentException e) 
                // There was an error with the resolution intent. Try again.
                mGoogleApiClient.connect();
            
         else 
            // Show dialog using GoogleApiAvailability.getErrorDialog()
            showErrorDialog(result.getErrorCode());
            mResolvingError = true;
        
    


    /* Creates a dialog for an error message */
    private void showErrorDialog(int errorCode) 
        // Create a fragment for the error dialog
        ErrorDialogFragment dialogFragment = new ErrorDialogFragment();
        // Pass the error that should be displayed
        Bundle args = new Bundle();
        args.putInt(DIALOG_ERROR, errorCode);
        dialogFragment.setArguments(args);
        dialogFragment.show(getSupportFragmentManager(), "errordialog");
    

    /* Called from ErrorDialogFragment when the dialog is dismissed. */
    public void onDialogDismissed() 
        mResolvingError = false;
    

    /* A fragment to display an error dialog */
    public static class ErrorDialogFragment extends DialogFragment 
        public ErrorDialogFragment() 
        

        @Override
        public Dialog onCreateDialog(Bundle savedInstanceState) 
            // Get the error code and retrieve the appropriate dialog
            int errorCode = this.getArguments().getInt(DIALOG_ERROR);
            return GoogleApiAvailability.getInstance().getErrorDialog(
                    this.getActivity(), errorCode, REQUEST_RESOLVE_ERROR);
        

        @Override
        public void onDismiss(DialogInterface dialog) 
            ((LocationActivity) getActivity()).onDialogDismissed();
        
    


    // Connect Google Api Client if it is not connected already
    @Override
    protected void onStart() 
        super.onStart();
        if (mGoogleApiClient != null) 
            mGoogleApiClient.connect();
        
    

    // Stop the service when we are leaving this activity
    @Override
    protected void onStop() 
        super.onStop();
        if (mGoogleApiClient != null) 
            mGoogleApiClient.disconnect();
        
    


你可以阅读官方文档here

【讨论】:

【参考方案3】:

您可以使用以下class 将用户移动到设置。首先检查位置,如果它不可用,请致电showSettingAlert

AlertDialog.Builder alertDialog = new AlertDialog.Builder(mContext);

// Setting Dialog Title
alertDialog.setTitle("GPS is settings");
// Setting Dialog Message
alertDialog.setMessage("GPS is not enabled. Do you want to go to settings menu?");
// On pressing Settings button
alertDialog.setPositiveButton("Settings", new DialogInterface.OnClickListener() 
    public void onClick(DialogInterface dialog, int which) 
        Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
        mContext.startActivity(intent);
    
);

// on pressing cancel button
alertDialog.setNegativeButton("Cancel", new DialogInterface.OnClickListener() 
    public void onClick(DialogInterface dialog, int which) 
        dialog.cancel();
    
);
// Showing Alert Message
alertDialog.show();

【讨论】:

正如我在Pehlaj 回答中评论的那样,我想避免将用户重定向到设备设置。根据 API 可能存在限制,但这是另一回事。我的目标是向用户显示一个对话框以打开位置。 检查下面的链接可能你会从那里得到一些想法saravananandroid.blogspot.in/2016/02/…【参考方案4】:

使用以下代码 sn-p 打开设备设置屏幕。

Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivity(intent);

在权限对话框中使用设置 API

GoogleApiClient googleApiClient = new GoogleApiClient.Builder(mContext).addApi(LocationServices.API).build();
    googleApiClient.connect();

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

LocationSettingsRequest.Builder lBuilder = new LocationSettingsRequest.Builder().addLocationRequest(lReq);
lBuilder.setAlwaysShow(true);

PendingResult<LocationSettingsResult> result = LocationServices.SettingsApi.checkLocationSettings(googleApiClient, lBuilder.build());
result.setResultCallback(new ResultCallback<LocationSettingsResult>() 
    @Override
    public void onResult(LocationSettingsResult result) 
        final Status status = result.getStatus();
        switch (status.getStatusCode()) 
            case LocationSettingsStatusCodes.SUCCESS:
                break;
        
    
);

【讨论】:

【参考方案5】:

试试

private void turnGPSOn()
   String provider = Settings.Secure.getString(getContentResolver(), Settings.Secure.LOCATION_PROVIDERS_ALLOWED);

   if(!provider.contains("gps")) //if gps is disabled
    final Intent poke = new Intent();
    poke.setClassName("com.android.settings", "com.android.settings.widget.SettingsAppWidgetProvider"); 
    poke.addCategory(Intent.CATEGORY_ALTERNATIVE);
    poke.setData(Uri.parse("3")); 
    sendBroadcast(poke);
 


private void turnGPSOff()
   String provider = Settings.Secure.getString(getContentResolver(), Settings.Secure.LOCATION_PROVIDERS_ALLOWED);

   if(provider.contains("gps")) //if gps is enabled
    final Intent poke = new Intent();
    poke.setClassName("com.android.settings", "com.android.settings.widget.SettingsAppWidgetProvider");
    poke.addCategory(Intent.CATEGORY_ALTERNATIVE);
    poke.setData(Uri.parse("3")); 
    sendBroadcast(poke);



private boolean canToggleGPS() 
   PackageManager pacman = getPackageManager();
PackageInfo pacInfo = null;

   try 
    pacInfo = pacman.getPackageInfo("com.android.settings", PackageManager.GET_RECEIVERS);
    catch (NameNotFoundException e) 
    return false; //package not found
   

   if(pacInfo != null)
    for(ActivityInfo actInfo : pacInfo.receivers)
        //test if recevier is exported. if so, we can toggle GPS.
        if(actInfo.name.equals("com.android.settings.widget.SettingsAppWidgetProvider") && actInfo.exported)
            return true;
        
    
 

 return false; //default

【讨论】:

我知道该解决方案,但我试图避免将用户重定向到设置。我的目标解决方案类似于 TripAdvisor 使用的解决方案。 开启 GPS 的意图不起作用。什么都不做【参考方案6】:

如何通过在您的应用中向用户显示位置对话框,以编程方式在 android 中打开位置。 这是简单的代码: 首先,添加google服务位置的依赖

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

在 MainActivity.java 中

public class MainActivity extends AppCompatActivity 


private Button TurnGPSOn;
private LocationRequest locationRequest;
private static final int REQUEST_CHECK_SETTINGS = 10001;



@Override
protected void onCreate(Bundle savedInstanceState) 
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    TurnGPSOn = findViewById(R.id.location_btn);
    TurnGPSOn.setOnClickListener(new View.OnClickListener() 
        @Override
        public void onClick(View v) 

            locationRequest = LocationRequest.create();
            locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
            locationRequest.setInterval(5000);
            locationRequest.setFastestInterval(2000);

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

            Task<LocationSettingsResponse> result = LocationServices.getSettingsClient(getApplicationContext())
                    .checkLocationSettings(builder.build());

            result.addOnCompleteListener(new OnCompleteListener<LocationSettingsResponse>() 
                @Override
                public void onComplete(@NonNull Task<LocationSettingsResponse> task) 

                    try 
                        LocationSettingsResponse response = task.getResult(ApiException.class);
                        Toast.makeText(MainActivity.this, "GPS is already tured on", Toast.LENGTH_SHORT).show();

                     catch (ApiException e) 

                        switch (e.getStatusCode()) 
                            case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:

                                try 
                                    ResolvableApiException resolvableApiException = (ResolvableApiException)e;
                                    resolvableApiException.startResolutionForResult(MainActivity.this,REQUEST_CHECK_SETTINGS);
                                 catch (IntentSender.SendIntentException ex) 
                                    ex.printStackTrace();
                                
                                break;

                            case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
                                //Device does not have location
                                break;
                        
                    
                
            );



        
    );




@Override
protected 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:
                Toast.makeText(this, "GPS is tured on", Toast.LENGTH_SHORT).show();

            case Activity.RESULT_CANCELED:
                Toast.makeText(this, "GPS required to be tured on", Toast.LENGTH_SHORT).show();
        
    

在activity_main.xml 中:

    <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_
    android:layout_
    android:gravity="center"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/location_btn"
        android:layout_
        android:layout_
        android:text="Turn On GPS"
        android:textAllCaps="false"
        android:textSize="16sp" />


</LinearLayout>

来源:https://github.com/Pritish-git/turnOn_location

【讨论】:

虽然此代码可能对 OP 有用,但提供 additional context 说明其工作原理和方式以及何时应该使用它将通过帮助其他读者来提高其长期价值。 对已得到很好回答的旧问题的新答案需要充分解释它们如何补充其他答案。

以上是关于要求用户打开位置的主要内容,如果未能解决你的问题,请参考以下文章

如何要求用户打开位置

什么条件使 iOS 13 要求用户授予“始终”位置访问权限?

从应用程序中删除了核心位置,但仍被要求提供用户位置

即使用户没有打开应用程序,是不是可以在 android 中跟踪 GPS 位置

当前位置失败 GoogleMap

苹果拒绝应用程序要求提供访问位置目的字符串 Info.plist