android 低功耗蓝牙BLE多连接,多设备通信

星期三, 05. 九月 2018 02:03上午 – beautifulzzzz

先是需求在项目清单配置内部增加三个权力:

前不久数不胜数做蓝牙5.0APP的都亟待同一时候连接多个设备,那该怎能力同时处理多少个设施呢?以下是本人的点子,首假设通过ArrayMap来保管差别器械的BluetoothGatt,然后使用分其他BluetoothGatt来和从机实行数据交互,我们得以绑定该service实行艺术的调用。

android
bluetooth——Bluetooth的敞开、寻找、配对与连接

最关键多少个类:

图片 1

<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
public class BluetoothLeService2 extends Service {

private ArrayMap<String, BluetoothGatt> gattArrayMap = new ArrayMap<>();
private BluetoothAdapter mBluetoothAdapter;

@Override
public void onCreate() {
    super.onCreate();
    initBluetooth();
}

/**
 * 蓝牙是否开启
 */
public boolean isBluetoothEnabled() {
    return mBluetoothAdapter.isEnabled();
}


private void initBluetooth() {
    BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
    mBluetoothAdapter = bluetoothManager.getAdapter();
}


@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    return super.onStartCommand(intent, Service.START_FLAG_RETRY, startId);
}


@Override
public IBinder onBind(Intent intent) {
    return mBinder;
}


public class LocalBinder extends Binder {
    public BluetoothLeService2 getService() {
        return BluetoothLeService2.this;
    }
}

private final IBinder mBinder = new LocalBinder();

@Override
public boolean onUnbind(Intent intent) {
    return super.onUnbind(intent);
}


/**
 * 连接设备
 *
 * @param address 设备地址
 */
public synchronized void connect(final String address) {
    BluetoothGatt gatt = gattArrayMap.get(address);
    if (gatt != null) {
        gatt.disconnect();
        gatt.close();
        gattArrayMap.remove(address);
    }
    BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
    if (device == null) return;
    device.connectGatt(this, false, mGattCallback);
}

//蓝牙连接,数据通信的回掉
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
    @Override
    public void onConnectionStateChange(final BluetoothGatt gatt, int status, int newState) {
        String address = gatt.getDevice().getAddress();
        if (status == BluetoothGatt.GATT_SUCCESS) {
            if (newState == BluetoothGatt.STATE_CONNECTED) {// 连接成功
                gatt.discoverServices();// 寻找服务
                gattArrayMap.put(address, gatt);
                Log.i("yushu", "connect succeed: ");
            } else if (newState == BluetoothGatt.STATE_DISCONNECTED) {// 断开连接
                onDisConnected(gatt, address);
                Log.i("yushu", "connect fail ");
            }
        } else {
            onDisConnected(gatt, address);
            Log.i("yushu", "connect fail ");
        }
    }


    @Override
    public void onServicesDiscovered(BluetoothGatt gatt, int status) {
        if (status == BluetoothGatt.GATT_SUCCESS) {
            enableNotification(gatt);//notification
        }
    }


    @Override
    public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
        byte[] value = characteristic.getValue();
/**
 * 这里可以拿到设备notification回来的数据
*/

    }


    @Override
    public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
        super.onReadRemoteRssi(gatt, rssi, status);
        if (status == BluetoothGatt.GATT_SUCCESS) {

        }
    }
};


private void onDisConnected(BluetoothGatt gatt, String address) {
    gatt.disconnect();
    gatt.close();
}


/**
 * 使能通知
 */
private void enableNotification(BluetoothGatt mBluetoothGatt) {
    if (mBluetoothGatt == null) return;
    BluetoothGattService ableService = mBluetoothGatt.getService(UUIDUtils.UUID_LOST_SERVICE);
    if (ableService == null) return;
    BluetoothGattCharacteristic TxPowerLevel = ableService.getCharacteristic(UUIDUtils.UUID_LOST_ENABLE);
    if (TxPowerLevel == null) return;
    setCharacteristicNotification(mBluetoothGatt, TxPowerLevel, true);
}

/**
 * 使能通知
 */
private void setCharacteristicNotification(BluetoothGatt mBluetoothGatt, BluetoothGattCharacteristic characteristic, boolean enabled) {
    if (mBluetoothGatt == null) return;
    mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
    if (UUIDUtils.UUID_LOST_ENABLE.equals(characteristic.getUuid())) {
        BluetoothGattDescriptor descriptor = characteristic.getDescriptor(UUIDUtils.CLIENT_CHARACTERISTIC_CONFIG);
        descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
        mBluetoothGatt.writeDescriptor(descriptor);
    }
}


