最近做了有關安卓BLE藍牙開發的東西,所以在這裏記錄一下,是一些入門的知識。希望能幫到正需要學習安卓ble藍牙開發的同學。
-
介紹:安卓 4.3(API 18)爲 BLE 的核心功能提供平臺支持和 API,App 可以利用它來發現設 備、查詢服務和讀寫特性。相比傳統的藍牙,BLE 更顯著的特點是低功耗。這一優 點使 Android App 可以與具有低功耗要求的 BLE 設備通信,如近距離傳感器、心臟 速率監視器、健身設備等。
-
角色和責任 :
以下是 Android 設備與 BLE 設備交互時的角色和責任:
中央 VS 外圍設備。 適用於 BLE 連接本身。中央設備掃描,尋找廣播;外 圍設備發出廣播。 GATT 服務端 VS GATT 客戶端。決定了兩個設備在建立連接後如何互相交 流。爲了方便理解,想象你有一個 Android 手機和一個用於活動跟蹤 BLE 設備,手機支 持中央角色,活動跟蹤器支持外圍(爲了建立 BLE 連接你需要注意兩件事,只支持 外圍設備的兩方或者只支持中央設備的兩方不能互相通信)。 當手機和運動追蹤器建立連接後,他們開始向另一方傳輸 GATT 數據。哪一方作爲 服務器取決於他們傳輸數據的種類。例如,如果運動追蹤器想向手機報告傳感器數 據,運動追蹤器是服務端。如果運動追蹤器更新來自手機的數據,手機會作爲服務 端。
代碼編寫:
- 權限部分:我開發過程中要了以下幾個權限,才能正常使用相應功能。有些運行時申請的權限請各位讀者自行申請權限。
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
2. 第一步:檢查設備是否支持BLE
private void check()//檢查設備是否支持BLE
{
if (this.checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, PERMISSION_REQUEST_COARSE_LOCATION); }
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE))
{
Toast.makeText(this, "此設備不支持BLE功能", Toast.LENGTH_SHORT).show();
finish();
}
}
3. 第二步:開啓BLE藍牙
mBluetoothAdapter 是藍牙設配器在整個藍牙開發中有重要功能,後續也會用到這個對象,所以這裏我們先初始化它。
private void bleTurnOn()//開啓BLE藍牙
{
final BluetoothManager bluetoothManager =(BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter();
// 確保藍牙在設備上可以開啓
if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled())
{
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
}
4. 開啓/停止掃描藍牙設備:
mBluetoothAdapter這裏充當了開啓/停止藍牙掃描的功能。
private void scanLeDevice(final boolean enable)
{
if(enable){
//時間超出預定掃描時間後,停止掃描。
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
if(mScanning) {
mScanning = false;
mBluetoothAdapter.stopLeScan(mLeScanCallback);
}
}
},SCAN_PERIOD);
mScanning = true;
mBluetoothAdapter.startLeScan(mLeScanCallback);
}else{
mScanning = false;
mBluetoothAdapter.stopLeScan(mLeScanCallback);
}
}
5.掃描的回調可以在這裏連接設備
private BluetoothAdapter.LeScanCallback mLeScanCallback =new
BluetoothAdapter.LeScanCallback() {
@Override
public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord)
{
if(device.getName()!=null&&device.getName().equals(bleName)){
connect(device);
}
Log.d("scanResult","掃描到了一個BLE設備"+device.getName());
runOnUiThread(new Runnable() {
@Override
public void run(){
Toast.makeText(MainActivity.this,"掃描到"+device.getName(),Toast.LENGTH_SHORT).show();
}
});
}
};
6.我們在這裏看一下
mGattCallback
的代碼。這也是BLE藍牙開發的重要核心。
連接成功時,發現服務,寫入數據....,都會回調
mGattCallback
的相應方法。
private BluetoothGattCallback mGattCallback= new BluetoothGattCallback() {
// 連接狀態改變的回調
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status,
int newState) {
};
// 發現服務回調
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
};
@Override
public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
// 由mBluetoothGatt.readRemoteRssi()調用得到,可不停刷新rssi信號強度
}
// 寫描述信息回調
@Override
public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor
descriptor, int status) {
};
// 寫操作回調
@Override
public void onCharacteristicWrite(BluetoothGatt gatt,BluetoothGattCharacteristic
characteristic, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
}
};
// 讀操作回調
@Override
public void onCharacteristicRead(BluetoothGatt gatt,BluetoothGattCharacteristic
characteristic, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
}
}
// 數據改變回調(接收BLE設備發送的數據)
@Override
public void onCharacteristicChanged(BluetoothGatt gatt,BluetoothGattCharacteristic
characteristic) {
};
};
}
7.連接設備
這裏我們首先停止掃描藍牙,然後用device.connectGatt()連接藍牙設備。
private void connect(BluetoothDevice device)
{
mBluetoothAdapter.stopLeScan(mLeScanCallback);
mBluetoothGatt=device.connectGatt(MainActivity.this,false,mGattCallback);
mScanning=false;
}
8.掃描服務:我們可以在
public void onConnectionStateChange(BluetoothGatt gatt, int status,
int newState) {
};
裏先判斷連接是否成功然後使用
mBluetoothGatt.discoverServices();
掃描設備的服務。這裏給出一個例子代碼:
public void onConnectionStateChange(final BluetoothGatt gatt, int status, int newState) {
if (newState == BluetoothProfile.STATE_CONNECTED) {//當前藍牙設備已經連接
intentAction = ACTION_GATT_CONNECTED;
mConnectionState = STATE_CONNECTED;//記錄連接狀態的
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this,gatt.getDevice().getName()+"設備已經連接",Toast.LENGTH_SHORT).show();
}
});
mBluetoothGatt.discoverServices();
Log.i("connected", "Connected to GATT server.");
Log.i("serviceFinding", "Attempting to start service discovery:" + mBluetoothGatt.discoverServices());
}
}
}
掃描到服務回調onServicesDiscovered(...)方法。
這裏給出示例代碼:
public void onServicesDiscovered(BluetoothGatt gatt, int status){
if (status == BluetoothGatt.GATT_SUCCESS) {
List<BluetoothGattService> serviceList= gatt.getServices();//獲取服務列表
}
}
9.針對一個服務我們可以獲取它的特徵列表。然後對相應特徵進行讀寫操作。
List<BluetoothGattCharacteristic> mlist=service.getCharacteristics();
10.讀取特徵數據
mBluetoothGatt.readCharacteristic(Characteristic a);
//使用mBluetoothGatt的readCharacteristic()進行讀取即可。
11.寫入特徵數據
private void writeData(byte hexData[], BluetoothGattCharacteristic characteristic){
characteristic.setValue(hexData);//先設置值,再寫入。數據是比特數組。
mBluetoothGatt.writeCharacteristic(characteristic);
}
12.注意要想寫入之後收到BLE設備的通知應該設置接受通知。示例代碼如下:
public void setCharacteristicNotification() {
BluetoothGattDescriptor descriptor = readCharacteristic.getDescriptors().get(0);
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
mBluetoothGatt.writeDescriptor(descriptor);
mBluetoothGatt.setCharacteristicNotification(readCharacteristic, true);
}
13.備註:
所有關於FTPClient的操作都要異步執行,否則就會出現錯誤。