權限申請
在AndroidManifest.xml中加入:
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
在代碼中動態(tài)申請權限,其中REQUEST_PERMISSION_ACCESS_LOCATION 為自定義int常量,
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);
LogTool.e(TAG, "沒有權限,請求權限");
return;
}
LogTool.i(TAG, "已有定位權限");
}
//做下面該做的事
}
重寫onRequestPermissionsResult,驗證獲取權限結果授瘦,如下圖:
@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
switch (requestCode) {
case REQUEST_PERMISSION_ACCESS_LOCATION:
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
} else {
Toast.makeText(this,"獲取權限失敗",Toast.LENGTH_SHORT).show();
}
break;
}
}
使能手機藍牙
在使用藍牙之前需要檢查手機藍牙是否開啟,若未開啟茂翔,需要提示將藍牙開啟
//獲取藍牙適配器實例
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
//若藍牙未開啟驰吓,則開啟藍牙
if (! bluetoothAdapter.isEnabled()) {
//使能藍牙
bluetoothAdapter.enable();
}
掃描藍牙設備
private void startScan() {
//SCAN_INTERVEL = 5000 毫秒后停止掃描
postDelayed(new Runnable() {
@Override
public void run() {
bluetoothAdapter.stopLeScan(leScanCallback);
}
}, SCAN_INTERVEL);
//開始掃描
bluetoothAdapter.startLeScan(leScanCallback);
}
其中l(wèi)eScanCallback為掃描回調方法涧尿,定義如下:
final BluetoothAdapter.LeScanCallback leScanCallback = new BluetoothAdapter.LeScanCallback() {
@Override
public void onLeScan(BluetoothDevice bluetoothDevice, int i, byte[] bytes) {
//這里當掃描到的設備,設備名不為null檬贰,就通過logi輸出設備名和MAC地址姑廉。
//這里也可以添加其他篩選條件,如特定設備名翁涤、或設備列表中是否已有桥言。
if(bluetoothDevice.getName() != null) {
//這里可以將設備添加到列表中,并通過ListView顯示出來
Log.i(TAG, "onLeScan: " + bluetoothDevice.getName() + " : " + bluetoothDevice.getAddress());
}
}
};
連接掃描到的藍牙設備
//MACADDR 為要連接的設備MAC地址葵礼,可以通過設備的getAddress()方法獲取
BluetoothDevice bluetoothDevice = bluetoothAdapter.getRemoteDevice(MACADDR);
BluetoothGatt bluetoothGatt;
if(bluetoothDevice != null)
{
bluetoothGatt = bluetoothDevice.connectGatt(context,true,gattCallback);
}
else{
LogTool.i(TAG, "onItemClick: 沒有該設備");
}
定義gattCallback限书,并重寫一系列方法,這些方法會在連接過程中被調用章咧,可以在這里做一些連接狀態(tài)的處理:
BluetoothGattCallback gattCallback = new BluetoothGattCallback() {
//連接狀態(tài)發(fā)生改變時調用
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
if(status == BluetoothGatt.GATT_SUCCESS) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
//建立連接
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
//連接斷開
}
}
}
//發(fā)現服務
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
//這里可以通過發(fā)送廣播倦西,接收到相應廣播后,對服務做相應處理赁严。
LogTool.i(TAG, "onServicesDiscovered:status:" + status);
} else {
LogTool.w(TAG, "onServicesDiscovered received: " + status);
System.out.println("onServicesDiscovered received: " + status);
}
}
@Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
//讀取到值扰柠,在這里讀數據
if (status == BluetoothGatt.GATT_SUCCESS) {
//數據處理
}
}
@Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
switch(status) {
case BluetoothGatt.GATT_SUCCESS:
LogTool.i(TAG, "write data success");
break;
case BluetoothGatt.GATT_FAILURE:
LogTool.i(TAG, "write again");
gatt.writeCharacteristic(characteristic);
break;
case BluetoothGatt.GATT_WRITE_NOT_PERMITTED:
LogTool.i(TAG, "write not permitted");
break;
}
super.onCharacteristicWrite(gatt,characteristic,status);
}
@Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
super.onCharacteristicChanged(gatt, characteristic);
}
};
服務和特征值獲取
這里獲取是繼上述的回調函數onServicesDiscovered,在廣播接受者中獲取相應的服務和特征值:
//寫數據的服務和characteristic
BluetoothGattService bluetoothGattService;
BluetoothGattCharacteristic characteristicRead;
BluetoothGattCharacteristic characteristicWrite;
//獲取服務
bluetoothGattService = bluetoothGatt.getService(UUID.fromString("0000ffe0-0000-1000-8000-00805f9b34fb"));
//獲取讀特征值
characteristicRead = bluetoothGattService.getCharacteristic(UUID.fromString("0000ffe7-0000-1000-8000-00805f9b34fb"));
//獲取寫特征值
characteristicWrite = bluetoothGattService.getCharacteristic(UUID.fromString("0000ffe6-0000-1000-8000-00805f9b34fb"));
//使能接收數據通知
List<BluetoothGattDescriptor> descriptors = characteristicRead.getDescriptors();
for (BluetoothGattDescriptor bgp : descriptors) {
LogTool.i(TAG, "setCharacteristicNotification: " + bgp);
bgp.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
bluetoothGatt.writeDescriptor(bgp);
}
數據的收發(fā)
接收數據
在上述的回調過程中疼约,若特征值為讀特征值卤档,則此時可以從特征值中讀取設備發(fā)送來的數據:
//這里例子里讀特征值的UUID為0000ffe7-0000-1000-8000-00805f9b34fb,在實際應用中視實際情況而定程剥。
if ( characteristic.getUuid().toString().equals("0000ffe7-0000-1000-8000-00805f9b34fb")){
// For all other profiles, writes the data formatted in HEX.對于所有的文件劝枣,寫入十六進制格式的文件
//這里讀取到數據,讀取的數據為byte數組
final byte[] data = characteristic.getValue();
LogTool.i(TAG, "broadcastUpdate: data length = " + data.length)织鲸;
}
發(fā)送數據
//為寫特征值設置要發(fā)送的數據舔腾,datas為byte數組
characteristicWrite.setValue(datas);
//gatt發(fā)送數據
bluetoothGatt.writeCharacteristic(characteristicWrite);
小結
BLE的使用主要難點在建立連接部分搂擦,需要在實際編程中理解連接過程以及相應
BluetoothGattCallback 回調調用過程稳诚。BluetoothGattCallback回調函數中不做實際的數據的處理,一般通過發(fā)送廣播瀑踢,在廣播接受者中處理相應的過程和數據扳还。