/**
 * 写数据到硬件,这里的服务UUID和特这的UUID参考硬件那边,两边要对应
 */
public synchronized void writeDataToDevice(byte[] bs, String address) {
    BluetoothGatt mBluetoothGatt = gattArrayMap.get(address);
    if (mBluetoothGatt == null) return;
    BluetoothGattService alertService = mBluetoothGatt.getService(UUIDUtils.UUID_LOST_SERVICE);
    if (alertService == null) return;
    BluetoothGattCharacteristic alertLevel = alertService.getCharacteristic(UUIDUtils.UUID_LOST_WRITE);
    if (alertLevel == null) return;
    alertLevel.setValue(bs);
    alertLevel.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE);
    mBluetoothGatt.writeCharacteristic(alertLevel);
}


public boolean readRssi(String address) {
    BluetoothGatt bluetoothGatt = gattArrayMap.get(address);
    return bluetoothGatt != null && bluetoothGatt.readRemoteRssi();
}


public void remove(String address) {
    BluetoothGatt bluetoothGatt = gattArrayMap.get(address);
    if (bluetoothGatt != null) {
        bluetoothGatt.disconnect();
        bluetoothGatt.close();
        gattArrayMap.remove(address);
    }
}

public void disConnect(String address) {
    BluetoothGatt bluetoothGatt = gattArrayMap.get(address);
    if (bluetoothGatt != null) {
        bluetoothGatt.disconnect();
        gattArrayMap.remove(address);
    }
}


@Override
public void onDestroy() {
    gattArrayMap.clear();
    super.onDestroy();
}
}

在接连叁次后退出再连接蓝牙5.0设备时会报以下错误:
06-14 10:37:49.916 6304-6347/com.bluetooth.demo W/System.err:
java.io.IOException: read failed, socket might closed or timeout, read
ret: -1

BluetoothAdapter bluetoothAdapter

1、前言

上生龙活虎篇讲了什么样编译安吹牛lueZ-5,本篇主要在于玩BlueZ,用命令行去操作BLE设备:

  • [BlueZ] 1、Download install and use the BlueZ and hcitool on PI
    3B+

图片 2

android里面蓝牙( Bluetooth® )是因而蓝牙5.0Adapter来进展操作的,所以率先大家须求得到到BluetoothAdapter的实例

翻开google表达文书档案

BluetoothSocket btSocket;

2、gatttool —— 老工具趟坑

刚开始接着 Get Started with Bluetooth Low Energy on
Linux
操作gatttool,开采坑太多(主因是工具老了):

