Android - 蓝牙LE无法找到任何设备

时间:2017-05-17 08:15:42

标签: android bluetooth-lowenergy android-bluetooth android-version

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

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

  • 最低SDK版本设置在API级别18(Android开始支持蓝牙LE的位置)
  • BLUETOOTH中授予的强制蓝牙权限(BLUETOOTH_ADMINAndroidManifest.xml)以及android.hardware.bluetooth_le功能设置为true
  • API级别23及更高版本上也需要ACCESS_FINE_LOCATIONACCESS_COARSE_LOCATION权限 - 因此它们也位于清单文件中(使用uses-permissionuses-permission-sdk-23标记),加上android.hardware.location.gps功能已设置
  • 还要求用户在应用首次启动时授予上述权限
  • 蓝牙和位置(GPS)已开启
  • 在授予权限(通过单击按钮进行管理)
  • 后启动扫描设备
  • 在API级别21及更高版本上使用较新的API方法,而不是自相同API级别以来不推荐使用的方法

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

并且是的,我知道:关于这一点有很多问题,人们说"在进行上述更改之后一切正常" ......不幸的是它对我不起作用,所以我对这个问题有点沮丧。如果有人在阅读这个主题之前遇到类似的事情,并在那里写评论或回答,我将非常感激! :)

使问题部分更长一些:

我的活动:

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$2@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.

1 个答案:

答案 0 :(得分:0)

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

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