I am using instascan.min js library to scan QR Codes in my web angular js application. but in my flutter web view, I got an error - Cannot access video stream (NotAllowedError), And I am unable to fix it. I don't have too much knowledge of flutter.
I have tried to give permission to camera access but it's not working.
//# My Flutter Code
import 'package:flutter/material.dart';
import 'package:flutter_webview_plugin/flutter_webview_plugin.dart';
void main () => runApp(MyApp());
class MyApp extends StatelessWidget{
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'FOTOFACE WALLET',
debugShowCheckedModeBanner: false,
home: Home(),
);
}
}
class Home extends StatefulWidget{
@override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home>{
@override
Widget build(BuildContext context) {
return WebviewScaffold(
appBar: PreferredSize(
preferredSize: Size.fromHeight(0),
child: AppBar(
automaticallyImplyLeading: true, // hides leading widget
backgroundColor: new Color(0xFF404E67),
)
),
url: "https://fotofacewallet.com",
initialChild: Center(
child: CircularProgressIndicator(),
),
);
}
}
//# this is my scanner code in angular js controller
$scope.scan = () => {
var overlay = $('.overlay'),
close = $('<div class="close" id="closescanbtn">close</div>');
overlay.append(close);
let scanner = new Instascan.Scanner({
video: document.getElementById('preview')
});
scanner.addListener('scan', function (content) {
scanner.stop();
$('.overlay').fadeOut();
$('.overlay').hide();
$scope.scanpayProcess(content);
});
Instascan.Camera.getCameras().then(function (cameras) {
if (cameras.length > 0) {
if(cameras[1]){
scanner.start(cameras[1]);
} else {
scanner.start(cameras[0]);
}
} else {
alert('No cameras found.');
}
}).catch(function (e) {
alert(e);
});
$('.overlay').show();
}
I am expecting a camera view in a flutter web view.
I have done something like this
on my index.html page or the file that you have created in your angular side
I have added one button :
<button type="button" onclick="displayMsg()" class="btn btn-default btn-login">Scan</button>
and handled its click event as below and we will post message as 'scan'
<script type="text/javascript">
function displayMsg(){
Print.postMessage("scan");
}
</script>
added this package in my pubspec.yaml file
flutter_barcode_scanner: ^0.1.5+1
do run flutter pub get
to update dependencies
then on my main.dart file
I have imported
import 'dart:async';
import 'package:flutter_barcode_scanner/flutter_barcode_scanner.dart';
in main.dart file added below code to handle the event triggered on displayMsg() function - 'scan' message
final Set<JavascriptChannel> jsChannels = [
JavascriptChannel(
name: 'Print',
onMessageReceived: (JavascriptMessage message) {
if(message.message == 'scan'){
print(message.message);
sBarcode(MyApp());
}
}),
].toSet();
sBarcode(someVal) async {
String bCode = await FlutterBarcodeScanner.scanBarcode("#ff6666", "Cancel", true); print(bCode);
someVal.enterBarcode(bCode); // to get the scanned barcode
return; }
enterBarcode(barc) {
flutterWebViewPlugin.evalJavascript("document.getElementById('yourtextboxid').value="
+ barc); }
This is how my complete main.dart file looks now
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_barcode_scanner/flutter_barcode_scanner.dart';
import 'package:flutter_webview_plugin/flutter_webview_plugin.dart';
const kAndroidUserAgent =
'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Mobile Safari/537.36';
String selectedUrl = 'add_your_url_here';
// ignore: prefer_collection_literals
final Set<JavascriptChannel> jsChannels = [
JavascriptChannel(
name: 'Print',
onMessageReceived: (JavascriptMessage message) {
if(message.message == 'scan'){
//MyApp.startBarcode();
print(message.message);
sBarcode(MyApp());
}
}),
].toSet();
sBarcode(someVal) async {
String bCode = await FlutterBarcodeScanner.scanBarcode("#ff6666", "Cancel", true);
print(bCode);
someVal.enterBarcode(bCode);
return;
}
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
final flutterWebViewPlugin = FlutterWebviewPlugin();
enterBarcode(barc) {
flutterWebViewPlugin.evalJavascript("document.getElementById('barcodenumber').value=" + barc);
}
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter WebView Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
routes: {
// '/': (_) => const MyHomePage(title: 'Flutter WebView Demo'),
'/': (_) {
return WebviewScaffold(
url: selectedUrl,
javascriptChannels: jsChannels,
withZoom: true,
withLocalStorage: true,
withJavascript: true,
hidden: true,
initialChild: Container(
color: Colors.white,
child: const Center(
child: Text('Loading...'),
),
),
);
},
},
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
// Instance of WebView plugin
final flutterWebViewPlugin = FlutterWebviewPlugin();
// On destroy stream
StreamSubscription _onDestroy;
// On urlChanged stream
StreamSubscription<String> _onUrlChanged;
// On urlChanged stream
StreamSubscription<WebViewStateChanged> _onStateChanged;
StreamSubscription<WebViewHttpError> _onHttpError;
StreamSubscription<double> _onProgressChanged;
StreamSubscription<double> _onScrollYChanged;
StreamSubscription<double> _onScrollXChanged;
final _urlCtrl = TextEditingController(text: selectedUrl);
final _codeCtrl = TextEditingController(text: 'window.navigator.userAgent');
final _scaffoldKey = GlobalKey<ScaffoldState>();
final _history = [];
@override
void initState() {
super.initState();
flutterWebViewPlugin.close();
_urlCtrl.addListener(() {
selectedUrl = _urlCtrl.text;
});
// Add a listener to on destroy WebView, so you can make came actions.
_onDestroy = flutterWebViewPlugin.onDestroy.listen((_) {
if (mounted) {
// Actions like show a info toast.
_scaffoldKey.currentState.showSnackBar(
const SnackBar(content: const Text('Webview Destroyed')));
}
});
// Add a listener to on url changed
_onUrlChanged = flutterWebViewPlugin.onUrlChanged.listen((String url) {
if (mounted) {
setState(() {
_history.add('onUrlChanged: $url');
});
}
});
_onProgressChanged =
flutterWebViewPlugin.onProgressChanged.listen((double progress) {
if (mounted) {
setState(() {
_history.add('onProgressChanged: $progress');
});
}
});
_onScrollYChanged =
flutterWebViewPlugin.onScrollYChanged.listen((double y) {
if (mounted) {
setState(() {
_history.add('Scroll in Y Direction: $y');
});
}
});
_onScrollXChanged =
flutterWebViewPlugin.onScrollXChanged.listen((double x) {
if (mounted) {
setState(() {
_history.add('Scroll in X Direction: $x');
});
}
});
_onStateChanged =
flutterWebViewPlugin.onStateChanged.listen((WebViewStateChanged state) {
print(state.type);
if (mounted) {
setState(() {
_history.add('onStateChanged: ${state.type} ${state.url}');
});
}
});
_onHttpError =
flutterWebViewPlugin.onHttpError.listen((WebViewHttpError error) {
if (mounted) {
setState(() {
_history.add('onHttpError: ${error.code} ${error.url}');
});
}
});
}
@override
void dispose() {
// Every listener should be canceled, the same should be done with this stream.
_onDestroy.cancel();
_onUrlChanged.cancel();
_onStateChanged.cancel();
_onHttpError.cancel();
_onProgressChanged.cancel();
_onScrollXChanged.cancel();
_onScrollYChanged.cancel();
flutterWebViewPlugin.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldKey,
appBar: AppBar(
title: const Text('Plugin example app'),
),
body: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
padding: const EdgeInsets.all(24.0),
child: TextField(controller: _urlCtrl),
),
RaisedButton(
onPressed: () {
flutterWebViewPlugin.launch(
selectedUrl,
rect: Rect.fromLTWH(
0.0, 0.0, MediaQuery.of(context).size.width, 300.0),
userAgent: kAndroidUserAgent,
invalidUrlRegex:
r'^(https).+(twitter)', // prevent redirecting to twitter when user click on its icon in flutter website
);
},
child: const Text('Open Webview (rect)'),
),
RaisedButton(
onPressed: () {
flutterWebViewPlugin.launch(selectedUrl, hidden: true);
},
child: const Text('Open "hidden" Webview'),
),
RaisedButton(
onPressed: () {
flutterWebViewPlugin.launch(selectedUrl);
},
child: const Text('Open Fullscreen Webview'),
),
RaisedButton(
onPressed: () {
Navigator.of(context).pushNamed('/widget');
},
child: const Text('Open widget webview'),
),
Container(
padding: const EdgeInsets.all(24.0),
child: TextField(controller: _codeCtrl),
),
RaisedButton(
onPressed: () {
final future =
flutterWebViewPlugin.evalJavascript(_codeCtrl.text);
future.then((String result) {
setState(() {
_history.add('eval: $result');
});
});
},
child: const Text('Eval some javascript'),
),
RaisedButton(
onPressed: () {
setState(() {
_history.clear();
});
flutterWebViewPlugin.close();
},
child: const Text('Close'),
),
RaisedButton(
onPressed: () {
flutterWebViewPlugin.getCookies().then((m) {
setState(() {
_history.add('cookies: $m');
});
});
},
child: const Text('Cookies'),
),
Text(_history.join('\n'))
],
),
),
);
}
}
check and test and let me know if that works for you or not, This is working fine at my end. Print will generate error in browser you need to test this in android or ios. Hope this helps.