AI 全自動實現 Flutter 藍牙自動連接

AI 輔助設計 Flutter 藍牙自動連接系統

前言

一篇由 AI 程式碼實現,連文章也是 AI 寫的文章。除了設計思想是我的,其它的都是 AI 實現的。AI 時代,更注重的是什麼,值錢的是什麼,可能是問題的解決能力吧。是一個好的方案設計吧。

一、專案背景與需求分析

1.1 業務場景描述

在現代工業物聯網系統中,藍牙連線已經成為一項不可或缺的基礎功能。我們的工業物聯網專案需要實現工業設備與外部藍牙設備(如藍牙音箱、印表機、感測器等)的自動連接功能。

與傳統手機 App 不同,工業物聯網環境對藍牙連線有著特殊且嚴苛的要求:

1. 高可靠性要求 工業系統不能容忍頻繁的連線失敗。一次看似簡單的藍牙斷線,可能導致重要的語音提示無法播放,影響整個物流調度流程。因此,我們需要設計一套完善的容錯機制,確保系統在各種異常情況下都能恢復連線。

2. 低延遲特性 連接過程必須盡可能快速。我們不能允許使用者等待數十秒甚至數分鐘才能完成基本的藍牙配對。AI 在設計時充分考慮了這一點,透過預檢查、快取機制等方式縮短連接時間。

3. 多版本相容 Android 系統的碎片化是所有行動開發者面臨的難題。不同版本的 Android 系統對藍牙權限的處理方式截然不同,從 Android 6.0 到 Android 14,每個版本都有其獨特的權限模型。我們的系統必須能夠優雅地適配所有這些版本。

1.2 技術選型分析

在專案初期,AI 對現有的 Flutter 藍牙生態進行了全面的調研和分析,最終選擇了以下技術棧:

yaml 体验AI代码助手 代码解读复制代码dependencies:
  flutter_bluetooth_serial: ^0.4.0    # 藍牙序列埠通訊
  permission_handler: ^11.0.0        # 權限管理

flutter_bluetooth_serial 是一個成熟穩定的 Flutter 藍牙套件,它提供了豐富的藍牙功能,包括:

  • 傳統藍牙(SPP)和低功耗藍牙(BLE)支援
  • 裝置探索和配對管理
  • 序列埠通訊能力
  • 完善的 API 設計

permission_handler 是 Flutter 生態中最流行的權限管理函式庫,它:

  • 統一了 Android 和 iOS 的權限處理邏輯
  • 提供了優雅的權限請求 API
  • 支援權限狀態檢查和永久拒絕處理

1.3 核心設計理念

AI 在設計這套藍牙自動連接系統時,遵循了以下核心原則:

漸進式複雜度:從最簡單的情境開始,逐步增加功能複雜性。初始版本只處理基本的連接,隨後逐步添加權限管理、自動重連、多裝置支援等功能。

防禦性程式設計:任何外部呼叫都可能失敗,因此我們必須對每一步操作都進行錯誤處理和狀態檢查。

使用者體驗優先:即使出現異常,也要給使用者提供清楚的回饋,而不是讓使用者面對一個「黑畫面」或「無回應」的系統。


二、權限管理系統深度解析

2.1 Android 權限演進歷史

要設計一個真正相容所有 Android 版本的藍牙系統,我們必須深入理解 Android 權限模型的演進歷史。

Android 6.0(API 23)- 執行階段權限時代 從 Android 6.0 開始,Google 引入了執行階段權限模型。藍牙掃描不再是無條件的,而是需要使用者明確授權位置權限。這是一個看似奇怪但合理的設計——因為藍牙掃描可以被用來定位使用者,所以 Google 將藍牙掃描與位置權限綁定。

Android 10(API 29)- 背景位置限制 Android 10 進一步收緊了位置權限的應用情境,使得在背景掃描藍牙變得更加困難。

Android 12(API 31)- 全新藍牙權限 API 這是最重要的變革。Android 12 引入了三個全新的藍牙權限:

  • BLUETOOTH_SCAN - 藍牙掃描權限
  • BLUETOOTH_CONNECT - 藍牙連接權限
  • BLUETOOTH_ADVERTISE - 藍牙廣播權限

這些新權限取代了之前的位置權限要求,使得權限管理更加清晰和直觀。

