android 傳統藍芽開發 (附示例原始碼)
前:本文為QiaoJim原創,轉載請附原文連結,謝謝合作!
----------------------------------------------------------------------------------
最近學習了android傳統藍芽,自己整理了一下思路,然後寫了一個BluetoothStudy小測試程式,來運用所理解的android傳統藍芽開發技術,寫下
一些心得和思路,供其他android熱愛者參考,也方便日後回顧。
部落格如有錯誤之處,歡迎留言之處,十分感謝。部落格最後會附上原始碼,可下載借鑑。
一、整體思路和對應相關方法
1、獲得BluetoothAdapter:
2、開啟藍芽:詢問使用者開啟(推薦)或直接bluetoothAdapter.enable();
3、查詢已繫結裝置,發現新裝置:bluetoothAdapter.getBondedDevices();bluetoothAdapter.startDiscovery();
4.1、服務端,一直監聽請求,當該端主動發出請求時,關閉該端的監聽,角色轉為客戶端:
bluetoothDevice.createRfcommSocketToServiceRecord(UUID);
4.2、客戶端,點選目標裝置,配對連線:
bluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME, UUID);
5、通過BluetoothSocket通訊:IO流讀寫
二、開發詳解
1、宣告許可權,注意可能需要的執行時許可權
<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" />
android 6.0以上裝置發現新藍芽時,需加入執行時許可權,否則無法監聽ACTION_FOUND廣播
if (Build.VERSION.SDK_INT >= 6.0) {
ActivityCompat.requestPermissions(getActivity(),
new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
Params.MY_PERMISSION_REQUEST_CONSTANT);
}
public void onRequestPermissionsResult(int requestCode, String permissions[],
int[] grantResults) {
switch (requestCode) {
case Params.MY_PERMISSION_REQUEST_CONSTANT: {
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// 執行時許可權已授權
}
return;
}
}
}
2、開啟藍芽,推薦用對話方塊形式讓使用者開啟
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
// 藍芽未開啟,詢問開啟
if (!bluetoothAdapter.isEnabled()) {
Intent turnOnBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(turnOnBtIntent, Params.REQUEST_ENABLE_BT);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case Params.REQUEST_ENABLE_BT: {
//使用者開啟藍芽
if (resultCode == RESULT_OK) {
//顯示已繫結藍芽裝置
showBondDevice();
}
break;
}
case Params.REQUEST_ENABLE_VISIBILITY: {
//設定該藍芽裝置可被其他裝置發現,600是設定的裝置可發現時間(部落格最後有簡單說明)
if (resultCode == 600) {
toast("藍芽已設定可見");
} else if (resultCode == RESULT_CANCELED) {
toast("藍芽設定可見失敗,請重試");
}
break;
}
}
}
3、通過BluetoothAdapter獲取已繫結的藍芽裝置
private void showBondDevice() {
deviceList.clear();
// 所有已繫結裝置,一個Set集合
Set<BluetoothDevice> tmp = bluetoothAdapter.getBondedDevices();
for (BluetoothDevice d : tmp) {
deviceList.add(d);
}
//更新列表
listAdapter.notifyDataSetChanged();
}
4、發現藍芽裝置,發現一個裝置,會發送一條ACTION_FOUND廣播,註冊廣播接收器,可獲得對應藍芽裝置資訊
bluetoothAdapter.startDiscovery();
intentFilter = new IntentFilter();
btReceiver = new MyBtReceiver();
//監聽 搜尋開始,搜尋結束,發現新裝置 3條廣播
intentFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
intentFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
intentFilter.addAction(BluetoothDevice.ACTION_FOUND);
getActivity().registerReceiver(btReceiver, intentFilter);
//廣播接收器
private class MyBtReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (BluetoothAdapter.ACTION_DISCOVERY_STARTED.equals(action)) {
toast("開始搜尋 ...");
} else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
toast("搜尋結束");
} else if (BluetoothDevice.ACTION_FOUND.equals(action)) {
//獲得發現的裝置
BluetoothDevice device =
intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if (device.getBondState() != BluetoothDevice.BOND_BONDED) {
deviceList.add(device);
listAdapter.notifyDataSetChanged();
}
}
}
}
5、裝置連線,伺服器端開啟執行緒一直等待連線,客戶端點選某個目標裝置,關閉伺服器執行緒監聽,並開啟執行緒,發出連線請求。
注意:客戶端連線前,一定cancelDiscovery()
// 藍芽已開啟
if (bluetoothAdapter.isEnabled()) {
showBondDevice();
// 預設開啟服務執行緒監聽
if (serverThread != null) {
serverThread.cancel();
}
serverThread = new ServerThread(bluetoothAdapter, uiHandler);
new Thread(serverThread).start();
}
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
// 關閉伺服器監聽
if (serverThread != null) {
serverThread.cancel();
serverThread=null;
}
BluetoothDevice device = deviceList.get(position);
// 開啟客戶端執行緒,連線點選的遠端裝置
clientThread = new ClientThread(bluetoothAdapter, device, uiHandler);
new Thread(clientThread).start();
// 通知 ui 連線的伺服器端裝置
Message message = new Message();
message.what = Params.MSG_CONNECT_TO_SERVER;
message.obj = device;
uiHandler.sendMessage(message);
}
});
6、建立BluetoothSocket連線以後,使用IO流資料傳輸,伺服器和客戶端讀寫資料類似,貼一部分程式碼供參考
public void writeData(String dataSend) {
if (serverThread != null) {
serverThread.write(dataSend);
} else if (clientThread != null) {
clientThread.write(dataSend);
}
}
//寫資料
public void write(String data){
try {
out.write(data.getBytes("utf-8"));
} catch (IOException e) {
e.printStackTrace();
}
}
new Thread(new Runnable() {
@Override
public void run() {
byte[] buffer = new byte[1024];
int len;
String content;
try {
//讀資料
while ((len=in.read(buffer)) != -1) {
content=new String(buffer, 0, len);
Message message = new Message();
message.what = Params.MSG_CLIENT_REV_NEW;
message.obj = content;
//更新 ui
uiHandler.sendMessage(message);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
7、其他說明
(1)新裝置繫結,bluetoothDevice.createBond()
(2)設定裝置可被發現的時間:
Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
enableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 600);
startActivityForResult(enableIntent, Params.REQUEST_ENABLE_VISIBILITY);
(3)伺服器獲得遠端裝置,bluetoothSocket.getRemoteDevice()
(4)通過MAC獲得藍芽裝置,bluetoothAdapter.getRemoteDevice(String address)
(5)關閉藍芽,bluetoothAdapter.disable()
三、原始碼示例下載
感謝閱讀,如有錯誤,請留言。如果覺得博文不錯,請點贊支援。
四、效果圖