Nativescript-plugin-firebase: Nativescript vue crash when you receive push notification on background mode (or app is closed)

Created on 13 Nov 2018  路  12Comments  路  Source: EddyVerbruggen/nativescript-plugin-firebase

repo https://github.com/academici/nativescript-vue-firebase

nativescript: 5.0
nativescript-vue: 2.0
tns-android: 5.0
nativescript-plugin-firebase: 7.4.1

  1. when the app is active, messages received successfully
  2. when the app is background or closed, messages are displayed in top panel. When clicking on the message, the app opens with an error:
An uncaught Exception occurred on "main" thread.
com.tns.NativeScriptException: 
Calling js method onViewAttachedToWindow failed

Error: Cannot assign primitive value to array of objects.
File: "file:///data/data/ru.iwant.app/files/app/vendor.js", line: 43034, column: 26

StackTrace: 
    Frame: function:'', file:'file:///data/data/ru.iwant.app/files/app/vendor.js', line: 43034, column: 27
    Frame: function:'javaObjectArray', file:'file:///data/data/ru.iwant.app/files/app/vendor.js', line: 43033, column: 10
    Frame: function:'createDummyZeroDurationAnimator', file:'file:///data/data/ru.iwant.app/files/app/vendor.js', line: 43040, column: 75
    Frame: function:'NoTransition.createAndroidAnimator', file:'file:///data/data/ru.iwant.app/files/app/vendor.js', line: 43053, column: 12
    Frame: function:'setupExitAndPopEnterAnimation', file:'file:///data/data/ru.iwant.app/files/app/vendor.js', line: 42909, column: 33
    Frame: function:'setupAllAnimation', file:'file:///data/data/ru.iwant.app/files/app/vendor.js', line: 42922, column: 3
    Frame: function:'_setAndroidFragmentTransitions', file:'file:///data/data/ru.iwant.app/files/app/vendor.js', line: 42402, column: 5
    Frame: function:'Frame._navigateCore', file:'file:///data/data/ru.iwant.app/files/app/vendor.js', line: 44121, column: 28
    Frame: function:'FrameBase.performNavigation', file:'file:///data/data/ru.iwant.app/files/app/vendor.js', line: 43381, column: 10
    Frame: function:'FrameBase._processNextNavigationEntry', file:'file:///data/data/ru.iwant.app/files/app/vendor.js', line: 43370, column: 14
    Frame: function:'Frame._processNextNavigationEntry', file:'file:///data/data/ru.iwant.app/files/app/vendor.js', line: 43969, column: 52
    Frame: function:'Frame._onAttachedToWindow', file:'file:///data/data/ru.iwant.app/files/app/vendor.js', line: 43935, column: 10
    Frame: function:'AttachListener.onViewAttachedToWindow', file:'file:///data/data/ru.iwant.app/files/app/vendor.js', line: 43839, column: 17


    at com.tns.Runtime.callJSMethodNative(Native Method)
    at com.tns.Runtime.dispatchCallJSMethodNative(Runtime.java:1116)
    at com.tns.Runtime.callJSMethodImpl(Runtime.java:996)
    at com.tns.Runtime.callJSMethod(Runtime.java:983)
    at com.tns.Runtime.callJSMethod(Runtime.java:967)
    at com.tns.Runtime.callJSMethod(Runtime.java:959)
    at com.tns.gen.java.lang.Object_vendor_43830_28_AttachListener.onViewAttachedToWindow(Object_vendor_43830_28_AttachListener.java:17)
    at android.view.View.dispatchAttachedToWindow(View.java:15406)
    at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:2953)
    at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:2960)
    at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:2960)
    at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:2960)
    at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:2960)
    at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:2960)
    at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1516)
    at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1246)
    at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6301)
    at android.view.Choreographer$CallbackRecord.run(Choreographer.java:871)
    at android.view.Choreographer.doCallbacks(Choreographer.java:683)
    at android.view.Choreographer.doFrame(Choreographer.java:619)
    at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:857)
    at android.os.Handler.handleCallback(Handler.java:751)
    at android.os.Handler.dispatchMessage(Handler.java:95)
    at android.os.Looper.loop(Looper.java:154)
    at android.app.ActivityThread.main(ActivityThread.java:6077)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:866)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:756)


Most helpful comment

