如何在运行时请求位置权限

boj*_*jan 51 java android

在清单文件中,我添加了粗略和精细的权限,当我在使用Android 6的设备上运行时,没有任何反应!我尝试了一切,但无法获得位置更新......

我究竟做错了什么?

public class MainActivity extends AppCompatActivity implements LocationListener {

    LocationManager locationManager;
    String provider;

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

        locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);

        provider = locationManager.getBestProvider(new Criteria(), false);

        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            // TODO: Consider calling
            //    ActivityCompat#requestPermissions
            // here to request the missing permissions, and then overriding
            //   public void onRequestPermissionsResult(int requestCode, String[] permissions,
            //                                          int[] grantResults)
            // to handle the case where the user grants the permission. See the documentation
            // for ActivityCompat#requestPermissions for more details.
            return;
        }
        Location location = locationManager.getLastKnownLocation(provider);

        if (location != null) {

            Log.i("Location Info", "Location achieved!");

        } else {

            Log.i("Location Info", "No location :(");

        }

    }


    @Override
    protected void onResume() {
        super.onResume();

        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            // TODO: Consider calling
            //    ActivityCompat#requestPermissions
            // here to request the missing permissions, and then overriding
            //   public void onRequestPermissionsResult(int requestCode, String[] permissions,
            //                                          int[] grantResults)
            // to handle the case where the user grants the permission. See the documentation
            // for ActivityCompat#requestPermissions for more details.
            return;
        }
        locationManager.requestLocationUpdates(provider, 400, 1, this);

    }

    @Override
    protected void onPause() {
        super.onPause();

        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            // TODO: Consider calling
            //    ActivityCompat#requestPermissions
            // here to request the missing permissions, and then overriding
            //   public void onRequestPermissionsResult(int requestCode, String[] permissions,
            //                                          int[] grantResults)
            // to handle the case where the user grants the permission. See the documentation
            // for ActivityCompat#requestPermissions for more details.
            return;
        }
        locationManager.removeUpdates(this);

    }

    @Override
    public void onLocationChanged(Location location) {

        Double lat = location.getLatitude();
        Double lng = location.getLongitude();

        Log.i("Location info: Lat", lat.toString());
        Log.i("Location info: Lng", lng.toString());

    }

    @Override
    public void onStatusChanged(String provider, int status, Bundle extras) {

    }

    @Override
    public void onProviderEnabled(String provider) {

    }

    @Override
    public void onProviderDisabled(String provider) {

    }

    public void getLocation(View view) {

        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            // TODO: Consider calling
            //    ActivityCompat#requestPermissions
            // here to request the missing permissions, and then overriding
            //   public void onRequestPermissionsResult(int requestCode, String[] permissions,
            //                                          int[] grantResults)
            // to handle the case where the user grants the permission. See the documentation
            // for ActivityCompat#requestPermissions for more details.
            return;
        }
        Location location = locationManager.getLastKnownLocation(provider);

        onLocationChanged(location);


    }

}
Run Code Online (Sandbox Code Playgroud)

Dan*_*ent 91

您需要在运行时实际请求位置权限(请注意代码中的注释,说明这一点).

这是经过测试和运行的代码,用于请求位置权限.

一定要导入android.Manifest:

import android.Manifest;
Run Code Online (Sandbox Code Playgroud)

然后将此代码放在Activity中:

public static final int MY_PERMISSIONS_REQUEST_LOCATION = 99;

public boolean checkLocationPermission() {
    if (ContextCompat.checkSelfPermission(this,
            Manifest.permission.ACCESS_FINE_LOCATION)
            != PackageManager.PERMISSION_GRANTED) {

        // Should we show an explanation?
        if (ActivityCompat.shouldShowRequestPermissionRationale(this,
                Manifest.permission.ACCESS_FINE_LOCATION)) {

            // Show an explanation to the user *asynchronously* -- don't block
            // this thread waiting for the user's response! After the user
            // sees the explanation, try again to request the permission.
            new AlertDialog.Builder(this)
                    .setTitle(R.string.title_location_permission)
                    .setMessage(R.string.text_location_permission)
                    .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialogInterface, int i) {
                            //Prompt the user once explanation has been shown
                            ActivityCompat.requestPermissions(MainActivity.this,
                                    new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
                                    MY_PERMISSIONS_REQUEST_LOCATION);
                        }
                    })
                    .create()
                    .show();


        } else {
            // No explanation needed, we can request the permission.
            ActivityCompat.requestPermissions(this,
                    new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
                    MY_PERMISSIONS_REQUEST_LOCATION);
        }
        return false;
    } else {
        return true;
    }
}