Android 13(API 33)- 進一步最佳化 Android 13 對藍牙權限進行了微調,使得開發者的體驗更加順暢。

2.2 權限檢查與請求流程

下面是 AI 設計的完整權限處理流程:

dart 体验AI代码助手 代码解读复制代码Future<int> _checkBlue() async {
  Completer<int> _compCheckBlue = Completer();
  print('目標設備列表: $defaultDriverName');

  try {
    // ============================================
    // 第一階段:位置權限處理(Android 12 以下必須)
    // ============================================
    print('開始檢查藍牙權限');

    // 檢查目前位置權限狀態
    PermissionStatus locationStatus = await Permission.location.status;
    print('位置權限狀態: $locationStatus');

    // 如果未授予位置權限,需要請求
    if (!locationStatus.isGranted) {
      print('位置權限未授予,請求權限');

      // 發起權限請求
      final locationResult = await Permission.location.request();
      print('請求位置權限結果: $locationResult');

      // 檢查請求結果
      if (!locationResult.isGranted) {
        print('權限不足,請授予"附近裝置"權限以使用藍牙功能');
        _compCheckBlue.complete(BluetoothStatus['PERMISSION_DENIED']);
        return _compCheckBlue.future;
      }
    }

    // ============================================
    // 第二階段:藍牙掃描權限(Android 12+)
    // ============================================
    // 檢查是否已授予藍牙掃描權限
    if (await Permission.bluetoothScan.isGranted == false) {
      print('藍牙掃描權限未授予,請求權限');

      // 請求藍牙掃描權限
      final bluetoothScanResult = await Permission.bluetoothScan.request();
      print('請求藍牙掃描權限結果: $bluetoothScanResult');

      // 檢查請求結果
      if (!bluetoothScanResult.isGranted) {
        print('權限不足,請授予"附近裝置"權限以使用藍牙功能');
        _compCheckBlue.complete(BluetoothStatus['PERMISSION_DENIED']);
        return _compCheckBlue.future;
      }
    }

    // ============================================
    // 第三階段:藍牙連接權限(Android 12+)
    // ============================================
    // 這個權限特別重要:必須在requestEnable()之前授予
    // 否則會導致藍牙無法正常開啟
    if (await Permission.bluetoothConnect.isGranted == false) {
      print('需要藍牙連接權限,正在請求...');

      final bluetoothConnectResult = await Permission.bluetoothConnect.request();
      print('請求藍牙連接權限結果: $bluetoothConnectResult');

      if (!bluetoothConnectResult.isGranted) {
        print('權限不足,請授予"附近裝置"權限以使用藍牙功能');
        _compCheckBlue.complete(BluetoothStatus['PERMISSION_DENIED']);
        return _compCheckBlue.future;
      }
    }

    print('權限檢查通過');

    // ============================================
    // 第四階段:藍牙硬體狀態檢查
    // ============================================

    // 檢查裝置是否支援藍牙
    final isAvailable = await FlutterBluetoothSerial.instance.isAvailable;
    if (isAvailable == false) {
      print('藍牙不可用,返回狀態碼: ${BluetoothStatus['BLUETOOTH_DISABLED']}');
      _compCheckBlue.complete(BluetoothStatus['BLUETOOTH_DISABLED']);
      return _compCheckBlue.future;
    }

    // 檢查藍牙是否已經開啟
    final isEnabled = await FlutterBluetoothSerial.instance.isEnabled;
    if (isEnabled == false) {
      // 嘗試請求使用者開啟藍牙
      final requestResult = await FlutterBluetoothSerial.instance.requestEnable();
      print('請求啟用藍牙結果: $requestResult');

      // 使用者拒絕開啟藍牙
      if (requestResult == false) {
        // 引導使用者前往系統設定頁面
        FlutterBluetoothSerial.instance.openSettings();
        print('藍牙未開啟,請在系統設定中手動開啟藍牙');
        _compCheckBlue.complete(BluetoothStatus['BLUETOOTH_DISABLED']);
        return _compCheckBlue.future;
      }
    }

    print('藍牙狀態: 開啟');

    // 所有檢查通過,返回裝置未找到狀態(等待後續掃描)
    _compCheckBlue.complete(BluetoothStatus['DEVICE_NOT_FOUND']);
  } catch (e) {
    // 捕獲所有異常,防止程式崩潰
    print('藍牙狀態檢查異常: $e');
    _compCheckBlue.complete(BluetoothStatus['PERMISSION_DENIED']);
  }

  return _compCheckBlue.future;
}

