最近在做藍牙相關的開發(fā),雖然說 FastBleLib 這樣的第三方藍牙連接庫非常方便,但是原生開發(fā)還是有必要了解一下的。
首先說明
1.不需要問硬件工程師UUID
2.不需要寫 UI
3.本案例只有一個類文件
4.沒有寫動態(tài)請求藍牙權限相關的,自己測試過程中,手動開啟所有權限即可。
5.代碼解釋全部寫在注釋,和日志
<uses-permission android:name="android.permission.BLUETOOTH"/>
<!--此權限不開,可能搜不到藍牙設備-->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
public class Main8Activity extends AppCompatActivity {
// 藍牙適配器對象,用于掃描藍牙設備
private BluetoothAdapter bluetoothAdapter;
// GATT 通信,連接藍牙,發(fā)送指令,以及接收藍牙通知 ( 這里所謂的通知,就是藍牙傳過來的數(shù)據(jù) )
private BluetoothGatt bluetoothGatt;
// 如果藍牙沒有開啟
private final static int REQUEST_ENABLE = 100;
// 掃描到的藍牙設備,因為 Set 不會重復,所以用這個數(shù)據(jù)結構
private Set<BluetoothDevice> bluetoothDeviceSet;
// 用戶發(fā)送指令的操作
private BluetoothGattCharacteristic writeBluetoothGattCharacteristic;
// 用于開啟通知的操作
private BluetoothGattCharacteristic notificationBluetoothGattCharacteristic;
// 服務和特征值
private UUID write_UUID_service;
private UUID write_UUID_chara;
private UUID read_UUID_service;
private UUID read_UUID_chara;
private UUID notify_UUID_service;
private UUID notify_UUID_chara;
private UUID indicate_UUID_service;
private UUID indicate_UUID_chara;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main8);
log("初始化藍牙掃描 的 set 集合");
bluetoothDeviceSet = new HashSet<>();
log("開始獲取藍牙適配器");
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if(bluetoothAdapter != null){
log("bluetoothAdapter 不為 null 當前設備支持藍牙");
if(!bluetoothAdapter.isEnabled()){
log("藍牙未啟動,正在使用 intent 啟用藍牙");
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(intent,REQUEST_ENABLE);
}else{
log("藍牙已經(jīng)啟動,不需要使用 intent 啟動藍牙");
bluetoothAdapter.getBluetoothLeScanner().startScan(scanCallback);
log("開始掃描藍牙設備");
}
}else{
log("bluetoothAdapter 為 null 所以當前設備不支持藍牙");
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == REQUEST_ENABLE){
if(resultCode == RESULT_OK){
log("用戶允許了開啟藍牙的請求");
log("開始掃描藍牙設備");
bluetoothAdapter.getBluetoothLeScanner().startScan(scanCallback);
}else if(resultCode == RESULT_CANCELED){
log("用戶拒絕了開啟藍牙的請求");
}
}
}
// 藍牙開始掃描回調(diào)
private ScanCallback scanCallback = new ScanCallback() {
@Override
public void onScanResult(int callbackType, ScanResult result) {
super.onScanResult(callbackType, result);
// bluetoothDevice 為掃描到的藍牙設備
BluetoothDevice bluetoothDevice = result.getDevice();
// 添加掃描到的藍牙設備到 set 集合
boolean addResult = bluetoothDeviceSet.add(bluetoothDevice);
// 如果 set 集合中未存在該藍牙對象,則返回true
if(addResult){
//log("onScanResult() 發(fā)現(xiàn)藍牙設備" + bluetoothDevice.getName() + "," + bluetoothDevice.getAddress());
//log("目前已經(jīng)發(fā)現(xiàn)" + bluetoothDeviceSet.size() + "個藍牙設備");
// 如果當前添加的設備 藍牙名稱為 HTC_38908 MAC地址為 88:25:83:F1:04:58,則發(fā)起連接
// 懶得寫 列表 UI 了,這里先直接指定好自己用來測試藍牙的設備
if("HTC_38908".equals(bluetoothDevice.getName()) && "88:25:83:F1:04:58".equals(bluetoothDevice.getAddress()) ){
log("發(fā)現(xiàn)需要連接的設備");
log("因為藍牙掃描比較消耗資源,所以連接前就關閉掃描");
// bluetoothAdapter.stopScan(scanCallback);
bluetoothAdapter.cancelDiscovery();
log("開始 GATT 通信");
bluetoothGatt = bluetoothDevice.connectGatt(Main8Activity.this,true,bluetoothGattCallback);
}
}
}
@Override
public void onBatchScanResults(List<ScanResult> results) {
super.onBatchScanResults(results);
}
@Override
public void onScanFailed(int errorCode) {
super.onScanFailed(errorCode);
}
};
private BluetoothGattCallback bluetoothGattCallback = new BluetoothGattCallback() {
@Override
public void onPhyUpdate(BluetoothGatt gatt, int txPhy, int rxPhy, int status) {
super.onPhyUpdate(gatt, txPhy, rxPhy, status);
}
@Override
public void onPhyRead(BluetoothGatt gatt, int txPhy, int rxPhy, int status) {
super.onPhyRead(gatt, txPhy, rxPhy, status);
}
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
super.onConnectionStateChange(gatt, status, newState);
if(BluetoothGatt.STATE_CONNECTED == newState){ // 藍牙連接狀態(tài)改變 為 -- 已連接
// 將會回調(diào) 本類中的 onServicesDiscovered() 這個方法
boolean result = gatt.discoverServices();
if(result){
log("藍牙連接成功");
}else{
log("藍牙連接失敗");
}
}else if(BluetoothGatt.STATE_DISCONNECTED == newState){ // 藍牙連接狀態(tài)改變?yōu)?-- 連接斷開
log("斷開連接");
}
}
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
super.onServicesDiscovered(gatt, status);
// 這里初始化 各種 服務 和 描述 ,用來發(fā)送藍牙指令的對象,還有接收藍牙數(shù)據(jù)對象
initServiceAndChara();
}
@Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicRead(gatt, characteristic, status);
log("onCharacteristicRead");
}
@Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicWrite(gatt, characteristic, status);
log("onCharacteristicWrite");
}
@Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
super.onCharacteristicChanged(gatt, characteristic);
// 這里將藍牙傳過來的數(shù)據(jù)轉換為 16 進制格式的字符串,便于閱讀
byte[] bytes = characteristic.getValue();
StringBuilder stringBuilder = new StringBuilder();
for (byte b : bytes) {
stringBuilder.append(String.format("%02x", b));
}
log("藍牙傳回來的內(nèi)容 ( 16進制 ) : " + stringBuilder.toString());
}
@Override
public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
super.onDescriptorRead(gatt, descriptor, status);
log("onDescriptorRead");
}
@Override
public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
super.onDescriptorWrite(gatt, descriptor, status);
log("onDescriptorWrite");
}
@Override
public void onReliableWriteCompleted(BluetoothGatt gatt, int status) {
super.onReliableWriteCompleted(gatt, status);
log("onReliableWriteCompleted");
}
@Override
public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
super.onReadRemoteRssi(gatt, rssi, status);
log("onReadRemoteRssi");
}
@Override
public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {
super.onMtuChanged(gatt, mtu, status);
log("onMtuChanged");
}
};
private void initServiceAndChara(){
List<BluetoothGattService> bluetoothGattServices= bluetoothGatt.getServices();
for (BluetoothGattService bluetoothGattService:bluetoothGattServices){
List<BluetoothGattCharacteristic> characteristics=bluetoothGattService.getCharacteristics();
for (BluetoothGattCharacteristic characteristic:characteristics){
int charaProp = characteristic.getProperties();
if ((charaProp & BluetoothGattCharacteristic.PROPERTY_READ) > 0) {
read_UUID_chara=characteristic.getUuid();
read_UUID_service=bluetoothGattService.getUuid();
log("read_chara="+read_UUID_chara+"----read_service="+read_UUID_service);
}
if ((charaProp & BluetoothGattCharacteristic.PROPERTY_INDICATE) > 0) {
indicate_UUID_chara=characteristic.getUuid();
indicate_UUID_service=bluetoothGattService.getUuid();
log("indicate_chara="+indicate_UUID_chara+"----indicate_service="+indicate_UUID_service);
}
if ((charaProp & BluetoothGattCharacteristic.PROPERTY_WRITE) > 0) {
write_UUID_chara=characteristic.getUuid();
write_UUID_service=bluetoothGattService.getUuid();
log("write_chara="+write_UUID_chara+"----write_service="+write_UUID_service);
}
if ((charaProp & BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE) > 0) {
write_UUID_chara=characteristic.getUuid();
write_UUID_service=bluetoothGattService.getUuid();
log("write_chara="+write_UUID_chara+"----write_service="+write_UUID_service);
// 寫入服務
BluetoothGattService service = bluetoothGatt.getService(write_UUID_service);
writeBluetoothGattCharacteristic = service.getCharacteristic(write_UUID_chara);
// 發(fā)送指令
sendBleData("*".getBytes());
}
if ((charaProp & BluetoothGattCharacteristic.PROPERTY_NOTIFY) > 0) {
notify_UUID_chara=characteristic.getUuid();
notify_UUID_service=bluetoothGattService.getUuid();
log("notify_chara="+notify_UUID_chara+"----notify_service="+notify_UUID_service);
// 初始化通知服務
BluetoothGattService service = bluetoothGatt.getService(notify_UUID_service);
notificationBluetoothGattCharacteristic = service.getCharacteristic(notify_UUID_chara);
// 開啟通知
bluetoothGatt.setCharacteristicNotification(notificationBluetoothGattCharacteristic,true);
}
}
}
}
/**
* 發(fā)送數(shù)據(jù)給藍牙
* @param data 數(shù)據(jù)byte[]
* */
private void sendBleData(byte[] data){
writeBluetoothGattCharacteristic.setValue(data);
bluetoothGatt.writeCharacteristic(writeBluetoothGattCharacteristic);
}
/**
* 日志
* @param log 日志內(nèi)容
* */
private void log(String log){
Log.i("藍牙",log);
}
}
以上,相信注釋里面已經(jīng)寫的很清楚了。
然后打開日志看就行了
