藍牙(英語:Bluetooth),一種無線通信技術標準,用來讓固定與移動設備,在短距離間交換數據,以造成我的局域網(PAN)。藍牙技術當前由藍牙技術聯盟(SIG)來負責維護其技術標準。java
藍牙可分爲經典藍牙(Classic Bluetooth)、低功耗藍牙(Bluetooth Low Energy)、雙模藍牙三大類。2009 年發佈的藍牙 3.0 及以前的藍牙版本包括 BR、EDR 和 HS(AMP) 三種藍牙技術,統稱爲經典藍牙技術,只支持經典藍牙技術的藍牙稱爲經典藍牙。2010 年 SIG 聯盟合併了 Wibree 聯盟,並把 Wibree 聯盟提出的低功耗無線技術從新命名爲低功耗藍牙技術(BLE)。2010 年發佈的藍牙 4.0 規格就同時包含經典藍牙和低功耗藍牙,只支持低功耗藍牙技術的藍牙稱爲低功率藍牙,同時支持經典藍牙和低功率藍牙技術的藍牙稱爲雙模藍牙。低功耗藍牙與經典藍牙技術是不兼容的,因此低功耗藍牙和經典藍牙二者之間是不能相互通訊的。android
經典藍牙技術持續保持鏈接,能夠傳輸大數據,適合文件傳輸、音頻播放等,兼容性高,廣播信道多,缺點是鏈接成本高,功耗高;低功耗藍牙鏈接速度快,低功耗,廣播信道少,缺點是數據傳輸量有限制。git
Android 平臺包含藍牙網絡堆棧支持,憑藉此項支持,設備能以無線方式與其餘藍牙設備交換數據。應用框架提供了經過 Android Bluetooth API 訪問藍牙功能的途徑。針對具備低功耗要求的藍牙設備,Android 4.3(API 級別 18)中引入了面向低功耗藍牙的 API 支持。即 SPP 協議(經典藍牙)和 GATT 協議(低功耗藍牙)的鏈接方式。 使用 Android 藍牙功能須要在 Manifest.xml 文件中聲明藍牙權限,若是使用了藍牙掃描功能還須要聲明位置權限,由於藍牙是具備定位功能的,目標版本是 Android 23 及以上版本須要添加動態權限申請。github
<uses-permission android:name="android.permission.BLUETOOTH" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> // 藍牙掃描須要位置權限 <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> 複製代碼
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter() if (!mBluetoothAdapter.isEnabled()) { Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT); } 複製代碼
Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices(); // If there are paired devices if (pairedDevices.size() > 0) { // Loop through paired devices for (BluetoothDevice device : pairedDevices) { // Add the name and address to an array adapter to show in a ListView mArrayAdapter.add(device.getName() + "\n" + device.getAddress()); } } 複製代碼
mBluetoothAdapter.startDiscovery(); // Create a BroadcastReceiver for ACTION_FOUND private final BroadcastReceiver mReceiver = new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { String action = intent.getAction(); // When discovery finds a device if (BluetoothDevice.ACTION_FOUND.equals(action)) { // Get the BluetoothDevice object from the Intent BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); // Add the name and address to an array adapter to show in a ListView mArrayAdapter.add(device.getName() + "\n" + device.getAddress()); } } }; // Register the BroadcastReceiver IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND); registerReceiver(mReceiver, filter); // Don't forget to unregister during onDestroy 複製代碼
private class ConnectThread extends Thread { private final BluetoothSocket mmSocket; private final BluetoothDevice mmDevice; private final InputStream mmInStream; private final OutputStream mmOutStream; public ConnectThread(BluetoothDevice device) { // Use a temporary object that is later assigned to mmSocket, // because mmSocket is final BluetoothSocket tmp = null; mmDevice = device; // Get a BluetoothSocket to connect with the given BluetoothDevice try { // MY_UUID is the app's UUID string, also used by the server code tmp = device.createRfcommSocketToServiceRecord(MY_UUID); } catch (IOException e) { } mmSocket = tmp; } public void run() { // Cancel discovery because it will slow down the connection mBluetoothAdapter.cancelDiscovery(); try { // Connect the device through the socket. This will block // until it succeeds or throws an exception mmSocket.connect(); tmpIn = socket.getInputStream(); tmpOut = socket.getOutputStream(); } catch (IOException connectException) { // Unable to connect; close the socket and get out try { mmSocket.close(); } catch (IOException closeException) { } return; } // Do work to manage the connection (in a separate thread) manageConnectedSocket(mmSocket); } /** Will cancel an in-progress connection, and close the socket */ public void cancel() { try { mmSocket.close(); } catch (IOException e) { } } } 複製代碼
private ScanCallback mLeScanCallback = new ScanCallback() { @Override public void onScanResult(int callbackType, ScanResult result) { super.onScanResult(callbackType, result); } @Override public void onBatchScanResults(List<ScanResult> results) { super.onBatchScanResults(results); } @Override public void onScanFailed(int errorCode) { super.onScanFailed(errorCode); } }; mHandler.postDelayed(new Runnable() { @Override public void run() { bluetoothLeScanner.stopScan(mLeScanCallback); } }, SCAN_PERIOD); bluetoothLeScanner.startScan(mLeScanCallback); 複製代碼
// Various callback methods defined by the BLE API. private final BluetoothGattCallback gattCallback = new BluetoothGattCallback() { @Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { String intentAction; if (newState == BluetoothProfile.STATE_CONNECTED) { intentAction = ACTION_GATT_CONNECTED; connectionState = STATE_CONNECTED; Log.i(TAG, "Connected to GATT server."); Log.i(TAG, "Attempting to start service discovery:" + bluetoothGatt.discoverServices()); } else if (newState == BluetoothProfile.STATE_DISCONNECTED) { intentAction = ACTION_GATT_DISCONNECTED; connectionState = STATE_DISCONNECTED; Log.i(TAG, "Disconnected from GATT server."); } } @Override // New services discovered public void onServicesDiscovered(BluetoothGatt gatt, int status) { if (status == BluetoothGatt.GATT_SUCCESS) { } 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); } } ... }; BluetoothGatt bluetoothGatt; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { bluetoothGatt = device.connectGatt(context, false, mGattCallback, BluetoothDevice.TRANSPORT_LE); } else { bluetoothGatt = device.connectGatt(context, false, mGattCallback); } 複製代碼
其實 Android 藍牙相關的 API 使用仍是比較簡單的,對於初次接觸藍牙開發的小白來講,弄清楚藍牙設備的類型以及鏈接方式就成功了一半(經典藍牙 SPP,低功耗藍牙 GATT)。另一半在於藍牙設備的適配及細節的掌握,適配問題能夠多聯繫藍牙設備供應商的技術支持,細節問題就靠平時積累和多搜索查閱資料了。 最後安利兩個 BLE 開源庫:RxAndroidBle、flutter_blue。markdown
@123lxw123, 本文版權屬於再惠研發團隊,歡迎轉載,轉載請保留出處。網絡