Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unhandled Exception: NoSuchMethodError: The method 'toRawHandle' was called on null

i am using firebase_messaging library in My Flutter Application for Firebase Push Notifications.

Currently my firebase_messaging version is firebase_messaging: ^5.1.5 which was recently updated an the latest one.

i am trying to receive notification in background as well as when application is terminated.

i have followed all the steps as mentioned in the documentation of firebase_messaging but unfortunately i am getting the above error in flutter.

this is my notification handler class in dart

notification_handler.dart

import 'dart:async';
import 'dart:io';
import 'dart:math';

import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:path_provider/path_provider.dart';
import 'package:http/http.dart' as http;

class NotificationHandler {
  FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin;
  FirebaseMessaging _fcm = FirebaseMessaging();
  StreamSubscription iosSubscription;
  static final NotificationHandler _singleton =
      new NotificationHandler._internal();

  factory NotificationHandler() {
    return _singleton;
  }
  NotificationHandler._internal();

  Future<dynamic> myBackgroundMessageHandler(
      Map<String, dynamic> message) async {
    print("onLaunch: $message");
    _showBigPictureNotification(message);
    // Or do other work.
  }

  initializeFcmNotification() async {
    flutterLocalNotificationsPlugin = new FlutterLocalNotificationsPlugin();

    var initializationSettingsAndroid =
        new AndroidInitializationSettings('ic_launcher');
    var initializationSettingsIOS = new IOSInitializationSettings(
        onDidReceiveLocalNotification: onDidReceiveLocalNotification);
    var initializationSettings = new InitializationSettings(
        initializationSettingsAndroid, initializationSettingsIOS);
    flutterLocalNotificationsPlugin.initialize(initializationSettings,
        onSelectNotification: onSelectNotification);

    if (Platform.isIOS) {
      iosSubscription = _fcm.onIosSettingsRegistered.listen((data) {
        // save the token  OR subscribe to a topic here
      });

      _fcm.requestNotificationPermissions(IosNotificationSettings());
    } else {
      _saveDeviceToken();
    }

    _fcm.configure(
      onMessage: (Map<String, dynamic> message) async {
        print("onMessage: $message");
        _showBigPictureNotification(message);
      },
      onBackgroundMessage: myBackgroundMessageHandler,
      onLaunch: (Map<String, dynamic> message) async {
        print("onLaunch: $message");
      },
      onResume: (Map<String, dynamic> message) async {
        print("onResume: $message");
      },
    );
  }

  /// Get the token, save it to the database for current user
  _saveDeviceToken() async {
    String fcmToken = await _fcm.getToken();
    print("FCM_TOKEN: $fcmToken");
  }

  Future<void> _showBigPictureNotification(message) async {
    var rng = new Random();
    var notifId = rng.nextInt(100);

    var largeIconPath = await _downloadAndSaveImage(
        'https://cdn.pixabay.com/photo/2019/04/21/21/29/pattern-4145023_960_720.jpg',
        'largeIcon');
    var bigPicturePath = await _downloadAndSaveImage(
        'https://cdn.pixabay.com/photo/2019/04/21/21/29/pattern-4145023_960_720.jpg',
        'bigPicture');
    var bigPictureStyleInformation = BigPictureStyleInformation(
        bigPicturePath, BitmapSource.FilePath,
        largeIcon: largeIconPath,
        largeIconBitmapSource: BitmapSource.FilePath,
        contentTitle: message['data']['title'],
        htmlFormatContentTitle: true,
        summaryText: message['data']['body'],
        htmlFormatSummaryText: true);
    var androidPlatformChannelSpecifics = AndroidNotificationDetails(
        '12', 'trading_id', message['data']['body'],
        importance: Importance.High,
        priority: Priority.High,
        style: AndroidNotificationStyle.BigPicture,
        styleInformation: bigPictureStyleInformation);
    var platformChannelSpecifics =
        NotificationDetails(androidPlatformChannelSpecifics, null);
    await flutterLocalNotificationsPlugin.show(
        notifId,
        message['data']['title'],
        message['data']['body'],
        platformChannelSpecifics,
        payload: message['data']['body']);
  }

