Skip to content

Commit

Permalink
Html non secure permissions (#1240)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
ekuleshov authored Dec 5, 2023
1 parent e3c92e3 commit 9907d20
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 74 deletions.
6 changes: 6 additions & 0 deletions permission_handler_html/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## 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

* Updates `permission_handler_platform_interface` dependency to version `^4.0.2`.
Expand Down
41 changes: 17 additions & 24 deletions permission_handler_html/example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,17 @@ void main() {
}

///Defines the main theme color
final MaterialColor themeMaterialColor =
BaseflowPluginExample.createMaterialColor(
const Color.fromRGBO(48, 49, 60, 1));
final MaterialColor themeMaterialColor = BaseflowPluginExample.createMaterialColor(const Color.fromRGBO(48, 49, 60, 1));

/// A Flutter application demonstrating the functionality of this plugin
class PermissionHandlerWidget extends StatefulWidget {
/// Create a page containing the functionality of this plugin
static ExamplePage createPage() {
return ExamplePage(
Icons.location_on, (context) => PermissionHandlerWidget());
return ExamplePage(Icons.location_on, (context) => PermissionHandlerWidget());
}

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

class _PermissionHandlerWidgetState extends State<PermissionHandlerWidget> {
Expand Down Expand Up @@ -64,8 +60,7 @@ class _PermissionState extends State<PermissionWidget> {
_PermissionState(this._permission);

final Permission _permission;
final PermissionHandlerPlatform _permissionHandler =
PermissionHandlerPlatform.instance;
final PermissionHandlerPlatform _permissionHandler = PermissionHandlerPlatform.instance;
PermissionStatus _permissionStatus = PermissionStatus.denied;

@override
Expand All @@ -76,8 +71,9 @@ class _PermissionState extends State<PermissionWidget> {
}

void _listenForPermissionStatus() async {
final status = await _permissionHandler.checkPermissionStatus(_permission);
setState(() => _permissionStatus = status);
await _permissionHandler
.checkPermissionStatus(_permission)
.then((status) => setState(() => _permissionStatus = status), onError: (error, st) => print('$error'));
}

Color getPermissionColor() {
Expand Down Expand Up @@ -111,8 +107,7 @@ class _PermissionState extends State<PermissionWidget> {
color: Colors.white,
),
onPressed: () {
checkServiceStatus(
context, _permission as PermissionWithService);
checkServiceStatus(context, _permission as PermissionWithService);
})
: null,
onTap: () {
Expand All @@ -121,21 +116,19 @@ class _PermissionState extends State<PermissionWidget> {
);
}

void checkServiceStatus(
BuildContext context, PermissionWithService permission) async {
void checkServiceStatus(BuildContext context, PermissionWithService permission) async {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text(
(await _permissionHandler.checkServiceStatus(permission)).toString()),
content: Text((await _permissionHandler.checkServiceStatus(permission)).toString()),
));
}

Future<void> requestPermission(Permission permission) async {
final status = await _permissionHandler.requestPermissions([permission]);

setState(() {
print(status);
_permissionStatus = status[permission] ?? PermissionStatus.denied;
print(_permissionStatus);
});
await _permissionHandler.requestPermissions([permission]).then(
(status) => setState(() {
print(status);
_permissionStatus = status[permission] ?? PermissionStatus.denied;
print(_permissionStatus);
}),
onError: (error, st) => print('$error'));
}
}
2 changes: 1 addition & 1 deletion permission_handler_html/lib/permission_handler_html.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import 'web_delegate.dart';

/// Platform implementation of the permission_handler Flutter plugin.
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 =
html.window.navigator.geolocation;
static final html.Permissions? _htmlPermissions =
Expand Down
77 changes: 29 additions & 48 deletions permission_handler_html/lib/web_delegate.dart
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ class WebDelegate {
static const _notificationsPermissionName = 'notifications';

/// 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.
static const _grantedPermissionStatus = 'granted';
Expand All @@ -57,18 +58,18 @@ class WebDelegate {
}
}

Future<PermissionStatus> _permissionStatusState(
String webPermissionName, html.Permissions? permissions) async {
final webPermissionStatus =
await permissions?.query({'name': webPermissionName});
Future<PermissionStatus> _permissionStatusState(String webPermissionName, html.Permissions? permissions) async {
final webPermissionStatus = await permissions?.query({'name': webPermissionName});
return _toPermissionStatus(webPermissionStatus?.state);
}

Future<bool> _requestMicrophonePermission(html.MediaDevices devices) async {
html.MediaStream? mediaStream;
Future<bool> _requestMicrophonePermission() async {
if (_devices == null) {
return false;
}

try {
mediaStream = await devices.getUserMedia({'audio': true});
html.MediaStream mediaStream = await _devices!.getUserMedia({'audio': true});

// In browsers, calling [getUserMedia] will start the recording
// automatically right after. This is undesired behavior as
Expand All @@ -77,7 +78,7 @@ class WebDelegate {
// The manual stop action is then needed here for to stop the automatic
// recording.

if (mediaStream.active!) {
if (mediaStream.active ?? false) {
final audioTracks = mediaStream.getAudioTracks();
if (audioTracks.isNotEmpty) {
audioTracks[0].stop();
Expand All @@ -90,11 +91,13 @@ class WebDelegate {
return true;
}

Future<bool> _requestCameraPermission(html.MediaDevices devices) async {
html.MediaStream? mediaStream;
Future<bool> _requestCameraPermission() async {
if (_devices == null) {
return false;
}

try {
mediaStream = await devices.getUserMedia({'video': true});
html.MediaStream mediaStream = await _devices!.getUserMedia({'video': true});

// In browsers, calling [getUserMedia] will start the recording
// automatically right after. This is undesired behavior as
Expand All @@ -103,7 +106,7 @@ class WebDelegate {
// The manual stop action is then needed here for to stop the automatic
// recording.

if (mediaStream.active!) {
if (mediaStream.active ?? false) {
final videoTracks = mediaStream.getVideoTracks();
if (videoTracks.isNotEmpty) {
videoTracks[0].stop();
Expand All @@ -117,45 +120,25 @@ class WebDelegate {
}

Future<bool> _requestNotificationPermission() async {
bool granted = false;
html.Notification.requestPermission().then((permission) => {
if (permission == "granted") {granted = true}
});

return granted;
return html.Notification.requestPermission().then((permission) => permission == "granted");
}

Future<bool> _requestLocationPermission(html.Geolocation geolocation) async {
Future<bool> _requestLocationPermission() async {
try {
await geolocation.getCurrentPosition();
return true;
return await _geolocation?.getCurrentPosition().then((value) => true) ?? false;
} on html.PositionError {
return false;
}
}

Future<PermissionStatus> _requestSingularPermission(
Permission permission) async {
bool permissionGranted = false;

switch (permission) {
case Permission.microphone:
permissionGranted = await _requestMicrophonePermission(_devices!);
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.',
);
}
Future<PermissionStatus> _requestSingularPermission(Permission permission) async {
bool permissionGranted = switch (permission) {
Permission.microphone => await _requestMicrophonePermission(),
Permission.camera => await _requestCameraPermission(),
Permission.notification => await _requestNotificationPermission(),
Permission.location => await _requestLocationPermission(),
_ => throw UnsupportedError('The ${permission.toString()} permission is currently not supported on web.')
};

if (!permissionGranted) {
return PermissionStatus.permanentlyDenied;
Expand All @@ -167,14 +150,12 @@ class WebDelegate {
/// they have not already been granted before.
///
/// Returns a [Map] containing the status per requested [Permission].
Future<Map<Permission, PermissionStatus>> requestPermissions(
List<Permission> permissions) async {
Future<Map<Permission, PermissionStatus>> requestPermissions(List<Permission> permissions) async {
final Map<Permission, PermissionStatus> permissionStatusMap = {};

for (final permission in permissions) {
try {
permissionStatusMap[permission] =
await _requestSingularPermission(permission);
permissionStatusMap[permission] = await _requestSingularPermission(permission);
} on UnimplementedError {
rethrow;
}
Expand Down
2 changes: 1 addition & 1 deletion permission_handler_html/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: permission_handler_html
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

environment:
Expand Down

0 comments on commit 9907d20

Please sign in to comment.