Android - 低功耗蓝牙找不到任何设备

Android - Bluetooth LE can't find any device

我想使用低功耗蓝牙 (BLE) 技术在两个受支持的 手机 之间建立连接(目前我只想将其用于 Android电话,iOS 将来可能会支持)。启动连接的客户端应该是 Android 设备 API 级别 19 (KitKat) 或更高。

我已经阅读了几个教程并尝试了几个关于如何在 Android 上实现蓝牙 LE 扫描的示例(包括 Google 自己的名为 BluetoothLeGatt 的示例项目)。根据 Android 文档和许多 SO 问题和答案,我的测试项目中已经完成了以下事情:

尽管上面列出了所有内容,开始扫描后未找到任何设备。目前我正在使用 6.0(Marshmallow,API 23)设备,一切似乎都很好——除了发现我周围的设备打开了蓝牙并设置为始终可见。但是当然,从设​​备设置中我可以找到所有这些,所以我不明白什么可能是丢失/错误的东西(顺便说一下,这是我第一次处理与蓝牙相关的东西...... :))。看起来扫描过程是无缝启动的,但是 none 的回调方法正在响应任何单个消息或变量。

是的,我知道:关于这个问题有很多问题,人们说"everything works after making the changes above"。 .. 不幸的是 它对我不起作用,所以我对这个问题有点沮丧。如果有人阅读这个主题之前遇到过类似的事情,并在那里写下评论或回答,我将非常感激! :)


要使问题部分更长:

我的activity:

import android.Manifest;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothManager;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanResult;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

import java.util.List;

public class MainActivity extends AppCompatActivity {

    private BluetoothAdapter mBluetoothAdapter;
    private boolean mScanning;
    private Handler mHandler;

    public static final int REQUEST_ENABLE_BT = 1;
    private static final int PERMISSION_REQUEST = 2;
    private static final long SCAN_PERIOD = 10000;

    private BluetoothAdapter.LeScanCallback mLeScanCallback;
    private ScanCallback scanCallback;

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

        mLeScanCallback = new BluetoothAdapter.LeScanCallback() {
            @Override
            public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
                if (device != null)
                    Toast.makeText(MainActivity.this, "Device found", Toast.LENGTH_SHORT).show();
            }
        };

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            scanCallback = new ScanCallback() {
                @Override
                public void onScanResult(int callbackType, ScanResult result) {
                    Toast.makeText(MainActivity.this, "Device found", Toast.LENGTH_SHORT).show();
                    super.onScanResult(callbackType, result);
                }

                @Override
                public void onBatchScanResults(List<ScanResult> results) {
                    Toast.makeText(MainActivity.this, "Batch returned", Toast.LENGTH_SHORT).show();
                    super.onBatchScanResults(results);
                }

                @Override
                public void onScanFailed(int errorCode) {
                    Toast.makeText(MainActivity.this, errorCode, Toast.LENGTH_SHORT).show();
                    super.onScanFailed(errorCode);
                }
            };
        }

        //Getting user's permission on API 23+
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION}, PERMISSION_REQUEST);
        }

        mHandler = new Handler();

        final BluetoothManager bluetoothManager =
            (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
        mBluetoothAdapter = bluetoothManager.getAdapter();

        if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
            Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
        }

        //A simple button which starts scan
        Button button = (Button) findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                scanLeDevice(true);
            }
        });
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        if (requestCode == PERMISSION_REQUEST)
            Toast.makeText(this, "Permission settings changed", Toast.LENGTH_SHORT).show();

        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == REQUEST_ENABLE_BT)
            Toast.makeText(this, "Bluetooth settings changed", Toast.LENGTH_SHORT).show();

        super.onActivityResult(requestCode, resultCode, data);
    }

    private void scanLeDevice(final boolean enable) {
        if (enable) {
            // Stops scanning after a pre-defined scan period.
            mHandler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    mScanning = false;
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
                        mBluetoothAdapter.getBluetoothLeScanner().stopScan(scanCallback);
                    else
                        mBluetoothAdapter.stopLeScan(mLeScanCallback);
                }
            }, SCAN_PERIOD);

            mScanning = true;

            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
                mBluetoothAdapter.getBluetoothLeScanner().startScan(scanCallback);
            else
                mBluetoothAdapter.startLeScan(mLeScanCallback);

        } else {
            mScanning = false;
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
                mBluetoothAdapter.getBluetoothLeScanner().stopScan(scanCallback);
            else
                mBluetoothAdapter.stopLeScan(mLeScanCallback);
        }
    }
}

我的清单:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.gery.example.bluelowexample">

    <uses-permission android:name="android.permission.BLUETOOTH"/>
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>

    <uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>

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

    <uses-permission-sdk-23 android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission-sdk-23 android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-feature android:name="android.hardware.location.gps" />


    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

我认为这个 logcat 有一切可以提供帮助的东西(过滤器也已关闭),但如果您还遗漏了其他东西,请提出要求... ;)

05-17 09:56:24.578 270-455/? I/BufferQueueProducer: [com.gery.example.bluelowexample/com.gery.example.bluelowexample.MainActivity](this:0x7f8ea54000,id:150,api:1,p:9879,c:270) queueBuffer: fps=0.03 dur=90743.60 max=9    0572.86 min=12.21
05-17 09:56:24.578 9879-9879/com.gery.example.bluelowexample D/BluetoothAdapter: getLeState() returning 12
05-17 09:56:24.580 9879-9879/com.gery.example.bluelowexample D/BluetoothAdapter: getLeState() returning 12
05-17 09:56:24.580 9879-9879/com.gery.example.bluelowexample D/BluetoothAdapter: STATE_ON
05-17 09:56:24.583 9879-9879/com.gery.example.bluelowexample D/BluetoothAdapter: getLeState() returning 12
05-17 09:56:24.585 270-270/? D/MALI: eglCreateImageKHR:539: [Crop] 0 0 0 0  img[1080 1920] 
05-17 09:56:24.590 10966-11003/? D/BtGatt.GattService: registerClient() - UUID=61759f7a-608a-43b4-b530-5487c6d83d95
05-17 09:56:24.590 10966-10983/? D/BtGatt.GattService: onClientRegistered() - UUID=61759f7a-608a-43b4-b530-5487c6d83d95, clientIf=5
05-17 09:56:24.591 9879-9900/com.gery.example.bluelowexample D/BluetoothLeScanner: onClientRegistered() - status=0 clientIf=5
05-17 09:56:24.592 10966-10977/? D/BluetoothAdapter: 203350351: getState(). Returning 12
05-17 09:56:24.592 10966-10977/? D/BtGatt.GattService: start scan without filters
05-17 09:56:24.593 940-1736/? D/AppOps: noteOperation: allowing code 1 uid 10141 package com.gery.example.bluelowexample
05-17 09:56:24.593 10966-10986/? D/BtGatt.ScanManager: handling starting scan
05-17 09:56:24.593 9879-9879/com.gery.example.bluelowexample I/BluetoothLeScanner: startRegisteration: mLeScanClients={com.gery.example.bluelowexample.MainActivity@f    05890c=android.bluetooth.le.BluetoothLeScanner$BleScanCallbackWrapper@c4ace96}
05-17 09:56:24.594 10966-10986/? D/BluetoothAdapter: getLeState() returning 12
05-17 09:56:24.595 10966-10986/? D/BluetoothAdapter: getLeState() returning 12
05-17 09:56:24.595 270-270/? I/SurfaceFlinger: [Built-in Screen (type:0)] fps:0.287394,dur:6959.09,max:6952.73,min:6.36
05-17 09:56:24.597 10966-10986/? D/BluetoothAdapter: getLeState() returning 12
05-17 09:56:24.598 10966-10986/? I/BtGatt.ScanManager: configureScanFilters: client=com.android.bluetooth.gatt.ScanClient@24
05-17 09:56:24.598 10966-10986/? I/BtGatt.ScanManager: getDeliveryMode:  DELIVERY_MODE_IMMEDIATE
05-17 09:56:24.598 10966-10986/? I/BtGatt.ScanManager: gattClientScanFilterEnableNative(com.android.bluetooth.gatt.ScanClient@24,true);
05-17 09:56:24.609 10966-10983/? D/BtGatt.GattService: onScanFilterEnableDisabled() - clientIf=5, status=0, action=1
05-17 09:56:24.610 10966-10983/? D/BtGatt.ScanManager: callback done for clientIf - 5 status - 0
05-17 09:56:24.610 10966-10986/? I/BtGatt.ScanManager: configureScanFilters: shouldUseAllPassFilter
05-17 09:56:24.610 10966-10986/? I/BtGatt.ScanManager: getDeliveryMode:  DELIVERY_MODE_IMMEDIATE
05-17 09:56:24.610 10966-10986/? D/BtGatt.ScanManager: configureFilterParamter 500 10000 1 0
05-17 09:56:24.610 10966-10986/? I/BtGatt.ScanManager: configureFilterParamter: deliveryMode=0 ,rssiThreshold=-128
05-17 09:56:24.610 10966-10986/? I/BtGatt.ScanManager: gattClientScanFilterParamAddNative
05-17 09:56:24.612 10966-10983/? D/BtGatt.GattService: onScanFilterParamsConfigured() - clientIf=5, status=0, action=0, availableSpace=49
05-17 09:56:24.612 10966-10983/? D/BtGatt.ScanManager: callback done for clientIf - 5 status - 0
05-17 09:56:24.612 10966-10986/? I/BtGatt.ScanManager: gattClientScanNative(true);
05-17 09:56:24.612 10966-10986/? D/BtGatt.ScanManager: configureRegularScanParams() - queue=1
05-17 09:56:24.612 10966-10986/? D/BtGatt.ScanManager: configureRegularScanParams() - ScanSetting Scan mode=0 mLastConfiguredScanSetting=-2147483648
05-17 09:56:24.613 10966-10986/? I/BtGatt.ScanManager: gattClientScanNative(false);
05-17 09:56:24.613 10966-10986/? D/BtGatt.ScanManager: configureRegularScanParams - scanInterval = 8000configureRegularScanParams - scanWindow = 800
05-17 09:56:24.613 10966-10986/? I/BtGatt.ScanManager: gattClientScanNative(true);
05-17 09:56:24.613 10966-10983/? D/BtGatt.GattService: onScanParamSetupCompleted : 0
05-17 09:56:24.614 940-971/? E/PROXIMITY: ProximitySensor: unknown event (type=3, code=0)
05-17 09:56:24.615 940-963/? D/AutomaticBrightnessController: calculateAmbientLux: [0, 100]: lux=2745.0, weight=1005000.0
05-17 09:56:24.615 940-963/? D/AutomaticBrightnessController: calculateAmbientLux: [-249, 0]: lux=2733.0, weight=2458999.5
05-17 09:56:24.615 940-963/? D/AutomaticBrightnessController: calculateAmbientLux: [-499, -249]: lux=2750.0, weight=2406500.0
05-17 09:56:24.615 940-963/? D/AutomaticBrightnessController: calculateAmbientLux: totalWeight=5870499.5, newAmbientLux=2742.023
05-17 09:56:24.615 940-963/? D/AutomaticBrightnessController: updateAmbientLux: ambientLux=2742.023, timeToBrighten=4000, timeToDarken=8000, current=2691.0
05-17 09:56:24.615 940-963/? D/AutomaticBrightnessController: updateAmbientLux: Scheduling ambient lux update for 76758807675880 (in 3999 ms)
05-17 09:56:24.619 10966-10987/? W/bt_hci: filter_incoming_event command complete event with no matching command. opcode: 0x200c.

我的问题的解决方案是更深入地了解 BLE 的工作原理。我需要意识到的是,支持 BLE 的设备不会自动显示自己,例如您在蓝牙设置屏幕中找到的设备 - 我必须手动[=18] =] 开始设备的广告。所以我搜索了一个例子并找到了这个教程:Tuts+ - BluetoothLEAdvertising。在这个例子中,我开始为其中一台设备做广告,然后我可以在另一台设备上找到该设备。所以,这是我的错... :)

这也意味着目前扫描的结果不依赖于制造商、API级别、构建版本等......但我可以想象这些因素可能会在未来造成一些麻烦.. .