Baseflow / flutter-permission-handler

Permission plugin for Flutter. This plugin provides a cross-platform (iOS, Android) API to request and check permissions.
https://baseflow.com
MIT License
2.05k stars 858 forks source link

[Question]:I'm facing Permission.PermentlyDenied issue even after requesting or manually giving the permission to app i'm not able to access files in external storage in android 13 whereas I don't face thise issue in android 11 or below #1304

Closed Harshu2032000 closed 7 months ago

Harshu2032000 commented 7 months ago

Please check the following before submitting a new issue.

Please select for which platform(s) you need help

Your question

// //this is the audio upload page, where an audio can be uploaded and played so far import 'dart:async'; import 'dart:io'; import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:file_picker/file_picker.dart'; import 'package:audioplayers/audioplayers.dart'; import 'package:permission_handler/permission_handler.dart'; import 'package:http/http.dart' as http; import 'dart:typed_data'; import 'package:flutter/services.dart';

import 'package:http/io_client.dart';

//this page is dedicated to upload an audio file and class AudioPlayerPage extends StatefulWidget { const AudioPlayerPage({Key? key}) : super(key: key);

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

class _AudioPlayerPageState extends State { AudioPlayer audioPlayer = AudioPlayer(); File? audioFile; double currentPosition = 0.0; double totalDuration = 0.0; Timer? timer; bool isPlaying = false; bool _isUploading = false; Map<String, dynamic>? _responseBody; String? _res, data; String? _errorMessage;

// Audioplayer is initialized @override void initState() { super.initState(); audioPlayer.onDurationChanged.listen((Duration duration) { setState(() { totalDuration = duration.inMilliseconds.toDouble(); }); }); //the timer for the player that counts according to the time played timer = Timer.periodic(const Duration(milliseconds: 500), (timer) { if (isPlaying) { audioPlayer.getCurrentPosition().then((Duration position) { setState(() { currentPosition = position.inMilliseconds.toDouble(); }); } as FutureOr Function(Duration? value)); } }); //the function to play and pause the audio audioPlayer.onPlayerStateChanged.listen((PlayerState state) { setState(() { isPlaying = state == PlayerState.playing; }); }); }

// Future pickAudio() async { // try { // FilePickerResult? result = await FilePicker.platform.pickFiles( // type: FileType.audio, // allowMultiple: false, // ); // // if (result != null && mounted) { // setState(() { // audioFile = File(result.files.single.path!); // currentPosition = 0.0; // totalDuration = 0.0; // }); // } // }catch (e) { // print('Error picking audio: $e'); // } // } // Function to request storage permission Future requestStoragePermission() async { PermissionStatus status = await Permission.storage.request();

if (!status.isGranted) {
  // print(status)
  // Permission denied, handle accordingly
  handlePermissionDenied();
}

}

Future pickAudio() async { try { // Request permission to access storage PermissionStatus status = await Permission.storage.status; // await requestStoragePermission(); print(status); await requestStoragePermission();

  if (status.isGranted) {
    // Permission granted, proceed with picking audio
    FilePickerResult? result = await FilePicker.platform.pickFiles(
      type: FileType.audio,
      allowMultiple: false,
    );

    if (result != null && mounted) {
      setState(() {
        audioFile = File(result.files.single.path!);
        currentPosition = 0.0;
        totalDuration = 0.0;
      });
    }
  } else if (status.isDenied) {
    // Permission denied, handle accordingly
    PermissionStatus status = await Permission.storage.request();
    // handlePermissionDenied();
  } else if (status.isPermanentlyDenied) {
    // Permission permanently denied, navigate the user to app settings to manually grant permission
    openAppSettings();
  }
} catch (e) {
  print('Error picking audio: $e');
}

}

//calling the audio function to play void playAudio() { if (audioFile != null) { audioPlayer.play(UrlSource(audioFile!.path)); } }

// calling the audio function to pause void pauseAudio() { audioPlayer.pause(); }

// disposing the audioplayer as soon as the page is exited @override void dispose() { audioPlayer.dispose(); timer?.cancel(); super.dispose(); }

String formatDuration(Duration duration) { String minutes = duration.inMinutes.remainder(60).toString().padLeft(2, '0'); String seconds = duration.inSeconds.remainder(60).toString().padLeft(2, '0'); return "$minutes:$seconds"; }

Future getGlobalContext() async { final sslCert = await rootBundle.load('assets/cert.pem'); final caCert = await rootBundle.load('assets/ca_certificate_bundle.pem'); final key = await rootBundle.load('assets/key.pem');

SecurityContext securityContext = SecurityContext(withTrustedRoots: true);
securityContext.setTrustedCertificatesBytes(caCert.buffer.asUint8List());
securityContext.useCertificateChainBytes(sslCert.buffer.asUint8List());
securityContext.usePrivateKeyBytes(key.buffer.asUint8List());

return securityContext;

}

Future getSSLPinningClient() async { HttpClient client = HttpClient(context: await getGlobalContext()); client.badCertificateCallback = (X509Certificate cert, String host, int port) => true; IOClient ioClient = IOClient(client); return ioClient; }