  Future<void> _showBigTextNotification(message) async {
    var rng = new Random();
    var notifId = rng.nextInt(100);
    var bigTextStyleInformation = BigTextStyleInformation(
        message['data']['body'],
        htmlFormatBigText: true,
        contentTitle: message['data']['title'],
        htmlFormatContentTitle: true,
        summaryText: message['data']['body'],
        htmlFormatSummaryText: true);
    var androidPlatformChannelSpecifics = AndroidNotificationDetails(
        '12', 'trading_id', '',
        importance: Importance.High,
        priority: Priority.High,
        style: AndroidNotificationStyle.BigText,
        styleInformation: bigTextStyleInformation);
    var platformChannelSpecifics =
        NotificationDetails(androidPlatformChannelSpecifics, null);
    await flutterLocalNotificationsPlugin.show(
        notifId,
        message['data']['title'],
        message['data']['body'],
        platformChannelSpecifics,
        payload: message['data']['body']);
  }

  Future onSelectNotification(String payload) async {
    if (payload != null) {
      debugPrint('notification payload: ' + payload);
    }
    // await Navigator.push(
    //   context,
    //   new MaterialPageRoute(builder: (context) => new SecondScreen(payload)),
    // );
  }

  Future<void> onDidReceiveLocalNotification(
      int id, String title, String body, String payload) async {
    // display a dialog with the notification details, tap ok to go to another page
  }

  Future<String> _downloadAndSaveImage(String url, String fileName) async {
    var directory = await getApplicationDocumentsDirectory();
    var filePath = '${directory.path}/$fileName';
    var response = await http.get(url);
    var file = File(filePath);
    await file.writeAsBytes(response.bodyBytes);
    return filePath;
  }
}

and i have called it like this in my home screen

   @override
  void initState() {
    // TODO: implement initState
    super.initState();
    new NotificationHandler().initializeFcmNotification();
  }
like image 758
Harish Penta Avatar asked Sep 09 '19 09:09

Harish Penta


4 Answers

EDIT1:

After surfing for several git threads and stackoverflow threads, I finally found the shortest answer that no one could tell:

"JUST PUT THE HANDLERS IN GLOBAL SCOPE"

in your whatever.dart file, just put the _firebaseMessaging and the 4 handlers, onMessage, onLaunch, etc... outside local class, and VOILA!! NO CRASH!


ORIGINAL:

I used bkmza answer , but was not OP fix for crossplatform

For some reason, setting

void initState() {
super.initState();
    _firebaseMessaging.configure
}

was not working, then I tried

Future.delayed(Duration(seconds: 1), () {
     _firebaseMessaging.configure
    }
);

And I got it working flawlessly :)

Maybe FCM initialisations was not ready to configure handlers, setting a delay after Firebase Core fully load made it work properly

like image 153
Kohls Avatar answered Oct 16 '22 11:10

Kohls


Since the latest version (5.15) you have to set the following delegate during initialization of the handlers:

onBackgroundMessage: myBackgroundMessageHandler

Please note, that your handler should be a global or static at least, vice verse you will have another runtime exception.

Here is a sample of initialization of the FCM:

_firebaseMessaging.configure(
  onBackgroundMessage: Theme.of(context).platform == TargetPlatform.iOS
      ? null
      : myBackgroundMessageHandler,
  onMessage: (Map<String, dynamic> message) async { },
  onResume: (Map<String, dynamic> message) async { },
  onLaunch: (Map<String, dynamic> message) async { },
);

And handler template:

Future<dynamic> myBackgroundMessageHandler(Map<String, dynamic> message) async { return Future<void>.value(); }

Official READM.me was updated and you can find a couple notes about it here.

Here is a PR which provide a possibility to handle background notification on android. You can find details here.

like image 37
bkmza Avatar answered Oct 16 '22 12:10

bkmza


When I use onBackgroundMessage the app has error or crash.

My implementation of Firebase Messaging

main.dart

