Android通過藍牙與PC通信
在程式設計模型上,這裡把電腦設計成伺服器端,用Java實作一個Windows電腦上的藍牙伺服器,名為:
PCBluetoothServer
。
Java SE
本身并沒有實作藍牙功能子產品,如果在Windows通過Java實作藍牙功能,需要額外的導入兩個jar(64位):
<dependencies>
<!-- https://mvnrepository.com/ -->
<dependency>
<groupId>io.ultreia</groupId>
<artifactId>bluecove</artifactId>
<version>2.1.1</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
</dependencies>
部署在Windows PC電腦上的藍牙伺服器端代碼 PCBluetoothServer.java
PCBluetoothServer.java
服務端接收到用戶端資訊後,會主動給用戶端回複資訊
public class PCBluetoothServer {
private String UUID = "0000110100001000800000805F9B34FB";
public static void main(String[] args) {
new PCBluetoothServer();
}
public PCBluetoothServer() {
try {
/**
* 開啟一個連接配接,等待通路
*/
String url = "btspp://localhost:" + UUID;
StreamConnectionNotifier notifier = (StreamConnectionNotifier) Connector
.open(url);
serverLoop(notifier);
} catch (Exception e) {
e.printStackTrace();
}
}
private void serverLoop(StreamConnectionNotifier notifier) {
try {
// infinite loop to accept connections.
while (true) {
System.out.println("等待連接配接");
/**
* 阻塞方法acceptAndOpen(),一直等待
*/
handleConnection(notifier.acceptAndOpen());
}
} catch (Exception e) {
System.out.println(e);
}
}
/**
* 處理連接配接請求,使用線程異步處理,避免一直等待處理完成
* 先要接收到用戶端資訊,才可以繼續執行
* @param conn
* @throws IOException
*/
private void handleConnection(StreamConnection conn) throws IOException {
new Thread(new Runnable() {
@Override
public void run() {
try {
OutputStream out = conn.openOutputStream();
InputStream in = conn.openInputStream();
DataOutputStream dos = new DataOutputStream(out);
DataInputStream dis = new DataInputStream(in);
// 阻塞方法
String read = dis.readUTF();
System.out.println("接收到Client:" + read);
//給用戶端回複資訊
dos.writeUTF("Server receive you Msg,Thank you!");
dos.close();
dis.close();
conn.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
}
Android用戶端
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.graphics.Color;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Set;
import java.util.UUID;
/**
* Android手機用戶端通過藍牙發送資料到部署在Windows PC電腦上。
* 如果運作失敗,請打開手機的設定,檢查是否賦予該App權限:
*
* <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
* <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
*
* <uses-permission android:name="android.permission.BLUETOOTH" />
* <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
*
* Android手機的藍牙用戶端。
* 代碼啟動後檢查目前手機是否已經和藍牙名稱為 TARGET_DEVICE_NAME 的配對成功。
* 本程式為測試程式,需要先手動使藍牙與PC進行配對
* TARGET_DEVICE_NAME 為PC端配對的藍牙裝置名
* MY_UUID 與PC端應該保持一緻
*
*/
public class MainActivity extends AppCompatActivity {
private BluetoothAdapter mBluetoothAdapter;
private BluetoothServerSocket serverSocket;
//要連接配接的目标藍牙裝置。
private final String TARGET_DEVICE_NAME = "DELL-PC";
private final String TAG = "藍牙調試";
private final String MY_UUID = "00001101-0000-1000-8000-00805F9B34FB";
/**
* @param
* @return
* @description 獲得和目前Android已經配對的藍牙裝置
* @date: 2020/4/5 10:05
* @author: lxf
*/
private BluetoothDevice getPairedDevices() {
// 獲得和目前Android已經配對的藍牙裝置。
Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
for (BluetoothDevice pairedDevice : pairedDevices) {
// 把已經取得配對的藍牙裝置名字和位址列印出來。
Log.d(TAG, pairedDevice.getName() + " : " + pairedDevice.getAddress());
if (TextUtils.equals(TARGET_DEVICE_NAME, pairedDevice.getName())) {
Log.d(TAG, "已配對目标裝置 -> " + TARGET_DEVICE_NAME);
return pairedDevice;
}
}
return null;
}
/**
* 開啟藍牙
*/
private void openBluetooth() {
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
BluetoothDevice device = getPairedDevices();
if (device == null) {
// 注冊廣播接收器。
// 接收藍牙發現訊息。
// IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
// registerReceiver(mBroadcastReceiver, filter);
// if (mBluetoothAdapter.startDiscovery()) {
// Log.d(TAG, "啟動藍牙掃描裝置...");
// }
} else {
try {
connectService(device, MY_UUID);
} catch (IOException e) {
e.printStackTrace();
}
}
}
private void connectService(BluetoothDevice device, String uuid) throws IOException {
try (BluetoothSocket socket = device.createRfcommSocketToServiceRecord(UUID.fromString(uuid));) {
Log.d(TAG, "連接配接服務端...");
socket.connect();
DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
/**
* 阻塞方法
*/
dos.writeUTF("hello server, I am client");
dos.flush();
DataInputStream dis = new DataInputStream(socket.getInputStream());
/**
* 阻塞方法
*/
String readUTF = dis.readUTF();
System.out.println("接收到服務端資訊:" + readUTF);
TextView textView = findViewById(R.id.textView);
textView.setText(readUTF);
textView.setTextColor(Color.RED);
dos.close();
dis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button myBtn = findViewById(R.id.myBtn);
myBtn.setOnClickListener(v -> {
Toast.makeText(MainActivity.this, "開啟藍牙", Toast.LENGTH_SHORT).show();
openBluetooth();
});
}
}
用戶端運作結果

服務端運作結果