0

最后我遇到了一个问题,由于缺少 ACCESS_COARSE_LOCATION 或 ACCESS_FINE_LOCATION,我无法扫描信标。

我尝试使用此处找到的代码来修复它找到的代码来修复它,但它实际上对我有部分帮助。

当此视图出现时在此处输入图像描述 ,我单击允许。之后我不再收到此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" />

蓝牙权限显然在库中。

我现在发现的是,这里有类似的问题。但是这种将用户重定向到位置选项屏幕的解决方案对我来说似乎并不干净。

4

2 回答 2

3

位置可以通过两种方式确定:

1.使用 NETWORK_PROVIDER

2.使用 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 接收器接收来自卫星的信号。对这些信号进行处理并确定精确位置。它在户外工作得更好——直接的天空/卫星视图和通信发生。

您需要指定权限

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

为了使用来自 GPS_PROVIDER 的位置。

精细位置: 它提供了更好、更准确的位置。因此,我建议您使用它来获取信标位置。它允许使用 GPS_PROVIDER 和 NETWORK_PROVIDER 或 GPS_PROVIDER 仅用于确定位置。

粗略的位置: 它提供不太准确的位置。它允许使用 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"/>
于 2016-12-19T07:13:04.147 回答
0

从 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();
        }
}
于 2016-12-18T17:03:53.340 回答