@Override
public void onRequestPermissionsResult(int requestCode,
                                       String permissions[], int[] grantResults) {
    switch (requestCode) {
        case MY_PERMISSIONS_REQUEST_LOCATION: {
            // If request is cancelled, the result arrays are empty.
            if (grantResults.length > 0
                    && grantResults[0] == PackageManager.PERMISSION_GRANTED) {

                // permission was granted, yay! Do the
                // location-related task you need to do.
                if (ContextCompat.checkSelfPermission(this,
                        Manifest.permission.ACCESS_FINE_LOCATION)
                        == PackageManager.PERMISSION_GRANTED) {

                    //Request location updates:
                    locationManager.requestLocationUpdates(provider, 400, 1, this);
                }

            } else {

                // permission denied, boo! Disable the
                // functionality that depends on this permission.

            }
            return;
        }

    }
}
Run Code Online (Sandbox Code Playgroud)

然后调用checkLocationPermission()方法onCreate():

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

    //.........

    checkLocationPermission();
}
Run Code Online (Sandbox Code Playgroud)

然后onResume(),您可以使用并onPause()完全按照问题使用.

这是一个更简洁的浓缩版本:

@Override
protected void onResume() {
    super.onResume();
    if (ContextCompat.checkSelfPermission(this,
            Manifest.permission.ACCESS_FINE_LOCATION)
            == PackageManager.PERMISSION_GRANTED) {

        locationManager.requestLocationUpdates(provider, 400, 1, this);
    }
}

@Override
protected void onPause() {
    super.onPause();
    if (ContextCompat.checkSelfPermission(this,
            Manifest.permission.ACCESS_FINE_LOCATION)
            == PackageManager.PERMISSION_GRANTED) {

        locationManager.removeUpdates(this);
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 很好的例子。谢谢!。请注意陷阱......确保您使用的是“android.Manifest”。Android Studio 似乎默认使用“my.app.package.Manifest”。 (2认同)
  • @hexicle你是对的。我只是按原样运行了这段代码,它肯定无法正常工作。最简单的解决方法是改为在onCreate()中调用`checkLocationPermission()`,因此我修改了答案。使用此解决方案,您可以完全按照问题中的方式使用onResume()和onPause()。谢谢您引起我的注意,干杯! (2认同)

And*_*ree 16

Android 10Android Q 中的位置权限隐私更改。

我们必须定义额外ACCESS_BACKGROUND_LOCATION权限,如果用户想访问他们的当前位置在后台这样用户需要获准运行时requestPermission()

如果我们使用低于10的Android设备,然后ACCESS_BACKGROUND_LOCATION允许自动允许使用ACCESS_FINE_LOCATIONACCESS_COARSE_LOCATION许可

如果我们不在ACCESS_BACKGROUND_LOCATION清单文件中指定,这种表格格式可能很容易理解。

在此处输入图片说明

AndroidManifest.xml

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" /> // here we defined ACCESS_BACKGROUND_LOCATION for Android 10 device
Run Code Online (Sandbox Code Playgroud)

MainActivity.java
通话checkRunTimePermission()onCreate()onResume()

public void checkRunTimePermission() {
   if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        if (ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED || 
             ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED||
             ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_BACKGROUND_LOCATION) == PackageManager.PERMISSION_GRANTED) {
                gpsTracker = new GPSTracker(context);

        } else {
                requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION},
                        10);
        }
   } else {
            gpsTracker = new GPSTracker(context); //GPSTracker is class that is used for retrieve user current location
   }
}

 @Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if (requestCode == 10) {
        if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            gpsTracker = new GPSTracker(context);
        } else {
            if (!ActivityCompat.shouldShowRequestPermissionRationale((Activity) context, Manifest.permission.ACCESS_FINE_LOCATION)) {
                // If User Checked 'Don't Show Again' checkbox for runtime permission, then navigate user to Settings
                AlertDialog.Builder dialog = new AlertDialog.Builder(context);
                dialog.setTitle("Permission Required");
                dialog.setCancelable(false);
                dialog.setMessage("You have to Allow permission to access user location");
                dialog.setPositiveButton("Settings", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        Intent i = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Uri.fromParts("package",
                                context.getPackageName(), null));
                        //i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                        startActivityForResult(i, 1001);
                    }
                });
                AlertDialog alertDialog = dialog.create();
                alertDialog.show();
            }
            //code for deny
        }
    }
}

