flutter_tts icon indicating copy to clipboard operation
flutter_tts copied to clipboard

App crashes at `com.tundralabs.fluttertts.FlutterTtsPlugin$4.onInit(FlutterTtsPlugin.java:110)`

Open dev-yakuza opened this issue 2 years ago • 14 comments

🐛 Bug Report

First, thanks for making the awesome open-source library. 🙇‍♂️

I developed an app with flutter_tts and deployed it recently.

And I got the Crashlytics report like the below.

Fatal Exception: java.lang.IllegalStateException: Reply already submitted
       at io.flutter.embedding.engine.dart.DartMessenger$Reply.reply(DartMessenger.java:35)
       at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler$1.success(MethodChannel.java:14)
       at com.tundralabs.fluttertts.FlutterTtsPlugin.onMethodCall(FlutterTtsPlugin.java:631)
       at com.tundralabs.fluttertts.FlutterTtsPlugin$5.run(FlutterTtsPlugin.java:6)
       at com.tundralabs.fluttertts.FlutterTtsPlugin$4.onInit(FlutterTtsPlugin.java:110)
       at android.speech.tts.TextToSpeech.dispatchOnInit(TextToSpeech.java:863)
       at android.speech.tts.TextToSpeech.access$800(TextToSpeech.java:77)
       at android.speech.tts.TextToSpeech$Connection$SetupConnectionAsyncTask.onPostExecute(TextToSpeech.java:2226)
       at android.speech.tts.TextToSpeech$Connection$SetupConnectionAsyncTask.onPostExecute(TextToSpeech.java:2181)
       at android.os.AsyncTask.finish(AsyncTask.java:771)
       at android.os.AsyncTask.access$900(AsyncTask.java:199)
       at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:788)
       at android.os.Handler.dispatchMessage(Handler.java:106)
       at android.os.Looper.loop(Looper.java:246)
       at android.app.ActivityThread.main(ActivityThread.java:8653)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:602)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1130)

I saw the issue comment https://github.com/dlutton/flutter_tts/issues/261#issuecomment-904129032, so I added delay like the below.

TtsController.tts = FlutterTts();
await Future.delayed(const Duration(seconds: 1));
...
if (await tts.getDefaultEngine == Constants.googleTtsName) return;

final engines = await tts.getEngines;
if (engines.contains(Constants.googleTtsName)) {
  await tts.setEngine(Constants.googleTtsName);
  await Future.delayed(const Duration(seconds: 1));
} else {
  ...
}

However, I still get the report. The crash is on Galaxy S20 FE 5G and Android OS 11. 😭

Expected behavior

I hope the crash doesn't occur.

Reproduction steps

I can't. I have a Google Pixel4a, but it works perfectly.

Configuration

Version: 3.2.2

Platform:

  • [ ] :iphone: iOS
  • [x] :robot: Android

dev-yakuza avatar Dec 09 '21 08:12 dev-yakuza

@dev-yakuza does this error only occur with setEngine?

dlutton avatar Dec 09 '21 18:12 dlutton

does this error only occur with setEngine?

@dlutton I'm not sure. Yesterday, I got 3 reports.

Screen Shot 2021-12-10 at 7 47 57

  • Galaxy Note10+ 5G / Android 11
Fatal Exception: java.lang.IllegalStateException: Reply already submitted
       at io.flutter.embedding.engine.dart.DartMessenger$Reply.reply(DartMessenger.java:35)
       at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler$1.success(MethodChannel.java:14)
       at com.tundralabs.fluttertts.FlutterTtsPlugin.onMethodCall(FlutterTtsPlugin.java:631)
       at com.tundralabs.fluttertts.FlutterTtsPlugin$5.run(FlutterTtsPlugin.java:6)
       at com.tundralabs.fluttertts.FlutterTtsPlugin$4.onInit(FlutterTtsPlugin.java:110)
       at android.speech.tts.TextToSpeech.dispatchOnInit(TextToSpeech.java:863)
       at android.speech.tts.TextToSpeech.access$800(TextToSpeech.java:77)
       at android.speech.tts.TextToSpeech$Connection$SetupConnectionAsyncTask.onPostExecute(TextToSpeech.java:2226)
       at android.speech.tts.TextToSpeech$Connection$SetupConnectionAsyncTask.onPostExecute(TextToSpeech.java:2181)
       at android.os.AsyncTask.finish(AsyncTask.java:771)
       at android.os.AsyncTask.access$900(AsyncTask.java:199)
       at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:788)
       at android.os.Handler.dispatchMessage(Handler.java:106)
       at android.os.Looper.loop(Looper.java:246)
       at android.app.ActivityThread.main(ActivityThread.java:8633)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:602)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1130)
  • Galaxy A31 / Android 10
