Android 藍牙技術 實現終端間數據傳輸

藍牙技術在智能硬件方面有不少用武之地,今天我就爲你們分享一下藍牙技術在 Android系統下的使用方法技巧。藍牙是一種短距離的無線通訊技術標準,藍牙協議分爲4層,即核心協議層、電纜替代協議層、電話控制協議層和採納的其它協議層。這4種協議中最重要的是核心協議。藍牙的核心協議包括基帶、鏈路管理、邏輯鏈路控制和適應協議四部分。其中鏈路管理(LMP)負責藍牙組件間鏈接的創建。邏輯鏈路控制與適應協議(L2CAP)位於基帶協議層上,屬於數據鏈路層,是一個爲高層傳輸和應用層協議屏蔽基帶協議的適配協議。

Android 支持的藍牙協議棧有:java

藍牙協議棧 說明
Bluz Linux官方藍牙協議棧,最成熟的開源藍牙協議棧,靈活高效。
BlueDroid 從Android 4.2開始,Google在Android中推出了它和博通公司一塊兒開發的BlueDroid以替代BlueZ,框架結構變得更爲簡潔和清晰。
BLE 低功耗藍牙協議棧,傳輸距離遠,速率快。

1.Android系統藍牙本地操做

Android 系統本地藍牙表明本地的藍牙適配器,也是全部藍牙交互的入口點,能夠對本地或者其餘終端設備進行操做。其中 BluetoothAdapter 是重要的類,表明本地藍牙適配器。android

1.判斷本地藍牙是否打開

BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); // null:表示不支持藍牙 boolean enabled = mBluetoothAdapter.isEnabled(); // true:處於打開狀態, false:處於關閉狀態

2.調用系統對話框啓動本地藍牙

// 添加藍牙權限,不須要動態受權 // <uses-permission android:name="android.permission.BLUETOOTH" /> // <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> startActivityForResult(new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE), 1);

3.靜默開啓本地藍牙 不會有對話框

在AndroidManifest文件中添加須要的權限:sql

<!-- 適配Android6.0/7.0 --> <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" /> <uses-feature android:name="android.hardware.bluetooth_le" android:required="true" />
  • 1

因爲藍牙所須要的權限包含Dangerous Permissions,因此咱們須要在Java代碼中進行動態受權處理:markdown

if (ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(context, new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, 1); }
  • 1

接下來咱們就能夠靜默開啓和關閉本地藍牙了:網絡

mBluetoothAdapter.enable(); // 開啓 //mBluetoothAdapter.disable(); // 關閉

4.本地藍牙主動搜索周邊藍牙

搜索分爲主動搜索和被動搜索。咱們開始進行主動搜索:框架

1.建立 BluetoothAdapter 對象,首先獲取已經配對的藍牙設備:socket

BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
Set<BluetoothDevice> bondedDevices = mBluetoothAdapter.getBondedDevices(); // 獲取已經配對的藍牙設備
  • 1

2.下面咱們定義廣播接收器ide

// 設置廣播信息過濾 IntentFilter filter = new IntentFilter(); filter.addAction(BluetoothDevice.ACTION_FOUND);//每搜索到一個設備就會發送一個該廣播 filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);//當所有搜索完後發送該廣播 filter.setPriority(Integer.MAX_VALUE);//設置優先級 // 註冊藍牙搜索廣播接收者,接收並處理搜索結果 this.registerReceiver(receiver, filter);

3.開始搜索周邊藍牙:ui

//若是當前在搜索,就先取消搜索 if (mBluetoothAdapter.isDiscovering()) { mBluetoothAdapter.cancelDiscovery(); } //開啓搜索 mBluetoothAdapter.startDiscovery();

搜索藍牙設備

2.Android系統藍牙遠程操做

1.藍牙的UUID

兩個藍牙設備進行鏈接時須要使用同一個UUID。但不少讀者可能發現,有不少型號的手機(多是非Android系統的手機)之間使用了不一樣的程序也可使用藍牙進行通信。從表面上看,它們之間幾乎不可能使用同一個UUID。this

UUID的格式以下:

xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

UUID的格式被分紅5段,其中中間3段的字符數相同,都是4,第1段是8個字符,最後一段是12個字符。因此UUID其實是一個8-4-4-4-12的字符串。

實際上,UUID和TCP的端口同樣,也有一些默認的值。例如,將藍牙模擬成串口的服務就使用了一個標準的UUID:

00001101-0000-1000-8000-00805F9B34FB

除此以外,還有不少標準的UUID,以下面就是兩個標準的UUID:

信息同步服務:00001104-0000-1000-8000-00805F9B34FB
文件傳輸服務:00001106-0000-1000-8000-00805F9B34FB

2.本地藍牙與周邊藍牙間數據傳輸

