android蓝牙4.0使用方法
藍(lán)牙介紹
????Android?4.3(API?Level?18)介紹了內(nèi)置平臺(tái)支持藍(lán)牙低能量的核心作用,并提供了API,應(yīng)用程序可以用它來(lái)發(fā)現(xiàn)設(shè)備,查詢服務(wù),和讀寫(xiě)字符。與傳統(tǒng)的藍(lán)牙相比,Bluetooth?Low?Energy?(BLE)?旨在提供顯著降低功耗。這使得Android應(yīng)用能夠與具有BLE的低耗能設(shè)備進(jìn)行通信,例如,傳感器、心率監(jiān)視器,健身設(shè)備,等等。
BLE?權(quán)限
????為了在應(yīng)用程序中使用藍(lán)牙功能,必須聲明藍(lán)牙藍(lán)牙許可。您需要這個(gè)權(quán)限執(zhí)行任何藍(lán)牙通信,如請(qǐng)求連接,接受連接,傳輸數(shù)據(jù)。?
????聲明藍(lán)牙權(quán)限需要在應(yīng)用的manifest?文件中加如下代碼:
<uses-permission?android:name="android.permission.BLUETOOTH"/>
<uses-permission?android:name="android.permission.BLUETOOTH_ADMIN"/>
?
如果你想聲明應(yīng)用程序僅BLE-capable設(shè)備可用,在你的應(yīng)用程序的清單包括以下:?
<uses-feature?android:name="android.hardware.bluetooth_le"?android:required="true"/>
然而,如果你想讓你的應(yīng)用程序可用的設(shè)備不支持BLE,你應(yīng)該還是這個(gè)元素包含在您的應(yīng)用程序的清單,但在運(yùn)行時(shí)設(shè)置android:required=“false”。在運(yùn)行時(shí)您可以決定BLE可用性通過(guò)使用PackageManager.hasSystemFeature():?
????????? //用這個(gè)檢查設(shè)備是否支持BLE。
???????? if?(!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE))?{
???????????????????? Toast.makeText(this,?R.string.ble_not_supported,?Toast.LENGTH_SHORT).show();
????????????????? ??finish();
??????????????? }
設(shè)置BLE
????BLE在您的應(yīng)用程序可以交互之前,你需要確認(rèn)在設(shè)備上是支持BLE,如果是這樣,確保啟用。注意這檢查需要設(shè)置<?uses-feature…/?>為false。
????如果不支持BLE,那么你應(yīng)該禁用任何BLE特性。如果支持,但是已經(jīng)禁用,你可以用你的應(yīng)用啟動(dòng)它。完成這個(gè)設(shè)置需要兩步,使用BluetoothAdapter。
1.獲取luetoothAdapter。
????BluetoothAdapter代表設(shè)備的藍(lán)牙適配器。整個(gè)系統(tǒng)有一個(gè)藍(lán)牙適配器,和您的應(yīng)用程序可以使用這個(gè)對(duì)象與它交互。下面的代碼片段顯示了如何獲取適配器。使用getSystemService?()返回一個(gè)BluetoothManager實(shí)例,然后獲取適配器。
Android?4.3(API?LEVEL?18)引入了BluetoothManager:
//初始化藍(lán)牙適配器
final?BluetoothManager?bluetoothManager?=
????????(BluetoothManager)?getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter?=?bluetoothManager.getAdapter();
2.啟動(dòng)藍(lán)牙
???接下來(lái),您需要確保啟用藍(lán)牙。用isEnabled()檢查藍(lán)牙當(dāng)前是否啟動(dòng)。如果這個(gè)方法返回false,那么藍(lán)牙是關(guān)閉的。下面的代碼片段檢查是否啟用藍(lán)牙。如果沒(méi)有,將提示用戶去設(shè)置啟用藍(lán)牙。
if?(mBluetoothAdapter?==?null?||?!mBluetoothAdapter.isEnabled())?{
????Intent?enableBtIntent?=?new?Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
????startActivityForResult(enableBtIntent,?REQUEST_ENABLE_BT);
}
?
搜索藍(lán)牙設(shè)備
??搜索藍(lán)牙設(shè)備使用startLeScan()方法。該方法以BluetoothAdapter.LeScanCallback作為參數(shù),您必須實(shí)現(xiàn)這個(gè)回調(diào),因?yàn)檫@是如何返回掃描結(jié)果。因?yàn)閽呙?/span>非常耗電,你應(yīng)該遵守如下規(guī)則:
·?只要找到了設(shè)備就應(yīng)該停止搜索。
·?不要在一個(gè)無(wú)限循環(huán)中搜索,?需要設(shè)置一個(gè)時(shí)間限制搜索.?
?
下面代碼作用是如何開(kāi)始和結(jié)束搜索:
?
?
public?class?DeviceScanActivity?extends?ListActivity?{
????private?BluetoothAdapter?mBluetoothAdapter;
????private?boolean?mScanning;
????private?Handler?mHandler;
????//?Stops?scanning?after?10?seconds.
????private?static?final?long?SCAN_PERIOD?=?10000;
????...
????private?void?scanLeDevice(final?boolean?enable)?{
????????if?(enable)?{
????????????//?Stops?scanning?after?a?pre-defined?scan?period.
????????????mHandler.postDelayed(new?Runnable()?{
????????????????@Override
????????????????public?void?run()?{
????????????????????mScanning?=?false;
????????????????????mBluetoothAdapter.stopLeScan(mLeScanCallback);
????????????????}
????????????},?SCAN_PERIOD);
????????????mScanning?=?true;
????????????mBluetoothAdapter.startLeScan(mLeScanCallback);
????????}?else?{
????????????mScanning?=?false;
????????????mBluetoothAdapter.stopLeScan(mLeScanCallback);
????????}
????????...
????}
...
}
????如果你想只掃描特定類(lèi)型的外圍設(shè)備,你可以使用startLeScan(UUID[],BluetoothAdapter.LeScanCallback),提供一個(gè)UUID對(duì)象數(shù)組,指定藍(lán)牙服務(wù)應(yīng)用程序所支持的。?
????這里使用BluetoothAdapter.LeScanCallback的實(shí)現(xiàn)用來(lái)顯示藍(lán)牙掃描結(jié)果:
private?LeDeviceListAdapter?mLeDeviceListAdapter;
...
//?Device?scan?callback.
private?BluetoothAdapter.LeScanCallback?mLeScanCallback?=
????????new?BluetoothAdapter.LeScanCallback()?{
????@Override
????public?void?onLeScan(final?BluetoothDevice?device,?int?rssi,
????????????byte[]?scanRecord)?{
????????runOnUiThread(new?Runnable()?{
???????????@Override
???????????public?void?run()?{
???????????????mLeDeviceListAdapter.addDevice(device);
???????????????mLeDeviceListAdapter.notifyDataSetChanged();
???????????}
???????});
???}
};
注意:不能在同一時(shí)間掃描BLE和傳統(tǒng)的藍(lán)牙。
鏈接?GATT?Server
??????與BLE設(shè)備交互的第一步是連接到它,更具體地說(shuō),連接到設(shè)備上的GATT服務(wù)器。連接到GATT服務(wù)器使用connectGatt()方法,這個(gè)方法取三個(gè)參數(shù):一個(gè)上下文對(duì)象,(布爾指示是否自動(dòng)連接到設(shè)備就可用),和BluetoothGattCallback回調(diào)函數(shù)。
mBluetoothGatt?=?device.connectGatt(this,?false,?mGattCallback);
????這個(gè)連接到GATT服務(wù)端通過(guò)BLE設(shè)備,并返回一個(gè)BluetoothGatt實(shí)例,然后您可以使用GATT客戶端進(jìn)行操作。調(diào)用者(Android應(yīng)用程序)是GATT客戶端。BluetoothGattCallback用于提供結(jié)果給客戶端,如連接狀態(tài),以及任何進(jìn)一步的GATT客戶端操作。
?????在這個(gè)例子中,有幸獲得應(yīng)用程序提供了一個(gè)活動(dòng)(DeviceControlActivity)連接,顯示數(shù)據(jù),并顯示GATT服務(wù)和支持的設(shè)備特征。基于用戶輸入,此活動(dòng)與一個(gè)服務(wù)交互稱(chēng)為BluetoothLeService,這服務(wù)與BLE設(shè)備交互是通過(guò)Android?BLE?API:
public?class?BluetoothLeService?extends?Service?{
????private?final?static?String?TAG?=?BluetoothLeService.class.getSimpleName();
????private?BluetoothManager?mBluetoothManager;
????private?BluetoothAdapter?mBluetoothAdapter;
????private?String?mBluetoothDeviceAddress;
????private?BluetoothGatt?mBluetoothGatt;
????private?int?mConnectionState?=?STATE_DISCONNECTED;
????private?static?final?int?STATE_DISCONNECTED?=?0;
????private?static?final?int?STATE_CONNECTING?=?1;
????private?static?final?int?STATE_CONNECTED?=?2;
????public?final?static?String?ACTION_GATT_CONNECTED?=
????????????"com.example.bluetooth.le.ACTION_GATT_CONNECTED";
????public?final?static?String?ACTION_GATT_DISCONNECTED?=
????????????"com.example.bluetooth.le.ACTION_GATT_DISCONNECTED";
????public?final?static?String?ACTION_GATT_SERVICES_DISCOVERED?=
????????????"com.example.bluetooth.le.ACTION_GATT_SERVICES_DISCOVERED";
????public?final?static?String?ACTION_DATA_AVAILABLE?=
????????????"com.example.bluetooth.le.ACTION_DATA_AVAILABLE";
????public?final?static?String?EXTRA_DATA?=
????????????"com.example.bluetooth.le.EXTRA_DATA";
????public?final?static?UUID?UUID_HEART_RATE_MEASUREMENT?=
????????????UUID.fromString(SampleGattAttributes.HEART_RATE_MEASUREMENT);
????//?Various?callback?methods?defined?by?the?BLE?API.
????private?final?BluetoothGattCallback?mGattCallback?=
????????????new?BluetoothGattCallback()?{
????????@Override
????????public?void?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());
????????????}?else?if?(newState?==?BluetoothProfile.STATE_DISCONNECTED)?{
????????????????intentAction?=?ACTION_GATT_DISCONNECTED;
????????????????mConnectionState?=?STATE_DISCONNECTED;
????????????????Log.i(TAG,?"Disconnected?from?GATT?server.");
????????????????broadcastUpdate(intentAction);
????????????}
????????}
????????@Override
????????//?New?services?discovered
????????public?void?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
????????public?void?onCharacteristicRead(BluetoothGatt?gatt,
????????????????BluetoothGattCharacteristic?characteristic,
????????????????int?status)?{
????????????if?(status?==?BluetoothGatt.GATT_SUCCESS)?{
????????????????broadcastUpdate(ACTION_DATA_AVAILABLE,?characteristic);
????????????}
????????}
?????...
????};
...
}
?
?
????當(dāng)一個(gè)特定的回調(diào)函數(shù)被觸發(fā),它調(diào)用適當(dāng)?shù)?span style="font-family:Times New Roman">broadcastUpdate()輔助方法并將其傳遞一個(gè)action。注意,本節(jié)中的數(shù)據(jù)解析執(zhí)行按照藍(lán)牙心率測(cè)量概要文件規(guī)范:
private?void?broadcastUpdate(final?String?action)?{
????final?Intent?intent?=?new?Intent(action);
????sendBroadcast(intent);
}
private?void?broadcastUpdate(final?String?action,
?????????????????????????????final?BluetoothGattCharacteristic?characteristic)?{
????final?Intent?intent?=?new?Intent(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.");
????????}
????????final?int?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.
????????final?byte[]?data?=?characteristic.getValue();
????????if?(data?!=?null?&&?data.length?>?0)?{
????????????final?StringBuilder?stringBuilder?=?new?StringBuilder(data.length);
????????????for(byte?byteChar?:?data)
????????????????stringBuilder.append(String.format("%02X?",?byteChar));
????????????intent.putExtra(EXTRA_DATA,?new?String(data)?+?"\n"?+
????????????????????stringBuilder.toString());
????????}
????}
????sendBroadcast(intent);
}
Back?in?DeviceControlActivity,?these?events?are?handled?by?a?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.
private?final?BroadcastReceiver?mGattUpdateReceiver?=?new?BroadcastReceiver()?{
????@Override
????public?void?onReceive(Context?context,?Intent?intent)?{
????????final?String?action?=?intent.getAction();
????????if?(BluetoothLeService.ACTION_GATT_CONNECTED.equals(action))?{
????????????mConnected?=?true;
????????????updateConnectionState(R.string.connected);
????????????invalidateOptionsMenu();
????????}?else?if?(BluetoothLeService.ACTION_GATT_DISCONNECTED.equals(action))?{
????????????mConnected?=?false;
????????????updateConnectionState(R.string.disconnected);
????????????invalidateOptionsMenu();
????????????clearUI();
????????}?else?if?(BluetoothLeService.
????????????????ACTION_GATT_SERVICES_DISCOVERED.equals(action))?{
????????????//?Show?all?the?supported?services?and?characteristics?on?the
????????????//?user?interface.
????????????displayGattServices(mBluetoothLeService.getSupportedGattServices());
????????}?else?if?(BluetoothLeService.ACTION_DATA_AVAILABLE.equals(action))?{
????????????displayData(intent.getStringExtra(BluetoothLeService.EXTRA_DATA));
????????}
????}
};
?
閱讀BLE屬性?
????一旦你的Android應(yīng)用程序連接到一個(gè)GATT服務(wù)器和發(fā)現(xiàn)服務(wù),它可以讀取和寫(xiě)入屬性。例如,這段代碼遍歷服務(wù)器的服務(wù)和數(shù)據(jù)并將它們顯示在UI中:
public?class?DeviceControlActivity?extends?Activity?{
????...
????//?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.
????private?void?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?=
????????????????new?ArrayList<HashMap<String,?String>>();
????????ArrayList<ArrayList<HashMap<String,?String>>>?gattCharacteristicData
????????????????=?new?ArrayList<ArrayList<HashMap<String,?String>>>();
????????mGattCharacteristics?=
????????????????new?ArrayList<ArrayList<BluetoothGattCharacteristic>>();
????????//?Loops?through?available?GATT?Services.
????????for?(BluetoothGattService?gattService?:?gattServices)?{
????????????HashMap<String,?String>?currentServiceData?=
????????????????????new?HashMap<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?=
????????????????????new?ArrayList<HashMap<String,?String>>();
????????????List<BluetoothGattCharacteristic>?gattCharacteristics?=
????????????????????gattService.getCharacteristics();
????????????ArrayList<BluetoothGattCharacteristic>?charas?=
????????????????????new?ArrayList<BluetoothGattCharacteristic>();
???????????//?Loops?through?available?Characteristics.
????????????for?(BluetoothGattCharacteristic?gattCharacteristic?:
????????????????????gattCharacteristics)?{
????????????????charas.add(gattCharacteristic);
????????????????HashMap<String,?String>?currentCharaData?=
????????????????????????new?HashMap<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通知
???當(dāng)一個(gè)特定的設(shè)備上的特征變化需要BLE的應(yīng)用通知。這個(gè)代碼片段顯示了如何設(shè)置一個(gè)通知特性,使用setCharacteristicNotification()方法:
?
?
private?BluetoothGatt?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);
?????一旦通知作為一個(gè)特性被啟用,如果遠(yuǎn)程設(shè)備上的特性變化將觸發(fā)onCharacteristicChanged()回調(diào)。
?
@Override
//?Characteristic?notification
public?void?onCharacteristicChanged(BluetoothGatt?gatt,
????????BluetoothGattCharacteristic?characteristic)?{
????broadcastUpdate(ACTION_DATA_AVAILABLE,?characteristic);
}
關(guān)閉客戶端應(yīng)用
?
????一旦應(yīng)用程序完成使用BLE設(shè)備,應(yīng)該調(diào)用close()方法去釋放系統(tǒng)資源。
public?void?close()?{
????if?(mBluetoothGatt?==?null)?{
????????return;
????}
????mBluetoothGatt.close();
????mBluetoothGatt?=?null;
}
總結(jié)
以上是生活随笔為你收集整理的android蓝牙4.0使用方法的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 阿里后端学习计划
- 下一篇: WDS+MDT网络部署操作系统