请求 ACCESS_COARSE_LOCATION 的权限后按允许不会打开位置 - 牛轧糖
Pressing allows after requesting permission for ACCESS_COARSE_LOCATION doesn't turn on location - nougat
最后我 运行 遇到了一个问题,由于缺少 ACCESS_COARSE_LOCATION 或 ACCESS_FINE_LOCATION,我无法扫描信标。
我尝试使用找到的代码 here 来修复它,但它实际上对我有部分帮助。
当这个视图出现时
我点击允许。之后我不再收到此 java.lang.SecurityException: Need ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission to get scan results
错误,但我仍然看不到我的信标,当我打开设置视图时,位置已关闭,如下图所示。
当我通过手指打开位置时,一切正常,所以我可以看到我的信标和应用程序正常工作。这里的问题是这些是某种错误,还是我错过了在打开对设备位置的访问后从代码后面打开位置的东西?
为了开发,我将 Nexus 5x 与 android 7.1.1.
一起使用
已编辑:
代码是从上面链接的教程中复制的,带有启动信标扫描器按钮的片段:
public void onBleClicked(View view)
{
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("This app needs location access");
builder.setMessage("Please grant location access so this app can detect beacons.");
builder.setPositiveButton(android.R.string.ok, null);
builder.setOnDismissListener(new DialogInterface.OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialog) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, PERMISSION_REQUEST_COARSE_LOCATION);
}
}
});
builder.show();
}
BleManager bleManager = new BleManager(this);
bleManager.tryToTurnOnBle();
}
声明权限的清单片段:
<!-- app only for phones -->
<uses-feature android:name="android.hardware.telephony"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
蓝牙权限显然在库中。
我现在发现的事实是,我有类似的问题here。
但是这个将用户重定向到位置选项屏幕的解决方案对我来说似乎不是一个干净的解决方案。
从 Android Marshmallow (6.0) 开始,必须在设置中打开位置,应用才能扫描包括信标在内的蓝牙 LE 设备。此要求是对应用程序获取动态权限的要求的补充。您可以看到下面的代码来查询正在打开的位置服务,并在需要时提示用户打开它。
private void verifyLocationServices() {
final LocationManager manager = (LocationManager) getSystemService(this.LOCATION_SERVICE);
if (!manager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage("This app requires that location services be enabled. Please enable location in settings.")
.setCancelable(false)
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
public void onClick(final DialogInterface dialog, final int id) {
startActivity(new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS));
}
});
final AlertDialog alert = builder.create();
alert.show();
}
}
可以通过两种方式确定位置:
1.Using NETWORK_PROVIDER
2.Using GPS_PROVIDER
NETWORK_PROVIDER: 它确定使用基站、wifi 接入点的用户的位置。它通常用于确定房间或建筑物内的位置。 此处获取不到GPS坐标
您可以指定
<uses-permission android:name=”android.permission.ACCESS_COARSE_LOCATION” />
或
<uses-permission android:name=”android.permission.ACCESS_FINE_LOCATION” />
为了使用 NETWORK_PROVIDER 获取位置。
GPS_PROVIDER:
它确定使用卫星的用户的位置。为此,获取 GPS 坐标并将其用于定位。智能手机中的 GPS 接收器接收来自卫星的信号。这些信号经过处理并且精确定位 determined.It 在户外效果更好 – 直接 sky/satellite 视图和通信发生。
您需要指定权限
<uses-permission android:name=”android.permission.ACCESS_FINE_LOCATION” />
为了使用来自 GPS_PROVIDER 的位置。
好的位置:
它提供了更好、更准确的位置。因此,我建议您使用它来获取您的信标位置。它允许同时使用 GPS_PROVIDER 和 NETWORK_PROVIDER 或 GPS_PROVIDER 仅用于确定位置。
粗略位置:
它提供不太准确的 locations.It 允许使用 NETWORK_PROVIDER 仅用于确定位置。
现在,开始实施吧。
- 在 AnroidManifest.xml 文件中声明上述两个权限:
- 在 java 部分,执行以下操作:
如果尚未授予权限,则请求权限:
private void requestPermission(Activity activity) {
ActivityCompat.requestPermissions(activity, new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.CALL_PHONE}, MainActivity.PERMISSION_REQUEST_CODE_LOCATION);
}
调用上述方法时,会出现询问权限的对话框。选择允许或拒绝时,将触发以下回调。
在 onRequestPermissionsResult
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case PERMISSION_REQUEST_CODE_LOCATION:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
boolean isGpsProviderEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
boolean isNetworkProviderEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
//Location permission is given. Check if the providers are available and start location updates.
if (isGpsProviderEnabled && isNetworkProviderEnabled) {
startLocationUpdates();
} else {
Log.d(TAG, "GPS and Network providers are disabled");
}
} else if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_DENIED) {
boolean should = ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this, Manifest.permission.ACCESS_FINE_LOCATION);
if (should) {
ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, MainActivity.PERMISSION_REQUEST_CODE_LOCATION);
} else {
promptSettings();
}
}
}
}
在 promptSettings() 方法中,让用户从“设置”屏幕启用位置。
private void promptSettings() {
AlertDialog.Builder builder;
builder = new AlertDialog.Builder(MainActivity.this);
builder.setTitle(getResources().getString(R.string.unable_to_find_location));
builder.setMessage(getResources().getString(R.string.message_denied_location_permission));
builder.setCancelable(false);
builder.setPositiveButton(getResources().getString(R.string.go_to_settings), (dialog, which) -> {
dialog.dismiss();
builder = null;
if (!checkPermission(MainActivity.this)) {
goToSettings();
}
});
builder.show();
}
在检查权限方法中:
public boolean checkPermission(Context context) {
int result = ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION);
return result == PackageManager.PERMISSION_GRANTED;
}
goToSettings() 允许用户转到设置屏幕:
private void goToSettings() {
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
Uri uri = Uri.fromParts("package", getPackageName(), null);
intent.setData(uri);
startActivityForResult(intent, 1);
}
注意:您需要在清单中授予以下权限才能扫描信标。我希望你这样做,如果没有请这样做。
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
最后我 运行 遇到了一个问题,由于缺少 ACCESS_COARSE_LOCATION 或 ACCESS_FINE_LOCATION,我无法扫描信标。
我尝试使用找到的代码 here 来修复它,但它实际上对我有部分帮助。
当这个视图出现时java.lang.SecurityException: Need ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission to get scan results
错误,但我仍然看不到我的信标,当我打开设置视图时,位置已关闭,如下图所示。
当我通过手指打开位置时,一切正常,所以我可以看到我的信标和应用程序正常工作。这里的问题是这些是某种错误,还是我错过了在打开对设备位置的访问后从代码后面打开位置的东西?
为了开发,我将 Nexus 5x 与 android 7.1.1.
一起使用已编辑: 代码是从上面链接的教程中复制的,带有启动信标扫描器按钮的片段:
public void onBleClicked(View view)
{
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("This app needs location access");
builder.setMessage("Please grant location access so this app can detect beacons.");
builder.setPositiveButton(android.R.string.ok, null);
builder.setOnDismissListener(new DialogInterface.OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialog) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, PERMISSION_REQUEST_COARSE_LOCATION);
}
}
});
builder.show();
}
BleManager bleManager = new BleManager(this);
bleManager.tryToTurnOnBle();
}
声明权限的清单片段:
<!-- app only for phones -->
<uses-feature android:name="android.hardware.telephony"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
蓝牙权限显然在库中。
我现在发现的事实是,我有类似的问题here。 但是这个将用户重定向到位置选项屏幕的解决方案对我来说似乎不是一个干净的解决方案。
从 Android Marshmallow (6.0) 开始,必须在设置中打开位置,应用才能扫描包括信标在内的蓝牙 LE 设备。此要求是对应用程序获取动态权限的要求的补充。您可以看到下面的代码来查询正在打开的位置服务,并在需要时提示用户打开它。
private void verifyLocationServices() {
final LocationManager manager = (LocationManager) getSystemService(this.LOCATION_SERVICE);
if (!manager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage("This app requires that location services be enabled. Please enable location in settings.")
.setCancelable(false)
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
public void onClick(final DialogInterface dialog, final int id) {
startActivity(new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS));
}
});
final AlertDialog alert = builder.create();
alert.show();
}
}
可以通过两种方式确定位置:
1.Using NETWORK_PROVIDER
2.Using GPS_PROVIDER
NETWORK_PROVIDER: 它确定使用基站、wifi 接入点的用户的位置。它通常用于确定房间或建筑物内的位置。 此处获取不到GPS坐标
您可以指定
<uses-permission android:name=”android.permission.ACCESS_COARSE_LOCATION” />
或
<uses-permission android:name=”android.permission.ACCESS_FINE_LOCATION” />
为了使用 NETWORK_PROVIDER 获取位置。
GPS_PROVIDER: 它确定使用卫星的用户的位置。为此,获取 GPS 坐标并将其用于定位。智能手机中的 GPS 接收器接收来自卫星的信号。这些信号经过处理并且精确定位 determined.It 在户外效果更好 – 直接 sky/satellite 视图和通信发生。
您需要指定权限
<uses-permission android:name=”android.permission.ACCESS_FINE_LOCATION” />
为了使用来自 GPS_PROVIDER 的位置。
好的位置: 它提供了更好、更准确的位置。因此,我建议您使用它来获取您的信标位置。它允许同时使用 GPS_PROVIDER 和 NETWORK_PROVIDER 或 GPS_PROVIDER 仅用于确定位置。
粗略位置: 它提供不太准确的 locations.It 允许使用 NETWORK_PROVIDER 仅用于确定位置。
现在,开始实施吧。 - 在 AnroidManifest.xml 文件中声明上述两个权限: - 在 java 部分,执行以下操作: 如果尚未授予权限,则请求权限:
private void requestPermission(Activity activity) {
ActivityCompat.requestPermissions(activity, new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.CALL_PHONE}, MainActivity.PERMISSION_REQUEST_CODE_LOCATION);
}
调用上述方法时,会出现询问权限的对话框。选择允许或拒绝时,将触发以下回调。
在 onRequestPermissionsResult
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case PERMISSION_REQUEST_CODE_LOCATION:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
boolean isGpsProviderEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
boolean isNetworkProviderEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
//Location permission is given. Check if the providers are available and start location updates.
if (isGpsProviderEnabled && isNetworkProviderEnabled) {
startLocationUpdates();
} else {
Log.d(TAG, "GPS and Network providers are disabled");
}
} else if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_DENIED) {
boolean should = ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this, Manifest.permission.ACCESS_FINE_LOCATION);
if (should) {
ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, MainActivity.PERMISSION_REQUEST_CODE_LOCATION);
} else {
promptSettings();
}
}
}
}
在 promptSettings() 方法中,让用户从“设置”屏幕启用位置。
private void promptSettings() {
AlertDialog.Builder builder;
builder = new AlertDialog.Builder(MainActivity.this);
builder.setTitle(getResources().getString(R.string.unable_to_find_location));
builder.setMessage(getResources().getString(R.string.message_denied_location_permission));
builder.setCancelable(false);
builder.setPositiveButton(getResources().getString(R.string.go_to_settings), (dialog, which) -> {
dialog.dismiss();
builder = null;
if (!checkPermission(MainActivity.this)) {
goToSettings();
}
});
builder.show();
}
在检查权限方法中:
public boolean checkPermission(Context context) {
int result = ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION);
return result == PackageManager.PERMISSION_GRANTED;
}
goToSettings() 允许用户转到设置屏幕:
private void goToSettings() {
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
Uri uri = Uri.fromParts("package", getPackageName(), null);
intent.setData(uri);
startActivityForResult(intent, 1);
}
注意:您需要在清单中授予以下权限才能扫描信标。我希望你这样做,如果没有请这样做。
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>