2.3 權限設計亮點

AI 在設計權限系統時採用了以下策略:

1. 漸進式權限請求

我們沒有一次性請求所有權限,而是分步驟逐一請求。這樣做的好處是:

  • 使用者更容易理解為什麼需要這些權限
  • 如果某個權限被永久拒絕,我們可以立即告知使用者,而不是等到後續操作才報錯
  • 提供更好的使用者體驗和透明度

2. 狀態快取與即時檢查

每次操作前都會檢查權限狀態,而不是依賴快取的權限結果。這樣可以避免因使用者手動撤銷權限而導致的異常。

3. 友善的錯誤提示

當權限被拒絕時,我們提供了清楚的錯誤資訊和解決建議:

  • 「請授予附近裝置權限以使用藍牙功能」
  • 「裝置藍牙未開啟,請在系統設定中開啟藍牙」

三、藍牙裝置掃描機制

3.1 掃描流程設計

裝置掃描是藍牙連接中最關鍵也是最複雜的步驟之一。AI 設計了以下掃描流程:

dart 体验AI代码助手 代码解读复制代码Future<dynamic> _scanBlue() async {
  Completer<dynamic> _compScanBlue = Completer();

  // 第一步:進行藍牙狀態和權限檢查
  await _checkBlue().then((value) async {
    int status = value;

    // 初始化掃描狀態
    resultScan = ScanResult.NONE;
    _thisScan = false;
    _discoveredDevices.clear();

    // 停止之前的掃描(避免資源衝突和重複掃描)
    await _discoverySubscription?.cancel();
    _scanTimer?.cancel();

    // 第二步:啟動藍牙裝置探索
    print('正在呼叫 startDiscovery()...');
    try {
      _discoverySubscription = FlutterBluetoothSerial.instance.startDiscovery().listen(
        (device) {
          // ============================================
          // 裝置去重處理
          // ============================================
          // 使用 Set 集合確保每個裝置只被處理一次
          if (_discoveredDevices.contains(device.device.address)) {
            return;
          }
          _discoveredDevices.add(device.device.address);

          // ============================================
          // 目標裝置匹配
          // ============================================
          // 檢查發現的裝置是否符合我們的目標裝置列表
          if (defaultDriverName.indexOf(device.device.name ?? '') > -1) {
            // 確保只處理第一個匹配的裝置
            if (!_thisScan) {
              // 判斷裝置的配對狀態
              resultScan = device.device.isBonded 
                ? ScanResult.BONDED    // 已與系統配對
                : ScanResult.UNPAIRED; // 未配對

              // 儲存目標裝置的 MAC 位址
              _defaultDriverMac = device.device.address.toString();
              _thisScan = true;

              print('找到目標裝置: ${device.device.name}, 位址: ${device.device.address}');
            }
          }
        },
        // 錯誤處理
        onError: (error) {
          print('掃描出錯: $error');
        },
        // 掃描完成處理
        onDone: () {
          print('掃描流結束');
        },
      );
      print('startDiscovery() 呼叫成功,監聽已設定');
    } catch (e) {
      print('啟動掃描異常: $e');
    }

    // 第三步:設定掃描超時定時器
    // 這是非常重要的保護機制,防止掃描無限進行浪費電量
    _scanTimer = Timer(Duration(seconds: scanDuration), () {
      _discoverySubscription?.cancel();
      // 返回掃描結果
      if (!_compScanBlue.isCompleted) {
        _compScanBlue.complete(resultScan == ScanResult.NONE ? status : resultScan);
      }
    });
  });

  return _compScanBlue.future;
}

3.2 掃描結果列舉

為了清楚地區分不同的掃描結果,AI 定義了以下列舉:

dart 体验AI代码助手 代码解读复制代码/// 藍牙掃描結果列舉
enum ScanResult {
  NONE,       // 未找到裝置 - 掃描完成但未發現目標裝置
  BONDED,     // 找到已配對裝置 - 之前已與系統配對過
  UNPAIRED   // 找到未配對裝置 - 需要進行配對操作
}

這個簡單的列舉對整個連接流程至關重要,它決定了後續應該採取什麼樣的連接策略。

