我想使用蓝牙低功耗(BLE)技术在两个支持的手机之间建立连接(目前我只想在Android手机上使用它,将来可能会支持iOS )。启动连接的客户端应该是API级别为19(KitKat)或更高级别的Android设备。
我已经阅读了几个教程并尝试了几个关于如何在Android上实现蓝牙LE扫描工作的示例(包括Google自己的示例项目BluetoothLeGatt)。基于Android文档和许多SO问题和答案,我的测试项目已经完成了以下工作:
BLUETOOTH
中授予的强制蓝牙权限(BLUETOOTH_ADMIN
和AndroidManifest.xml
)以及android.hardware.bluetooth_le
功能设置为true
值ACCESS_FINE_LOCATION
和ACCESS_COARSE_LOCATION
权限 - 因此它们也位于清单文件中(使用uses-permission
和uses-permission-sdk-23
标记),加上android.hardware.location.gps
功能已设置尽管上面列出了所有内容,启动扫描后没有找到设备。目前我正在使用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.
答案 0 :(得分:0)
我的问题的解决方案是更深入地了解BLE的工作原理。我需要意识到的是支持BLE的设备没有自动显示,例如您在蓝牙设置屏幕中找到的设备 - 我必须手动开始广告装置。所以我搜索了一个例子并找到了这个教程:Tuts+ - BluetoothLEAdvertising。通过这个例子,我开始宣传其中一个设备,然后我可以在另一个设备上找到该设备。所以,这是我的坏......:)
这也意味着目前扫描的结果不依赖于制造商,API级别,构建版本等......但我可以想象这些因素将来可能会引起一些麻烦......