I created a web video chat app that needs permission to access the Camera, Microphone and Location before making a call. The app works fine in browsers like Chrome and Firefox. The issue is that I'm trying to integrate this web app into an Android app using Android WebView. Even after granting permissions for the Camera, Microphone and Location in the WebView, I'm getting an 'Access Denied' error when opening the web app. I've tried updating the AndroidManifest.xml file and using the permission_handler package, but the error persists. I'm new to Flutter and would appreciate any help in solving this issue.
Code Language: Flutter
pubspec.yaml webview_flutter: ^4.10.0 webview_flutter_android: ^4.0.1 webview_flutter_wkwebview: ^3.16.1 webview_flutter_web: ^0.2.3+3 permission_handler: ^11.3.1
Here is what I tried so far
AndroidManifest.xml
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-feature android:name="android.hardware.location.gps" />
<uses-feature android:name="android.hardware.location" />
<uses-feature
android:name="android.hardware.camera"
android:required="true" />
<activity>
...
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<intent-filter android:label="Deep Link">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:host="profile" android:scheme="scan" />
</intent-filter>
<intent-filter android:label="App Links">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:host="profile" android:scheme="https" />
</intent-filter>
</activity>
<activity android:name="io.flutter.embedding.android.FlutterActivity">
<meta-data android:name="android.webkit.WebView.EnableSafeBrowsing" android:value="true" />
</activity>
WebView.dart
import 'package:flutter/material.dart';
import 'package:vc/utils/app_state.dart';
import 'package:webview_flutter/webview_flutter.dart';
import 'package:vc/utils/WebViewController.dart';
class WebViewPage extends StatefulWidget {
final String url;
const WebViewPage({Key? key, required this.url}) : super(key: key);
@override
State<WebViewPage> createState() => _WebViewPageState();
}
class _WebViewPageState extends State<WebViewPage> {
late WebViewController _controller;
final String redirectUrl = "vc://thankyou";
@override
void initState() {
super.initState();
_initializeWebView();
}
Future<void> _initializeWebView() async {
try {
final controller = await CustomWebViewController.createController(
url: widget.url,
redirectUrl: redirectUrl,
onRedirect: _handleRedirection,
);
setState(() {
_controller = controller;
});
} catch (e) {
debugPrint('Error initializing WebViewController: $e');
}
}
void _handleRedirection(String url) {
debugPrint("Redirecting to: $url");
final uniqueID = AppState().uniqueID ?? '';
Navigator.pop(context);
if (uniqueID.isNotEmpty) {
Navigator.pushNamed(context, '/thankyou', arguments: uniqueID);
} else {
Navigator.pushNamed(context, '/thankyou');
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("CallPage"),
),
body: _controller == null
? const Center(child: CircularProgressIndicator())
: WebViewWidget(controller: _controller),
);
}
}
WebViewController.dart
import 'package:permission_handler/permission_handler.dart';
import 'package:webview_flutter/webview_flutter.dart';
class CustomWebViewController {
static Future<WebViewController> createController({
required String url,
required String redirectUrl,
required Function(String) onRedirect,
}) async {
await _requestCameraPermission();
final controller = WebViewController();
await controller.setJavaScriptMode(JavaScriptMode.unrestricted);
await controller.setNavigationDelegate(
NavigationDelegate(
onPageStarted: (String currentUrl) {
if (currentUrl.startsWith(redirectUrl)) {
onRedirect(currentUrl);
}
},
),
);
await controller.loadRequest(Uri.parse(url));
return controller;
}
static Future<void> _requestCameraPermission() async {
final status = await Permission.camera.request();
if (status.isGranted) {
print('Camera permission granted');
} else if (status.isPermanentlyDenied) {
print('Camera permission permanently denied');
await openAppSettings();
} else {
print('Camera permission denied');
}
}
}