Android communication between devices via Bluetooth (BLE Bluetooth Low-Energy) | client | server

This article by saying that BLE(Bluetooth Low Energy)to achieve a Bluetooth chat effect; we usually use the phone to connect to some of the BLE are smart or intelligent hardware device then communicates, that is to act as a mobile phone 客户端, a smart device acts 服务端; rarely useful to pass BLE let two mobile phones to communicate, mobile phones can act as both 客户端can also act as服务端

First, the word does not say, look at the renderings

BLE minimum support Android4.3 (API = 18), but also act as a server so if the minimum support Android5.0 (API = 21)

Second, we need to add permissions needed to run dynamic applications in Android6.0 more ACCESS_FINE_LOCATIONprivileges to get to the surrounding Bluetooth devices

<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<!--  android M 以上版本获取周边蓝牙设备必须定位权限  -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-feature
    android:name="android.hardware.bluetooth_le"
    android:required="true" />

Third, initialize Bluetooth, open Bluetooth

BluetoothManager bluetoothManager = (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE);
BluetoothAdapter bluetoothAdapter = bluetoothManager.getAdapter();
  • Turn on Bluetooth
	/**
     * 打开蓝牙
     */
    public boolean enableBluetooth() {
        if (bluetoothAdapter == null) return false;
        if (!bluetoothAdapter.isEnabled()) {
            return bluetoothAdapter.enable();
        } else {
            return true;
        }
    }

Fourth, create our BLE server, waiting for client connections; we can set up Bluetooth nameBleChatServer

//开启BLE蓝牙服务
startAdvertising("BleChatServer");
  • Service code calls the open
/**
 * 创建Ble服务端,接收连接
 */
public void startAdvertising(String name) {
    //BLE广告设置
    AdvertiseSettings settings = new AdvertiseSettings.Builder()
            .setConnectable(true)
            .setTimeout(0)
            .setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_HIGH)
            .setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_LATENCY)
            .build();
    AdvertiseData advertiseData = new AdvertiseData.Builder()
            .setIncludeDeviceName(true)
            .setIncludeTxPowerLevel(true)
            .build();
    bluetoothAdapter.setName(name);
    //开启服务
    BluetoothLeAdvertiser bluetoothLeAdvertiser = bluetoothAdapter.getBluetoothLeAdvertiser();
    bluetoothLeAdvertiser.startAdvertising(settings, advertiseData, advertiseCallback);
}

  • BLE open callback service successful, then we need to expose our service UUID to interact simultaneously read and write at the service UUID include a characteristic value
/**
 * Ble服务监听
 */
private AdvertiseCallback advertiseCallback = new AdvertiseCallback() {
    @Override
    public void onStartSuccess(AdvertiseSettings settingsInEffect) {
        super.onStartSuccess(settingsInEffect);
        Log.e(TAG, "服务开启成功 " + settingsInEffect.toString());
        addService();
    }
};
  • Add the service UUID

//服务uuid
public static UUID UUID_SERVER = UUID.fromString("0000fff2-0000-1000-8000-00805f9b34fb");
//读的特征值¸
public static UUID UUID_CHAR_READ = UUID.fromString("0000ffe3-0000-1000-8000-00805f9b34fb");
//写的特征值
public static UUID UUID_CHAR_WRITE = UUID.fromString("0000ffe4-0000-1000-8000-00805f9b34fb");


/**
 * 添加读写服务UUID,特征值等
 */
private void addService() {
    BluetoothGattService gattService = new BluetoothGattService(UUID_SERVER, BluetoothGattService.SERVICE_TYPE_PRIMARY);
    //只读的特征值
   BluetoothGattCharacteristic characteristicRead = new BluetoothGattCharacteristic(UUID_CHAR_READ,
            BluetoothGattCharacteristic.PROPERTY_READ | BluetoothGattCharacteristic.PROPERTY_NOTIFY,
            BluetoothGattCharacteristic.PERMISSION_READ);
    //只写的特征值
    BluetoothGattCharacteristic characteristicWrite = new BluetoothGattCharacteristic(UUID_CHAR_WRITE,
            BluetoothGattCharacteristic.PROPERTY_WRITE | BluetoothGattCharacteristic.PROPERTY_READ
                    | BluetoothGattCharacteristic.PROPERTY_NOTIFY,
            BluetoothGattCharacteristic.PERMISSION_WRITE | BluetoothGattCharacteristic.PERMISSION_READ);
    //将特征值添加至服务里
    gattService.addCharacteristic(characteristicRead);
    gattService.addCharacteristic(characteristicWrite);
    //监听客户端的连接
   BluetoothGattServer bluetoothGattServer = bluetoothManager.openGattServer(this, gattServerCallback);
   //添加服务
    bluetoothGattServer.addService(gattService);
}
  • gattServerCallbackClient connections up callback
