连接到 BLE 设备
Connect to BLE device
所以我制作了这个应用程序,我可以在其中找到所有具有名称的 BLE 设备。但是我怎样才能使特定字段之一可点击并自动连接到设备,这样我就可以从它开始writing/reading?
适配器
public class ListAdapter_BTLE_Devices extends ArrayAdapter<BTLE_Device> {
Activity activity;
int layoutResourceID;
ArrayList<BTLE_Device> devices;
public ListAdapter_BTLE_Devices(Activity activity, int resource, ArrayList<BTLE_Device> objects) {
super(activity.getApplicationContext(), resource, objects);
this.activity = activity;
layoutResourceID = resource;
devices = objects;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
LayoutInflater inflater =
(LayoutInflater) activity.getApplicationContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(layoutResourceID, parent, false);
}
BTLE_Device device = devices.get(position);
String name = device.getName();
String address = device.getAddress();
int rssi = device.getRSSI();
TextView BLE_name = (TextView) convertView.findViewById(R.id.BLE_name);
if (name != null && name.length() > 0) {
BLE_name.setText(device.getName());
}
else {
BLE_name.setText("No Name");
}
TextView BLE_rssi = (TextView) convertView.findViewById(R.id.BLE_rssi);
BLE_rssi.setText("RSSI: " + Integer.toString(rssi));
TextView BLE_macaddr = (TextView) convertView.findViewById(R.id.BLE_macaddr);
if (address != null && address.length() > 0) {
BLE_macaddr.setText("MAC-addr: "+device.getAddress());
}
else {
BLE_macaddr.setText("No Address");
}
return convertView;
}
}
编辑
我想我现在可能已经连接到 GATT,所以我所做的是..
首先,我从 Mainactivity 中获取 MAC-addr,然后将其保存在意图中,并启动另一个 activity onclick。
在这里我做了以下
DeviceAddress = intent.getStringExtra(MainActivity.EXTRAS_BLE_ADDRESS);
BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(DeviceAddress);
device.connectGatt(this, false, mGattCallback);
当我调用 connectGatt 时,它会打印消息 Log.d(TAG, "Connection State: 1");
,这是正确的方法吗?
private BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
Log.d(TAG, "Connection State Change: "+status+" -> "+connectionState(newState));
if (status == BluetoothGatt.GATT_SUCCESS && newState == BluetoothProfile.STATE_CONNECTED) {
/*
* Once successfully connected, we must next discover all the services on the
* device before we can read and write their characteristics.
*/
Log.d(TAG, "Connection State: 1");
gatt.discoverServices();
} else if (status == BluetoothGatt.GATT_SUCCESS && newState == BluetoothProfile.STATE_DISCONNECTED) {
/*
* If at any point we disconnect, send a message to clear the weather values
* out of the UI
*/
Log.d(TAG, "Connection State: 2");
} else if (status != BluetoothGatt.GATT_SUCCESS) {
/*
* If there is a failure at any stage, simply disconnect
*/
Log.d(TAG, "Connection State: 3");
gatt.disconnect();
}
}
您可以向您的 holder 添加一个视图并为其设置一个点击监听器。视图可以是围绕您的显示卡(或您使用的任何内容)的透明矩形。
我建议 this 深入阅读有关 BLE 用法的内容。在点击侦听器上,您可以对连接请求进行排队。
要首先连接到设备,您必须执行 BLE 扫描(如果您使用启动代码)运行回调并将其添加到找到的设备列表中。
添加过滤器以仅允许您要查找的设置设备。由于 BLE 通告一个最大 31 字节的数据包,你应该在这里有一些数据来识别你的设备,例如制造商 ID 或数据等。或者如果你正在做一个简单的项目,你可以在设备地址中以编程方式硬编码。
然后当从扫描中发现此设备时,您可以停止 BLE 扫描并自动排队连接请求。这将要求发出 GATT 请求,因此授予您访问 GATT 服务和设备特征的权限。
如果你的蓝牙 LE 有问题我建议你使用我的蓝牙 le 库(不要重新发明轮子,我花了大约 3/4 个月来制作这个库,蓝牙 le 通信真的很棘手制作),它是开源的,所以你也可以看到有一个实现示例的代码,我 link 你在 github 页面:https://github.com/niedev/BluetoothCommunicator
要在项目中使用该库,您必须将 jitpack.io 添加到根 build.gradle(项目):
allprojects {
repositories {
...
maven { url 'https://jitpack.io' }
}
}
然后将最新版本的 BluetoothCommunicator 添加到您的应用程序中build.gradle
dependencies {
implementation 'com.github.niedev:BluetoothCommunicator:1.0.6'
}
要使用此库,请将这些权限添加到您的清单中:
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
然后在清单中的应用程序标签中添加android:largeHeap="true":
例子
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<application
android:name="com.bluetooth.communicatorexample.Global"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:largeHeap="true"
android:theme="@style/Theme.Speech">
<activity android:name="com.bluetooth.communicatorexample.MainActivity"
android:configChanges="orientation|screenSize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
一旦你下载了库并设置了清单,你需要创建一个蓝牙通信器对象,它是处理蓝牙低功耗库所有操作的对象,如果你想在多个活动中管理蓝牙连接我建议您将此对象另存为扩展应用程序的自定义 class 的属性并创建一个 getter,这样您就可以从任何 activity 或以下服务访问 bluetoothCommunicator:
((custom class name) getApplication()).getBluetoothCommunicator();
下一步是初始化bluetoothCommunicator,参数是:一个上下文,其他设备看到我们的名称(限制为18个字符,只能是BluetoothTools.getSupportedUTFCharacters(上下文)中列出的字符,因为广告信标的字节数是有限的)和策略(目前唯一支持的策略是BluetoothCommunicator。STRATEGY_P2P_WITH_RECONNECTION)
bluetoothCommunicator = new BluetoothCommunicator(this, "device name", BluetoothCommunicator.STRATEGY_P2P_WITH_RECONNECTION);
然后添加蓝牙通讯器回调,回调会监听蓝牙通讯器的所有事件:
bluetoothCommunicator.addCallback(new BluetoothCommunicator.Callback() {
@Override
public void onBluetoothLeNotSupported() {
super.onBluetoothLeNotSupported();
Notify that bluetooth low energy is not compatible with this device
}
@Override
public void onAdvertiseStarted() {
super.onAdvertiseStarted();
Notify that advertise has started, if you want to do something after the start of advertising do it here, because
after startAdvertise there is no guarantee that advertise is really started (it is delayed)
}
@Override
public void onDiscoveryStarted() {
super.onDiscoveryStarted();
Notify that discovery has started, if you want to do something after the start of discovery do it here, because
after startDiscovery there is no guarantee that discovery is really started (it is delayed)
}
@Override
public void onAdvertiseStopped() {
super.onAdvertiseStopped();
Notify that advertise has stopped, if you want to do something after the stop of advertising do it here, because
after stopAdvertising there is no guarantee that advertise is really stopped (it is delayed)
}
@Override
public void onDiscoveryStopped() {
super.onDiscoveryStopped();
Notify that discovery has stopped, if you want to do something after the stop of discovery do it here, because
after stopDiscovery there is no guarantee that discovery is really stopped (it is delayed)
}
@Override
public void onPeerFound(Peer peer) {
super.onPeerFound(peer);
Here for example you can save peer in a list or anywhere you want and when the user
choose a peer you can call bluetoothCommunicator.connect(peer founded) but if you want to
use a peer for connect you have to have peer updated (see onPeerUpdated or onPeerLost), if you use a
non updated peer the connection might fail
instead if you want to immediate connect where peer is found you can call bluetoothCommunicator.connect(peer) here
}
@Override
public void onPeerLost(Peer peer){
super.onPeerLost(peer);
It means that a peer is out of range or has interrupted the advertise,
here you can delete the peer lost from a eventual collection of founded peers
}
@Override
public void onPeerUpdated(Peer peer,Peer newPeer){
super.onPeerUpdated(peer,newPeer);
It means that a founded peer (or connected peer) has changed (name or address or other things),
if you have a collection of founded peers, you need to replace peer with newPeer if you want to connect successfully to that peer.
In case the peer updated is connected and you have saved connected peers you have to update the peer if you want to successfully
send a message or a disconnection request to that peer.
}
@Override
public void onConnectionRequest(Peer peer){
super.onConnectionRequest(peer);
It means you have received a connection request from another device (peer) (that have called connect)
for accept the connection request and start connection call bluetoothCommunicator.acceptConnection(peer);
for refusing call bluetoothCommunicator.rejectConnection(peer); (the peer must be the peer argument of onConnectionRequest)
}
@Override
public void onConnectionSuccess(Peer peer,int source){
super.onConnectionSuccess(peer,source);
This means that you have accepted the connection request using acceptConnection or the other
device has accepted your connection request and the connection is complete, from now on you
can send messages or data (or disconnection request) to this peer until onDisconnected
To send messages to all connected peers you need to create a message with a context, a header, represented by a single character string
(you can use a header to distinguish between different types of messages, or you can ignore it and use a random
character), the text of the message, or a series of bytes if you want to send any kind of data and the peer you want to send the message to
(must be connected to avoid errors), example: new Message(context,"a","hello world",peer);
If you want to send message to a specific peer you have to set the sender of the message with the corresponding peer.
To send disconnection request to connected peer you need to call bluetoothCommunicator.disconnect(peer);
}
@Override
public void onConnectionFailed(Peer peer,int errorCode){
super.onConnectionFailed(peer,errorCode);
This means that your connection request is rejected or has other problems,
to know the cause of the failure see errorCode (BluetoothCommunicator.CONNECTION_REJECTED
means rejected connection and BluetoothCommunicator.ERROR means generic error)
}
@Override
public void onConnectionLost(Peer peer){
super.onConnectionLost(peer);
This means that a connected peer has lost the connection with you and the library is trying
to restore it, in this case you can update the gui to notify this problem.
You can still send messages in this situation, all sent messages are put in a queue
and sent as soon as the connection is restored
}
@Override
public void onConnectionResumed(Peer peer){
super.onConnectionResumed(peer);
Means that connection lost is resumed successfully
}
@Override
public void onMessageReceived(Message message,int source){
super.onMessageReceived(message,source);
Means that you have received a message containing TEXT, for know the sender you can call message.getSender() that return
the peer that have sent the message, you can ignore source, it indicate only if you have received the message
as client or as server
}
@Override
public void onDataReceived(Message data,int source){
super.onDataReceived(data,source);
Means that you have received a message containing DATA, for know the sender you can call message.getSender() that return
the peer that have sent the message, you can ignore source, it indicate only if you have received the message
as client or as server
}
@Override
public void onDisconnected(Peer peer,int peersLeft){
super.onDisconnected(peer,peersLeft);
Means that the peer is disconnected, peersLeft indicate the number of connected peers remained
}
@Override
public void onDisconnectionFailed(){
super.onDisconnectionFailed();
Means that a disconnection is failed, super.onDisconnectionFailed will reactivate bluetooth for forcing disconnection
(however the disconnection will be notified in onDisconnection)
}
});
终于可以开始发现了and/or广告:
bluetoothCommunicator.startAdvertising();
bluetoothCommunicator.startDiscovery();
所有其他可以做的动作在我之前写的回调代码中的注释中解释。
所以我制作了这个应用程序,我可以在其中找到所有具有名称的 BLE 设备。但是我怎样才能使特定字段之一可点击并自动连接到设备,这样我就可以从它开始writing/reading?
适配器
public class ListAdapter_BTLE_Devices extends ArrayAdapter<BTLE_Device> {
Activity activity;
int layoutResourceID;
ArrayList<BTLE_Device> devices;
public ListAdapter_BTLE_Devices(Activity activity, int resource, ArrayList<BTLE_Device> objects) {
super(activity.getApplicationContext(), resource, objects);
this.activity = activity;
layoutResourceID = resource;
devices = objects;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
LayoutInflater inflater =
(LayoutInflater) activity.getApplicationContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(layoutResourceID, parent, false);
}
BTLE_Device device = devices.get(position);
String name = device.getName();
String address = device.getAddress();
int rssi = device.getRSSI();
TextView BLE_name = (TextView) convertView.findViewById(R.id.BLE_name);
if (name != null && name.length() > 0) {
BLE_name.setText(device.getName());
}
else {
BLE_name.setText("No Name");
}
TextView BLE_rssi = (TextView) convertView.findViewById(R.id.BLE_rssi);
BLE_rssi.setText("RSSI: " + Integer.toString(rssi));
TextView BLE_macaddr = (TextView) convertView.findViewById(R.id.BLE_macaddr);
if (address != null && address.length() > 0) {
BLE_macaddr.setText("MAC-addr: "+device.getAddress());
}
else {
BLE_macaddr.setText("No Address");
}
return convertView;
}
}
编辑
我想我现在可能已经连接到 GATT,所以我所做的是..
首先,我从 Mainactivity 中获取 MAC-addr,然后将其保存在意图中,并启动另一个 activity onclick。
在这里我做了以下
DeviceAddress = intent.getStringExtra(MainActivity.EXTRAS_BLE_ADDRESS);
BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(DeviceAddress);
device.connectGatt(this, false, mGattCallback);
当我调用 connectGatt 时,它会打印消息 Log.d(TAG, "Connection State: 1");
,这是正确的方法吗?
private BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
Log.d(TAG, "Connection State Change: "+status+" -> "+connectionState(newState));
if (status == BluetoothGatt.GATT_SUCCESS && newState == BluetoothProfile.STATE_CONNECTED) {
/*
* Once successfully connected, we must next discover all the services on the
* device before we can read and write their characteristics.
*/
Log.d(TAG, "Connection State: 1");
gatt.discoverServices();
} else if (status == BluetoothGatt.GATT_SUCCESS && newState == BluetoothProfile.STATE_DISCONNECTED) {
/*
* If at any point we disconnect, send a message to clear the weather values
* out of the UI
*/
Log.d(TAG, "Connection State: 2");
} else if (status != BluetoothGatt.GATT_SUCCESS) {
/*
* If there is a failure at any stage, simply disconnect
*/
Log.d(TAG, "Connection State: 3");
gatt.disconnect();
}
}
您可以向您的 holder 添加一个视图并为其设置一个点击监听器。视图可以是围绕您的显示卡(或您使用的任何内容)的透明矩形。
我建议 this 深入阅读有关 BLE 用法的内容。在点击侦听器上,您可以对连接请求进行排队。
要首先连接到设备,您必须执行 BLE 扫描(如果您使用启动代码)运行回调并将其添加到找到的设备列表中。
添加过滤器以仅允许您要查找的设置设备。由于 BLE 通告一个最大 31 字节的数据包,你应该在这里有一些数据来识别你的设备,例如制造商 ID 或数据等。或者如果你正在做一个简单的项目,你可以在设备地址中以编程方式硬编码。
然后当从扫描中发现此设备时,您可以停止 BLE 扫描并自动排队连接请求。这将要求发出 GATT 请求,因此授予您访问 GATT 服务和设备特征的权限。
如果你的蓝牙 LE 有问题我建议你使用我的蓝牙 le 库(不要重新发明轮子,我花了大约 3/4 个月来制作这个库,蓝牙 le 通信真的很棘手制作),它是开源的,所以你也可以看到有一个实现示例的代码,我 link 你在 github 页面:https://github.com/niedev/BluetoothCommunicator
要在项目中使用该库,您必须将 jitpack.io 添加到根 build.gradle(项目):
allprojects {
repositories {
...
maven { url 'https://jitpack.io' }
}
}
然后将最新版本的 BluetoothCommunicator 添加到您的应用程序中build.gradle
dependencies {
implementation 'com.github.niedev:BluetoothCommunicator:1.0.6'
}
要使用此库,请将这些权限添加到您的清单中:
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
然后在清单中的应用程序标签中添加android:largeHeap="true":
例子
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<application
android:name="com.bluetooth.communicatorexample.Global"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:largeHeap="true"
android:theme="@style/Theme.Speech">
<activity android:name="com.bluetooth.communicatorexample.MainActivity"
android:configChanges="orientation|screenSize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
一旦你下载了库并设置了清单,你需要创建一个蓝牙通信器对象,它是处理蓝牙低功耗库所有操作的对象,如果你想在多个活动中管理蓝牙连接我建议您将此对象另存为扩展应用程序的自定义 class 的属性并创建一个 getter,这样您就可以从任何 activity 或以下服务访问 bluetoothCommunicator:
((custom class name) getApplication()).getBluetoothCommunicator();
下一步是初始化bluetoothCommunicator,参数是:一个上下文,其他设备看到我们的名称(限制为18个字符,只能是BluetoothTools.getSupportedUTFCharacters(上下文)中列出的字符,因为广告信标的字节数是有限的)和策略(目前唯一支持的策略是BluetoothCommunicator。STRATEGY_P2P_WITH_RECONNECTION)
bluetoothCommunicator = new BluetoothCommunicator(this, "device name", BluetoothCommunicator.STRATEGY_P2P_WITH_RECONNECTION);
然后添加蓝牙通讯器回调,回调会监听蓝牙通讯器的所有事件:
bluetoothCommunicator.addCallback(new BluetoothCommunicator.Callback() {
@Override
public void onBluetoothLeNotSupported() {
super.onBluetoothLeNotSupported();
Notify that bluetooth low energy is not compatible with this device
}
@Override
public void onAdvertiseStarted() {
super.onAdvertiseStarted();
Notify that advertise has started, if you want to do something after the start of advertising do it here, because
after startAdvertise there is no guarantee that advertise is really started (it is delayed)
}
@Override
public void onDiscoveryStarted() {
super.onDiscoveryStarted();
Notify that discovery has started, if you want to do something after the start of discovery do it here, because
after startDiscovery there is no guarantee that discovery is really started (it is delayed)
}
@Override
public void onAdvertiseStopped() {
super.onAdvertiseStopped();
Notify that advertise has stopped, if you want to do something after the stop of advertising do it here, because
after stopAdvertising there is no guarantee that advertise is really stopped (it is delayed)
}
@Override
public void onDiscoveryStopped() {
super.onDiscoveryStopped();
Notify that discovery has stopped, if you want to do something after the stop of discovery do it here, because
after stopDiscovery there is no guarantee that discovery is really stopped (it is delayed)
}
@Override
public void onPeerFound(Peer peer) {
super.onPeerFound(peer);
Here for example you can save peer in a list or anywhere you want and when the user
choose a peer you can call bluetoothCommunicator.connect(peer founded) but if you want to
use a peer for connect you have to have peer updated (see onPeerUpdated or onPeerLost), if you use a
non updated peer the connection might fail
instead if you want to immediate connect where peer is found you can call bluetoothCommunicator.connect(peer) here
}
@Override
public void onPeerLost(Peer peer){
super.onPeerLost(peer);
It means that a peer is out of range or has interrupted the advertise,
here you can delete the peer lost from a eventual collection of founded peers
}
@Override
public void onPeerUpdated(Peer peer,Peer newPeer){
super.onPeerUpdated(peer,newPeer);
It means that a founded peer (or connected peer) has changed (name or address or other things),
if you have a collection of founded peers, you need to replace peer with newPeer if you want to connect successfully to that peer.
In case the peer updated is connected and you have saved connected peers you have to update the peer if you want to successfully
send a message or a disconnection request to that peer.
}
@Override
public void onConnectionRequest(Peer peer){
super.onConnectionRequest(peer);
It means you have received a connection request from another device (peer) (that have called connect)
for accept the connection request and start connection call bluetoothCommunicator.acceptConnection(peer);
for refusing call bluetoothCommunicator.rejectConnection(peer); (the peer must be the peer argument of onConnectionRequest)
}
@Override
public void onConnectionSuccess(Peer peer,int source){
super.onConnectionSuccess(peer,source);
This means that you have accepted the connection request using acceptConnection or the other
device has accepted your connection request and the connection is complete, from now on you
can send messages or data (or disconnection request) to this peer until onDisconnected
To send messages to all connected peers you need to create a message with a context, a header, represented by a single character string
(you can use a header to distinguish between different types of messages, or you can ignore it and use a random
character), the text of the message, or a series of bytes if you want to send any kind of data and the peer you want to send the message to
(must be connected to avoid errors), example: new Message(context,"a","hello world",peer);
If you want to send message to a specific peer you have to set the sender of the message with the corresponding peer.
To send disconnection request to connected peer you need to call bluetoothCommunicator.disconnect(peer);
}
@Override
public void onConnectionFailed(Peer peer,int errorCode){
super.onConnectionFailed(peer,errorCode);
This means that your connection request is rejected or has other problems,
to know the cause of the failure see errorCode (BluetoothCommunicator.CONNECTION_REJECTED
means rejected connection and BluetoothCommunicator.ERROR means generic error)
}
@Override
public void onConnectionLost(Peer peer){
super.onConnectionLost(peer);
This means that a connected peer has lost the connection with you and the library is trying
to restore it, in this case you can update the gui to notify this problem.
You can still send messages in this situation, all sent messages are put in a queue
and sent as soon as the connection is restored
}
@Override
public void onConnectionResumed(Peer peer){
super.onConnectionResumed(peer);
Means that connection lost is resumed successfully
}
@Override
public void onMessageReceived(Message message,int source){
super.onMessageReceived(message,source);
Means that you have received a message containing TEXT, for know the sender you can call message.getSender() that return
the peer that have sent the message, you can ignore source, it indicate only if you have received the message
as client or as server
}
@Override
public void onDataReceived(Message data,int source){
super.onDataReceived(data,source);
Means that you have received a message containing DATA, for know the sender you can call message.getSender() that return
the peer that have sent the message, you can ignore source, it indicate only if you have received the message
as client or as server
}
@Override
public void onDisconnected(Peer peer,int peersLeft){
super.onDisconnected(peer,peersLeft);
Means that the peer is disconnected, peersLeft indicate the number of connected peers remained
}
@Override
public void onDisconnectionFailed(){
super.onDisconnectionFailed();
Means that a disconnection is failed, super.onDisconnectionFailed will reactivate bluetooth for forcing disconnection
(however the disconnection will be notified in onDisconnection)
}
});
终于可以开始发现了and/or广告:
bluetoothCommunicator.startAdvertising();
bluetoothCommunicator.startDiscovery();
所有其他可以做的动作在我之前写的回调代码中的注释中解释。