initState(){
  ....
  HelperClass.initFCM(some dependencies);
}

helperClass.dart

class HelperClass
{
final FirebaseMessaging _firebaseMessaging = FirebaseMessaging();

Future<dynamic> backgroundMessageHandler(Map<String, dynamic> message) {
  print("_backgroundMessageHandler");
  if (message.containsKey('data')) {
    // Handle data message
    final dynamic data = message['data'];
    print("_backgroundMessageHandler data: ${data}");
  }

  if (message.containsKey('notification')) {
    // Handle notification message
    final dynamic notification = message['notification'];
    print("_backgroundMessageHandler notification: ${notification}");
  }

  Future<void> initFCM(...){
    _firebaseMessaging.configure(
      .....,
      onBackgroundMessage: backgroundMessageHandler,
      .....
      );
  }
}

I can't configure firebase at the main.dart because I have some logic about this. For example I am initing the FCM only if user is logged, etc. So I have to configure firebase inside a class.

When started the app I have got error with ToRawHandle()

E/flutter (23610): [ERROR:flutter/lib/ui/ui_dart_state.cc(148)] Unhandled Exception: NoSuchMethodError: The method 'toRawHandle' was called on null.
E/flutter (23610): Receiver: null
E/flutter (23610): Tried calling: toRawHandle()
E/flutter (23610): #0      Object.noSuchMethod  (dart:core-patch/object_patch.dart:51:5)
E/flutter (23610): #1      FirebaseMessaging.configure 
package:firebase_messaging/firebase_messaging.dart:12

When I set the function to STATIC like this

static Future<dynamic> backgroundMessageHandler(Map<String, dynamic> message) {
      print("_backgroundMessageHandler");
      if (message.containsKey('data')) {
        // Handle data message
        final dynamic data = message['data'];
        print("_backgroundMessageHandler data: ${data}");
      }

      if (message.containsKey('notification')) {
        // Handle notification message
        final dynamic notification = message['notification'];
        print("_backgroundMessageHandler notification: ${notification}");
      }

The APP crash during configuring firebase

uid: 10532
signal 6 (SIGABRT), code -1 (SI_QUEUE), fault addr --------
    x0  0000000000000000  x1  0000000000005fda  x2  0000000000000006  x3  00000077dc702860
    x4  00000077dc702740  x5  00000077dc702740  x6  00000077dc702740  x7  0000000000000000
    x8  00000000000000f0  x9  204a59b65fcacfed  x10 fffffff0fffffbdf  x11 0000000000000000
    x12 0000000000000000  x13 0000000000000010  x14 0000000000000020  x15 00000077dc702740
    x16 00000078d0ef68b8  x17 00000078d0ed4710  x18 00000077cd1e8000  x19 00000000000000ac
    x20 0000000000005f77  x21 00000000000000b2  x22 0000000000005fda  x23 00000000ffffffff
    x24 000000000000003a  x25 00000077dc703020  x26 000000000000003a  x27 0000000000000001
    x28 0000000000000001  x29 00000077dc702910
    sp  00000077dc702840  lr  00000078d0e8744c  pc  00000078d0e8746c
backtrace:
      #00 pc 000000000008246c  /apex/com.android.runtime/lib64/bionic/libc.so (abort+160) (BuildId: 5812256023147338b8a9538321d4c456)
      #01 pc 00000000011c8d80  /data/app/com.kleinpetr.app-DIUNepS7D_5Cnpsb5tArzA==/lib/arm64/libflutter.so!libflutter.so (offset 0x11c0000) (BuildId: d8bf9b314511c944)
      #02 pc 00000000011d39a0  /data/app/com.kleinpetr.app-DIUNepS7D_5Cnpsb5tArzA==/lib/arm64/libflutter.so!libflutter.so (offset 0x11c0000) (BuildId: d8bf9b314511c944)
      #03 pc 00000000011d7c54  /data/app/com.kleinpetr.app-DIUNepS7D_5Cnpsb5tArzA==/lib/arm64/libflutter.so!libflutter.so (offset 0x11c0000) (BuildId: d8bf9b314511c944)
      #04 pc 00000000011cf744  /data/app/com.kleinpetr.app-DIUNepS7D_5Cnpsb5tArzA==/lib/arm64/libflutter.so!libflutter.so (offset 0x11c0000) (BuildId: d8bf9b314511c944)
      #05 pc 00000000011d5a78  /data/app/com.kleinpetr.app-DIUNepS7D_5Cnpsb5tArzA==/lib/arm64/libflutter.so!libflutter.so (offset 0x11c0000) (BuildId: d8bf9b314511c944)
      #06 pc 00000000011d6154  /data/app/com.kleinpetr.app-DIUNepS7D_5Cnpsb5tArzA==/lib/arm64/libflutter.so!libflutter.so (offset 0x11c0000) (BuildId: d8bf9b314511c944)
      #07 pc 00000000011d55b0  /data/app/com.kleinpetr.app-DIUNepS7D_5Cnpsb5tArzA==/lib/arm64/libflutter.so!libflutter.so (offset 0x11c0000) (BuildId: d8bf9b314511c944)
      #08 pc 00000000011da7c8  /data/app/com.kleinpetr.app-DIUNepS7D_5Cnpsb5tArzA==/lib/arm64/libflutter.so!libflutter.so (offset 0x11c0000) (BuildId: d8bf9b314511c944)
      #09 pc 0000000000017efc  /system/lib64/libutils.so (android::Looper::pollInner(int)+864) (BuildId: 519d0734bba3d4086a9088e9bcb201de)
      #10 pc 0000000000017afc  /system/lib64/libutils.so (android::Looper::pollOnce(int, int*, int*, void**)+56) (BuildId: 519d0734bba3d4086a9088e9bcb201de)
      #11 pc 0000000000013644  /system/lib64/libandroid.so (ALooper_pollOnce+96) (BuildId: 8ab9f24e53265b4640c6f4dd253b4b1f)
      #12 pc 00000000011da74c  /data/app/com.kleinpetr.app-DIUNepS7D_5Cnpsb5tArzA==/lib/arm64/libflutter.so!libflutter.so (offset 0x11c0000) (BuildId: d8bf9b314511c944)
      #13 pc 00000000011d54fc  /data/app/com.kleinpetr.app-DIUNepS7D_5Cnpsb5tArzA==/lib/arm64/libflutter.so!libflutter.so (offset 0x11c0000) (BuildId: d8bf9b314511c944)
      #14 pc 00000000011d86a0  /data/app/com.kleinpetr.app-DIUNepS7D_5Cnpsb5tArzA==/lib/arm64/libflutter.so!libflutter.so (offset 0x11c0000) (BuildId: d8bf9b314511c944)
      #15 pc 00000000000e372c  /apex/com.android.runtime/lib64/bionic/libc.so (__pthread_start(void*)+36) (BuildId: 5812256023147338b8a9538321d4c456)
      #16 pc 0000000000084004  /apex/com.android.runtime/lib64/bionic/libc.so (__start_thread+64) (BuildId: 5812256023147338b8a9538321d4c456)
Lost connection to device.
like image 5
Petr Klein Avatar answered Oct 16 '22 11:10

Petr Klein


It is important that the onBackgroundMessageHandler provided is a top-level (on that does not depend on any instance variable or field) function. Thus, there are two ways to do this:

1.) (the most appropriate) Define the handler outside any class to make sure it is globally available and not dependent on any instance variable.

Example:

Future<void> onBackgroundNotificationData(RemoteMessage message) async {
  print(message.data);

  // do sommething...
}

2.) Define the handler as a static method in a class or interface. Note this works because in dart static methods can't access instance variables methods or fields and as such it meets the structural-requirements of the onBackgroundMessage-handler.

Example:

class MyServiceClass {
  static Future<void> onBackgroundNotificationData(RemoteMessage message) async {
    print(message.data);

    // do sommething...
  }
}

Using any of the above methods should help resolve the issue.

like image 1
John Oyekanmi Avatar answered Oct 16 '22 12:10

John Oyekanmi