Future _uploadAudio() async { setState(() { _isUploading = true; });

try {
  final client = await getSSLPinningClient();
  String base64Audio = base64Encode(await audioFile!.readAsBytes());
  String fileName = audioFile!.path.split('/').last;

  final response = await client.post(
    Uri.parse('http://10.244.3.46:8001/api/process_media/'),
    headers: {'Content-Type': 'application/json'},
    body: jsonEncode({'media_file': base64Audio, 'unique_reference': fileName}),
  );

  if (response.statusCode == 200) {
    setState(() {
      _responseBody = json.decode(response.body);
      _isUploading = false;
      _res = 'Audio uploaded successfully';
    });
    print('Audio uploaded successfully');
  } else {
    setState(() {
      _isUploading = false;
      _res = 'Failed to upload audio: ${response.statusCode}';
    });
    print('Failed to upload audio: ${response.statusCode}');
  }
} catch (error) {
  setState(() {
    _errorMessage = error.toString();
    _isUploading = false;
  });
  print('Error uploading audio: $error');
}

}

void handlePermissionDenied() { // Handle permission denied scenario // Inform the user and provide guidance on how to grant the permission manually showDialog( context: context, builder: (BuildContext context) { return AlertDialog( title: Text("Permission Denied"), content: Text( "You have denied permission to access the audio file. Please grant the permission manually to proceed."), actions: [ TextButton( child: Text("OK"), onPressed: () { Navigator.of(context).pop(); }, ), ], ); }, ); } this is the code where i'm using flutter-permission-handler and below are the logs for android 13 and android 11 respectively Android 13: W/libc (15162): Access denied finding property "persist.unipnp.debug" W/xample.dfimages(15162): type=1400 audit(0.0:4165): avc: denied { read } for name="u:object_r:unipnp_prop:s0" dev="tmpfs" ino=17842 scontext=u:r:untrusted_app:s0:c234,c256,c512,c768 tcontext=u:object_r:unipnp_prop:s0 tclass=file permissive=0 app=com.example.dfimages W/libc (15162): Access denied finding property "persist.unipnp.debug" W/xample.dfimages(15162): type=1400 audit(0.0:4166): avc: denied { read } for name="u:object_r:unipnp_prop:s0" dev="tmpfs" ino=17842 scontext=u:r:untrusted_app:s0:c234,c256,c512,c768 tcontext=u:object_r:unipnp_prop:s0 tclass=file permissive=0 app=com.example.dfimages W/ziparchive(15162): Unable to open '/system_ext/framework/unipnp-framework.dm': No such file or directory W/ziparchive(15162): Unable to open '/system_ext/framework/unipnp-framework.dm': No such file or directory I/mali_gralloc(15162): register: id=0x29a00000a65, importpid=-1 D/ProfileInstaller(15162): Installing profile for com.example.dfimages I/mali_gralloc(15162): register: id=0x29a00000a66, importpid=-1 I/flutter (15162): PermissionStatus.denied D/CompatibilityChangeReporter(15162): Compat change id reported: 78294732; UID 10234; state: ENABLED D/VRIMainActivity: performTraversals relayoutWindow: maybeSyncSeqId=-1 ,mSyncSeqId=0 ,relayoutResult=0 D/VRIMainActivity: performTraversals relayoutWindow: maybeSyncSeqId=-1 ,mSyncSeqId=0 ,relayoutResult=0 I/mali_gralloc(15162): register: id=0x29a00000a68, importpid=-1

Android 11:

D/ProfileInstaller( 4744): Installing profile for com.example.dfimages I/gralloc4( 4744): register: id=26900008679 E/libc ( 4744): Access denied finding property "persist.vendor.sf.fbc" E/libc ( 4744): Access denied finding property "persist.vendor.gpu.fbc" E/libc ( 4744): Access denied finding property "persist.vendor.vsp.fbc" I/gralloc4( 4744): register: id=2690000867a I/gralloc4( 4744): register: id=2690000867b I/gralloc4( 4744): register: id=2690000867c I/ActivityThread( 4744): smart_link is not supported!!! I/flutter ( 4744): PermissionStatus.granted D/FilePickerDelegate( 4744): Selected type audio/* E/OpenGLRenderer( 4744): reset ##### pid = 4862 I/gralloc4( 4744): register: id=26900008680 I/gralloc4( 4744): unregister: id=2690000867a I/gralloc4( 4744): unregister: id=26900008679 I/gralloc4( 4744): unregister: id=2690000867c W/libEGL ( 4744): EGLNativeWindowType 0xb400006f3d05dbe0 disconnect failed I/gralloc4( 4744): unregister: id=2690000867b I/gralloc4( 4744): unregister: id=26900008680 W/libEGL ( 4744): EGLNativeWindowType 0xb400006f3d0575b0 disconnect failed

Version

flutter -- 2.19 permission_handler: ^10.4.5

mvanbeusekom commented 7 months ago

Hi @Harshu2032000,

Please have a look at our FAQ in the README, specifically the "Requesting "storage" permissions always returns "denied" on Android 13+. What can I do?" question.

This explains that the Permission.storage permission has been deprecated by Google since Android 13.+. Additional information can also be find in this comment.