private BluetoothGattServerCallback gattServerCallback = new BluetoothGattServerCallback() {
    @Override
    public void onConnectionStateChange(BluetoothDevice device, int status, int newState) {
        super.onConnectionStateChange(device, status, newState);
        ServerActivity.this.device = device;
        String state = "";
        if (newState == BluetoothProfile.STATE_CONNECTED) {
            state = "连接成功";
        } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
            state = "连接断开";
        }
        Log.e(TAG, "onConnectionStateChange device=" + device.toString() + " status=" + status + " newState=" + state);
    }
    @Override
    public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId, BluetoothGattCharacteristic characteristic, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) {
        super.onCharacteristicWriteRequest(device, requestId, characteristic, preparedWrite, responseNeeded, offset, value);
        String data = new String(value);
        Log.e(TAG, "收到了客户端发过来的数据 " + data);
        //告诉客户端发送成功
        bluetoothGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, characteristic.getValue());
    }
};

Fifth, the UUID and services here have to mention this thing characteristic values

  • BLE has a more service Service, which is above the new BluetoothGattService, clients can find by UUID
  • A Service has multiple features Characteristic, client service first found by UUID values ​​to find features by UUID

Sixth, to end here BLE service has been achieved, the client scans can be found to open this service up

Seven, to create the server has finished, the next step is to scan the client's connection with the

  • First is the need to turn on Bluetooth, refer to the first 二、三step; the Android Mabove also need to apply for dynamic positioning in order to obtain permission to surrounding Bluetooth devices
/**
 * 扫描设备
 */
public void startScan() {
    if (bluetoothAdapter == null) return;
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        BluetoothLeScanner scanner = bluetoothAdapter.getBluetoothLeScanner();
        if (scanner != null) {
            scanner.startScan(scanCallback);
        }
    } else {
        bluetoothAdapter.startLeScan(leScanCallback);
    }
}
//扫描的监听回调
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private ScanCallback scanCallback = new ScanCallback() {
    @Override
    public void onScanResult(int callbackType, ScanResult result) {
        super.onScanResult(callbackType, result);
        BluetoothDevice device = result.getDevice();
        //device就是周边的设备了
    }
};
private BluetoothAdapter.LeScanCallback leScanCallback = new BluetoothAdapter.LeScanCallback() {
    @Override
    public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
         //device就是周边的设备了
    }
};

Eight, to establish a connection, send and receive data with the server

//device就是我们扫描回调内拿到的设备(BleChatServer)
BluetoothGatt bluetoothGatt = device.getDevice().connectGatt(this, false, bluetoothGattCallback);
  • Callback connection status
private BluetoothGattCallback bluetoothGattCallback = new BluetoothGattCallback() {
    @Override
    public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
        super.onConnectionStateChange(gatt, status, newState);
        if (newState == BluetoothProfile.STATE_CONNECTED) {
            Log.e(TAG, "onConnectionStateChange 连接成功");
            //查找服务
            gatt.discoverServices();
        } else if (newState == BluetoothProfile.STATE_CONNECTING) {
            Log.e(TAG, "onConnectionStateChange 连接中......");
        } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
            Log.e(TAG, "onConnectionStateChange 连接断开");
        } else if (newState == BluetoothProfile.STATE_DISCONNECTING) {
            Log.e(TAG, "onConnectionStateChange 连接断开中......");
        }
    }
    @Override
    public void onServicesDiscovered(BluetoothGatt gatt, int status) {
        super.onServicesDiscovered(gatt, status);
        //设置读特征值的监听,接收服务端发送的数据
        BluetoothGattService service = bluetoothGatt.getService(UUID_SERVER);
        BluetoothGattCharacteristic characteristic = service.getCharacteristic(UUID_CHAR_READ);
        boolean b = bluetoothGatt.setCharacteristicNotification(characteristic, true);
        Log.e(TAG, "onServicesDiscovered 设置通知 " + b);
    }
    @Override
    public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
        super.onCharacteristicChanged(gatt, characteristic);
        String data = new String(characteristic.getValue());
        Log.e(TAG, "onCharacteristicChanged 接收到了数据 " + data);
    }
};
  • Here UUID_SERVER, UUID_CHAR_READwhat we in the server settings
  • 在发现服务回调这里,我们需要对我们在服务端设置的读特征值进行通知设置;这样当服务端写入了数据,就会回调我们的onCharacteristicChanged()拿到数据

客户端发送数据给服务端,也就是往我们服务端定义的写特征值写入数据

/**
 * 发送数据
 *
 * @param msg
 */
public void sendData(String msg) {
    //找到服务
    BluetoothGattService service = bluetoothGatt.getService(UUID_SERVER);
    //拿到写的特征值
    BluetoothGattCharacteristic characteristic = service.getCharacteristic(UUID_CHAR_WRITE);
    bluetoothGatt.setCharacteristicNotification(characteristic, true);
    characteristic.setValue(msg.getBytes());
    bluetoothGatt.writeCharacteristic(characteristic);
    Log.e(TAG, "sendData 发送数据成功");
}

到这里一个蓝牙聊天的案例就完成了Demo下载地址

发布了140 篇原创文章 · 获赞 546 · 访问量 54万+

Guess you like

Origin blog.csdn.net/a_zhon/article/details/96166596