Fatal Exception: java.lang.IllegalStateException: Reply already submitted
       at io.flutter.embedding.engine.dart.DartMessenger$Reply.reply(DartMessenger.java:35)
       at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler$1.success(MethodChannel.java:14)
       at com.tundralabs.fluttertts.FlutterTtsPlugin.getDefaultEngine(FlutterTtsPlugin.java:6)
       at com.tundralabs.fluttertts.FlutterTtsPlugin.onMethodCall(FlutterTtsPlugin.java:583)
       at com.tundralabs.fluttertts.FlutterTtsPlugin$5.run(FlutterTtsPlugin.java:6)
       at com.tundralabs.fluttertts.FlutterTtsPlugin$4.onInit(FlutterTtsPlugin.java:110)
       at android.speech.tts.TextToSpeech.dispatchOnInit(TextToSpeech.java:835)
       at android.speech.tts.TextToSpeech.access$1500(TextToSpeech.java:63)
       at android.speech.tts.TextToSpeech$Connection$SetupConnectionAsyncTask.onPostExecute(TextToSpeech.java:2226)
       at android.speech.tts.TextToSpeech$Connection$SetupConnectionAsyncTask.onPostExecute(TextToSpeech.java:2181)
       at android.os.AsyncTask.finish(AsyncTask.java:755)
       at android.os.AsyncTask.access$900(AsyncTask.java:192)
       at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:772)
       at android.os.Handler.dispatchMessage(Handler.java:107)
       at android.os.Looper.loop(Looper.java:237)
       at android.app.ActivityThread.main(ActivityThread.java:8107)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1100)
  • Galaxy A12 / Android 11
Fatal Exception: java.lang.IllegalStateException: Reply already submitted
       at io.flutter.embedding.engine.dart.DartMessenger$Reply.reply(DartMessenger.java:35)
       at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler$1.success(MethodChannel.java:14)
       at com.tundralabs.fluttertts.FlutterTtsPlugin.onMethodCall(FlutterTtsPlugin.java:631)
       at com.tundralabs.fluttertts.FlutterTtsPlugin$5.run(FlutterTtsPlugin.java:6)
       at com.tundralabs.fluttertts.FlutterTtsPlugin$4.onInit(FlutterTtsPlugin.java:110)
       at android.speech.tts.TextToSpeech.dispatchOnInit(TextToSpeech.java:863)
       at android.speech.tts.TextToSpeech.access$800(TextToSpeech.java:77)
       at android.speech.tts.TextToSpeech$Connection$SetupConnectionAsyncTask.onPostExecute(TextToSpeech.java:2226)
       at android.speech.tts.TextToSpeech$Connection$SetupConnectionAsyncTask.onPostExecute(TextToSpeech.java:2181)
       at android.os.AsyncTask.finish(AsyncTask.java:771)
       at android.os.AsyncTask.access$900(AsyncTask.java:199)
       at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:788)
       at android.os.Handler.dispatchMessage(Handler.java:106)
       at android.os.Looper.loop(Looper.java:246)
       at android.app.ActivityThread.main(ActivityThread.java:8653)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:602)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1130)

dev-yakuza avatar Dec 09 '21 22:12 dev-yakuza

@dlutton I service the app for Korean. 🇰🇷 And Galaxy in Korea doesn't have GoogleTTS initially. 😭

So, I have checking the engine logic like below.

if (await tts.getDefaultEngine == Constants.googleTtsName) return;

final engines = await tts.getEngines;
if (engines.contains(Constants.googleTtsName)) {
  await tts.setEngine(Constants.googleTtsName);
  await Future.delayed(const Duration(seconds: 1));
} else {
  Get.dialog(
     // Alert with download button of Play store
  );
}

Today, I will try to remove the logic and test it to make sure the crashes occur in setEngine. 🔬

(Question) I saw https://github.com/dlutton/flutter_tts/issues/261#issuecomment-904000289. If there is no Google TTS, Is there no problem? 🤔

dev-yakuza avatar Dec 09 '21 23:12 dev-yakuza

@dev-yakuza Google TTS is the default, however if you're trying to set the engine and receiving that error, it could be an issue with setEngine. I'll look into that.

dlutton avatar Dec 09 '21 23:12 dlutton

@dlutton

Today, I will try to remove the logic and test it to make sure the crashes occur in setEngine. 🔬

I tested it. And there are no crash reports, So getDefaultEngine, getEngines, or setEngine makes the app crash.

I hope this info is helpful to debug it 🙏

dev-yakuza avatar Dec 10 '21 23:12 dev-yakuza

@dev-yakuza that's extremely helpful. I'll use that to pinpoint the issues with those methods on Android. Thank you

dlutton avatar Dec 12 '21 19:12 dlutton

@dlutton I got same issue like below:

