蓝牙LE Scan在后台无法在Android M上运行 [英] Bluetooth LE Scan doesn't work on Android M in the background

查看:119
本文介绍了蓝牙LE Scan在后台无法在Android M上运行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下代码可在运行Android 5.1.1(构建LMY48M)的Nexus 9上很好地工作,但不能在运行Android 6.0(构建MPA44l)的Nexus 9上工作.

The following code works great on my Nexus 9 running Android 5.1.1 (Build LMY48M), but won't work on a Nexus 9 running Android 6.0 (Build MPA44l)

List<ScanFilter> filters = new ArrayList<ScanFilter>();
ScanSettings settings = (new ScanSettings.Builder().setScanMode(ScanSettings.SCAN_MODE_LOW_POWER)).build();
ScanFilter.Builder builder = new ScanFilter.Builder();
builder.setManufacturerData((int) 0x0118, new byte[]{(byte) 0xbe, (byte) 0xac}, new byte[]{(byte) 0xff, (byte)0xff});
ScanFilter scanFilter = builder.build();
filters.add(scanFilter);
mBluetoothLeScanner.startScan(filters, settings, new ScanCallback() {
  ...
});

在Android 5.x上,当看到与扫描过滤器匹配的制造商广告时,以上代码将产生回调. (请参阅下面的Logcat示例输出.)在具有MPA44l的Nexus 9上,未收到回调.如果您将扫描过滤器注释掉,则在Nexus 9上会成功接收到回调.

On Android 5.x, the above code yields a callback when a manufacturer advertisement matching the scan filter is seen. (See example Logcat output below.) On the Nexus 9 with MPA44l, no callbacks are received. If you comment out the scan filter, callbacks are received successfully on the Nexus 9.

09-22 00:07:28.050    1748-1796/org.altbeacon.beaconreference D/BluetoothLeScanner﹕ onScanResult() - ScanResult{mDevice=00:07:80:03:89:8C, mScanRecord=ScanRecord [mAdvertiseFlags=6, mServiceUuids=null, mManufacturerSpecificData={280=[-66, -84, 47, 35, 68, 84, -49, 109, 74, 15, -83, -14, -12, -111, 27, -87, -1, -90, 0, 1, 0, 1, -66, 0]}, mServiceData={}, mTxPowerLevel=-2147483648, mDeviceName=null], mRssi=-64, mTimestampNanos=61272522487278}

有人看到ScanFilters在Android M上工作吗?

Has anybody seen ScanFilters work on Android M?

推荐答案

问题不是扫描过滤器,而是仅当应用程序在后台时才使用扫描过滤器. (此解决方案已不再适用于Android 10,请参见下文..)从Android M开始,除非应用程序具有以下两个权限之一,否则将禁止在后台进行Bluetooth LE扫描:

The problem was not the scan filter, but that the scan filter was only being used when the app was in the background. ( This solution is out of date for Android 10 see below.) Starting with Android M, Bluetooth LE scanning in the background is blocked unless the app has one of the following two permissions:

android.permission.ACCESS_COARSE_LOCATION
android.permission.ACCESS_FINE_LOCATION

我正在测试的应用程序未请求这两个权限,因此在Android M上(后台扫描过滤器处于活动状态)仅在后台运行.添加第一个解决了该问题.

The app I was testing did not request either of these permissions, so it did not work in the background (the only time the scan filter was active) on Android M. Adding the first one solved the problem.

我意识到这是问题所在,因为我在Logcat中看到以下行:

I realized this was the problem because I saw the following line in Logcat:

09-22 22:35:20.152  5158  5254 E BluetoothUtils: Permission denial: Need ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission to get scan results

有关详细信息,请参见此处: https://code .google.com/p/android-developer-preview/issues/detail?id = 2964

See here for details: https://code.google.com/p/android-developer-preview/issues/detail?id=2964

从Android 10开始,粗略的位置是不够的-您需要精确的位置和特殊的背景权限才能在后台检测BLE广告和信标.请参见在您的AndroidManifest.xml中放置以下内容:

Place the following in your AndroidManifest.xml:

<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.ACCESS_BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

然后在您的活动中添加如下代码,以动态地向用户请求这些权限:

Then add code like follows to your Activity to dynamically request these permissions from the user:

    private static final int PERMISSION_REQUEST_FINE_LOCATION = 1;
    private static final int PERMISSION_REQUEST_BACKGROUND_LOCATION = 2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ...



        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (this.checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION)
                    == PackageManager.PERMISSION_GRANTED) {
                if (this.checkSelfPermission(Manifest.permission.ACCESS_BACKGROUND_LOCATION)
                        != PackageManager.PERMISSION_GRANTED) {
                    if (this.shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_BACKGROUND_LOCATION)) {
                        final AlertDialog.Builder builder = new AlertDialog.Builder(this);
                        builder.setTitle("This app needs background location access");
                        builder.setMessage("Please grant location access so this app can detect beacons in the background.");
                        builder.setPositiveButton(android.R.string.ok, null);
                        builder.setOnDismissListener(new DialogInterface.OnDismissListener() {

                            @TargetApi(23)
                            @Override
                            public void onDismiss(DialogInterface dialog) {
                                requestPermissions(new String[]{Manifest.permission.ACCESS_BACKGROUND_LOCATION},
                                        PERMISSION_REQUEST_BACKGROUND_LOCATION);
                            }

                        });
                        builder.show();
                    }
                    else {
                        final AlertDialog.Builder builder = new AlertDialog.Builder(this);
                        builder.setTitle("Functionality limited");
                        builder.setMessage("Since background location access has not been granted, this app will not be able to discover beacons in the background.  Please go to Settings -> Applications -> Permissions and grant background location access to this app.");
                        builder.setPositiveButton(android.R.string.ok, null);
                        builder.setOnDismissListener(new DialogInterface.OnDismissListener() {

                            @Override
                            public void onDismiss(DialogInterface dialog) {
                            }

                        });
                        builder.show();
                    }

                }
            } else {
                if (!this.shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_FINE_LOCATION)) {
                    requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION,
                                    Manifest.permission.ACCESS_BACKGROUND_LOCATION},
                            PERMISSION_REQUEST_FINE_LOCATION);
                }
                else {
                    final AlertDialog.Builder builder = new AlertDialog.Builder(this);
                    builder.setTitle("Functionality limited");
                    builder.setMessage("Since location access has not been granted, this app will not be able to discover beacons.  Please go to Settings -> Applications -> Permissions and grant location access to this app.");
                    builder.setPositiveButton(android.R.string.ok, null);
                    builder.setOnDismissListener(new DialogInterface.OnDismissListener() {

                        @Override
                        public void onDismiss(DialogInterface dialog) {
                        }

                    });
                    builder.show();
                }

            }
        }
    }

这篇关于蓝牙LE Scan在后台无法在Android M上运行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