Flutter 錄音應用中的權限請求問題

在開發 Flutter 錄音應用時,除了在 AndroidManifest.xml 中正確聲明必要權限外,還必須在程式執行期間動態請求權限,才能順利使用錄音功能。隨著 Android 系統版本的演進,各個版本對權限管理的要求也有所不同。本文將重點說明以下三個部分:

  1. 動態請求權限的重要性
  2. Android 版本差異對權限請求的影響
  3. 完整範例程式碼的逐步解析

一、為什麼需要動態請求權限?

從 Android 6.0(API 23)開始,許多敏感權限(如錄音、存取檔案)必須在應用運行時向使用者動態請求。如果僅在 AndroidManifest.xml 中聲明權限,而不在程式碼中實際請求,則應用將無法使用這些功能。

常見的權限包括:

  • 錄音權限RECORD_AUDIO
  • 檔案存取權限
    • Android 12 及以下:READ_EXTERNAL_STORAGE 和 WRITE_EXTERNAL_STORAGE
    • Android 13+:READ_MEDIA_AUDIO(在 Flutter 的 permission_handler 套件中使用 Permission.audio 來請求)
  • 前台服務權限(Android 14+):例如 FOREGROUND_SERVICE_MICROPHONE,用於需要前台服務的長時間錄音

二、Android 版本差異與權限請求

隨著 Android 版本的更新,權限管理也在發生變化:

  • Android 6.0+(API 23)

    • 需要動態請求 RECORD_AUDIO 權限。
  • Android 13+(API 33)

    • 存取錄音檔案的權限由原本的 READ_EXTERNAL_STORAGE 轉換為 READ_MEDIA_AUDIO,因此在 Flutter 中請求存取權限時應使用 Permission.audio
  • Android 14+(API 34)

    • 如果應用採用前台服務錄音(例如長時間錄音),則可能需要額外的前台服務權限(如 FOREGROUND_SERVICE_MICROPHONE)來保證服務正常運作。

根據這些版本差異,我們需要在程式碼中根據當前設備的 Android 版本動態調整請求權限的邏輯。


三、完整範例程式碼解析

下面提供一個完整的範例程式碼,展示如何根據不同 Android 版本動態請求錄音與存取檔案的權限,並詳細解釋每個部分的作用。

dart
import 'dart:io'; import 'package:permission_handler/permission_handler.dart'; import 'package:device_info_plus/device_info_plus.dart'; /// 檢查並請求錄音與存取檔案所需權限 Future<bool> checkPermission() async { // 1. 請求錄音權限:這是錄音功能必須的權限,從 Android 6.0(API 23)開始必須動態請求。 final microphoneStatus = await Permission.microphone.request(); late PermissionStatus storageStatus; if (Platform.isAndroid) { // 2. 取得 Android 系統的 SDK 版本號,用以決定採用哪種權限請求方式 int androidVersion = await getAndroidVersion(); // 3. 根據 Android 版本決定存取權限: // - Android 13+(API 33 以上):使用 Permission.audio (對應 READ_MEDIA_AUDIO) // - Android 12 及以下:使用傳統的存取權限 Permission.storage (對應 READ_EXTERNAL_STORAGE) if (androidVersion >= 33) { storageStatus = await Permission.audio.request(); } else { storageStatus = await Permission.storage.request(); } // 4. 額外處理 Android 14+(API 34)的情況: // 如果應用需要使用前台服務進行錄音,則需要額外確保前台服務相關權限已獲得。 // 這裡作為示例,我們再次請求錄音權限來檢查前台服務狀態, // 實際上可以根據需求請求並檢查具體的前台服務權限(通常在 AndroidManifest.xml 中配置即可)。 if (androidVersion >= 34) { final foregroundStatus = await Permission.microphone.request(); if (!foregroundStatus.isGranted) { print("前台錄音權限被拒絕!"); return false; } } } else { // 如果非 Android 平台(例如 iOS),則使用一般存取權限 storageStatus = await Permission.storage.request(); } // 5. 返回錄音和存取權限是否都獲得:只有兩者都獲得時,應用才能順利使用錄音功能。 return microphoneStatus.isGranted && storageStatus.isGranted; } /// 取得 Android 版本號 Future<int> getAndroidVersion() async { // 若非 Android 平台,直接返回 0 if (!Platform.isAndroid) return 0; final deviceInfo = DeviceInfoPlugin(); final androidInfo = await deviceInfo.androidInfo; // androidInfo.version.sdkInt 即代表當前 Android 系統的 SDK 版本 return androidInfo.version.sdkInt; }

詳細說明

  1. 引入套件與環境檢查

    • dart:io:用於檢查當前平台(例如 Platform.isAndroid)。
    • permission_handler:負責在應用運行時動態請求所需權限。
    • device_info_plus:用於獲取設備資訊,尤其是 Android 的 SDK 版本號,方便根據版本差異調整權限請求策略。
  2. 錄音權限的請求

    • 程式一開始即請求 Permission.microphone,確保錄音功能可以正常使用。
  3. 根據 Android 版本請求存取權限

    • 使用 getAndroidVersion() 函式取得當前設備的 SDK 版本:
      • 若版本在 33(Android 13)以上,則使用 Permission.audio 請求權限,對應 AndroidManifest.xml 中的 READ_MEDIA_AUDIO
      • 若版本在 33 以下(Android 12 及以下),則使用傳統的 Permission.storage 請求權限,對應 READ_EXTERNAL_STORAGE
  4. 處理 Android 14+ 的前台服務需求

    • 若設備版本在 34(Android 14)以上,且應用需要使用前台服務進行長時間錄音,則需額外確認前台服務相關權限是否已獲得。
    • 範例中再次請求 Permission.microphone 來模擬此檢查,實際上可以根據應用需求調整或直接在 AndroidManifest.xml 中進行配置。
  5. 返回權限檢查結果

    • 只有當錄音和存取權限均獲得授權時,checkPermission() 才返回 true,否則返回 false,提示應用需要向使用者解釋或重新請求權限。

結論

在 Flutter 錄音應用中正確處理權限請求是確保應用順利運作的關鍵。

  • Android 6.0+(API 23):必須在應用運行時動態請求 RECORD_AUDIO 權限。
  • Android 13+(API 33):權限管理有變,存取音訊檔案的權限由 READ_EXTERNAL_STORAGE 改為 READ_MEDIA_AUDIO,故在 Flutter 中應使用 Permission.audio
  • Android 14+(API 34):若錄音透過前台服務進行,則可能需要額外處理前台服務權限(例如 FOREGROUND_SERVICE_MICROPHONE)。

希望這篇文章能夠幫助你了解 Flutter 錄音應用中的權限請求邏輯,並根據不同 Android 版本調整你的權限管理策略。Happy Coding!

留言

此網誌的熱門文章

怎麼讓 VS Code 自動排版變漂亮? Prettier ESLint

如何創建並推送 Docker 映像檔至 AWS ECR