3.3 掃描設計亮點

1. 裝置去重機制

使用 Set<String> 儲存裝置位址,可以自動去除重複發現。這是非常必要的,因為藍牙掃描過程中,同一個裝置可能會被多次發現。

2. 單次匹配策略

設定 _thisScan 標誌,確保只處理第一個匹配的裝置。這避免了當多個目標裝置同時存在時的歧義。

3. 超時保護機制

使用 Timer 設定掃描超時,這是節約電量的關鍵。在物聯網環境中,電力是寶貴資源,我們不能讓藍牙無限掃描下去。

4. 配對狀態識別

在掃描階段就區分已配對和未配對裝置,可以讓後續的連接策略更加精準。


四、連接策略實現

4.1 已配對裝置連接

對於已經與系統配對的裝置,連接過程相對簡單:

dart 体验AI代码助手 代码解读复制代码/// 連接已配對的藍牙裝置
/// 適用情境:裝置之前已經成功配對過
/// 優勢:速度快,使用者體驗好
Future<int> _connectToBondedDevice() async {
  print('發現已配對裝置,直接連接裝置位址: $_defaultDriverMac');

  try {
    // 直接透過 MAC 位址建立連接
    final connection = await BluetoothConnection.toAddress(_defaultDriverMac);
    _connection = connection;
    print('藍牙連接成功');
    return BluetoothStatus['CONNECTED_SUCCESS'];
  } catch (e) {
    print('藍牙連接失敗: $e');
    return BluetoothStatus['CONNECTION_FAILED'];
  }
}

適用情境

  • 裝置之前已經成功配對過
  • 配對資訊仍然保存在系統中
  • 需要快速重連

AI 設計思路: 已配對裝置的連接是最簡單的情境,因為配對過程已經在之前完成,現在只需要建立連接即可。我們使用 BluetoothConnection.toAddress() 方法直接建立連接。

4.2 未配對裝置連接

對於未配對的裝置,需要先進行配對操作:

dart 体验AI代码助手 代码解读复制代码/// 配對並連接未配對的藍牙裝置
/// 適用情境:首次連接或配對資訊已遺失
/// 流程:配對 -> 連接
Future<int> _bondAndConnectDevice() async {
  print('發現未配對裝置,先配對裝置位址: $_defaultDriverMac');

  try {
    // 第一步:裝置配對
    // 這會觸發系統的配對對話框(如果需要 PIN 碼)
    await FlutterBluetoothSerial.instance.bondDeviceAtAddress(_defaultDriverMac);
    print('配對成功,開始藍牙連接');

    // 第二步:建立連接
    final connection = await BluetoothConnection.toAddress(_defaultDriverMac);
    _connection = connection;
    print('配對和連接成功');
    return BluetoothStatus['CONNECTED_SUCCESS'];
  } catch (e) {
    print('配對或連接失敗: $e');
    return BluetoothStatus['CONNECTION_FAILED'];
  }
}

適用情境

  • 首次連接新裝置
  • 之前配對資訊被清除
  • 需要使用者確認配對

AI 設計思路: 未配對裝置的連接需要兩個步驟:先配對,再連接。這裡使用 bondDeviceAtAddress() 方法觸發系統配對流程。這個方法可能會彈出系統配對對話框(如果裝置需要 PIN 碼)。

4.3 連接狀態預檢查

在實際連接之前,我們需要檢查是否已經建立了連接:

dart 体验AI代码助手 代码解读复制代码/// 檢查是否已連接到目標裝置
Future<bool> _checkIfConnected() async {
  print('========== 檢查目標裝置連接狀態 ==========');

  try {
    // 1. 檢查記憶體中是否已有有效連接
    // 這是最快的檢查方式
    if (_connection != null && _connection!.isConnected) {
      print('已建立藍牙連接');
      return true;
    }

    // 2. 取得已配對裝置列表,檢查目標裝置是否已配對
    // 如果裝置已經配對但未連接,我們可以快速重連
    final bondedDevices = await FlutterBluetoothSerial.instance.getBondedDevices();
    for (var device in bondedDevices) {
      if (defaultDriverName.contains(device.name)) {
        print('發現已配對的目標裝置: ${device.name}');
        return true;
      }
    }

    print('未連接到目標裝置');
    return false;
  } catch (e) {
    print('檢查連接狀態異常: $e');
    return false;
  }
}

