Flutter Chime js sdk 使用

之前项目用过但是是针对 ios 和 android 的,现在需要针对 web 的,所以需要重新记录下。

问题

先搞清楚,硬件的权限和 web 的权限,因为用到摄像头和麦克风。
基本原理就是 web 上用到摄像头和麦克风,需要在启动 web 前先把平台的相关权限申请好。

webview_flutter 还是 inappwebview

开始用的 webview_flutter,但是发现权限问题,好一通网上查找都没解决,因为之前项目里 chime 本身原来接入的就是 inappwebview,所以索性切换到 inappwebview。

安卓配置

  1. AndroidManifest.xml 中添加权限:

    <manifest xmlns:android="http://schemas.android.com/apk/res/android">
        <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.RECORD_AUDIO"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
    <!--    <uses-permission android:name="android.permission.BLUETOOTH" />-->
    <!--    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />-->
    <application
        android:label="test_pdf_editor"
        android:name="${applicationName}"
        android:icon="@mipmap/ic_launcher">
        <activity/>
    </application>
    </manifest>
  2. app/build.gradle 中添加版本:

    android {
        ...
        defaultConfig {
            ...
            minSdk = 28 // 最低版本 23 以上
        }
    }
  3. dart 中使用

    /// 一次性请求摄像头 & 麦克风权限
    static Future<void> _requestCameraAndMicrophonePermission() async {
        final statuses = await [
        Permission.camera,
        Permission.microphone,
        ].request();
    
        // 分别检查状态
        final cameraStatus = statuses[Permission.camera];
        final micStatus = statuses[Permission.microphone];
    
        // 摄像头权限
        if (cameraStatus != null && cameraStatus.isGranted) {
        debugPrint('Camera permission granted');
        } else if (cameraStatus != null && cameraStatus.isPermanentlyDenied) {
        debugPrint('Camera permission permanently denied');
        // 引导用户去系统设置开启权限
        await openAppSettings();
        } else {
        debugPrint('Camera permission denied');
        }
    
        // 麦克风权限
        if (micStatus != null && micStatus.isGranted) {
        debugPrint('Microphone permission granted');
        } else if (micStatus != null && micStatus.isPermanentlyDenied) {
        debugPrint('Microphone permission permanently denied');
        await openAppSettings();
        } else {
        debugPrint('Microphone permission denied');
        }
    }
  4. 在需要使用摄像头和麦克风的地方调用,最后这个初始化 webview 的代码比较重要,因为可能 voice input 有声音,但是 voice output 没有声音,所以需要设置 mediaPlaybackRequiresUserGesturefalse,允许自动播放,也就是麦克风和 speaker,网页上显示 speaker 下拉框是 device selection unavailable 基本没有关系,做这个配置就可以了。

    await _requestCameraAndMicrophonePermission();
    InAppWebView(
            // 初始 URL
            initialUrlRequest: URLRequest(url: WebUri(widget.url)),
    
            // 初始配置,比如是否允许 JS
            initialSettings: InAppWebViewSettings(
              javaScriptEnabled: true,
              mediaPlaybackRequiresUserGesture: false,  // 自動再生を許可
              useOnLoadResource: true,
              useShouldOverrideUrlLoading: true,
              allowsInlineMediaPlayback: true,
              mixedContentMode: MixedContentMode.MIXED_CONTENT_ALWAYS_ALLOW,
            ),

windows webview 問題

先开始一直用的 webview_windows,但是发现权限问题,也就是点击打开 web 页面的时候,没有弹出权限弹窗,然后页面显示异常。然后切换到 desktop_webview_window 后,发现正常出现了弹窗。

アプリ和 windows 包区分的问题

结论

  • Flutter 并不支持在 pubspec.yaml 内直接区分平台添加依赖,因此没法在 pubspec 中做“只在 Windows 下引入 desktop_webview_window”之类的写法。
  • 通常我们会把所有可能用到的平台包都放进 dependencies,然后在代码层面用条件导入或“分文件”去避免在非目标平台上实际导入并编译那些插件。
  • 这在实际项目中是非常常见且推荐的做法,一般不会对不相关平台编译造成任何阻塞或报错,也不会有太大性能或打包体积的负面影响。

简单总结

不需要也无法在 pubspec 中“区分”来引入,直接一起引入就好,关键是要用条件导入或分文件来控制代码层面对插件的引用,避免不兼容问题。