Exception java.lang.IllegalStateException: 
  at io.flutter.embedding.engine.dart.DartMessenger$Reply.reply (DartMessenger.java)
  at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler$1.success (MethodChannel.java)
  at com.tundralabs.fluttertts.FlutterTtsPlugin.getDefaultEngine (FlutterTtsPlugin.java)
  at com.tundralabs.fluttertts.FlutterTtsPlugin.onMethodCall (FlutterTtsPlugin.java)
  at com.tundralabs.fluttertts.FlutterTtsPlugin$5.run (FlutterTtsPlugin.java)
  at com.tundralabs.fluttertts.FlutterTtsPlugin$4.onInit (FlutterTtsPlugin.java)
  at android.speech.tts.TextToSpeech.dispatchOnInit (TextToSpeech.java:863)
  at android.speech.tts.TextToSpeech.access$800 (TextToSpeech.java:77)
  at android.speech.tts.TextToSpeech$Connection$SetupConnectionAsyncTask.onPostExecute (TextToSpeech.java:2226)
  at android.speech.tts.TextToSpeech$Connection$SetupConnectionAsyncTask.onPostExecute (TextToSpeech.java:2181)
  at android.os.AsyncTask.finish (AsyncTask.java:771)
  at android.os.AsyncTask.access$900 (AsyncTask.java:199)
  at android.os.AsyncTask$InternalHandler.handleMessage (AsyncTask.java:788)
  at android.os.Handler.dispatchMessage (Handler.java:106)
  at android.os.Looper.loop (Looper.java:246)
  at android.app.ActivityThread.main (ActivityThread.java:8512)
  at java.lang.reflect.Method.invoke (Method.java)
  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:602)
  at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1130)

This error sometimes occurs not always. I found that they only occur on Samsung devices. The versions I'm using are 3.2.2 and 3.5.0

TranTuanManh avatar Aug 02 '22 14:08 TranTuanManh

@TranTuanManh are you also only receiving these errors with getDefaultEngine, getEngines, or setEngine?

dlutton avatar Aug 03 '22 17:08 dlutton

@dlutton Yes. I hope you can fix it soon. Thank you for the awesome lib.

TranTuanManh avatar Aug 04 '22 01:08 TranTuanManh

I've got the same issue when submitting an Android App to Google Play Console, pre-launch report.

It tested on 3 different devices samsung SM-G981U1 Android 10 (SDK 29), google Pixel 6 Android 12 (SDK 31) and google Redfin 64-bit Android 13 (SDK 33) only

Same error for all three:

java.lang.IllegalStateException: Reply already submitted
	at w2.c$g.a(Unknown Source:35)
	at j3.k$a$a.a(Unknown Source:14)
	at u2.g.B(Unknown Source:14)
	at u2.g.i(Unknown Source:576)
	at u2.g.P(Unknown Source:15)
	at u2.g.g(Unknown Source:0)
	at u2.e.run(Unknown Source:6)
	at u2.g.O(Unknown Source:95)
	at u2.g.c(Unknown Source:0)
	at u2.a.onInit(Unknown Source:2)
	at android.speech.tts.TextToSpeech.lambda$dispatchOnInit$0$TextToSpeech(TextToSpeech.java:890)
	at android.speech.tts.TextToSpeech$$ExternalSyntheticLambda17.run(Unknown Source:4)
	at android.speech.tts.TextToSpeech.dispatchOnInit(TextToSpeech.java:899)
	at android.speech.tts.TextToSpeech.access$900(TextToSpeech.java:79)
	at android.speech.tts.TextToSpeech$Connection$SetupConnectionAsyncTask.onPostExecute(TextToSpeech.java:2280)
	at android.speech.tts.TextToSpeech$Connection$SetupConnectionAsyncTask.onPostExecute(TextToSpeech.java:2240)
	at android.os.AsyncTask.finish(AsyncTask.java:771)
	at android.os.AsyncTask.access$900(AsyncTask.java:199)
	at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:788)
	at android.os.Handler.dispatchMessage(Handler.java:106)
	at android.os.Looper.loopOnce(Looper.java:201)
	at android.os.Looper.loop(Looper.java:288)
	at android.app.ActivityThread.main(ActivityThread.java:7839)
	at java.lang.reflect.Method.invoke(Native Method)
	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)

Does anybody know a workaround to this issue?

chimura avatar Jan 24 '23 11:01 chimura

@chimura do you know which method is being invoked when this error appears?

dlutton avatar Jan 25 '23 17:01 dlutton

@dlutton Yeah, setEngine with the string for the default android tts as argument.

chimura avatar Feb 01 '23 09:02 chimura

thank you @chimura

dlutton avatar Feb 02 '23 01:02 dlutton

I am having the same issue with version 3.6.3. I had an old project with v3.5.1 that was working fine.

Weird thing is after I run flutter clean and downloaded packages again, everything is the same but now v3.5.1 crashes too. It only had the flutter_tts as dependencies.

It seems to crash when we try to set the same engine that is already being used.

For now I did something like this, and it is working:

FlutterTts _tts=FlutterTts();
String engine = '';
bool get isAndroid => !kIsWeb && Platform.isAndroid;

//call this instead of _tts.setEngine
Future setEngine(String newEngine) async {
    if (isAndroid) {
      //set on first call
      if (engine.isEmpty) {
        engine = await _tts.getDefaultEngine;
        //just in case there is only 1 engine and is not google (getDefaultEngine)
        var engines = await _tts.getEngines;
        if (engines.length == 1 && engines[0] != engine) {
          engine = engines[0];
        }
      }
      //change if necessary
      if (engine != newEngine) {
        await _tts.setEngine(newEngine);
        engine = newEngine;
      }
    }
  }

hioshih avatar Mar 12 '23 18:03 hioshih