五、自動重連機制

5.1 重連策略設計

這是實現「自動連接」功能的核心機制。透過智慧的重連策略,我們可以確保在各種異常情況下都能恢復連接:

dart 体验AI代码助手 代码解读复制代码Future connBlue() async {
  await _connBlue().then((value) {
    int status;
    String? _errorMsg;

    status = value as int;

    // 根據不同狀態碼設定友善的錯誤資訊
    if (status == BluetoothStatus['CONNECTION_FAILED']) {
      _errorMsg = '找到音箱, 連接失敗';
    } else if (status == BluetoothStatus['CONNECTED_SUCCESS']) {
      _errorMsg = '找到音箱,連接成功';
    } else if (status == BluetoothStatus['CONNECTED']) {
      _errorMsg = '音箱已經連接';
    } else if (status == BluetoothStatus['DEVICE_NOT_FOUND']) {
      _errorMsg = '沒有找到音箱,請確認音箱已經開啟';
    } else if (status == BluetoothStatus['BLUETOOTH_DISABLED']) {
      _errorMsg = '裝置藍牙未開啟,請在系統設定中開啟藍牙';
    } else if (status == BluetoothStatus['PERMISSION_DENIED']) {
      _errorMsg = '沒有取得所需權限(藍牙掃描),請在系統設定中手動授予"附近裝置"權限';
    } else {
      _errorMsg = '未知錯誤';
    }

    print(_errorMsg);

    // ============================================
    // 核心:自動重連邏輯
    // ============================================
    // 只有在以下可恢復的錯誤情況下才進行重試
    if ([
      BluetoothStatus['DEVICE_NOT_FOUND'],    // 裝置未找到
      BluetoothStatus['BLUETOOTH_DISABLED'], // 藍牙未開啟
      BluetoothStatus['PERMISSION_DENIED'],   // 權限被拒(可能使用者後來授予了)
      BluetoothStatus['CONNECTION_FAILED']    // 連接失敗(可能是暫時性的)
    ].contains(status)) {
      // 等待指定間隔後自動重試
      Timer(Duration(seconds: scanTimeInterval), () async {
        connBlue();  // 遞迴呼叫,形成循環直到成功
      });
    } else {
      // 對於已連接等狀態,不需要重試
      print('連接成功或不需要重試,流程結束');
    }
  });
}

5.2 重連參數設定

dart 体验AI代码助手 代码解读复制代码class BlueTooth {
  // 自動連接裝置名稱列表
  // 可以設定多個裝置名,系統會依序嘗試連接
  List defaultDriverName = [];

  // 每次掃描的持續時間(秒)
  // 建議值:5-15 秒
  // 太短可能找不到裝置,太長浪費電量
  int scanDuration = 10;

  // 兩次掃描之間的間隔時間(秒)
  // 建議值:10-30 秒
  // 這個間隔要足夠讓使用者開啟裝置
  int scanTimeInterval = 15;
}

5.3 重連設計亮點

1. 智慧重試條件

我們只對可恢復的錯誤進行重試:

  • DEVICE_NOT_FOUND:裝置未找到,可能裝置剛開啟
  • BLUETOOTH_DISABLED:藍牙被關閉,可能使用者剛開啟
  • PERMISSION_DENIED:權限被拒絕,可能使用者後來授予了
  • CONNECTION_FAILED:連接失敗,可能是暫時性問題

對於永久性錯誤(如未知錯誤),我們選擇不重試,避免無意義的循環。

2. 可設定間隔

允許自訂重試間隔,平衡使用者體驗和耗電量。在不同情境下可以調整這個值:

  • 系統啟動時:較短間隔(5-10 秒)
  • 日常維護:正常間隔(15 秒)
  • 低電量模式:較長間隔(30 秒以上)

3. 遞迴重試

使用遞迴呼叫實現持續重連,直到成功或使用者介入。這種設計簡單而有效,不需要額外的心跳機制。


六、完整連接流程圖

scss 体验AI代码助手 代码解读复制代码┌──────────────────────────────────────────────────────────────────────┐
│                           connBlue() 入口                            │
│                    系統啟動時自動呼叫                                │
└──────────────────────────────────────────────────────────────────────┘
                                    │
                                    ▼
