首页 > 解决方案 > Web Camera 插件无法在 Flutter 中运行(仅在 iOS 中)

问题描述

我使用“camera.dart”包来访问网络摄像头。它在机器浏览器上运行良好,但一旦涉及移动设备,问题就会出现。即使在安卓上也可以。但在 iOS 上,在请求许可后,相机流未加载。任何帮助都将非常感谢您发现我缺少的部分。我的代码在 Camera 类中如下所示。

String getRandString() {
  var random = Random.secure();
  var values = List<int>.generate(8, (i) =>  random.nextInt(255));
  return base64UrlEncode(values);
}

类实现

 class _WebcamPageState extends State<WebcamPage> {
  // VideoElement
  late final VideoElement _webcamVideoElement;

  final String videoTag = getRandString();
@override
  void initState() {
  super.initState();

     // Create an video element which will be provided with stream source
     _webcamVideoElement = VideoElement();

    // Register an webcam
    ui.platformViewRegistry.registerViewFactory(
    videoTag, (int viewId) => _webcamVideoElement);
 
    loadCameraStream();

  }

 // I suppose the issue is here
  void loadCameraStream() { 

   var constraints = {
      "audio": false,
      "video": {
              'mandatory':
                  { 'minAspectRatio': 1.333, 'maxAspectRatio': 1.334 },
              'optional':
              [{ 'minFrameRate': 60 },
              { 'maxWidth': 400 }]
      }
  };
  window.navigator.mediaDevices?.getUserMedia(constraints).then((MediaStream stream) {
   _webcamVideoElement.srcObject = stream;
   _webcamVideoElement.play();
  });
  }


@override
  Widget build(BuildContext context) =>
     Scaffold(
         body: SingleChildScrollView(
         child: Container(
                          height: 500.0,
                          child: HtmlElementView(key: UniqueKey(),
                          viewType:videoTag),
                        )
          )//SingleChildScrollView
      );//Scaffold

 }

我有单独的处置方法

@override
  void dispose() {

   if (_webcamVideoElement.srcObject != null &&
    (_webcamVideoElement.srcObject!.active ?? false)) {
    _webcamVideoElement.pause();
    var tracks = _webcamVideoElement.srcObject?.getTracks();
    _webcamVideoElement.srcObject = null;

  tracks?.forEach((track) {
    track.stop();
  });
  }
   super.dispose();
 }

标签: flutterflutter-web

解决方案


对于那些像我一样被困住的人,这里有一个简单的演示应用程序代码,可以在任何浏览器和任何设备上运行。

import 'package:flutter/material.dart';
import 'dart:html' as html;
import 'dart:ui' as ui;

void main() {
 runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
 Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Container(),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () async {
          await showDialog(
              context: context,
              builder: (BuildContext context) {
                return FractionallySizedBox(
                  heightFactor: 0.5,
                  widthFactor: 0.5,
                  child: WebCam(),
                );
              });
        },
        // tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}

class WebCam extends StatefulWidget {
  @override
  _WebCamState createState() => _WebCamState();
}

class _WebCamState extends State<WebCam> {
  static html.VideoElement _webcamVideoElement = html.VideoElement();

  @override
  void initState() {
    super.initState();

  // Register a webcam
  // ignore: undefined_prefixed_name
    ui.platformViewRegistry.registerViewFactory('webcamVideoElement',
        (int viewId) {
      getMedia();
      return _webcamVideoElement;
    });
  }

  getMedia() {
    html.window.navigator.mediaDevices
        .getUserMedia({"video": true}).then((streamHandle) {
      _webcamVideoElement
        ..srcObject = streamHandle
        ..autoplay = true;
    }).catchError((onError) {
      print(onError);
    });
  }

  switchCameraOff() {
    if (_webcamVideoElement.srcObject != null &&
        _webcamVideoElement.srcObject.active) {
      var tracks = _webcamVideoElement.srcObject.getTracks();

      //stopping tracks and setting srcObject to null to switch camera off
      _webcamVideoElement.srcObject = null;

      tracks.forEach((track) {
        track.stop();
      });
    }
  }

  @override
  void dispose() {
    switchCameraOff();

    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Stack(
        children: [
          Container(
              child: new HtmlElementView(
            key: UniqueKey(),
            viewType: 'webcamVideoElement',
          )),
          Container(
            child: Column(
              children: [
                RaisedButton(
                  child: Text('Play/Pause'),
                  onPressed: () async {
                    if (_webcamVideoElement.paused) {
                      _webcamVideoElement.play();
                    } else {
                       _webcamVideoElement.pause();
                    }
                   },
                ),
                RaisedButton(
                  child: Text('Switch off'),
                  onPressed: () {
                    switchCameraOff();
                  },
                ),
                 RaisedButton(
                  child: Text('Switch on'),
                  onPressed: () {
                    if (_webcamVideoElement.srcObject == null) getMedia();
                  },
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }
}

推荐阅读