Issue
Permission_handler.dart
import 'package:flutter/material.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:status_saver/utils/splash_screen.dart';
class PermissionHandler extends StatefulWidget {
const PermissionHandler({ Key? key }) : super(key: key);
@override
_PermissionHandlerState createState() => _PermissionHandlerState();
}
class _PermissionHandlerState extends State<PermissionHandler> {
Future<Widget> permissionCheck() async {
var permissionStatus = await Permission.storage.status;
if (!permissionStatus.isGranted){
await Permission.storage.request();
}
permissionStatus = await Permission.storage.status;
if(permissionStatus.isGranted) return SplashScreen();
else {
return AlertDialog(
title: Text('Permission Required'), // To display the title it is optional
content: Text('Cannot proceed without permission'), // Message which will be pop up on the screen
// Action widget which will provide the user to acknowledge the choice
actions: [
TextButton( // FlatButton widget is used to make a text to work like a button
child: Text('Open App Settings'),
onPressed: () => openAppSettings(),
// function used to perform after pressing the button
),
],
);
}
}
@override
Widget build(BuildContext context) {
return FutureBuilder(
builder: (ctx, snapshot) {
// Checking if future is resolved or not
if (snapshot.connectionState == ConnectionState.done) {
// If we got an error
if (snapshot.hasError) {
return Center(
child: Text(
'${snapshot.error} occured',
style: TextStyle(fontSize: 18),
),
);
// if we got our data
} else {
return snapshot.data as Widget;
}
}
// Displaying LoadingSpinner to indicate waiting state
return Center(
child: CircularProgressIndicator(),
);
},
// Future that needs to be resolved
// inorder to display something on the Canvas
future: permissionCheck(),
);
}
}
Main.dart
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:status_saver/services/permission_handler.dart';
import 'package:status_saver/utils/router.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return GetMaterialApp(
title: 'Hello World',
debugShowCheckedModeBanner: false,
onGenerateRoute: AppRouter.generateRoute,
theme: ThemeData(
// This is the theme of your application.
//
// Try running your application with "flutter run". You'll see the
// application has a blue toolbar. Then, without quitting the app, try
// changing the primarySwatch below to Colors.green and then invoke
// "hot reload" (press "r" in the console where you ran "flutter run",
// or simply save your changes to "hot reload" in a Flutter IDE).
// Notice that the counter didn't reset back to zero; the application
// is not restarted.
primarySwatch: Colors.blue,
),
home: PermissionHandler(),
);
}
}
scenario
At the start of the app i want to ask for storage permission What i did - create class
PermissionHandler
and assign it tohome
attributePermissionHandler() - stateful widget, shall trigger splashscreen after finishing its business logic
expected behaviour
- Ask user permission until user grants it
- if user grants permission. directly trigger splash screen instead of permission handler screen ( adds black screen and then splash screen currently as permission check code is ran everytime app starts)
*if user clicks on
dont ask again
take user to app settings and check again if permission is granted or not
current behaviour
- ask for permission at start of the app for single time, if accepted it loads splash screen else a new dialogue is popped up which takes user to appsettings
- after giving permission from appsettings when user comesback to app code is unable to check permission is granted or not and nothing happens further (problem)
- if i ask for permssion until user grants it using while loop. if user denies permission by clicking on
dont ask agin
checkbox, while loop will keep requesting for permission but dialogue will not present (current behaviour of permission_handler) which leads to infite loop and nothing will happen further - after permission is granted. if user comes back to app Future builder still execute following code and then triggers splashscreen instead directly triggering splash screen. (Bad UI experience)
return Center(
child: CircularProgressIndicator(),
);
Problem 1
[ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled Exception: PlatformException(PermissionHandler.PermissionManager, A request for permissions is
already running, please wait for it to finish before doing another request (note that you can request multiple permissions at the same time)., null, null)
[ ] E/flutter ( 787): #0 StandardMethodCodec.decodeEnvelope (package:flutter/src/services/message_codecs.dart:607:7)
[ ] E/flutter ( 787): #1 MethodChannel._invokeMethod (package:flutter/src/services/platform_channel.dart:156:18)
[ ] E/flutter ( 787): <asynchronous suspension>
[ ] E/flutter ( 787): #2 MethodChannelPermissionHandler.requestPermissions
(package:permission_handler_platform_interface/src/method_channel/method_channel_permission_handler.dart:71:9)
[ ] E/flutter ( 787): <asynchronous suspension>
[ ] E/flutter ( 787): #3 _PermissionHandlerScreenState.permissionServices (package:status_saver/services/permission_handler.dart:38:50)
[ ] E/flutter ( 787): <asynchronous suspension>
[ ] E/flutter ( 787): #4 _PermissionHandlerScreenState.permissionServiceCall (package:status_saver/services/permission_handler.dart:19:5)
[ ] E/flutter ( 787): <asynchronous suspension>
[ ] E/flutter ( 787):
error is thrown when I press deny button
problem 2
after giving permissions from app settings
error is thrown: no permissions defined in the manifest for: []
manifest files have storage permissions defined,(I removed code for camera , and microphone for easy testing so not a problem about them)
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
Solution
Please refer to below example code
Solution 1: Users are restricted to navigating to any other routes/screens without allowing all the permissions mentioned
class MyApp extends StatelessWidget {
MyApp({Key key}) : super(key: key);
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primaryColor: Color(0xfff00B074),
textTheme: const TextTheme(
bodyText1: TextStyle(
fontSize: 18.0,
fontFamily: 'Barlow-Medium',
color: Color(0xff464255)),
),
),
home: PermissionHandlerScreen(),
);
}
}
class PermissionHandlerScreen extends StatefulWidget {
@override
_PermissionHandlerScreenState createState() =>
_PermissionHandlerScreenState();
}
class _PermissionHandlerScreenState extends State<PermissionHandlerScreen> {
@override
void initState() {
super.initState();
permissionServiceCall();
}
permissionServiceCall() async {
await permissionServices().then(
(value) {
if (value != null) {
if (value[Permission.storage].isGranted &&
value[Permission.camera].isGranted &&
value[Permission.microphone].isGranted) {
/* ========= New Screen Added ============= */
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (context) => SplashScreen()),
);
}
}
},
);
}
/*Permission services*/
Future<Map<Permission, PermissionStatus>> permissionServices() async {
// You can request multiple permissions at once.
Map<Permission, PermissionStatus> statuses = await [
Permission.storage,
Permission.camera,
Permission.microphone,
//add more permission to request here.
].request();
if (statuses[Permission.storage].isPermanentlyDenied) {
await openAppSettings().then(
(value) async {
if (value) {
if (await Permission.storage.status.isPermanentlyDenied == true &&
await Permission.storage.status.isGranted == false) {
openAppSettings();
// permissionServiceCall(); /* opens app settings until permission is granted */
}
}
},
);
} else {
if (statuses[Permission.storage].isDenied) {
permissionServiceCall();
}
}
if (statuses[Permission.microphone].isPermanentlyDenied) {
await openAppSettings().then(
(value) async {
if (value) {
if (await Permission.microphone.status.isPermanentlyDenied == true &&
await Permission.microphone.status.isGranted == false) {
openAppSettings();
// permissionServiceCall(); /* opens app settings until permission is granted */
}
}
},
);
} else {
if (statuses[Permission.microphone].isDenied) {
permissionServiceCall();
}
}
if (statuses[Permission.camera].isPermanentlyDenied) {
await openAppSettings().then(
(value) async {
if (value) {
if (await Permission.camera.status.isPermanentlyDenied == true &&
await Permission.camera.status.isGranted == false) {
openAppSettings();
// permissionServiceCall(); /* opens app settings until permission is granted */
}
}
},
);
//openAppSettings();
//setState(() {});
} else {
if (statuses[Permission.camera].isDenied) {
permissionServiceCall();
}
}
/*{Permission.camera: PermissionStatus.granted, Permission.storage: PermissionStatus.granted}*/
return statuses;
}
@override
Widget build(BuildContext context) {
permissionServiceCall();
return WillPopScope(
onWillPop: () {
SystemNavigator.pop();
},
child: Scaffold(
body: Container(
child: Center(
child: InkWell(
onTap: () {
permissionServiceCall();
},
child: Text("Click here to enable Enable Permission Screen")),
),
),
),
);
}
}
class SplashScreen extends StatelessWidget {
const SplashScreen({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () {
SystemNavigator.pop();
},
child: Scaffold(
body: Center(
child: Text(
"Splash Screen",
),
),
),
);
}
}
Solution 2:
class MyApp extends StatelessWidget {
MyApp({Key key}) : super(key: key);
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primaryColor: Color(0xfff00B074),
textTheme: const TextTheme(
bodyText1: TextStyle(
fontSize: 18.0,
fontFamily: 'Barlow-Medium',
color: Color(0xff464255)),
),
),
home: PermissionHandlerScreen(),
);
}
}
class PermissionHandlerScreen extends StatefulWidget {
@override
_PermissionHandlerScreenState createState() =>
_PermissionHandlerScreenState();
}
class _PermissionHandlerScreenState extends State<PermissionHandlerScreen> {
@override
void initState() {
super.initState();
permissionServiceCall();
}
permissionServiceCall() async {
await permissionServices().then(
(value) {
if (value != null) {
if (value[Permission.storage].isGranted &&
value[Permission.camera].isGranted &&
value[Permission.microphone].isGranted) {
/* ========= New Screen Added ============= */
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (context) => SplashScreen()),
);
}
}
},
);
}
/*Permission services*/
Future<Map<Permission, PermissionStatus>> permissionServices() async {
// You can request multiple permissions at once.
Map<Permission, PermissionStatus> statuses = await [
Permission.storage,
Permission.camera,
Permission.microphone,
//add more permission to request here.
].request();
if (statuses[Permission.storage].isPermanentlyDenied) {
openAppSettings();
//setState(() {});
} else {
if (statuses[Permission.storage].isDenied) {
permissionServiceCall();
}
}
if (statuses[Permission.microphone].isPermanentlyDenied) {
openAppSettings();
// setState(() {});
} else {
if (statuses[Permission.microphone].isDenied) {
permissionServiceCall();
}
}
if (statuses[Permission.camera].isPermanentlyDenied) {
openAppSettings();
// setState(() {});
} else {
if (statuses[Permission.camera].isDenied) {
permissionServiceCall();
}
}
/*{Permission.camera: PermissionStatus.granted, Permission.storage: PermissionStatus.granted}*/
return statuses;
}
@override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () {
SystemNavigator.pop();
},
child: Scaffold(
body: Container(
child: Center(
child: InkWell(
onTap: () {
permissionServiceCall();
},
child: Text("Click here to enable Enable Permissions")),
),
),
),
);
}
}
class SplashScreen extends StatelessWidget {
const SplashScreen({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () {
SystemNavigator.pop();
},
child: Scaffold(
body: Center(
child: Text(
"Splash Screen",
),
),
),
);
}
}
Answered By - Tejaswini Dev
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.