To anyone else facing this issue, this is something that's only happening when using both nativescript-vue and nativescript-plugin-firebase, having to do with the way Vue observes value changes. The solution is to sanitize the message that you receive from the onMessageReceivedCallback handler with a simple JSON.parse(JSON.stringify(message)) before you pass it to anywhere that any NativeScript-Vue instance can access it.

      onMessageReceivedCallback: (message) => {
        // sanitize the message or the NativeScript-Vue app will crash on observing it!
        const messageString = JSON.stringify(message)
        const sanitizedMessage = JSON.parse(messageString)
        console.log('Push message received: ' + messageString)
        store.dispatch('handlePushNotification', sanitizedMessage)
      }

More detail: https://github.com/nativescript-vue/nativescript-vue/issues/376#issuecomment-479220153
Credit for the original fix goes to @rubensfernandes who found the solution in the original thread.

All 12 comments

I have no idea what could cause that. Perpaps you鈥檒l need to delay calling firebase.init a little?

@EddyVerbruggen with setTimeout 10s same error

OK. You鈥檒l need to dig around yourself a little because I can鈥檛 help you this week.

I am having the same problem. But only when the app is closed.
While the app is still running but in background the notification receiver handler is triggered properly...

@academici can I ask what your click_action is named and how the notification array is built?

I noted when I have no click_action at the correct place I can tap the notification (while app is closed) and nothing happens.

So, I fixed the array to add the click_action at 'andriod' -> 'notification' -> 'click_action'.
Previously (old variant) it was located in 'notification' -> 'click_action'

So, I think the question to you and me might be how to properly format the notification array being submitted (through firebase) to the device(s)

// working example, but with the error raised by @academici 
"notification" => array(
                "title" => $title,  //Any value 
                "body" => $message,  //Any value 
                "icon" => "fcm_push_icon"  //White icon Android resource 
            ),
            'android' => [
                'notification' => [
                    'click_action' => 'FCM_PLUGIN_ACTIVITY'
                ]
            ]

@academici I workaround this by doing a delay initialization of firebase.

So instead of firebase.init() I wait 5 sec. and then init it

setTimeout(function() { firebase.init() }, 5000);

Can you confirm this is working for you, too?

@ole1986 i did not use "click_action". With "click_action" when app is closed nothing happens when click on notification. When app is running, notifications works.
SetTimeout tried to use, same error.

Instead of adding the firebase.init() into the main.js I have added it into the first "View" being called by Vue.

so, when you have for instance

new Vue({
  render: h => h("frame", [h(App)])
}).$start();

The App should be the right place. Example

import * as firebase from "nativescript-plugin-firebase"
export default {
  created: {
    /* without setTimeout also seem to work here */
    firebase.init([...]).then([...])
  },
  [...]
}

To anyone else facing this issue, this is something that's only happening when using both nativescript-vue and nativescript-plugin-firebase, having to do with the way Vue observes value changes. The solution is to sanitize the message that you receive from the onMessageReceivedCallback handler with a simple JSON.parse(JSON.stringify(message)) before you pass it to anywhere that any NativeScript-Vue instance can access it.

      onMessageReceivedCallback: (message) => {
        // sanitize the message or the NativeScript-Vue app will crash on observing it!
        const messageString = JSON.stringify(message)
        const sanitizedMessage = JSON.parse(messageString)
        console.log('Push message received: ' + messageString)
        store.dispatch('handlePushNotification', sanitizedMessage)
      }

More detail: https://github.com/nativescript-vue/nativescript-vue/issues/376#issuecomment-479220153
Credit for the original fix goes to @rubensfernandes who found the solution in the original thread.

@AdmiralPotato would it make sense to add that to the Firebase code so users don't have to? I don't expect it to break any current behavior so I wouldn't mind.

@EddyVerbruggen I would have suggested this earlier, but I'm not yet familiar with any of the extra properties, methods, or capabilities of the returned Message object. Is there anything special, platform-specific, or otherwise inaccessible by other means that existing users would lose access to?

Perhaps the first argument returned by the handler could be a sanitized version of the Message object, to provide the most useful expected behavior, making things a little easier on everyone - and the second argument could be the original, non-sanitized Message object, if it does indeed provide any singularly unique value?

I ran into this issue as well and @AdmiralPotato 's solution worked for me

Was this page helpful?
0 / 5 - 0 ratings

Related issues

b02505048 picture b02505048  路  3Comments

ButterMeWaffle picture ButterMeWaffle  路  4Comments

Aceman18 picture Aceman18  路  3Comments

vchimev picture vchimev  路  3Comments

bunower picture bunower  路  3Comments