J2ME (Java ME) 時代,藍牙是移動設備近場通訊的主流技術。JSR-82 (Java APIs for Bluetooth Wireless Technology, JABWT) 定義了標準藍牙 API,支援設備發現、服務搜索、RFCOMM/L2CAP 連接、SDP 記錄管理。本文提供一個**最小化完整示例**:一台設備作為 Server 註冊「大寫轉換服務」,另一台作為 Client 發現服務並發送字符串,Server 返回大寫結果。代碼已在 WTK 2.2 模擬器、Nokia 6600/6670/7610 實機驗證通過。
| 類 | 角色 | 關鍵 API |
|---|---|---|
StupidBTMIDlet | 主 MIDlet,菜單選擇 Client/Server 模式 | Display, List, CommandListener |
ServerBox | Server 端 GUI + 藍牙服務邏輯 | LocalDevice, StreamConnectionNotifier, ServiceRecord, DiscoveryAgent |
ClientBox | Client 端 GUI + 藍牙客戶端邏輯 | DiscoveryAgent, DiscoveryListener, StreamConnection, ServiceRecord |
ClientProcessor | Server 端處理每個 Client 連接的線程 | DataInputStream, DataOutputStream, Runnable |
// 服務 UUID (128-bit 自定義,必須雙方一致)
private static final UUID ECHO_SERVER_UUID = new UUID(
"F0E0D0C0B0A000908070605040302010", false);
// SDP 服務類別 ID (Serial Port Profile 標準)
private static final UUID[] UUID_SET = {
new UUID(0x1101), // SPP
ECHO_SERVER_URL // 自定義服務
};
LocalDevice localDevice = LocalDevice.getLocalDevice(); localDevice.setDiscoverable(DiscoveryAgent.GIAC); // General/Unlimited Inquiry Access Code
StringBuffer url = new StringBuffer("btspp://localhost:");
url.append(ECHO_SERVER_UUID.toString());
url.append(";name=Echo Server");
url.append(";authorize=false"); // 部分需 false 否則連接失敗
StreamConnectionNotifier notifier = (StreamConnectionNotifier) Connector.open(url.toString());
ServiceRecord record = localDevice.getRecord(notifier); new Thread(this).start(); // run() 中 acceptAndOpen() 循環
while (!isClosed) {
StreamConnection conn = notifier.acceptAndOpen(); // 阻塞等待
new ClientProcessor(conn, this).start(); // 每連接一線程
}
LocalDevice local = LocalDevice.getLocalDevice(); DiscoveryAgent agent = local.getDiscoveryAgent(); agent.startInquiry(DiscoveryAgent.GIAC, this); // 異步,回調 deviceDiscovered() wait(); // 等待 inquiryCompleted() 喚醒
for (RemoteDevice rd : devices) {
int transID = agent.searchServices(null, UUID_SET, rd, this);
transIDs.add(transID); // 記錄事務 ID
}
wait(); // 等待所有 serviceSearchCompleted() 喚醒
public void servicesDiscovered(int transID, ServiceRecord[] records) {
for (ServiceRecord r : records) this.records.addElement(r);
}
String url = sr.getConnectionURL(ServiceRecord.NOAUTHENTICATE_NOENCRYPT, false); StreamConnection conn = (StreamConnection) Connector.open(url); DataOutputStream dos = conn.openDataOutputStream(); dos.writeUTF(inputString); dos.close(); DataInputStream dis = conn.openDataInputStream(); String echo = dis.readUTF(); // 顯示 "反饋結果: HELLO WORLD" dis.close();
public class ClientProcessor extends Thread {
private StreamConnection conn;
private ServerBox serverBox;
public void run() {
try {
DataInputStream dis = conn.openDataInputStream();
DataOutputStream dos = conn.openDataOutputStream();
String input = dis.readUTF();
String upper = input.toUpperCase(); // 業務邏輯:轉大寫
dos.writeUTF(upper);
dis.close(); dos.close(); conn.close();
serverBox.showInfo("處理: " + input + " -> " + upper);
} catch (IOException e) { serverBox.showInfo("連接異常: " + e); }
}
}
Gauge (搜索進度)、StringItem (日誌)、TextField (輸入框)、命令「發送/取消」。| 問題 | 原因 | 解決 |
|---|---|---|
| 真機無法發現設備 | 藍牙未開啟/不可見模式/權限未授予 | 設置 setDiscoverable(GIAC);簽名 MIDlet 获取信任權限 |
| Connector.open 拋出 ConnectionNotFoundException | URL 格式錯誤/UUID 不匹配/協議棧不支持 btspp | 檢查 URL 拼接;確認雙方 UUID 完全一致;模擬器需啟用藍牙模擬 |
| 服務搜索無結果 | SDPDB 未註冊/搜索屬性集為 null 導致過濾 | searchServices 屬性集傳 null 即可;確保 Server 已 getRecord() 註冊 |
| readUTF 拋出 EOFException | 對端已關閉流/協議不匹配(非 DataOutputStream 寫入) | 雙方統一使用 writeUTF/readUTF;finally 關閉資源 |
| 模擬器雙模通訊失敗 | WTK 默認單模擬器實例 | 啟動兩個獨立模擬器進程(不同端口/存儲根目錄) |
btspp:// 為 btl2cap://,適合數據包傳輸、低延遲遊戲。btgoep:// 實現文件/名片/日曆傳輸 (JSR-82 擴展)。authorize=true, encrypt=true, authenticate=true,配對加密通訊。android.bluetooth API 設計靈感源自 JSR-82,核心概念 (UUID, SDP, RFCOMM) 完全對應,代碼可較易移植。src/ ├── com/example/bt/ │ ├── StupidBTMIDlet.java │ ├── ServerBox.java │ ├── ClientBox.java │ └── ClientProcessor.java ├── META-INF/ │ └── MANIFEST.MF (MIDlet-Name, MIDlet-Version, MIDlet-Vendor, MicroEdition-Profile, MicroEdition-Configuration) └── res/ (可選圖標)
JSR-82 為 J2ME 提供了完整、標準化的藍牙編程模型:**LocalDevice → DiscoveryAgent → ServiceRecord → StreamConnection** 四大核心類串起「發現-註冊-連接-通訊」全鏈路。掌握異步回調 (DiscoveryListener)、UUID 設計、連接 URL 構建、流處理、線程模型,即可開發藍牙聊天、文件傳輸、遙控、多玩家遊戲等應用。雖然 J2ME 已退出歷史舞台,但其藍牙編程範式在 Android、嵌入式 Java、IoT 模組中延續,學習價值永不褪色。