經過藍牙傳輸數據與Socket相似。在網絡中使用Socket和ServerSocket控制客戶端和服務端的數據讀寫。而藍牙通信也由客戶端和服務端Socket來完成。藍牙客戶端Socket是BluetoothSocket,藍牙服務端Socket是BluetoothServerSocket。這兩個類都在android.bluetooth包中。

不管是BluetoothSocket,仍是BluetoothServerSocket,都須要一個UUID(全局惟一標識符,Universally Unique Identifier),UUID至關於Socket的端口,而藍牙地址至關於Socket的IP。

咱們開始進行模擬一個藍牙數據的傳輸:

首先來看客戶端:

(1)定義全局常量變量

private ListView lvDevices; private BluetoothAdapter mBluetoothAdapter; private List<String> bluetoothDevices = new ArrayList<String>(); private ArrayAdapter<String> arrayAdapter; private final UUID MY_UUID = UUID .fromString("abcd1234-ab12-ab12-ab12-abcdef123456");//隨便定義一個 private BluetoothSocket clientSocket; private BluetoothDevice device; private OutputStream os;//輸出流
  • 1

(2)在onCreate方法中作初始化操做

mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

lvDevices = (ListView) findViewById(R.id.lv_devices);
//獲取已經配對的藍牙設備 Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices(); if (pairedDevices.size() > 0) { for (BluetoothDevice device : pairedDevices) { bluetoothDevices.add(device.getName() + ":"+ device.getAddress()); } } arrayAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, android.R.id.text1,bluetoothDevices); lvDevices.setAdapter(arrayAdapter); lvDevices.setOnItemClickListener(this);//Activity實現OnItemClickListener接口 //每搜索到一個設備就會發送一個該廣播 IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND); this.registerReceiver(receiver, filter); //當所有搜索完後發送該廣播 filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED); this.registerReceiver(receiver, filter);
  • 1

藍牙設備的廣播接收器以下:

/** * 定義廣播接收器 */ private final BroadcastReceiver receiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (BluetoothDevice.ACTION_FOUND.equals(action)) { BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); if (device.getBondState() != BluetoothDevice.BOND_BONDED) { bluetoothDevices.add(device.getName() + ":" + device.getAddress()); arrayAdapter.notifyDataSetChanged();//更新適配器 } } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) { //已搜素完成 } } };

(4)咱們建立一個Button按鈕,當點擊Button時進行搜索,Button點擊事件以下:

//若是當前在搜索,就先取消搜索 if (mBluetoothAdapter.isDiscovering()) { mBluetoothAdapter.cancelDiscovery(); } //開啓搜索 mBluetoothAdapter.startDiscovery();
  • 1

(5)接下來咱們設置列表的點擊事件:

@Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { String s = arrayAdapter.getItem(position); String address = s.substring(s.indexOf(":") + 1).trim();//把地址解析出來 //主動鏈接藍牙服務端 try { //判斷當前是否正在搜索 if (mBluetoothAdapter.isDiscovering()) { mBluetoothAdapter.cancelDiscovery(); } try { if (device == null) { //得到遠程設備 device = mBluetoothAdapter.getRemoteDevice(address); } if (clientSocket == null) { //建立客戶端藍牙Socket clientSocket = device.createRfcommSocketToServiceRecord(MY_UUID); //開始鏈接藍牙,若是沒有配對則彈出對話框提示咱們進行配對 clientSocket.connect(); //得到輸出流(客戶端指向服務端輸出文本) os = clientSocket.getOutputStream(); } } catch (Exception e) { } if (os != null) { //往服務端寫信息 os.write("藍牙信息來了".getBytes("utf-8")); } } catch (Exception e) { } }

(2)定義服務端線程類:

private Handler handler = new Handler() { public void handleMessage(Message msg) { Toast.makeText(getApplicationContext(), String.valueOf(msg.obj), Toast.LENGTH_LONG).show(); super.handleMessage(msg); } }; //服務端監聽客戶端的線程類 private class AcceptThread extends Thread { public AcceptThread() { try { serverSocket = mBluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID); } catch (Exception e) { } } public void run() { try { socket = serverSocket.accept(); is = socket.getInputStream(); while(true) { byte[] buffer =new byte[1024]; int count = is.read(buffer); Message msg = new Message(); msg.obj = new String(buffer, 0, count, "utf-8"); handler.sendMessage(msg); } } catch (Exception e) { } } }

(3)在onCreate方法中初始化線程類並開啓

mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
acceptThread = new AcceptThread();
acceptThread.start();
  • 1
  • 2
  • 3

咱們運行程序看一下效果圖:

client

點擊「搜索藍牙設備」按鈕,就會搜索到另外一臺手機的藍牙信息,咱們點擊條目,另外一臺手機會出現以下變化:

server

彈出Toast,此時證實咱們的藍牙數據已經傳輸過來了。

相關文章
相關標籤/搜索