您好,登錄后才能下訂單哦!
本篇內容介紹了“android藍牙簡單開發的方法是什么”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!
前段時間學習了一些藍牙開發的知識,記錄一下Android中藍牙的簡單開發。下面是最重要的兩個類。
BluetoothAdapter : 藍牙適配器,通過getDefaultAdapter ()去獲取一個實例,如果設備不支持藍牙的話,返回的是一個null對象,通過它,可以打開、關閉藍牙,掃描設備、向指定設備創建socket通道…
BluetoothDevice : 代表一個設備對象,可以通過它獲取設備的名字、地址、類型等,也可以創建匹配,建立socket通道等等。
<uses-permission android:name="android.permission.BLUETOOTH"/> 使用藍牙所需要的權限 <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/> 使用掃描和設置藍牙的權限(申明這一個權限必須申明上面一個權限)
Android6以上版本,掃描其他藍牙還需要位置權限
// Android 9 以下版本 <user-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> // Android 9 以上 <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); // 如果設備不支持藍牙 if (mBluetoothAdapter == null){ return; } // 設備支持藍牙功能,調用startActivityForResult去啟動藍牙 if (!mBluetoothAdapter.isEnabled()){ startBlueTooth.launch(new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)); }
打開藍牙功能是通過startActivity去啟動的,但是startActivity這個函數已經過期了,所以我使用官方推薦的Activity Result替代它
ActivityResultLauncher<Intent> startBlueTooth = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), new ActivityResultCallback<ActivityResult>() { @Override public void onActivityResult(ActivityResult result) { if (result==null){ Toast.makeText(BlueToothActivity.this, "open failed", Toast.LENGTH_SHORT).show(); }else { if (result.getResultCode() == RESULT_CANCELED){ Toast.makeText(BlueToothActivity.this,"用戶取消",Toast.LENGTH_SHORT); } } } });
通過廣播去接收藍牙狀態的改變
class BluetoothStateChangeReceiver extends BroadcastReceiver{ public int DEFAULT_VALUE_BLUETOOTH = 1000; @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)){ int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,DEFAULT_VALUE_BLUETOOTH); switch(state){ case BluetoothAdapter.STATE_ON: Log.d(TAG, "onReceive: open"); break; case BluetoothAdapter.STATE_OFF: Log.d(TAG, "onReceive: off"); break; case BluetoothAdapter.STATE_TURNING_ON : Log.d(TAG, "onReceive: 正在打開"); break; case BluetoothAdapter.STATE_TURNING_OFF: Log.d(TAG, "onReceive: 正在關閉"); break; } } } }
別忘了廣播的注冊和解注冊
IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED); stateReceiver = new BluetoothStateChangeReceiver() ; registerReceiver(stateReceiver,filter);
同樣通過廣播接收,action是BluetoothDevice.ACTION_FOUND
class MyReceiver extends BroadcastReceiver{ @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (BluetoothDevice.ACTION_FOUND.equals(action)) { // 從intent對象中獲取藍牙設備的信息 BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); // 當發現新設備不存在于配對列表中時添加 if (device.getBondState() != BluetoothDevice.BOND_BONDED) { blueNames.add(device.getName()+"\t"+device.getAddress()); } blueAdpater.notifyDataSetChanged(); Log.d(TAG, "onReceive: " + device.getName()); } } }
動態注冊廣播
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND); registerReceiver(mReceiver,filter);
開啟掃描
mBluetoothAdapter.startDiscovery();
public class BondReceiver extends BroadcastReceiver{ @Override public void onReceive(Context context, Intent intent) { if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(intent.getAction())){ BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); switch(device.getBondState()){ case BluetoothDevice.BOND_BONDED: Log.d(TAG, "onReceive: 配對完成"); break; case BluetoothDevice.BOND_BONDING: Log.d(TAG, "onReceive: 正在配對"); break; case BluetoothDevice.BOND_NONE: Log.d(TAG, "onReceive: 取消配對"); break; } } } }
已經配對的設備會被存儲起來,通過BluetoothAdpater直接獲取即可
Set<BluetoothDevice> paireDevices = mBluetoothAdapter.getBondedDevices(); if (paireDevices.size()>0){ for (BluetoothDevice pairedDevice : pairedDevices) { blueNames.add(pairedDevice.getName()+" "+pairedDevice.getAddress()); Log.d(TAG, "onClick: "+pairedDevice.getName()); } }
想要在兩臺設備之間創建連接,必須實現客戶端和服務端機制,他們之間使用套接字機制進行連接,服務端開放服務器套接字,客戶端通過MAC地址向服務端發起連接。客戶端和服務端以不同的方式獲得BluetoothSocket
,當客戶端和服務端在同一個RFCOMM通道上分別擁有已連接的BluetoothSocket
時,將他們視為彼此已經連接,于是每臺設備都獲得輸入和輸出流式傳輸,并開始傳輸數據。
連接技術
一種實現技術是自動將每臺設備準備為一個服務器,從而使每臺設備開放一個服務套接字并偵聽連接,在此情況下,任何一臺設備都可以發起與另一臺設備的連接并稱為客戶端。
服務器
設置服務器套接字并接受連接,步驟依次如下
1、調用listenUsingRfcommWithServiceRecord()獲取一個BluetoothServerSocket
, 該函數需要兩個參數,第一個是服務器的名稱,自己取一個即可,第二個是UUID,用來對信息做唯一性標識,我們可以從網上眾多UUID生成器中隨機的生成一個,然后使用UUID.fromString(String)初始化一個UUID。
2、通過accept()函數開始偵聽連接請求
只有遠程設備發送的連接請求中UUID與使用此套接字注冊的UUID相匹配時服務器才會接受請求,accept函數會返回已連接的BluetoothSocket
3、連接成功后調用close()
關閉BluetoothSocket
private class AcceptThread extends Thread{ private final BluetoothServerSocket mmServerSocket; private String mSocketType; public AcceptThread(boolean secure){ BluetoothServerSocket tmp = null; mSocketType = secure ? "secure" : "Insercure"; try{ if (secure){ tmp = bluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME_SECURE,MY_UUID_SECURE); }else{ tmp = bluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME_INSECURE,MY_UUID_INSECURE); } } catch (IOException e) { Log.e(TAG,"socket type"+ mSocketType + "listen() failed",e); } mmServerSocket = tmp; } @Override public void run() { Log.d(TAG, "Socket Type: " + mSocketType + "BEGIN mAcceptThread" + this); setName("AcceptThread"+ mSocketType); BluetoothSocket socket = null; Log.d(TAG, "run: 開始監聽"); while (true){ try{ socket = mmServerSocket.accept(); Log.d("acceptThread", "run: 連接成功"); connected(socket,socket.getRemoteDevice(),mSocketType); } catch (IOException e) { Log.e(TAG, "Socket Type: " + mSocketType + "accept() failed", e); break; } } Log.i(TAG, "END mAcceptThread, socket Type: " + mSocketType); } public void cancel() { Log.d(TAG, "Socket Type" + mSocketType + "cancel " + this); try { mmServerSocket.close(); } catch (IOException e) { Log.e(TAG, "Socket Type" + mSocketType + "close() of server failed", e); } } }
上面的secure和Insecure只是使用了不同的UUID而已。
客戶端
遠程設備開啟監聽后,我們就發起向此設備的連接,首先必須先獲得遠程設備的BluetoothDevice對象,然后獲取BluetoothSocket發起連接。
基本步驟如下
1、使用BluetoothDevice
通過調用createRfcommSocketToServiceRecord(UUID)
獲取 BluetoothSocket
。
2、通過connect發起連接
private class ConnectThread extends Thread{ private final BluetoothSocket mmSocket; private final BluetoothDevice mmDevice; private String mSocketType; public ConnectThread(BluetoothDevice device, boolean secure){ mmDevice = device; BluetoothSocket tmp = null; mSocketType = secure ? "Secure" : "Insecure"; try { if (secure){ tmp = device.createRfcommSocketToServiceRecord(MY_UUID_SECURE); }else { tmp = device.createRfcommSocketToServiceRecord(MY_UUID_INSECURE); } } catch (IOException e) { Log.e(TAG, "Socket Type: " + mSocketType + "create() failed", e); } mmSocket = tmp; } @Override public void run() { Log.i(TAG, "BEGIN mConnectThread SocketType:" + mSocketType); setName("ConnectThred"+mSocketType); // 總是取消發現,因為它會減慢連接 bluetoothAdapter.cancelDiscovery(); // connect // Make a connection to the BluetoothSocket try { // This is a blocking call and will only return on a // successful connection or an exception mmSocket.connect(); Log.d(TAG, "run: socket連接成功"); } catch (IOException e) { // Close the socket Log.d(TAG, "run: 關閉socket"); try { mmSocket.close(); } catch (IOException e2) { Log.e(TAG, "unable to close() " + mSocketType + " socket during connection failure", e2); } return; } connected(mmSocket,mmDevice,mSocketType); } public void cancel(){ try{ mmSocket.close(); } catch (IOException e) { Log.e(TAG, "close() of connect " + mSocketType + " socket failed", e); } } }
發送數據
連接成功后,我們就可以通過socket發送數據了,客戶端的Socket對象是BluetoothSocket
, 服務端的socket是BluetoothServerSocket
,特別注意不要混淆了。使用getInputStream
和getOutputStream
分別獲取通過套接字處理數據傳輸的InputStream
和OutputStream
。寫數據比較簡單,但是讀數據就需要一個單獨的線程一直監聽才行。
private class ConnectedThread extends Thread{ private final BluetoothSocket mmSocket; private InputStream mmInStream; private OutputStream mmOutStream; public ConnectedThread(BluetoothSocket socket, String socketType) throws IOException { Log.d(TAG, "create ConnectedThread: " + socketType); mmSocket = socket; InputStream tmpIn = null; OutputStream tmpOut = null; try{ tmpIn = socket.getInputStream(); tmpOut = socket.getOutputStream(); if (socket != null){ tmpOut.write(new String("hello").getBytes()); Log.d(TAG, "ConnectedThread: socket不是null"); } } catch (IOException e) { Log.e(TAG,"temp socket not created", e); } mmInStream = tmpIn; mmOutStream = tmpOut; // mmOutStream.write(new String("hello").getBytes()); } @RequiresApi(api = Build.VERSION_CODES.KITKAT) @Override public void run() { Log.i(TAG, "BEGIN mConnectedThread"); byte[] buffer = new byte[1024]; int bytes; while (true){ try{ bytes = mmInStream.read(buffer); // send the bytes to the ui Activity String text = encodeByteToString(buffer,bytes); Log.d(TAG, "run: 收到消息:"+ text); chatItems.add(text); mHandler.sendMessage(mHandler.obtainMessage()); } catch (IOException e) { Log.d(TAG, "run: 沒有收到消息"); e.printStackTrace(); break; } } } public String encodeByteToString(byte[] data,int length) { byte[] temp = new byte[length]; for (int i = 0; i < length; i++) { temp[i] = data[i]; } try { return new String(temp,"utf-8"); } catch (UnsupportedEncodingException e) { return ""; } } public void write(byte[] buffer){ try{ mmOutStream.write(buffer); // mHandler.obtainMessage(Constants.MESSAGE_WRITE,-1,-1,buffer).sendToTarget(); } catch (IOException e) { e.printStackTrace(); } } public void cancel(){ try{ mmSocket.close(); Log.d(TAG, "cancel: connectedThread"); } catch (IOException e) { Log.e(TAG, "close() of connect socket failed", e); } } }
“android藍牙簡單開發的方法是什么”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。