iT邦幫忙

2025 iThome 鐵人賽

DAY 19
0
Modern Web

Web Bluetooth API 實戰:30 天打造通用 BLE 偵錯工具系列 第 19

Day 19:萬物皆可連:acceptAllDevices 的力量與責任

  • 分享至 

  • xImage
  •  

昨天,我們學習了 Web Bluetooth API 的三大黃金法則,如同飛行員在起飛前 meticulously 檢查儀表板,確保了萬無一失。我們的 scanButton.onclick 函式已經整裝待發,try...catch 這個強大的安全網也已鋪設完畢,就等待著那條能喚醒魔法的指令。

今天,所有的理論和等待都將告一段落。我們將寫下並執行自專案啟動以來,最令人激動的一行程式碼:navigator.bluetooth.requestDevice()。這行程式碼將會打通虛擬與現實的壁壘,讓我們的網頁第一次真正地「感知」到周遭的物理世界。

在發射火箭之前,我們需要為它設定航向。requestDevice() 中的設定選項,決定了我們要尋找什麼樣的裝置。今天,我們將學習其中最簡單、最直接,也最符合我們「通用偵錯工具」目標的選項:acceptAllDevices: true。我們將一同見證它「萬物皆可連」的強大之處,並探討其背後,身為開發者需要承擔的責任與權衡。

準備好,點火程序,正式開始!


1. navigator.bluetooth.requestDevice(options) 函式詳解

這是我們與藍牙世界互動的唯一入口

  • 功能:向使用者請求權限,並顯示一個由瀏覽器原生提供的 UI 視窗,讓使用者可以從附近掃描到的藍牙裝置列表中,選擇一個來進行配對。

  • 非同步:它是一個標準的非同步函式,會立即回傳一個 Promise

  • 使用者手勢:再次強調,它必須click 等使用者手勢事件中被呼叫。

  • options 物件:它接收一個設定物件作為參數,用來告訴瀏覽器,我們對什麼樣的裝置感興趣。


2. acceptAllDevices: true 的力量

這是 options 物件中最簡單直接的一個屬性。

  • 作用:當你設定 acceptAllDevices: true 時,你等於在告訴瀏覽器:「別過濾了,把附近所有正在廣播的低功耗藍牙裝置,全都顯示在列表裡給我看!

  • 適用場景:這對於我們的「通用偵錯工具」來說,是完美的選項。因為我們的目標,就是要能探索和連接任何未知的裝置。

程式碼實戰:喚醒掃描視窗

現在,是時候將這行魔法指令,放入我們昨天的 try...catch 區塊中了。

打開 app.js,修改 scanButton.onclick 函式:

// app.js

scanButton.onclick = async () => {
  // 我們的預檢程式碼...
  if (!navigator.bluetooth) {
    statusText.textContent = 'Error: Web Bluetooth is not supported in this browser.';
    return;
  }
  console.log('瀏覽器支援 Web Bluetooth API!');

  try {
    // ---- ↓↓↓ 今天新增的核心程式碼 ↓↓↓ ----

    console.log('Requesting Bluetooth device...');
    statusText.textContent = '正在請求藍牙裝置...請在彈出視窗中選擇';

    // 呼叫 API,並等待使用者選擇一個裝置
    const device = await navigator.bluetooth.requestDevice({
      acceptAllDevices: true
    });

    console.log('使用者已選擇裝置:', device);
    // 更新 UI,顯示已選擇的裝置名稱(如果裝置有名稱的話)
    statusText.textContent = `已選擇裝置: ${device.name || `ID: ${device.id}`}`;

    // 將獲取到的真實裝置資訊,存入我們之前設計好的 gattProfile 物件中
    gattProfile.device.name = device.name;
    gattProfile.device.id = device.id;

    console.log('GATT Profile 已更新:', gattProfile);

    // TODO: 明天的任務 -> 連接到這個裝置...

    // ---- ↑↑↑ 今天新增的核心程式碼 ↑↑↑ ----
  } catch(error) {
    // 這裡將會捕捉到使用者點擊「取消」時的錯誤
    console.error('掃描時發生錯誤:', error);
    statusText.textContent = `錯誤: ${error.message}`;
  }
};

見證奇蹟的時刻

  1. 確保你使用的是支援的瀏覽器 (Chrome/Edge)。

  2. 確保你已經透過 "Live Server" 或其他方式,在 localhost 下運行你的網頁。

  3. 確保你電腦或手機的藍牙已經開啟。

  4. 確保附近有一個正在廣播的 BLE 裝置(例如,你前幾天用手機 App 創建的虛擬裝置,或者一個藍牙滑鼠、手環等)。

點擊「掃描藍牙裝置」按鈕!

你應該會看到瀏覽器彈出一個原生的視窗,上面列出了附近可用的藍牙裝置。

  • 成功路徑:選擇一個裝置,點擊「配對 (Pair)」。彈窗消失,await 順利完成,回傳一個 device 物件。你的網頁狀態文字會更新,Console 也會印出裝置的詳細資訊。

  • 失敗路徑:在彈窗中,點擊「取消 (Cancel)」。requestDevice() 的 Promise 會立刻變為 rejected 狀態,await 將拋出一個錯誤。我們的 catch 區塊會立刻捕獲到這個錯誤,並在網頁和 Console 中顯示 DOMException: User cancelled the requestDevice() 這樣的訊息。這完美地展示了 try...catch 的作用!


3. acceptAllDevices 的責任

「萬物皆可連」的能力非常強大,但它並非萬靈丹。

  • 對於我們的工具:它是正確的選擇,因為我們的目標就是探索一切。

  • 對於專業的、單一用途的應用:它是一個糟糕的選擇

想像一下,你正在為一個「智慧咖啡杯」開發專用的網頁 App。你希望使用者在點擊「連接」時,只看到附近的「智慧咖啡杯」,而不是他鄰居的智慧電視、辦公室的藍牙鍵盤和路上行人的運動手環。向使用者展示一個包含數十個無關裝置的混亂列表,會造成極大的困擾,這是非常差的使用者體驗。

在這種情況下,我們應該使用「過濾器 (Filters)」來代替 acceptAllDevices。過濾器可以讓我們精準地告訴瀏覽器:「我只對那些廣播自己擁有『咖啡杯服務 UUID』的裝置感興趣」。這將是我們後續課程會探討的進階主題。


總結與後續

今天我們已經成功地「發現」了島嶼,並將它(device 物件)標記在了我們的地圖 (gattProfile) 上。但是,我們人還在船上,尚未登陸。

明天,我們的任務就是建立連接。我們將學習如何使用 device.gatt.connect() 這個方法,在我們的網頁和使用者選擇的裝置之間,建立一條穩定可靠的通訊鏈路,為接下來探索裝置內部的服務與特徵,做好萬全準備。

那麼今天的內容就到這邊,感謝你能看到這裡,在這邊祝你早安、午安、晚安,我們明天見。


上一篇
Day 18:Web Bluetooth API 導論:安全限制與瀏覽器支援
下一篇
Day 20:建立連結:連接 GATT 伺服器與日誌記錄
系列文
Web Bluetooth API 實戰:30 天打造通用 BLE 偵錯工具22
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言