@Override
public void startActivityForResult(Intent intent, int requestCode) {
    super.startActivityForResult(intent, requestCode);
    switch (requestCode) {
        case 1001:
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                if (ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED ||
                        ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED 
                        || ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_BACKGROUND_LOCATION) == PackageManager.PERMISSION_GRANTED) {
                    gpsTracker = new GPSTracker(context);
                    if (gpsTracker.canGetLocation()) {
                        latitude = gpsTracker.getLatitude();
                        longitude = gpsTracker.getLongitude();
                    }
                } else {
                    requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION,
                        Manifest.permission.ACCESS_BACKGROUND_LOCATION},10);
                }
            }
            break;
        default:
            break;
    }
}
Run Code Online (Sandbox Code Playgroud)

build.gradle(应用程序级别)

android {
    compileSdkVersion 29 //should be >= 29
    buildToolsVersion "29.0.2"
    useLibrary 'org.apache.http.legacy'
    defaultConfig {
        applicationId "com.example.runtimepermission"
        minSdkVersion 21
        targetSdkVersion 29 //should be >= 29
        versionCode 1
        versionName "1.0"
        multiDexEnabled true
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        vectorDrawables.useSupportLibrary = true
    }
}
Run Code Online (Sandbox Code Playgroud)

在这里你可以找到GPSTracker.java文件代码


Yas*_*has 10

谷歌已经创建了一个易于权限管理的库.它叫做EasyPermissions

以下是使用此库请求位置权限的简单示例.

public class MainActivity extends AppCompatActivity {

