Commit 9907d20b by Eugene Kuleshov Committed by GitHub

Html non secure permissions (#1240)

* fixed plugin init with non-https web app

* fixed plugin init with non-https web app

* fixed handling of nullable values

* fixed _locationPermissionName

* better error handling

* PR feedback

* PR feedback
parent e3c92e38
## 0.1.1
* Fixed plugin initialization for non-https web app.
* Fixed location permission name
* Improved error handling in the example app
## 0.1.0+1 ## 0.1.0+1
* Updates `permission_handler_platform_interface` dependency to version `^4.0.2`. * Updates `permission_handler_platform_interface` dependency to version `^4.0.2`.
......
...@@ -11,21 +11,17 @@ void main() { ...@@ -11,21 +11,17 @@ void main() {
} }
///Defines the main theme color ///Defines the main theme color
final MaterialColor themeMaterialColor = final MaterialColor themeMaterialColor = BaseflowPluginExample.createMaterialColor(const Color.fromRGBO(48, 49, 60, 1));
BaseflowPluginExample.createMaterialColor(
const Color.fromRGBO(48, 49, 60, 1));
/// A Flutter application demonstrating the functionality of this plugin /// A Flutter application demonstrating the functionality of this plugin
class PermissionHandlerWidget extends StatefulWidget { class PermissionHandlerWidget extends StatefulWidget {
/// Create a page containing the functionality of this plugin /// Create a page containing the functionality of this plugin
static ExamplePage createPage() { static ExamplePage createPage() {
return ExamplePage( return ExamplePage(Icons.location_on, (context) => PermissionHandlerWidget());
Icons.location_on, (context) => PermissionHandlerWidget());
} }
@override @override
_PermissionHandlerWidgetState createState() => _PermissionHandlerWidgetState createState() => _PermissionHandlerWidgetState();
_PermissionHandlerWidgetState();
} }
class _PermissionHandlerWidgetState extends State<PermissionHandlerWidget> { class _PermissionHandlerWidgetState extends State<PermissionHandlerWidget> {
...@@ -64,8 +60,7 @@ class _PermissionState extends State<PermissionWidget> { ...@@ -64,8 +60,7 @@ class _PermissionState extends State<PermissionWidget> {
_PermissionState(this._permission); _PermissionState(this._permission);
final Permission _permission; final Permission _permission;
final PermissionHandlerPlatform _permissionHandler = final PermissionHandlerPlatform _permissionHandler = PermissionHandlerPlatform.instance;
PermissionHandlerPlatform.instance;
PermissionStatus _permissionStatus = PermissionStatus.denied; PermissionStatus _permissionStatus = PermissionStatus.denied;
@override @override
...@@ -76,8 +71,9 @@ class _PermissionState extends State<PermissionWidget> { ...@@ -76,8 +71,9 @@ class _PermissionState extends State<PermissionWidget> {
} }
void _listenForPermissionStatus() async { void _listenForPermissionStatus() async {
final status = await _permissionHandler.checkPermissionStatus(_permission); await _permissionHandler
setState(() => _permissionStatus = status); .checkPermissionStatus(_permission)
.then((status) => setState(() => _permissionStatus = status), onError: (error, st) => print('$error'));
} }
Color getPermissionColor() { Color getPermissionColor() {
...@@ -111,8 +107,7 @@ class _PermissionState extends State<PermissionWidget> { ...@@ -111,8 +107,7 @@ class _PermissionState extends State<PermissionWidget> {
color: Colors.white, color: Colors.white,
), ),
onPressed: () { onPressed: () {
checkServiceStatus( checkServiceStatus(context, _permission as PermissionWithService);
context, _permission as PermissionWithService);
}) })
: null, : null,
onTap: () { onTap: () {
...@@ -121,21 +116,19 @@ class _PermissionState extends State<PermissionWidget> { ...@@ -121,21 +116,19 @@ class _PermissionState extends State<PermissionWidget> {
); );
} }
void checkServiceStatus( void checkServiceStatus(BuildContext context, PermissionWithService permission) async {
BuildContext context, PermissionWithService permission) async {
ScaffoldMessenger.of(context).showSnackBar(SnackBar( ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text( content: Text((await _permissionHandler.checkServiceStatus(permission)).toString()),
(await _permissionHandler.checkServiceStatus(permission)).toString()),
)); ));
} }
Future<void> requestPermission(Permission permission) async { Future<void> requestPermission(Permission permission) async {
final status = await _permissionHandler.requestPermissions([permission]); await _permissionHandler.requestPermissions([permission]).then(
(status) => setState(() {
setState(() { print(status);
print(status); _permissionStatus = status[permission] ?? PermissionStatus.denied;
_permissionStatus = status[permission] ?? PermissionStatus.denied; print(_permissionStatus);
print(_permissionStatus); }),
}); onError: (error, st) => print('$error'));
} }
} }
...@@ -9,7 +9,7 @@ import 'web_delegate.dart'; ...@@ -9,7 +9,7 @@ import 'web_delegate.dart';
/// Platform implementation of the permission_handler Flutter plugin. /// Platform implementation of the permission_handler Flutter plugin.
class WebPermissionHandler extends PermissionHandlerPlatform { class WebPermissionHandler extends PermissionHandlerPlatform {
static final html.MediaDevices _devices = html.window.navigator.mediaDevices!; static final html.MediaDevices? _devices = html.window.navigator.mediaDevices;
static final html.Geolocation _geolocation = static final html.Geolocation _geolocation =
html.window.navigator.geolocation; html.window.navigator.geolocation;
static final html.Permissions? _htmlPermissions = static final html.Permissions? _htmlPermissions =
......
...@@ -34,7 +34,8 @@ class WebDelegate { ...@@ -34,7 +34,8 @@ class WebDelegate {
static const _notificationsPermissionName = 'notifications'; static const _notificationsPermissionName = 'notifications';
/// The permission name to request access to the user's location. /// The permission name to request access to the user's location.
static const _locationPermissionName = 'location'; /// https://developer.mozilla.org/en-US/docs/Web/API/Permissions/query#name
static const _locationPermissionName = 'geolocation';
/// The status indicates that permission has been granted by the user. /// The status indicates that permission has been granted by the user.
static const _grantedPermissionStatus = 'granted'; static const _grantedPermissionStatus = 'granted';
...@@ -57,18 +58,18 @@ class WebDelegate { ...@@ -57,18 +58,18 @@ class WebDelegate {
} }
} }
Future<PermissionStatus> _permissionStatusState( Future<PermissionStatus> _permissionStatusState(String webPermissionName, html.Permissions? permissions) async {
String webPermissionName, html.Permissions? permissions) async { final webPermissionStatus = await permissions?.query({'name': webPermissionName});
final webPermissionStatus =
await permissions?.query({'name': webPermissionName});
return _toPermissionStatus(webPermissionStatus?.state); return _toPermissionStatus(webPermissionStatus?.state);
} }
Future<bool> _requestMicrophonePermission(html.MediaDevices devices) async { Future<bool> _requestMicrophonePermission() async {
html.MediaStream? mediaStream; if (_devices == null) {
return false;
}
try { try {
mediaStream = await devices.getUserMedia({'audio': true}); html.MediaStream mediaStream = await _devices!.getUserMedia({'audio': true});
// In browsers, calling [getUserMedia] will start the recording // In browsers, calling [getUserMedia] will start the recording
// automatically right after. This is undesired behavior as // automatically right after. This is undesired behavior as
...@@ -77,7 +78,7 @@ class WebDelegate { ...@@ -77,7 +78,7 @@ class WebDelegate {
// The manual stop action is then needed here for to stop the automatic // The manual stop action is then needed here for to stop the automatic
// recording. // recording.
if (mediaStream.active!) { if (mediaStream.active ?? false) {
final audioTracks = mediaStream.getAudioTracks(); final audioTracks = mediaStream.getAudioTracks();
if (audioTracks.isNotEmpty) { if (audioTracks.isNotEmpty) {
audioTracks[0].stop(); audioTracks[0].stop();
...@@ -90,11 +91,13 @@ class WebDelegate { ...@@ -90,11 +91,13 @@ class WebDelegate {
return true; return true;
} }
Future<bool> _requestCameraPermission(html.MediaDevices devices) async { Future<bool> _requestCameraPermission() async {
html.MediaStream? mediaStream; if (_devices == null) {
return false;
}
try { try {
mediaStream = await devices.getUserMedia({'video': true}); html.MediaStream mediaStream = await _devices!.getUserMedia({'video': true});
// In browsers, calling [getUserMedia] will start the recording // In browsers, calling [getUserMedia] will start the recording
// automatically right after. This is undesired behavior as // automatically right after. This is undesired behavior as
...@@ -103,7 +106,7 @@ class WebDelegate { ...@@ -103,7 +106,7 @@ class WebDelegate {
// The manual stop action is then needed here for to stop the automatic // The manual stop action is then needed here for to stop the automatic
// recording. // recording.
if (mediaStream.active!) { if (mediaStream.active ?? false) {
final videoTracks = mediaStream.getVideoTracks(); final videoTracks = mediaStream.getVideoTracks();
if (videoTracks.isNotEmpty) { if (videoTracks.isNotEmpty) {
videoTracks[0].stop(); videoTracks[0].stop();
...@@ -117,45 +120,25 @@ class WebDelegate { ...@@ -117,45 +120,25 @@ class WebDelegate {
} }
Future<bool> _requestNotificationPermission() async { Future<bool> _requestNotificationPermission() async {
bool granted = false; return html.Notification.requestPermission().then((permission) => permission == "granted");
html.Notification.requestPermission().then((permission) => {
if (permission == "granted") {granted = true}
});
return granted;
} }
Future<bool> _requestLocationPermission(html.Geolocation geolocation) async { Future<bool> _requestLocationPermission() async {
try { try {
await geolocation.getCurrentPosition(); return await _geolocation?.getCurrentPosition().then((value) => true) ?? false;
return true;
} on html.PositionError { } on html.PositionError {
return false; return false;
} }
} }
Future<PermissionStatus> _requestSingularPermission( Future<PermissionStatus> _requestSingularPermission(Permission permission) async {
Permission permission) async { bool permissionGranted = switch (permission) {
bool permissionGranted = false; Permission.microphone => await _requestMicrophonePermission(),
Permission.camera => await _requestCameraPermission(),
switch (permission) { Permission.notification => await _requestNotificationPermission(),
case Permission.microphone: Permission.location => await _requestLocationPermission(),
permissionGranted = await _requestMicrophonePermission(_devices!); _ => throw UnsupportedError('The ${permission.toString()} permission is currently not supported on web.')
break; };
case Permission.camera:
permissionGranted = await _requestCameraPermission(_devices!);
break;
case Permission.notification:
permissionGranted = await _requestNotificationPermission();
break;
case Permission.location:
permissionGranted = await _requestLocationPermission(_geolocation!);
break;
default:
throw UnsupportedError(
'The ${permission.toString()} permission is currently not supported on web.',
);
}
if (!permissionGranted) { if (!permissionGranted) {
return PermissionStatus.permanentlyDenied; return PermissionStatus.permanentlyDenied;
...@@ -167,14 +150,12 @@ class WebDelegate { ...@@ -167,14 +150,12 @@ class WebDelegate {
/// they have not already been granted before. /// they have not already been granted before.
/// ///
/// Returns a [Map] containing the status per requested [Permission]. /// Returns a [Map] containing the status per requested [Permission].
Future<Map<Permission, PermissionStatus>> requestPermissions( Future<Map<Permission, PermissionStatus>> requestPermissions(List<Permission> permissions) async {
List<Permission> permissions) async {
final Map<Permission, PermissionStatus> permissionStatusMap = {}; final Map<Permission, PermissionStatus> permissionStatusMap = {};
for (final permission in permissions) { for (final permission in permissions) {
try { try {
permissionStatusMap[permission] = permissionStatusMap[permission] = await _requestSingularPermission(permission);
await _requestSingularPermission(permission);
} on UnimplementedError { } on UnimplementedError {
rethrow; rethrow;
} }
......
name: permission_handler_html name: permission_handler_html
description: Permission plugin for Flutter. This plugin provides the web API to request and check permissions. description: Permission plugin for Flutter. This plugin provides the web API to request and check permissions.
version: 0.1.0+1 version: 0.1.1
homepage: https://github.com/baseflow/flutter-permission-handler homepage: https://github.com/baseflow/flutter-permission-handler
environment: environment:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment