Skip to content

Fixed web issue #760

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 8 additions & 12 deletions android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -26,31 +26,27 @@ apply plugin: 'kotlin-android'

android {
compileSdk 33
namespace 'net.touchcapture.qr.flutterqr' // ✅ Place it here

sourceSets {
main.java.srcDirs += 'src/main/kotlin'
}
defaultConfig {
// minSdkVersion is determined by Native View.
minSdkVersion 20
targetSdkVersion 33
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
multiDexEnabled true
}

kotlinOptions {
jvmTarget = '11'
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
}

compileOptions {
// Flag to enable support for the new language APIs
coreLibraryDesugaringEnabled true
// Sets Java compatibility to Java 11
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
coreLibraryDesugaringEnabled true
}
if (project.android.hasProperty('namespace')) {
namespace 'net.touchcapture.qr.flutterqr'

kotlinOptions {
jvmTarget = '11'
}
}

Expand All @@ -59,5 +55,5 @@ dependencies {
implementation('com.journeyapps:zxing-android-embedded:4.3.0') { transitive = false }
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.zxing:core:3.5.2'
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.3'
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.4' // ✅ latest stable
}
53 changes: 22 additions & 31 deletions lib/src/web/flutter_qr_web.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ import 'dart:async';
import 'dart:core';
import 'dart:html' as html;
import 'dart:js_util';
import 'dart:ui' as ui;

// ignore_for_file: avoid_web_libraries_in_flutter
import 'web_view_registry.dart';
import 'package:flutter/material.dart';

import '../../qr_code_scanner.dart';
Expand All @@ -24,21 +25,16 @@ class WebQrView extends StatefulWidget {
final CameraFacing? cameraFacing;

const WebQrView(
{Key? key,
required this.onPlatformViewCreated,
this.onPermissionSet,
this.cameraFacing = CameraFacing.front})
{Key? key, required this.onPlatformViewCreated, this.onPermissionSet, this.cameraFacing = CameraFacing.front})
: super(key: key);

@override
_WebQrViewState createState() => _WebQrViewState();

static html.DivElement vidDiv =
html.DivElement(); // need a global for the registerViewFactory
static html.DivElement vidDiv = html.DivElement(); // need a global for the registerViewFactory

static Future<bool> cameraAvailable() async {
final sources =
await html.window.navigator.mediaDevices!.enumerateDevices();
final sources = await html.window.navigator.mediaDevices!.enumerateDevices();
// List<String> vidIds = [];
var hasCam = false;
for (final e in sources) {
Expand Down Expand Up @@ -66,8 +62,7 @@ class _WebQrViewState extends State<WebQrView> {
html.VideoElement video = html.VideoElement();
String viewID = 'QRVIEW-' + DateTime.now().millisecondsSinceEpoch.toString();

final StreamController<Barcode> _scanUpdateController =
StreamController<Barcode>();
final StreamController<Barcode> _scanUpdateController = StreamController<Barcode>();
late CameraFacing facing;

Timer? _frameIntervall;
Expand All @@ -80,9 +75,14 @@ class _WebQrViewState extends State<WebQrView> {

// video = html.VideoElement();
WebQrView.vidDiv.children = [video];
// ignore: UNDEFINED_PREFIXED_NAME
ui.platformViewRegistry
.registerViewFactory(viewID, (int id) => WebQrView.vidDiv);
// ignore: undefined_prefixed_name
platformViewRegistry.registerViewFactory(
viewID,
(int id) => WebQrView.vidDiv,
);

print('[QR Scanner Web] viewID: $viewID');

// giving JavaScipt some time to process the DOM changes
Timer(const Duration(milliseconds: 500), () {
start();
Expand All @@ -92,8 +92,7 @@ class _WebQrViewState extends State<WebQrView> {
Future start() async {
await _makeCall();
_frameIntervall?.cancel();
_frameIntervall =
Timer.periodic(const Duration(milliseconds: 200), (timer) {
_frameIntervall = Timer.periodic(const Duration(milliseconds: 200), (timer) {
_captureFrame2();
});
}
Expand Down Expand Up @@ -137,8 +136,7 @@ class _WebQrViewState extends State<WebQrView> {
widget.onPermissionSet?.call(_controller!, true);
_localStream = stream;
video.srcObject = _localStream;
video.setAttribute('playsinline',
'true'); // required to tell iOS safari we don't want fullscreen
video.setAttribute('playsinline', 'true'); // required to tell iOS safari we don't want fullscreen
await video.play();
} catch (e) {
cancel();
Expand Down Expand Up @@ -177,16 +175,14 @@ class _WebQrViewState extends State<WebQrView> {
if (_localStream == null) {
return null;
}
final canvas =
html.CanvasElement(width: video.videoWidth, height: video.videoHeight);
final canvas = html.CanvasElement(width: video.videoWidth, height: video.videoHeight);
final ctx = canvas.context2D;
// canvas.width = video.videoWidth;
// canvas.height = video.videoHeight;
ctx.drawImage(video, 0, 0);
final imgData = ctx.getImageData(0, 0, canvas.width!, canvas.height!);

final size =
Size(canvas.width?.toDouble() ?? 0, canvas.height?.toDouble() ?? 0);
final size = Size(canvas.width?.toDouble() ?? 0, canvas.height?.toDouble() ?? 0);
if (size != _size) {
setState(() {
_setCanvasSize(size);
Expand All @@ -197,8 +193,7 @@ class _WebQrViewState extends State<WebQrView> {
final code = jsQR(imgData.data, canvas.width, canvas.height);
// ignore: unnecessary_null_comparison
if (code != null && code.data != null) {
_scanUpdateController
.add(Barcode(code.data, BarcodeFormat.qrcode, code.data.codeUnits));
_scanUpdateController.add(Barcode(code.data, BarcodeFormat.qrcode, code.data.codeUnits));
}
} on NoSuchMethodError {
// Do nothing, this exception occurs continously in web release when no
Expand Down Expand Up @@ -246,7 +241,7 @@ class _WebQrViewState extends State<WebQrView> {
);
}

void _setCanvasSize(ui.Size size) {
void _setCanvasSize(Size size) {
setState(() {
_size = size;
});
Expand All @@ -263,9 +258,7 @@ class QRViewControllerWeb implements QRViewController {
@override
Future<CameraFacing> flipCamera() async {
// TODO: improve error handling
_state.facing = _state.facing == CameraFacing.front
? CameraFacing.back
: CameraFacing.front;
_state.facing = _state.facing == CameraFacing.front ? CameraFacing.back : CameraFacing.front;
await _state.start();
return _state.facing;
}
Expand Down Expand Up @@ -325,9 +318,7 @@ class QRViewControllerWeb implements QRViewController {
}
}

Widget createWebQrView(
{onPlatformViewCreated, onPermissionSet, CameraFacing? cameraFacing}) =>
WebQrView(
Widget createWebQrView({onPlatformViewCreated, onPermissionSet, CameraFacing? cameraFacing}) => WebQrView(
onPlatformViewCreated: onPlatformViewCreated,
onPermissionSet: onPermissionSet,
cameraFacing: cameraFacing,
Expand Down
4 changes: 4 additions & 0 deletions lib/src/web/web_view_registry.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// ignore: avoid_web_libraries_in_flutter
import 'dart:ui_web' as ui_web;

final platformViewRegistry = ui_web.platformViewRegistry;