    private final int REQUEST_LOCATION_PERMISSION = 1;

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

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);

        // Forward results to EasyPermissions
        EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this);
    }

    @AfterPermissionGranted(REQUEST_LOCATION_PERMISSION)
    public void requestLocationPermission() {
        String[] perms = {Manifest.permission.ACCESS_FINE_LOCATION};
        if(EasyPermissions.hasPermissions(this, perms)) {
            Toast.makeText(this, "Permission already granted", Toast.LENGTH_SHORT).show();
        }
        else {
            EasyPermissions.requestPermissions(this, "Please grant the location permission", REQUEST_LOCATION_PERMISSION, perms);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

@AfterPermissionsGranted(REQUEST_CODE)用于指示在REQUEST_CODE授予请求代码的权限请求之后需要执行的方法.

在上述情况下,requestLocationPermission()如果用户授予访问位置服务的许可,则调用方法方法.因此,该方法既充当回调又充当请求权限的方法.

您可以为授予的权限和拒绝权限实现单独的回调.它在github页面中解释.

  • 提到这个图书馆非常有帮助,非常感谢 (2认同)

mas*_*wok 6

下面是我在 28 及以下、29 和 30 上请求前台和后台位置权限的解决方案。API 之间的差异很微妙但很重要。

API 28及以下版本,系统将前台和后台位置权限视为相同。如果您授予位置权限,则应用程序将隐式授予这两种权限。

API 29,可以同时请求前台和后台权限。

API 30,您必须请求前台位置权限,然后在授予前台位置权限后才请求后台位置权限。如果您同时请求前台和后台权限,那么系统将忽略该请求。另一个区别是用户必须在应用程序位置权限设置中允许后台位置权限,而不是通过系统对话框。

下面的解决方案仅在用户接受前台和后台位置跟踪后才启动指定的操作(例如后台位置跟踪):

LocationPermissionUtil.kt

private const val REQUEST_CODE_FOREGROUND = 1
private const val REQUEST_CODE_FOREGROUND_AND_BACKGROUND = 2

object LocationPermissionUtil {

    private fun Context.isPermissionGranted(permission: String): Boolean = ActivityCompat
        .checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED

    private val Context.isFineLocationPermissionGranted
        get() = isPermissionGranted(
            Manifest.permission.ACCESS_FINE_LOCATION
        )

    private val Context.isBackgroundPermissionGranted
        get() = when {
            Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q -> ActivityCompat.checkSelfPermission(
                this,
                Manifest.permission.ACCESS_BACKGROUND_LOCATION
            ) == PackageManager.PERMISSION_GRANTED
            else -> isFineLocationPermissionGranted
        }

    private val Context.isFineAndBackgroundLocationPermissionsGranted
        get() = isFineLocationPermissionGranted && isBackgroundPermissionGranted

    private fun Activity.checkFineLocationPermission() {
        if (isFineLocationPermissionGranted) return

        val shouldShowFineLocationPermissionRationale = ActivityCompat
            .shouldShowRequestPermissionRationale(
                this,
                Manifest.permission.ACCESS_FINE_LOCATION
            )

        if (shouldShowFineLocationPermissionRationale) {
            presentAlertDialog(
                R.string.dialog_fine_location_rationale_title,
                R.string.dialog_fine_location_rationale_description,
                R.string.yes,
            ) {
                requestLocationPermissions()
            }
        } else {
            requestLocationPermissions()
        }
    }

    private fun Activity.requestLocationPermissions() =
        if (Build.VERSION.SDK_INT == Build.VERSION_CODES.Q) {
            requestFineLocationAndBackground()
        } else {
            ActivityCompat.requestPermissions(
                this,
                arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
                REQUEST_CODE_FOREGROUND
            )
        }

    @TargetApi(29)
    private fun Activity.requestFineLocationAndBackground() {
        ActivityCompat.requestPermissions(
            this,
            arrayOf(
                Manifest.permission.ACCESS_FINE_LOCATION,
                Manifest.permission.ACCESS_BACKGROUND_LOCATION
            ),
            REQUEST_CODE_FOREGROUND_AND_BACKGROUND
        )
    }

    @TargetApi(29)
    private fun Activity.checkBackgroundLocationPermission() {
        if (isFineAndBackgroundLocationPermissionsGranted) return

        val shouldShowBackgroundPermissionRationale = ActivityCompat
            .shouldShowRequestPermissionRationale(
                this,
                Manifest.permission.ACCESS_BACKGROUND_LOCATION
            )

        if (shouldShowBackgroundPermissionRationale) {
            presentAlertDialog(
                R.string.dialog_background_location_rationale_title,
                R.string.dialog_background_location_rationale_description,
                R.string.yes,
            ) {
                requestFineLocationAndBackground()
            }
        } else {
            requestFineLocationAndBackground()
        }
    }

    fun checkLocationPermissions(activity: Activity, action: () -> Unit) = with(activity) {
        if (isFineAndBackgroundLocationPermissionsGranted) {
            action()
            return
        }

        checkFineLocationPermission()
    }

    fun onRequestPermissionsResult(
        activity: Activity,
        requestCode: Int,
        action: () -> Unit
    ) = with(activity) {
        when (requestCode) {
            REQUEST_CODE_FOREGROUND -> {
                if (!isFineLocationPermissionGranted) {
                    checkFineLocationPermission()
                    return
                }

                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
                    checkBackgroundLocationPermission()
                } else {
                    action()
                }
            }
            REQUEST_CODE_FOREGROUND_AND_BACKGROUND -> {
                if (!isFineLocationPermissionGranted) {
                    checkFineLocationPermission()
                    return
                }

                if (isBackgroundPermissionGranted) {
                    action()
                } else {
                    checkBackgroundLocationPermission()
                }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

活动:

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContentView(R.layout.activity_main)

        LocationPermissionUtil.checkLocationPermissions(this, this::onLocationPermissionsGranted)
    }

    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<out String>,
        grantResults: IntArray
    ) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)

        LocationPermissionUtil.onRequestPermissionsResult(
            this,
            requestCode,
            this::onLocationPermissionsGranted
        )
    }

    private fun onLocationPermissionsGranted() {
        Toast.makeText(
            this,
            "Background location permitted, starting location tracking...",
            Toast.LENGTH_LONG
        ).show()
    }

}
Run Code Online (Sandbox Code Playgroud)

  • 你好@masterwok什么是presentAlertDialog?Android studio 无法解决这个问题。 (2认同)