In the sample app LastKnownLocationExampleWidget deny the permission close and reopen the app I get the following exception and the app crashes.
E/AndroidRuntime(12916): Process: com.baseflow.geolocator_example, PID: 12916
E/AndroidRuntime(12916): java.lang.IllegalStateException: Reply already submitted
E/AndroidRuntime(12916): at io.flutter.embedding.engine.dart.DartMessenger$Reply.reply(DartMessenger.java:139)
E/AndroidRuntime(12916): at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler$1.success(MethodChannel.java:235)
E/AndroidRuntime(12916): at com.baseflow.geolocator.MethodCallHandlerImpl.lambda$onGetLastKnownPosition$2(MethodCallHandlerImpl.java:149)
E/AndroidRuntime(12916): at com.baseflow.geolocator.-$$Lambda$MethodCallHandlerImpl$tyxDngVVF7PcImb4PihgQ0FJ8po.onPositionChanged(Unknown Source:2)
E/AndroidRuntime(12916): at com.baseflow.geolocator.location.-$$Lambda$FyNSKWRJ6K8pfIKflyK9zilTOk0.onSuccess(Unknown Source:4)
E/AndroidRuntime(12916): at com.google.android.gms.tasks.zzn.run(Unknown Source:4)
E/AndroidRuntime(12916): at android.os.Handler.handleCallback(Handler.java:883)
E/AndroidRuntime(12916): at android.os.Handler.dispatchMessage(Handler.java:100)
E/AndroidRuntime(12916): at android.os.Looper.loop(Looper.java:214)
E/AndroidRuntime(12916): at android.app.ActivityThread.main(ActivityThread.java:7356)
E/AndroidRuntime(12916): at java.lang.reflect.Method.invoke(Native Method)
E/AndroidRuntime(12916): at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
E/AndroidRuntime(12916): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
Version: 6.0.0+3
Platform:
@humazed thanks for the bug report. I kinda know where the error is coming from (and I can make it go away), but I cannot really reproduce it and according to the stack traces you send me this error should not happen in the first place.
So I am wondering if you can help me figure out what is causing this issue so I can solve it in the correct manner. So to give you some details, here is what I think is happening (based on the stack trace information and the steps you describe):
Step 1:
So far all is good.
Step 2:
The crash happens because the App somehow enters the Java onRequestPermissionResult(int requestCode, String[] permissions, int[] grantResults) without having showed the permission popup and the permissions and grantResults arrays are empty. In my previous update (6.0.0+3) I detect that these parameters are empty and try to send back that permissions are denied (see code snippet below):
@Override
public boolean onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
if (requestCode != PERMISSION_REQUEST_CODE || permissions.length == 0 || grantResults.length == 0) {
if (this.resultCallback != null) {
this.resultCallback.onResult(LocationPermission.denied);
}
return false;
}
....
}
As you would guess sending back the permission status in this situation will trigger the exception you listed above, because information has already been send on the channel. This is strange because from the way I understand the steps you take this would be a fresh channel and really should be the first time information is send back on the channel.
What is also strange is that the onRequestPermissionResults is being called with empty permissions and grantResults parameters. I can prevent the exception from occurring by updating the code to:
@Override
public boolean onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
if (requestCode != PERMISSION_REQUEST_CODE) {
if (this.resultCallback != null) {
this.resultCallback.onResult(LocationPermission.denied);
}
return false;
}
if (permissions.length == 0 || grantResults.length == 0) {
return false;
}
....
}
But I am afraid this will mask the real problem that is occurring. Can you help me finding the real problem by checking the following:
Your help would be greatly appreciated.
Step 1:
run the app and deny permission.
Step 2:
Click the back button.
Step 3:
open the app and see the crash.
will send you a screen recording.
recording of the bug
https://drive.google.com/file/d/1dh2dIdiUWcOEysYX1Fh37kuCAc3-gTCl/view?usp=sharing
device:
pixel_2_XL_API_28 emulator
Hi,
I'm experiencing the same problem.
The steps to reproduce mine is simply: Allow location, then allow file and my apps crashed
Device:
Pixel_3a
D/AndroidRuntime(31159): Shutting down VM
E/AndroidRuntime(31159): FATAL EXCEPTION: main
E/AndroidRuntime(31159): Process: rest.clinimetric, PID: 31159
E/AndroidRuntime(31159): java.lang.RuntimeException: Failure delivering result ResultInfo{who=@android:requestPermissions:, request=35569, result=-1, data=Intent { act=android.content.pm.action.REQUEST_PERMISSIONS (has extras) }} to activity {rest.clinimetric/rest.clinimetric.MainActivity}: java.lang.IllegalStateException: Reply already submitted
E/AndroidRuntime(31159): at android.app.ActivityThread.deliverResults(ActivityThread.java:4845)
E/AndroidRuntime(31159): at android.app.ActivityThread.handleSendResult(ActivityThread.java:4886)
E/AndroidRuntime(31159): at android.app.servertransaction.ActivityResultItem.execute(ActivityResultItem.java:51)
E/AndroidRuntime(31159): at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
E/AndroidRuntime(31159): at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
E/AndroidRuntime(31159): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2016)
E/AndroidRuntime(31159): at android.os.Handler.dispatchMessage(Handler.java:107)
E/AndroidRuntime(31159): at android.os.Looper.loop(Looper.java:214)
E/AndroidRuntime(31159): at android.app.ActivityThread.main(ActivityThread.java:7356)
E/AndroidRuntime(31159): at java.lang.reflect.Method.invoke(Native Method)
E/AndroidRuntime(31159): at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
E/AndroidRuntime(31159): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
E/AndroidRuntime(31159): Caused by: java.lang.IllegalStateException: Reply already submitted
E/AndroidRuntime(31159): at io.flutter.embedding.engine.dart.DartMessenger$Reply.reply(DartMessenger.java:139)
E/AndroidRuntime(31159): at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler$1.success(MethodChannel.java:235)
E/AndroidRuntime(31159): at com.baseflow.geolocator.MethodCallHandlerImpl.lambda$onRequestPermission$0(MethodCallHandlerImpl.java:133)
E/AndroidRuntime(31159): at com.baseflow.geolocator.-$$Lambda$MethodCallHandlerImpl$HgwoSKdIeyav7j8ZZJufnb77Lqo.onResult(Unknown Source:2)
E/AndroidRuntime(31159): at com.baseflow.geolocator.permission.PermissionManager.onRequestPermissionsResult(PermissionManager.java:103)
E/AndroidRuntime(31159): at io.flutter.embedding.engine.FlutterEnginePluginRegistry$FlutterEngineActivityPluginBinding.onRequestPermissionsResult(FlutterEnginePluginRegistry.java:664)
E/AndroidRuntime(31159): at io.flutter.embedding.engine.FlutterEnginePluginRegistry.onRequestPermissionsResult(FlutterEnginePluginRegistry.java:364)
E/AndroidRuntime(31159): at io.flutter.embedding.android.FlutterActivityAndFragmentDelegate.onRequestPermissionsResult(FlutterActivityAndFragmentDelegate.java:573)
E/AndroidRuntime(31159): at io.flutter.embedding.android.FlutterActivity.onRequestPermissionsResult(FlutterActivity.java:602)
E/AndroidRuntime(31159): at android.app.Activity.dispatchRequestPermissionsResult(Activity.java:8289)
E/AndroidRuntime(31159): at android.app.Activity.dispatchActivityResult(Activity.java:8139)
E/AndroidRuntime(31159): at android.app.ActivityThread.deliverResults(ActivityThread.java:4838)
E/AndroidRuntime(31159): ... 11 more
I/Process (31159): Sending signal. PID: 31159 SIG: 9
Lost connection to device.
Hi @humazed, thank you for providing the reproduction steps, I think I have figured out the real problem that is occurring. I believe the error is happening because the permissions are requested multiple times while the first call is still being handled, which triggers a warning on the Android activity "W/Activity(24060): Can request only one set of permissions at a time", and results in the onRequestPermissionsResult being called with the empty permissions and grantResults parameters. This can for example happen when we directly call the getLastKnownPosition from the Flutter build method which can be triggered multiple times. Or as an example, I can reproduce the problem consistently using the following example code:
import 'package:flutter/material.dart';
import 'package:geolocator/geolocator.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: MyHomePage(title: 'Geolocator #396'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState
extends State<MyHomePage>
with WidgetsBindingObserver {
@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
}
@override
void didChangeDependencies() {
getCurrentPosition(forceAndroidLocationManager: true).then((position) => print('Start: $position'));
super.didChangeDependencies();
}
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
print(state);
getCurrentPosition(forceAndroidLocationManager: true).then((position) => print('Resume: $position'));
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),// This trailing comma makes auto-formatting nicer for build methods.
);
}
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
}
The problem is that this only happens when you need to request for permissions. Remember that the getLastKnownPosition, getCurrentPosition and getPositionStream methods will automatically request permissions when applicable. The dilemma is that once you have already requested permission it is just fine to call the getLastKnownPosition (or one of the other position methods) multiple times. So I can handle this in three ways:
onRequestPermissionResults which ignores the call when the permissions and grantResults parameters are empty;getLastKnownPosition, getCurrentPosition and getPositionStream methods once if their is already an existing request running;getLastKnownPosition, getCurrentPosition and getPositionStream methods and leave it up to the developers to handle permissions.At the moment I am feeling the most for the first solution, since the others will have other disadvantages or are really introducing huge breaking changes. I will implement the first solution now to make sure we have a workable solution. But I am interested in how you would feel about the different options?
Hi @humazed, @NindoK, I have just released version 6.0.0+4 of the geolocator plugin which should solve this issue using the 1st option I described in the comment above.
Thanks to the information from @humazed I was able to reproduce the problem and confirm that this change should fix the issue. You might however still see the warning "W/Activity(24060): Can request only one set of permissions at a time" which you can ignore.
Let me know if this will solve the issue for you, in the meantime I will keep this issue open.
Thanks it fixed it!
Hi @NindoK, thank you for testing and confirming the problem is fixed. Will close the issue now.
I can also confirm it is fixed thank you
On Tue, Sep 8, 2020 at 7:49 PM Maurits van Beusekom <
[email protected]> wrote:
Closed #513 https://github.com/Baseflow/flutter-geolocator/issues/513.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/Baseflow/flutter-geolocator/issues/513#event-3742130966,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/ACDNYJVA5E6SXFCN6LAIUITSEZVBHANCNFSM4QZMGFKQ
.
I am still experiencing this crash in 6.0.0+4, as the package clashes with a different permission handler's request. This makes sense according to the explanation here. Do you think it'd be possible to add a manual option to disable the automatic permission resolution of the methods?
Thank you!
Hi @xJon, could you maybe provide a stack trace or some logging that shows the problem that is occurring? Can you maybe provide some information on the other plugin you are using that you mentioned is clashing with the geolocator?
We have seen similar issues with other plugins that don't handle the Android onRequestPermissionResult call back correctly, I am thinking this might be the problem here but I would like to investigate and see if I can help out.
Hi @mvanbeusekom, yes this is my log:
java.lang.RuntimeException: Failure delivering result ResultInfo{who=@android:requestPermissions:, request=109, result=-1, data=Intent { act=android.content.pm.action.REQUEST_PERMISSIONS (has extras) }} to activity {com.gather/com.gather.MainActivity}: java.lang.IllegalStateException: Reply already submitted
at android.app.ActivityThread.deliverResults(ActivityThread.java:3699)
at android.app.ActivityThread.handleSendResult(ActivityThread.java:3742)
at android.app.ActivityThread.-wrap16(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1393)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
Caused by: java.lang.IllegalStateException: Reply already submitted
at io.flutter.embedding.engine.dart.DartMessenger$Reply.reply(DartMessenger.java:139)
at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler$1.error(MethodChannel.java:240)
at com.baseflow.geolocator.MethodCallHandlerImpl.lambda$onGetLastKnownPosition$3(MethodCallHandlerImpl.java:150)
at com.baseflow.geolocator.-$$Lambda$MethodCallHandlerImpl$OCefduhIkqAV59oMDlIQqmk7z8g.onError(lambda)
at com.baseflow.geolocator.location.GeolocationManager.lambda$handlePermissions$2(GeolocationManager.java:128)
at com.baseflow.geolocator.location.-$$Lambda$GeolocationManager$boCQNh-1HzLRO8yyNdeq6cg70Yc.onResult(lambda)
at com.baseflow.geolocator.permission.PermissionManager.onRequestPermissionsResult(PermissionManager.java:161)
at io.flutter.embedding.engine.FlutterEnginePluginRegistry$FlutterEngineActivityPluginBinding.onRequestPermissionsResult(FlutterEnginePluginRegistry.java:664)
at io.flutter.embedding.engine.FlutterEnginePluginRegistry.onRequestPermissionsResult(FlutterEnginePluginRegistry.java:364)
at io.flutter.embedding.android.FlutterActivityAndFragmentDelegate.onRequestPermissionsResult(FlutterActivityAndFragmentDelegate.java:573)
at io.flutter.embedding.android.FlutterActivity.onRequestPermissionsResult(FlutterActivity.java:602)
at android.app.Activity.dispatchRequestPermissionsResult(Activity.java:6553)
at android.app.Activity.dispatchActivityResult(Activity.java:6432)
at android.app.ActivityThread.deliverResults(ActivityThread.java:3695)
at android.app.ActivityThread.handleSendResult(ActivityThread.java:3742)
at android.app.ActivityThread.-wrap16(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1393)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
I made sure I am using the latest version of the package.
The other package I am using is permission_handler.
It is odd though, as I am unable to reproduce this issue continuously; I re-added now the code which seemed to cause the issue, and I don't experience the crash.
I would also like to point out that having a feature to disable the automatic permission resolution would be useful for apps which prefer to request certain permissions when first loading / on the splash screen, or when calling getCurrentPosition() and then getLastKnownPosition() (which would otherwise send 2 separate permission requests).
There should be no need to disable the automatic permission resolution since the geolocator will first check if permissions have been granted / disabled before taking any action and request permission. Meaning if you already took care of handling permissions the geolocator would simply skip the permission resolution.
Could it be that you were running an older version of the geolocator plugin and re-adding the code made sure you updated to the latest version of the geolocator? Maybe you ran the flutter pub upgrade in between?
I could've swore I ran flutter pub upgrade beforehand too, but maybe I didn't. I will update you if the issue arises again.
I don't fully understand what you mean with the automatic permission resolution, as currently if the user denies my first request when the app launches (using the permission_handler package), they will receive another request when getCurrentPosition() runs and another one when getLastKnownPosition() runs (assuming they deny all of them).
@xJon What he means is that if a user has "always allowed" permissions or "denied (dont ask me again)" permission, the plugin will not make a request to Android to display the permissions dialog.
The reason you user gets a request is probably because they allowed or denied their permission temporarily (or "just this once").
@ianendboss I see. Thank you for the explanation!