flutter_local_notifications
flutter_local_notifications copied to clipboard
Exception NoSuchMethodError
With plugin version 9.6.1 I see the following crash for some users, I was not able to replicate it myself. Does anybody know if this is a bug or if I am doing something wrong?
Fatal Exception: java.lang.NoSuchMethodError: No static method e(Landroid/content/Context;)Landroidx/core/app/n; in class Landroidx/core/app/n; or its super classes (declaration of 'androidx.core.app.n' appears in /data/app/~~v8yhhqH2FHoMiGDXLA-pgQ==/androidx.test.tools.crawler-WljZg1GOGnOmmNq4rJSXqg==/base.apk) at com.dexterous.flutterlocalnotifications.FlutterLocalNotificationsPlugin.getNotificationManager(FlutterLocalNotificationsPlugin.java) at com.dexterous.flutterlocalnotifications.FlutterLocalNotificationsPlugin.cancelAllNotifications(FlutterLocalNotificationsPlugin.java:2) at com.dexterous.flutterlocalnotifications.FlutterLocalNotificationsPlugin.onMethodCall(FlutterLocalNotificationsPlugin.java:323) at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler.onMessage(MethodChannel.java:17) at io.flutter.embedding.engine.dart.DartMessenger.invokeHandler(DartMessenger.java:18) at io.flutter.embedding.engine.dart.DartMessenger.lambda$dispatchMessageToQueue$0(DartMessenger.java:20) at io.flutter.embedding.engine.dart.DartMessenger.$r8$lambda$TsixYUB5E6FpKhMtCSQVHKE89gQ(DartMessenger.java) at io.flutter.embedding.engine.dart.DartMessenger$$InternalSyntheticLambda$0$ceffc6bae7d364cb48afaf1aaebd60bf9050360d0efb9035ebc54f0851df0a05$0.run(DartMessenger.java:12) at android.os.Handler.handleCallback(Handler.java:938) at android.os.Handler.dispatchMessage(Handler.java:99) 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(Method.java) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)
I'm having a similar issue too (Flutter 2.10.5 / Dart 2.16.2).
I uploaded my app to the Google Play Store and the Pre-launch report brought up this crash report:
java.lang.NoSuchMethodError: No static method e(Landroid/content/Context;)Landroidx/core/app/i; in class Landroidx/core/app/i; or its super classes (declaration of 'androidx.core.app.i' appears in base.apk)
at com.dexterous.flutterlocalnotifications.FlutterLocalNotificationsPlugin.getNotificationManager(Unknown Source:0)
at com.dexterous.flutterlocalnotifications.FlutterLocalNotificationsPlugin.cancelAllNotifications(Unknown Source:2)
at com.dexterous.flutterlocalnotifications.FlutterLocalNotificationsPlugin.onMethodCall(Unknown Source:323)
at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler.onMessage(Unknown Source:17)
at io.flutter.embedding.engine.dart.DartMessenger.invokeHandler(Unknown Source:18)
at io.flutter.embedding.engine.dart.DartMessenger.lambda$dispatchMessageToQueue$0(Unknown Source:20)
at io.flutter.embedding.engine.dart.DartMessenger.a(Unknown Source:0)
at io.flutter.embedding.engine.dart.a.run(Unknown Source:12)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at androidx.test.espresso.base.Interrogator.loopAndInterrogate(Interrogator.java:10)
at androidx.test.espresso.base.UiControllerImpl.loopUntil(UiControllerImpl.java:7)
at androidx.test.espresso.base.UiControllerImpl.loopMainThreadUntilIdle(UiControllerImpl.java:16)
at androidx.test.espresso.ViewInteraction.doPerform(ViewInteraction.java:3)
at androidx.test.espresso.ViewInteraction.-$$Nest$mdoPerform(Unknown Source:0)
at androidx.test.espresso.ViewInteraction$1.call(ViewInteraction.java:6)
at androidx.test.espresso.ViewInteraction$1.call(ViewInteraction.java:1)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
Difficult for me to say what is going with a minimal app and steps to reproduce this. Things that come mind are if Proguard rules were configured correctly or perhaps that are other settings your apps needs based on your situation that may not be applicable to all apps e.g. enabling multidex
Thanks for your reply. I did check the Proguard rules and, as far as I can see, it's set up correctly I think. It's below, if want want to take a look - See if there's anything I've missed!
## Flutter wrapper
-keep class io.flutter.app.** { *; }
-keep class io.flutter.plugin.** { *; }
-keep class io.flutter.util.** { *; }
-keep class io.flutter.view.** { *; }
-keep class io.flutter.** { *; }
-keep class io.flutter.plugins.** { *; }
-dontwarn io.flutter.embedding.**
## Gson rules
# Gson uses generic type information stored in a class file when working with fields. Proguard
# removes such information by default, so configure it to keep all of it.
-keepattributes Signature
# For using GSON @Expose annotation
-keepattributes *Annotation*
# Gson specific classes
-dontwarn sun.misc.**
#-keep class com.google.gson.stream.** { *; }
# Prevent proguard from stripping interface information from TypeAdapter, TypeAdapterFactory,
# JsonSerializer, JsonDeserializer instances (so they can be used in @JsonAdapter)
-keep class * implements com.google.gson.TypeAdapter
-keep class * implements com.google.gson.TypeAdapterFactory
-keep class * implements com.google.gson.JsonSerializer
-keep class * implements com.google.gson.JsonDeserializer
# Prevent R8 from leaving Data object members always null
-keepclassmembers,allowobfuscation class * {
@com.google.gson.annotations.SerializedName <fields>;
}
# Retain generic signatures of TypeToken and its subclasses with R8 version 3.0 and higher.
-keep,allowobfuscation,allowshrinking class com.google.gson.reflect.TypeToken
-keep,allowobfuscation,allowshrinking class * extends com.google.gson.reflect.TypeToken
My Notifications class helper, in case it's useful. You'll see a few Crashlytics logs in there, as I was trying to determine where it was crashing. In each case, it was crashing in the init()
function with the call to await flutterLocalNotificationsPlugin.initialize()
import 'dart:async';
import 'package:firebase_crashlytics/firebase_crashlytics.dart';
import 'package:flutter/material.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:timezone/data/latest.dart' as tz;
import 'package:timezone/timezone.dart' as tz;
import 'package:whitu/helpers/native_timezone.dart';
FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
NotificationAppLaunchDetails notificationAppLaunchDetails;
// Notification channels
class NotificationChannel {
final String id;
final String name;
final String description;
const NotificationChannel({this.id, this.name, this.description});
}
// Singleton notifications helper.
class Notifications {
// Singleton.
static final Notifications _instance = new Notifications.internal();
factory Notifications() => _instance;
Notifications.internal();
// Notification channels.
static const NotificationChannel appChannel = NotificationChannel(
id: 'Main', name: 'Main App Notifications', description: 'App notifications');
static const NotificationChannel dailyChannel = NotificationChannel(
id: 'Daily', name: 'Daily Reminders', description: 'Receive daily reminders');
// Cancel notifications.
Future<void> cancel({@required int id}) async => await flutterLocalNotificationsPlugin.cancel(id);
Future<void> cancelAll() async => await flutterLocalNotificationsPlugin.cancelAll();
// Initialise on create. We should only do this once.
Future<void> init() async {
FirebaseCrashlytics.instance.log("notifications: Get local time zone.");
await _getLocalTimeZone();
notificationAppLaunchDetails = await flutterLocalNotificationsPlugin.getNotificationAppLaunchDetails();
// Initialise the plugin. app_icon.png needs to be a added as a drawable resource in
// android/app/src/main/res/drawable.
FirebaseCrashlytics.instance.log("notifications: Add Android initialisation settings.");
var initializationSettingsAndroid = AndroidInitializationSettings('notification_icon');
// Ask for permissions on iOS, on app start.
FirebaseCrashlytics.instance.log("notifications: Add iOS initialisation settings.");
var initializationSettingsIOS = IOSInitializationSettings(
requestSoundPermission: true,
requestBadgePermission: true,
requestAlertPermission: true,
onDidReceiveLocalNotification: _onDidReceiveLocalNotification,
);
FirebaseCrashlytics.instance.log("notifications: Apply Android/iOS initialisation settings.");
var initializationSettings = InitializationSettings(
android: initializationSettingsAndroid,
iOS: initializationSettingsIOS,
);
FirebaseCrashlytics.instance.log("notifications: Initialise the notifications.");
// What we should call when the user taps on the notification.
await flutterLocalNotificationsPlugin.initialize(
initializationSettings,
onSelectNotification: _onSelectNotification,
);
}
// Display a simple notification.
Future<void> show({
int id = 0,
@required String title,
String body,
String payload,
}) async {
BigTextStyleInformation style = _styleText(title: title, body: body);
await flutterLocalNotificationsPlugin.show(
id, title, body, _notificationDetails(appChannel, style), payload: payload);
}
Future<void> showDaily({
int id = 0,
@required Time time,
@required String title,
String body,
String payload,
}) async {
BigTextStyleInformation style = _styleText(title: title, body: body);
await flutterLocalNotificationsPlugin.zonedSchedule(
id,
title,
body,
_nextInstanceOfTime(time),
_notificationDetails(dailyChannel, style),
payload: payload,
matchDateTimeComponents: DateTimeComponents.time,
androidAllowWhileIdle: true,
uiLocalNotificationDateInterpretation: UILocalNotificationDateInterpretation.absoluteTime,
);
}
// Get the next occurrence of the specified notification time.
tz.TZDateTime _nextInstanceOfTime(Time time) {
final tz.TZDateTime now = tz.TZDateTime.now(tz.local);
tz.TZDateTime scheduledDate =
tz.TZDateTime(tz.local, now.year, now.month, now.day, time.hour, time.minute);
// Add a day, if the time has already passed.
if (scheduledDate.isBefore(now)) {
scheduledDate = scheduledDate.add(const Duration(days: 1));
}
return scheduledDate;
}
// Retrieve the phone's current time zone.
Future<void> _getLocalTimeZone() async {
tz.initializeTimeZones();
final String timezoneName = await NativeTimezone.getLocalTimezone();
tz.setLocalLocation(tz.getLocation(timezoneName));
}
// Callback for handling when a notification is triggered while the app is in the foreground.
Future<void> _onDidReceiveLocalNotification(int id, String title, String body, String payload) async {
if (payload != null) {
debugPrint('iOS notification payload: ${payload ?? 'None'}');
}
}
// Calback for when the notification has been tapped on.
Future<void> _onSelectNotification(String payload) async {
if (payload != null) {
debugPrint('nNotification payload: ${payload ?? 'None'}');
}
}
BigTextStyleInformation _styleText({String title, String body}) {
return BigTextStyleInformation(
body,
htmlFormatBigText: true,
contentTitle: title,
htmlFormatContentTitle: true,
);
}
// Platform channel specifics.
NotificationDetails _notificationDetails(
NotificationChannel channel,
BigTextStyleInformation styleInformation,
) {
var androidPlatformChannelSpecifics = AndroidNotificationDetails(
channel.id, channel.name,
channelDescription: channel.description,
styleInformation: styleInformation,
importance: Importance.high,
priority: Priority.high,
ticker: 'ticker',
);
var iOSPlatformChannelSpecifics = IOSNotificationDetails();
return NotificationDetails(
android: androidPlatformChannelSpecifics,
iOS: iOSPlatformChannelSpecifics,
);
}
}
The rules look fine to me for the gson stuff. Not sure about the Flutter ones. One thing to note is logs point to an error where it looks like it can't resolve a method within the Android APIs themselves as opposed to something from this plugin so not something I can help with
@tnaseem providing Dart code won't help with these issues, which is why I mentioned a minimal app and that could be a link to a GitHub repo
No worries. I'll get it done after the weekend and see if it still happens. I'll need to run the test on Firebase TestLab to see if it shows up the crashes then. Only seems to happen on a few of their test devices.
I am using the latest GSON rules and it is still happening
This also started showing for me in crashlytics:
Fatal Exception: java.lang.NoSuchMethodError: No static method e(Landroid/content/Context;)Landroidx/core/app/l; in class Landroidx/core/app/l; or its super classes (declaration of 'androidx.core.app.l' appears in base.apk)
at com.dexterous.flutterlocalnotifications.FlutterLocalNotificationsPlugin.getNotificationManager(FlutterLocalNotificationsPlugin.java)
at com.dexterous.flutterlocalnotifications.FlutterLocalNotificationsPlugin.cancelAllNotifications(FlutterLocalNotificationsPlugin.java:2)
at com.dexterous.flutterlocalnotifications.FlutterLocalNotificationsPlugin.onMethodCall(FlutterLocalNotificationsPlugin.java:323)
at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler.onMessage(MethodChannel.java:17)
at io.flutter.embedding.engine.dart.DartMessenger.invokeHandler(DartMessenger.java:18)
at io.flutter.embedding.engine.dart.DartMessenger.lambda$dispatchMessageToQueue$0(DartMessenger.java:20)
at io.flutter.embedding.engine.dart.DartMessenger.$r8$lambda$TsixYUB5E6FpKhMtCSQVHKE89gQ(DartMessenger.java)
at io.flutter.embedding.engine.dart.DartMessenger$$InternalSyntheticLambda$0$ceffc6bae7d364cb48afaf1aaebd60bf9050360d0efb9035ebc54f0851df0a05$0.run(DartMessenger.java:12)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7050)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:494)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:965)
No code changes or new release, started appearing 6 days ago
Found this, looks related: https://issuetracker.google.com/issues/238234609
That's interesting, in Crashlytics mine appears on those same devices mentioned in the last comment on that thread. ie.:
- Galaxy S20 5G
- Galaxy 8
- AQUOS sense2 SH-01L
- Pixel 5
(https://issuetracker.google.com/issues/238234609#comment6)
That's interesting, in Crashlytics mine appears on those same devices mentioned in the last comment on that thread. ie.:
- Galaxy S20 5G
- Galaxy 8
- AQUOS sense2 SH-01L
- Pixel 5
(https://issuetracker.google.com/issues/238234609#comment6)
That's my comment 😅, I confirmed later that this only happens when the pre release report is running
Looks like this is to do with an issue outside of the plugin. Will keep this open for now so others know about this.
According to the comment at https://issuetracker.google.com/issues/237785592#comment96, this has been fixed by the Google team so will close this