android 低耗能BluetoothBLE多连接,多设备通讯

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

首先须要在事项清单配置内部增添多个权力:

未来无数做蓝牙( Bluetooth® 卡塔尔APP的都亟需同时连接多少个设施,那该怎么手艺同一时间管理五个道具呢?以下是自家的办法,主借使透过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();
}
}

在连年一回后退出再连接Bluetooth设备时会报以下错误:
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.0( Bluetooth® 卡塔 尔(阿拉伯语:قطر‎Adapter来进展操作的,所以首先我们须求取获得蓝牙Adapter的实例

翻开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]

索性就用IPhone自带的劳动做测量试验了~

[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()

为了制止上述失实应该在服务端连接壹回就重新初始化

bluetooth艾达pter.startDiscovery();//开首搜求周围的蓝牙( Bluetooth® 卡塔 尔(英语:State of Qatar)设备,寻找的时候会爆发七个广播如下

然则想要获取到配成对过的装置,我们必需是在

威尼斯网址开户网站 8

startDiscovery()方法是一个异步方法,它会对此外Bluetooth设备开展查找,持续时间为12秒。寻找进程实际上是在System
Service中开展,大家能够通过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);

上面我们谈一下Bluetooth的<b>张开药方式</b>,最近作者知道的措施有3种
第一种:

播音选用类蓝牙( Bluetooth® 卡塔 尔(英语:State of Qatar)Receiver的落实如下:

//强制打开蓝牙
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));

搜寻到了后头就能够把每三个蓝牙( Bluetooth® 卡塔尔设备的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设备。我们只需在代码里面注册那个广播采用器,在调用Bluetooth的追寻方法,就可以知道进行蓝牙5.0的物色了。

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

此处要求专心的是,假若您的代码将运维在(Build.VEEvoqueSION.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>蓝牙( Bluetooth® 卡塔尔国的配对</b>,近年来楼主采取的是由此反射的花样来调用蓝牙5.0( Bluetooth® 卡塔 尔(英语:State of Qatar)Device的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=”;

相关文章