ble 蓝牙API

    xiaoxiao2025-06-15  15

    整理翻译自:https://developer.android.com/guide/topics/connectivity/bluetooth-le.html

    首次翻译,内容错误请指正,不明白的地方可以参考原文

    在你的应用通过BLE通信之前,你需要检查你的设备是否支持BLE,如果支持,确保已经使能蓝牙功能,如果不支持BLE,那你需要在你应用里优雅的不要使用蓝牙的一些特性 如果你的设备支持BLE,但是被禁用了,你可以在你的程序里使能蓝牙,这项操作可以通过BluetoothAdapter,分两步来完成。 使能蓝牙 1.  获取BluetoothAdapter BlueAdapter操作自身蓝牙,整个系统中只有一个Bluetooth Adapter // Initializes Bluetooth adapter.privateBluetoothAdapter mBluetoothAdapter; finalBluetoothManager bluetoothManager =        (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);mBluetoothAdapter = bluetoothManager.getAdapter(); 2. 使能蓝牙 // Ensures Bluetooth is available on the device and it is enabled. If not,// displays a dialog requesting user permission to enable Bluetooth.if(mBluetoothAdapter ==null||!mBluetoothAdapter.isEnabled()){    Intent enableBtIntent =newIntent(BluetoothAdapter.ACTION_REQUEST_ENABLE);    startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);} 扫描BLE 设备 你可以通过  startLeScan()   方法查照附近的BLE设备,这个方法需要传入一个BluetoothAdapter.LeScanCallback  的参数,这个参数是一个回调参数,你需要实现其中的回调。扫描操作对电量比较敏感,你需要遵循以下原则: 1. 一旦找到设备就停止扫描 2. 不要在循环中调用扫描,设置一个扫描时间限值,如果先前扫到的设备可能暂时不在扫描的有效距离之内,所以继续扫描有可能耗干电量。 扫描过程: /** * Activity for scanning and displaying available BLE devices. */publicclassDeviceScanActivityextendsListActivity{    privateBluetoothAdapter mBluetoothAdapter;    privateboolean mScanning;    privateHandler mHandler;    // Stops scanning after 10 seconds.    privatestaticfinallong SCAN_PERIOD =10000;    ...    privatevoid scanLeDevice(finalboolean enable){        if(enable){            // Stops scanning after a pre-defined scan period.            mHandler.postDelayed(newRunnable(){                @Override                publicvoid run(){                    mScanning =false;                    mBluetoothAdapter.stopLeScan(mLeScanCallback);                }            }, SCAN_PERIOD);            mScanning =true;            mBluetoothAdapter.startLeScan(mLeScanCallback);        }else{            mScanning =false;            mBluetoothAdapter.stopLeScan(mLeScanCallback);        }        ...    }...} 如果你只想扫描指定类型的外围设备,你可以调用方法 startLeScan(UUID[], BluetoothAdapter.LeScanCallback),替代上述扫描。这个方法提供了一个UUID 数组 作为程序支持的GATT Server服务的标志。 扫描回调函数 privateBluetoothAdapter.LeScanCallback mLeScanCallback =        newBluetoothAdapter.LeScanCallback(){    @Override    publicvoid onLeScan(finalBluetoothDevice device,int rssi,            byte[] scanRecord){        runOnUiThread(newRunnable(){           @Override           publicvoid run(){               mLeDeviceListAdapter.addDevice(device);               mLeDeviceListAdapter.notifyDataSetChanged();           }       });   }}; 注意:扫描的过程中可以扫到BLE设备,同时也可以扫描到经典蓝牙设备 连接一个 GATT Server 与BLE设备通信的首要步骤就是去连接他,准确的说应该是连接他的GATT Server。您可以调用 connectGatt()  方法 连接一个BLE设备的GATT Server。这个方法有三个形参,Context 对象, 自动连接标志(autoConnect 标志这个设备蓝牙可用时是否自动连接这个BLE设备) 和 BluetoothGattCallback  回调的引用,如下: mBluetoothGatt = device.connectGatt(this,false, mGattCallback); 连接作为主设备的GATT Server,返回了一个 BluetoothGatt  句柄,通过这个句柄你可以进行一些GATT Client的一些操作。调用者就是GATT Client,例如Android应用程序。回调函数BluetoothGattCallback 主要是用来向Client传递一些结果,例如连接状态,以及进一步的GATT Client的操作 在这个例子中,BLE 应用程序提供了一个Activity 来连接,显示数据  显示设备支持的 GATT services  和 characteristics 。Activity 获取用户的输入,与一个被称为BluetoothLeService 的Service进行通信。这个服务通过Android BLE API 与BLE设备进行通信 // A service that interacts with the BLE device via the Android BLE API.publicclassBluetoothLeServiceextendsService{    privatefinalstaticString TAG =BluetoothLeService.class.getSimpleName();    privateBluetoothManager mBluetoothManager;    privateBluetoothAdapter mBluetoothAdapter;    privateString mBluetoothDeviceAddress;    privateBluetoothGatt mBluetoothGatt;    privateint mConnectionState = STATE_DISCONNECTED;    privatestaticfinalint STATE_DISCONNECTED =0;    privatestaticfinalint STATE_CONNECTING =1;    privatestaticfinalint STATE_CONNECTED =2;    publicfinalstaticString ACTION_GATT_CONNECTED =            "com.example.bluetooth.le.ACTION_GATT_CONNECTED";    publicfinalstaticString ACTION_GATT_DISCONNECTED =            "com.example.bluetooth.le.ACTION_GATT_DISCONNECTED";    publicfinalstaticString ACTION_GATT_SERVICES_DISCOVERED =            "com.example.bluetooth.le.ACTION_GATT_SERVICES_DISCOVERED";    publicfinalstaticString ACTION_DATA_AVAILABLE =            "com.example.bluetooth.le.ACTION_DATA_AVAILABLE";    publicfinalstaticString EXTRA_DATA =            "com.example.bluetooth.le.EXTRA_DATA";    publicfinalstatic UUID UUID_HEART_RATE_MEASUREMENT =            UUID.fromString(SampleGattAttributes.HEART_RATE_MEASUREMENT);    // Various callback methods defined by the BLE API.    privatefinalBluetoothGattCallback mGattCallback =            newBluetoothGattCallback(){        @Override        publicvoid onConnectionStateChange(BluetoothGatt gatt,int status,                int newState){            String intentAction;            if(newState ==BluetoothProfile.STATE_CONNECTED){                intentAction = ACTION_GATT_CONNECTED;                mConnectionState = STATE_CONNECTED;                broadcastUpdate(intentAction);                Log.i(TAG,"Connected to GATT server.");                Log.i(TAG,"Attempting to start service discovery:"+                        mBluetoothGatt.discoverServices());            }elseif(newState ==BluetoothProfile.STATE_DISCONNECTED){                intentAction = ACTION_GATT_DISCONNECTED;                mConnectionState = STATE_DISCONNECTED;                Log.i(TAG,"Disconnected from GATT server.");                broadcastUpdate(intentAction);            }        }        @Override        // New services discovered        publicvoid onServicesDiscovered(BluetoothGatt gatt,int status){            if(status ==BluetoothGatt.GATT_SUCCESS){                broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);            }else{                Log.w(TAG,"onServicesDiscovered received: "+ status);            }        }        @Override        // Result of a characteristic read operation        publicvoid onCharacteristicRead(BluetoothGatt gatt,                BluetoothGattCharacteristic characteristic,                int status){            if(status ==BluetoothGatt.GATT_SUCCESS){                broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);            }        }     ...    };...} 当回调被触发后,会调用一个合适的broadcastUpdate() 方法传这个动作 privatevoid broadcastUpdate(finalString action){    finalIntent intent =newIntent(action);    sendBroadcast(intent);}privatevoid broadcastUpdate(finalString action,                             finalBluetoothGattCharacteristic characteristic){    finalIntent intent =newIntent(action);    // This is special handling for the Heart Rate Measurement profile. Data    // parsing is carried out as per profile specifications.    if(UUID_HEART_RATE_MEASUREMENT.equals(characteristic.getUuid())){        int flag = characteristic.getProperties();        int format =-1;        if((flag &0x01)!=0){            format =BluetoothGattCharacteristic.FORMAT_UINT16;            Log.d(TAG,"Heart rate format UINT16.");        }else{            format =BluetoothGattCharacteristic.FORMAT_UINT8;            Log.d(TAG,"Heart rate format UINT8.");        }        finalint heartRate = characteristic.getIntValue(format,1);        Log.d(TAG,String.format("Received heart rate: %d", heartRate));        intent.putExtra(EXTRA_DATA,String.valueOf(heartRate));    }else{        // For all other profiles, writes the data formatted in HEX.        finalbyte[] data = characteristic.getValue();        if(data !=null&& data.length >0){            finalStringBuilder stringBuilder =newStringBuilder(data.length);            for(byte byteChar : data)                stringBuilder.append(String.format("%02X ", byteChar));            intent.putExtra(EXTRA_DATA,newString(data)+"\n"+                    stringBuilder.toString());        }    }    sendBroadcast(intent);} 回到 主Activity(DeviceControlActivity),这些事件主要通过广播 BroadcastReceiver 来传递 // Handles various events fired by the Service.// ACTION_GATT_CONNECTED: connected to a GATT server.// ACTION_GATT_DISCONNECTED: disconnected from a GATT server.// ACTION_GATT_SERVICES_DISCOVERED: discovered GATT services.// ACTION_DATA_AVAILABLE: received data from the device. This can be a// result of read or notification operations.privatefinalBroadcastReceiver mGattUpdateReceiver =newBroadcastReceiver(){    @Override    publicvoid onReceive(Context context,Intent intent){        finalString action = intent.getAction();        if(BluetoothLeService.ACTION_GATT_CONNECTED.equals(action)){            mConnected =true;            updateConnectionState(R.string.connected);            invalidateOptionsMenu();        }elseif(BluetoothLeService.ACTION_GATT_DISCONNECTED.equals(action)){            mConnected =false;            updateConnectionState(R.string.disconnected);            invalidateOptionsMenu();            clearUI();        }elseif(BluetoothLeService.                ACTION_GATT_SERVICES_DISCOVERED.equals(action)){            // Show all the supported services and characteristics on the            // user interface.            displayGattServices(mBluetoothLeService.getSupportedGattServices());        }elseif(BluetoothLeService.ACTION_DATA_AVAILABLE.equals(action)){            displayData(intent.getStringExtra(BluetoothLeService.EXTRA_DATA));        }    }};

    读取BLE的属性

    一旦您的应用连接到BLE的GATT Server 并获取了对应的services,就可以对属性进行读写了,例如下述例子就是遍历Service和Characteristic,并展示到UI上 publicclassDeviceControlActivityextendsActivity{    ...    // Demonstrates how to iterate through the supported GATT    // Services/Characteristics.    // In this sample, we populate the data structure that is bound to the    // ExpandableListView on the UI.    privatevoid displayGattServices(List<BluetoothGattService> gattServices){        if(gattServices ==null)return;        String uuid =null;        String unknownServiceString = getResources().                getString(R.string.unknown_service);        String unknownCharaString = getResources().                getString(R.string.unknown_characteristic);        ArrayList<HashMap<String,String>> gattServiceData =                newArrayList<HashMap<String,String>>();        ArrayList<ArrayList<HashMap<String,String>>> gattCharacteristicData                =newArrayList<ArrayList<HashMap<String,String>>>();        mGattCharacteristics =                newArrayList<ArrayList<BluetoothGattCharacteristic>>();        // Loops through available GATT Services.        for(BluetoothGattService gattService : gattServices){            HashMap<String,String> currentServiceData =                    newHashMap<String,String>();            uuid = gattService.getUuid().toString();            currentServiceData.put(                    LIST_NAME,SampleGattAttributes.                            lookup(uuid, unknownServiceString));            currentServiceData.put(LIST_UUID, uuid);            gattServiceData.add(currentServiceData);            ArrayList<HashMap<String,String>> gattCharacteristicGroupData =                    newArrayList<HashMap<String,String>>();            List<BluetoothGattCharacteristic> gattCharacteristics =                    gattService.getCharacteristics();            ArrayList<BluetoothGattCharacteristic> charas =                    newArrayList<BluetoothGattCharacteristic>();           // Loops through available Characteristics.            for(BluetoothGattCharacteristic gattCharacteristic :                    gattCharacteristics){                charas.add(gattCharacteristic);                HashMap<String,String> currentCharaData =                        newHashMap<String,String>();                uuid = gattCharacteristic.getUuid().toString();                currentCharaData.put(                        LIST_NAME,SampleGattAttributes.lookup(uuid,                                unknownCharaString));                currentCharaData.put(LIST_UUID, uuid);                gattCharacteristicGroupData.add(currentCharaData);            }            mGattCharacteristics.add(charas);            gattCharacteristicData.add(gattCharacteristicGroupData);         }    ...    }...} 接收 GATT通知 当从设备上的Characteristic 变化时,BLE设备能够接收到这个变化,这个功能对于一个BLE app来说是很常见的。下述例子就是通过调用 setCharacteristicNotification() 方法针对特定的Characteristic设置通知响应 privateBluetoothGatt mBluetoothGatt;BluetoothGattCharacteristic characteristic;boolean enabled;...mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);...BluetoothGattDescriptor descriptor = characteristic.getDescriptor(        UUID.fromString(SampleGattAttributes.CLIENT_CHARACTERISTIC_CONFIG));descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);mBluetoothGatt.writeDescriptor(descriptor); 如果一个Characteristic被设置上了通知,则远端的Characteristic变化时, onCharacteristicChanged() 回调就会被调用 @Override// Characteristic notificationpublicvoid onCharacteristicChanged(BluetoothGatt gatt,        BluetoothGattCharacteristic characteristic){    broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);} 关闭蓝牙连接 publicvoid close(){    if(mBluetoothGatt ==null){        return;    }    mBluetoothGatt.close();    mBluetoothGatt =null;}
    转载请注明原文地址: https://ju.6miu.com/read-1299959.html
    最新回复(0)