┌──────────────────────────────────────────────────────────────────────┐
│                    _checkIfConnected() 檢查連接狀態                  │
│  ┌────────────────────────────────────────────────────────────────┐  │
│  │  檢查方式:                                                    │  │
│  │  1. 檢查記憶體中的連接物件是否有效 (_connection.isConnected)  │  │
│  │  2. 取得已配對裝置列表,檢查目標裝置是否已配對                 │  │
│  └────────────────────────────────────────────────────────────────┘  │
└──────────────────────────────────────────────────────────────────────┘
                                    │
                    ┌───────────────┴───────────────┐
                    │                               │
                    ▼                               ▼
            ┌─────────────┐               ┌─────────────────┐
            │  已連接/已配對 │               │   未連接/未配對  │
            │  (return true) │               │ (return false)  │
            └─────────────┘               └─────────────────┘
                    │                               │
                    ▼                               ▼
        ┌───────────────────┐           ┌─────────────────────────────┐
        │ 返回 CONNECTED    │           │     _scanBlue() 開始掃描    │
        │ 直接結束流程      │           │  ┌─────────────────────────┐│
        └───────────────────┘           │  │ 1. 權限檢查              ││
                                        │  │ 2. 裝置掃描              ││
                                        │  │ 3. 目標匹配              ││
                                        │  │ 4. 超時保護              ││
                                        │  └─────────────────────────┘│
                                        └─────────────────────────────┘
                                                            │
                                            ┌───────────────┴───────────────┐
                                            ▼                               ▼
                                    ┌─────────────┐               ┌─────────────┐
                                    │ ScanResult  │               │ ScanResult   │
                                    │   BONDED    │               │  UNPAIRED    │
                                    │ (已配對)    │               │ (未配對)     │
                                    └─────────────┘               └─────────────┘
                                            │                               │
                                            ▼                               ▼
                            ┌───────────────────────────┐ ┌─────────────────────────────┐
                            │ _connectToBondedDevice() │ │ _bondAndConnectDevice()     │
                            │   直接連接已配對裝置      │ │   1. 配對裝置               │
                            │   速度快,使用者體驗好    │ │   2. 建立連接               │
                            └───────────────────────────┘ └─────────────────────────────┘
                                            │                               │
                                            └───────────────┬───────────────┘
                                                            │
                                                            ▼
                                            ┌─────────────────────────────────┐
                                            │     判斷連接結果狀態碼          │
                                            │  CONNECTED_SUCCESS (201)       │
                                            │  CONNECTION_FAILED (400)        │
                                            └─────────────────────────────────┘
                                                            │
                        ┌───────────────────────────────────┼───────────────────────────────────┐
                        │                                   │                                   │
                        ▼                                   ▼                                   ▼
                ┌─────────────┐                   ┌─────────────┐                   ┌─────────────┐
                │   201成功   │                   │  400失敗    │                   │  其他錯誤   │
                │  流程結束  │                   │  等待重試   │                   │   (結束)    │
                └─────────────┘                   └─────────────┘                   └─────────────┘
                                                    │
                                                    ▼
                                            ┌─────────────────┐
                                            │ 等待scanTimeInterval秒  │
                                            │    自動重試     │
                                            └─────────────────┘
                                                    │
                                                    ▼
                                        ┌─────────────────────────┐
                                        │    connBlue() 遞迴     │
                                        │    (回到起點)          │
                                        └─────────────────────────┘

七、狀態碼定義與錯誤處理

7.1 狀態碼設計

AI 設計了 HTTP 風格的狀態碼,便於理解和記憶:

dart 体验AI代码助手 代码解读复制代码/// 藍牙連接狀態碼
const Map BluetoothStatus = {
  "CONNECTED": 200,           // 已連接到目標裝置
  "CONNECTED_SUCCESS": 201,   // 連接成功
  "CONNECTION_FAILED": 400,   // 連接失敗
  "DEVICE_NOT_FOUND": 404,    // 未找到裝置
  "BLUETOOTH_DISABLED": 401, // 藍牙未開啟/不可用
  "PERMISSION_DENIED": 403,   // 權限不足
  "UNKNOWN_ERROR": 500,       // 未知錯誤
};

設計思路

  • 2xx 系列表示成功
  • 4xx 系列表示用戶端錯誤(裝置未找到、權限問題等)
  • 5xx 系列表示伺服器或未知錯誤