采用sudo gatttool -b 4D:69:98:0E:91:5E -I去连接
意识会报错:Error: connect error: Connection refused (111)
最终参照他事他说加以调查LINK-11开掘必要加random选项([\#1](https://stackoverflow.com/questions/32947807/cannot-connect-to-ble-device-on-raspberry-pi))

➜  ~  sudo gatttool -b 4D:69:98:0E:91:5E -I
[4D:69:98:0E:91:5E][LE]> connect
Attempting to connect to 4D:69:98:0E:91:5E
Error: connect error: Connection refused (111)
[4D:69:98:0E:91:5E][LE]> exit
➜  ~  sudo gatttool  -t random  -b 4D:69:98:0E:91:5E -I
[4D:69:98:0E:91:5E][LE]> connect
Attempting to connect to 4D:69:98:0E:91:5E
Connection successful
[4D:69:98:0E:91:5E][LE]> 
(gatttool:3104): GLib-WARNING **: Invalid file descriptor.

过叁回会10S机动断开,网络说这么些工具老了,不提议用了([\#2](https://www.spinics.net/lists/linux-bluetooth/msg67617.html)):

There are new tools to use with GATT, bluetoothctl/bluetoothd is the preferred since with that you have GAP, etc, 
but if want to use a stand alone tool then I suggest you use btgatt-client.

图片 3

//先获取BlueToothAdapter的实例
BluetoothAdapter blueToothAdapter = BluetoothAdapter.getDefaultAdapter();

图片 4

BluetoothDevice device

3、bluetoothctl——NB的新工具

指令行走入bluetoothctl操作碰着([\#6](https://mcuoneclipse.com/2016/12/19/tutorial-ble-pairing-the-raspberry-pi-3-model-b-with-hexiwear/))

bluetoothctl

本人在四弟大上用lightblue模拟二个BLE设备ty_prod,之后对其service举办修改,调用scan
on实行搜寻依然老的,
末尾开掘要先用remove移除从前的配备,之后再scan就能并发[NEW] Device 72:3B:E1:81:4E:4F ty_prod设备
注: 用lightblue模拟的设备的MAC不是一向的
注:
作者发觉在lightblue中不管怎么模拟BLE设备,一旦被连上搜索到的service都以IPone的

[bluetooth]# devices
Device 28:ED:6A:A0:26:B7 ty_prod
Device 58:71:33:00:00:24 Bluetooth Keyboard
Device 00:1A:7D:DA:71:0A SHEN-PC
Device 94:87:E0:B3:AC:6F Mi Phone
[bluetooth]# remove 28:ED:6A:A0:26:B7 
...
[bluetooth]# scan on
Discovery started
[NEW] Device 72:3B:E1:81:4E:4F ty_prod
[bluetooth]# scan off
...
Discovery stopped
[bluetooth]# connect 72:3B:E1:81:4E:4F
Attempting to connect to 72:3B:E1:81:4E:4F
[CHG] Device 72:3B:E1:81:4E:4F Connected: yes
Connection successful
[ty_prod]

大致就用三星手提式有线电话机自带的劳动做测验了~

[ty_prod]# info
Device 28:ED:6A:A0:26:B7 (public)
    Name: tuya_mdev_test
    Alias: tuya_mdev_test
    Appearance: 0x0040
    Icon: phone
    Paired: yes
    Trusted: no
    Blocked: no
    Connected: yes
    LegacyPairing: no
    UUID: Fax                       (00001111-0000-1000-8000-00805f9b34fb)
    UUID: Generic Access Profile    (00001800-0000-1000-8000-00805f9b34fb)
    UUID: Generic Attribute Profile (00001801-0000-1000-8000-00805f9b34fb)
    UUID: Current Time Service      (00001805-0000-1000-8000-00805f9b34fb)
    UUID: Device Information        (0000180a-0000-1000-8000-00805f9b34fb)
    UUID: Battery Service           (0000180f-0000-1000-8000-00805f9b34fb)
    UUID: Vendor specific           (7905f431-b5ce-4e99-a40f-4b1e122d00d0)
    UUID: Vendor specific           (89d3502b-0f36-433a-8ef4-c502ad55f8dc)
    UUID: Vendor specific           (9fa480e0-4967-4542-9390-d343dc5d04ae)
    UUID: Vendor specific           (d0611e78-bbb4-4591-a5f8-487910ae4366)
[CHG] Device 28:ED:6A:A0:26:B7 ServicesResolved: no
[CHG] Device 28:ED:6A:A0:26:B7 Connected: no

大家用Current Time Service,列出具备attributes操作如下:

[tuya_mdev_test]# menu gatt
[tuya_mdev_test]# list-attributes 28:ED:6A:A0:26:B7
...
Primary Service
    /org/bluez/hci0/dev_47_B1_26_C1_81_18/service0041
    00001805-0000-1000-8000-00805f9b34fb
    Current Time Service
Characteristic
    /org/bluez/hci0/dev_47_B1_26_C1_81_18/service0041/char0045
    00002a0f-0000-1000-8000-00805f9b34fb
    Local Time Information
Characteristic
    /org/bluez/hci0/dev_47_B1_26_C1_81_18/service0041/char0042
    00002a2b-0000-1000-8000-00805f9b34fb
    Current Time
Descriptor
    /org/bluez/hci0/dev_47_B1_26_C1_81_18/service0041/char0042/desc0044
    00002902-0000-1000-8000-00805f9b34fb
    Client Characteristic Configuration
...

上面Current Time Service相应的服务如下图:

图片 5

我们筛选Current Time进行操作UUID:0x2A2B

[ty_prod]# select-attribute /org/bluez/hci0/dev_47_B1_26_C1_81_18/service0041/char0042
[tuya_mdev_test:/service0041/char0042]# read
Attempting to read /org/bluez/hci0/dev_47_B1_26_C1_81_18/service0041/char0042
[CHG] Attribute /org/bluez/hci0/dev_47_B1_26_C1_81_18/service0041/char0042 Value:
  e2 07 09 05 01 24 11 03 f1 02                    .....$....      
  e2 07 09 05 01 24 11 03 f1 02                    .....$.... 
[tuya_mdev_test:/service0041/char0042]# attribute-info
Characteristic - Current Time
    UUID: 00002a2b-0000-1000-8000-00805f9b34fb
    Service: /org/bluez/hci0/dev_47_B1_26_C1_81_18/service0041
    Value:
  e2 07 09 05 01 2e 01 03 f5 02                    ..........      
    Notifying: yes
    Flags: read
    Flags: notify

读出结果大概意思应该是:2018-9/5-1:36:17 周三

读取一下0x180A的Device Information:

[tuya_mdev_test:/service0006/char0007]# select-attribute /org/bluez/hci0/dev_47_B1_26_C1_81_18/service0047/char004a
[tuya_mdev_test:/service0047/char004a]# attribute-info
Characteristic - Model Number String
    UUID: 00002a24-0000-1000-8000-00805f9b34fb
    Service: /org/bluez/hci0/dev_47_B1_26_C1_81_18/service0047
    Flags: read
[tuya_mdev_test:/service0047/char004a]# read
Attempting to read /org/bluez/hci0/dev_47_B1_26_C1_81_18/service0047/char004a
[CHG] Attribute /org/bluez/hci0/dev_47_B1_26_C1_81_18/service0047/char004a Value:
  69 50 68 6f 6e 65 36 2c 32                       iPhone6,2       
  69 50 68 6f 6e 65 36 2c 32                       iPhone6,2    

当然写、使能notify也很简短,看help就能够。最后断开连接、并脱离!!!

[tuya_mdev_test:/service0047/char004a]# disconnect 28:ED:6A:A0:26:B7
Attempting to disconnect from 28:ED:6A:A0:26:B7
[CHG] Device 28:ED:6A:A0:26:B7 ServicesResolved: no
Successful disconnected
[CHG] Device 28:ED:6A:A0:26:B7 Connected: no
[bluetooth]# quit

图片 6

在检索以前,大家能够先获得与我们配成对过的装置

Paste_Image.png

bluetoothAdapter =
BluetoothAdapter.getDefaultAdapter();

LINKS

[1].Cannot connect to BLE device on Raspberry
Pi
[2].Invalid file descriptor gatttool of bluez
5.32
[3].Get Started with Bluetooth Low Energy on
Linux
[4].Reverse Engineering a Bluetooth Low Energy Light
Bulb
[5].Doing Bluetooth Low Energy on
Linux
[6].Tutorial: BLE Pairing the Raspberry Pi 3 Model B with
Hexiwear

图片 7

@beautifulzzzz
智能硬件、物联网,热爱技术,关注产品
博客:http://blog.beautifulzzzz.com
园友交流群:414948975
//获取已经配对过的设备的集合
Set<BluetoothDevice> bondedDevices = blueToothAdapter.getBondedDevices()

为了幸免上述失实应该在服务端连接二回就复位

bluetoothAdapter.startDiscovery();//早前找出左近的蓝牙5.0设备,寻找的时候会爆发两个广播如下

只是想要获取到配对过的配备,大家不得不是在

图片 8

startDiscovery()方法是多少个异步方法,它会对其他蓝牙( Bluetooth® )设备开展搜寻,持续时间为12秒。寻觅进程实际上是在System
瑟维斯中开展,大家能够通过cancelDiscovery()方法来终止那一个搜索。在系统查找蓝牙5.0设备的长河中,系统或者会发送以下八个广播:ACTION_DISCOVERY_START(发轫搜寻),ACTION_DISCOVERY_FINISHED(寻觅结束)和ACTION_FOUND(找到设备)。ACTION_FOUND那一个才是大家想要的。所以在startDiscovery此前大家相应登记二个广播如下:

//手机有蓝牙设备并且蓝牙是打开的
blueToothAdapter != null && blueToothAdapter.isEnabled()

Paste_Image.png

IntentFilter intentfilter = new IntentFilter(
                BluetoothDevice.ACTION_FOUND);
        bluetoothReceiver = new BluetoothReceiver();
        // 注册bluetoothReceiver
        registerReceiver(bluetoothReceiver, intentfilter);

上面大家谈一下蓝牙5.0的<b>展开药形式</b>,近日小编知道的措施有3种
第一种:

广播选择类BluetoothReceiver的落实如下:

//强制打开蓝牙
blueToothAdapter.enable();
   public class BluetoothReceiver extends BroadcastReceiver {

        @SuppressLint("ShowToast")
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            Toast.makeText(MainActivity.this, "扫描中...", 100).show();
            // device对象代表被扫描到的远程设备的对象
            // 将搜索到的蓝牙设备在ListView中显示出来

            if (BluetoothDevice.ACTION_FOUND.equals(action)) {
                BluetoothDevice device = intent
                        .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                String str = device.getName() + "|" + device.getAddress();

                if (lstDevices.indexOf(str) == -1)// 防止重复添加
                    lstDevices.add(str); // 获取设备名称和mac地址
                adtDevices.notifyDataSetChanged();

            }

        }

    }

第二种:

private List<String> lstDevices = new ArrayList<String>();

//会以dialog的形式打开一个activity,并且如果我们通过startActivityForResult的形式的话
//还能查看蓝牙是否被打开,或者处理蓝牙被打开之后的操作
//如果是result_ok的话那么是打开,反之打开失败
startActivityForResult(new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE));

追寻到了随后就能把种种蓝牙5.0设备的name呈现在一个listview中,点击listview中的某个设备之后,就能与之开始接二连三:

第三种:

String str = lstDevices.get(arg2);
            String[] values = str.split("\\|");
            String address = values[1];
            Log.e("address", values[1]);

            uuid = UUID.fromString(SPP_UUID);
            Log.e("uuid", uuid.toString());
            // btDev是远端的蓝牙设备,get到之后,用btsocket得到其中的socket,建立连接的套接字
            BluetoothDevice btDev = bluetoothAdapter.getRemoteDevice(address);
            try {
                btSocket = (BluetoothSocket) btDev
                        .getClass()
                        .getMethod("createRfcommSocket",
                                new Class[] { int.class })
                        .invoke(btDev, Integer.valueOf(1));
            } catch (IllegalAccessException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IllegalArgumentException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            // 取消查找
            bluetoothAdapter.cancelDiscovery();

            try {
                Toast.makeText(MainActivity.this, "正在连接...", Toast.LENGTH_SHORT)
                        .show();
                btSocket.connect();
                Log.e(TAG,
                        " BT connection established, data transfer link open.");

                Toast.makeText(MainActivity.this, "连接成功,进入控制界面",
                        Toast.LENGTH_SHORT).show();

                // 打开控制界面
                Intent intent = new Intent(MainActivity.this,
                        CtrlActivity.class);
                startActivity(intent);
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
                Log.e(TAG, " Connection failed.", e);
                Toast.makeText(MainActivity.this, "连接失败", Toast.LENGTH_SHORT)
                        .show();
            }
//设置本地设备可以被其它设备搜索,可被搜索的时间是有限的,最多为300s
//效果和第二种类似
Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
startActivity(discoverableIntent);

btSocket = btDev.createRfcommSocketToServiceRecord(SPP_UUID);

<b>关闭蓝牙( Bluetooth® )</b>大家能够调用

早先用这种方法给btSocket赋值时,btSocket.connect()便是抛出极其,后来改用如下方式就足以健康连接了

blueToothAdapter.disable();

btSocket = (BluetoothSocket) btDev
                        .getClass()
                        .getMethod(“createRfcommSocket”,
                                new Class[] { int.class })
                        .invoke(btDev, Integer.valueOf(1));

接下去是<b>Bluetooth搜索</b>
首先借使想要开启Bluetooth寻觅,那么只须求调用

专一在奉行connect()操作以前一定要先

blueToothAdapter.startDiscovery();
bluetoothAdapter.cancelDiscovery();

而是大家该怎么接收我们搜索到的设备呢,很分明当然是透过接收播放的花样来抽取。所以大家应有自定义三个播放选取器,

class BluetoothReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {

            if (intent.getAction().equals(BluetoothDevice.ACTION_FOUND)) {
                Log.e(getPackageName(), "找到新设备了");
                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
            }
        }
    }

如上代码,大家可以赢获得寻找到的蓝牙( Bluetooth® )设备。大家只需在代码里面注册这一个广播选拔器,在调用蓝牙5.0的探寻方法,就可见进行蓝牙( Bluetooth® )的搜寻了。

//注册广播
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(BluetoothDevice.ACTION_FOUND);
registerReceiver(new BluetoothReceiver(), intentFilter);

这里须求当心的是,固然你的代码将运维在(Build.VEEscortSION.SDK_INT >=
23)的道具上,那么必得加上以下放权力限,并在代码中动态的报名权限

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

private void requestPermission() {
        if (Build.VERSION.SDK_INT >= 23) {
            int checkAccessFinePermission = ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION);
            if (checkAccessFinePermission != PackageManager.PERMISSION_GRANTED) {
                ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
                        REQUEST_PERMISSION_ACCESS_LOCATION);
                Log.e(getPackageName(), "没有权限,请求权限");
                return;
            }
            Log.e(getPackageName(), "已有定位权限");
            //这里可以开始搜索操作
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
        switch (requestCode) {
            case REQUEST_PERMISSION_ACCESS_LOCATION: {
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    Log.e(getPackageName(), "开启权限permission granted!");
                    //这里可以开始搜索操作
                } else {
                    Log.e(getPackageName(), "没有定位权限,请先开启!");
                }
            }
        }
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }

再来正是<b>蓝牙5.0的配成对</b>,这几天楼主接纳的是因而反射的花样来调用BluetoothDevice的createBondde()方法,假使大家想监听配对的这几个进度,那么大家得认为广播接纳器再登记二个action。

try {
      //如果想要取消已经配对的设备,只需要将creatBond改为removeBond
       Method method = BluetoothDevice.class.getMethod("createBond");
       Log.e(getPackageName(), "开始配对");
       method.invoke(device);
    } catch (Exception e) {
      e.printStackTrace();
    }

//绑定状态发生变化
intentFilter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);

播音选用器里面我们得以那样写

if (intent.getAction().equals(BluetoothDevice.ACTION_BOND_STATE_CHANGED)) {
                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                switch (device.getBondState()) {
                    case BluetoothDevice.BOND_NONE:
                        Log.e(getPackageName(), "取消配对");
                        break;
                    case BluetoothDevice.BOND_BONDING:
                        Log.e(getPackageName(), "配对中");
                        break;
                    case BluetoothDevice.BOND_BONDED:
                        Log.e(getPackageName(), "配对成功");
                        break;
                }
}

再来正是<b>向业已配对的设备发送数据</b>
发送数据分为服务端和顾客端,通过socket来进展新闻的互相。

服务端

new Thread(new Runnable() {
            @Override
            public void run() {
                InputStream is = null;
                try {
                    BluetoothServerSocket serverSocket = blueToothAdapter.listenUsingRfcommWithServiceRecord("serverSocket", uuid);
                    mHandler.sendEmptyMessage(startService);
                    BluetoothSocket accept = serverSocket.accept();
                    is = accept.getInputStream();

                    byte[] bytes = new byte[1024];
                    int length = is.read(bytes);

                    Message msg = new Message();
                    msg.what = getMessageOk;
                    msg.obj = new String(bytes, 0, length);
                    mHandler.sendMessage(msg);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();

客户端

new Thread(new Runnable() {
            @Override
            public void run() {
                OutputStream os = null;
                try {
                    BluetoothSocket socket = strArr.get(i).createRfcommSocketToServiceRecord(uuid);
                    socket.connect();
                    os = socket.getOutputStream();
                    os.write("testMessage".getBytes());
                    os.flush();
                    mHandler.sendEmptyMessage(sendOver);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();

能够看看无论是服务端还是客商端,都急需新起一个子线程来操作。那么服务端和客商端是怎么分辨对方的吗,那么就须要用到<b>UUID</b>了,唯有当服务端和顾客端的<b>UUID</b>同时手艺够成立连接。

<b>蓝牙( Bluetooth® )连接发送数据的时候的坑</b>
当博主第四回写好客商端服务端测量检验的时候,服务端一直报错

java.io.IOException: bt socket closed, read return: -1

也正是那句话报错

is.read(bytes)

即时直接认为是读取再次回到值是-1就可以报错,可是不对啊,从前这么写也没错失,在互连网百度了半天,看了人家的博客论坛也并未有衰亡办法,最终才注意到报错的前一句,

bt socket closed

事先一向以为是怎么服务端那边,报错连接才会断开,后来意气风发想客商端也会断开连接啊,那才找到难题所在。原本是自己立马write完数据以往将连接关闭了,那才致使服务端那边连接断开的。所以最首要的事体要说3遍,千万别急着断开连接,千万别急着断开连接,千万别急着断开连接。

<a
href=”;

发表评论

电子邮件地址不会被公开。 必填项已用*标注