7.2 錯誤資訊對應

dart 体验AI代码助手 代码解读复制代码// 狀態碼到錯誤資訊的對應
String getErrorMessage(int status) {
  switch (status) {
    case 200: return '已連接到目標裝置';
    case 201: return '連接成功';
    case 400: return '連接失敗,請檢查裝置';
    case 404: return '未找到裝置,請確認裝置已開啟';
    case 401: return '藍牙未開啟,請在系統設定中開啟';
    case 403: return '權限不足,請授予藍牙權限';
    default: return '未知錯誤';
  }
}

八、使用範例與最佳實務

8.1 基本用法

dart 体验AI代码助手 代码解读复制代码// 建立藍牙連接器實例
final bluetooth = BlueTooth();

// 設定目標裝置名稱
// 系統會自動連接列表中的第一個匹配裝置
bluetooth.defaultDriverName = ['Speaker001', 'BT-Speaker', 'MyBluetooth'];

// 配置參數(可選)
bluetooth.scanDuration = 10;      // 每次掃描 10 秒
bluetooth.scanTimeInterval = 15; // 重試間隔 15 秒

// 啟動自動連接
bluetooth.connBlue();

8.2 在應用程式啟動時自動連接

dart 体验AI代码助手 代码解读复制代码void main() {
  runApp(MyApp());

  // 應用程式啟動後自動嘗試藍牙連接
  // 使用 addPostFrameCallback 確保在 Widget 樹建構完成後執行
  WidgetsBinding.instance.addPostFrameCallback((_) {
    final bluetooth = BlueTooth();
    bluetooth.defaultDriverName = ['Speaker001'];
    bluetooth.connBlue();
  });
}

8.3 監聽連接狀態

dart 体验AI代码助手 代码解读复制代码// 可以在外部監聽連接狀態變化
class BluetoothStatusNotifier extends ChangeNotifier {
  bool _isConnected = false;

  bool get isConnected => _isConnected;

  void updateStatus(bool connected) {
    _isConnected = connected;
    notifyListeners();
  }
}

九、總結與最佳化建議

9.1 設計亮點總結

特性 實作方式 優勢
權限管理 分步請求 + 狀態檢查 相容 Android 6.0 到 14.0 所有版本
裝置掃描 Set 去重 + 超時保護 效率高,資源占用少
差異化連接 Bonded/Unpaired 分支 針對性強,成功率高
自動重連 遞迴 + 定時器 穩定可靠,無需人工介入
日誌系統 完整的狀態記錄 便於問題排查

9.2 後續最佳化方向

1. 連接狀態持久化 記錄成功連接的裝置資訊(MAC 位址、裝置名稱),下次啟動時優先嘗試連接歷史裝置,而不是每次都掃描。

2. 多裝置支援 擴展系統支援同時連接多個藍牙裝置(音箱 + 印表機 + 感測器等),實現更豐富的系統功能。

3. 電量最佳化 根據裝置電量水準動態調整掃描頻率和重試間隔,在低電量模式下降低掃描頻率以節省電力。

4. UI 回饋 新增連接狀態的視覺化介面,讓使用者清楚地知道目前連接狀態,以及何時需要手動介入。

5. 連接品質監控 新增連接品質檢測,在連接不穩定時主動斷線並重連,提供更穩定的連接體驗。


這套藍牙自動連接系統已經在工業物聯網中穩定運行,透過 AI 的輔助設計,成功處理了 Android 碎片化帶來的各種相容性問題,實現了真正意義上「即插即用」的自動連接體驗。系統能夠在啟動後自動連接藍牙裝置,無需使用者任何介入,大大提升了物聯網系統的使用者體驗和功能完整性。


原文出處:https://juejin.cn/post/7634768133992349696


精選技術文章翻譯,幫助開發者持續吸收新知。

共有 0 則留言


精選技術文章翻譯,幫助開發者持續吸收新知。
🏆 本月排行榜
🥇
站長阿川
📝11   💬8  
247
🥈
我愛JS
💬1  
5
🥉
Gigi
2
評分標準:發文×10 + 留言×3 + 獲讚×5 + 點讚×1 + 瀏覽數÷10
本數據每小時更新一次
📢 贊助商廣告 · 我要刊登