Cordova-plugin-firebase: (Android) 点击通知不会触发 onNotificationOpen 回调

创建于 2016-09-21  ·  28评论  ·  资料来源: arnesson/cordova-plugin-firebase

科尔多瓦 6.3.1
Phonegap Firebase 插件 0.1.12
设备: LG G5 与 Android 6.0.1

这是我正在使用的代码:
`var app = {
// 应用程序构造器
初始化:函数(){
this.bindEvents();
},
// 绑定事件监听器
//
// 绑定启动时需要的任何事件。 常见事件有:
// “加载”、“设备就绪”、“离线”和“在线”。
绑定事件:函数(){
document.addEventListener('deviceready', this.onDeviceReady, false);
},
// 设备就绪事件处理程序
//
// 'this' 的作用域是事件。 为了调用'receivedEvent'
// 函数,我们必须显式调用'app.receivedEvent(...);'
onDeviceReady: 函数 () {
console.log ("Estamos en onDeviceReady");
if (navigator.connection.type == Connection.NONE) {
navigator.notification.alert('Se requiere conexión a Internet');
} 别的 {
window.FirebasePlugin.onNotificationOpen(function(notification) {
控制台日志(通知);
navigator.notification.alert(“Recibido”);
}, 函数(错误){
控制台日志(错误);
});
}
},

};
app.initialize();`

我在所有情况下都在系统托盘中收到通知:应用程序在后台,前台和关闭,当我点击通知时,在三种情况下应用程序打开但未触发回调。

代码有什么问题吗?

提前致谢。

最有用的评论

我已经重新编写了整个onNotificationOpen处理,并且几乎可以按我的预期工作,即:

  • 通知与前台的客户端一起到达,打开通知并在当前客户端中调用onNotificationOpen (无需重新加载)
  • 通知在后台与客户端一起到达,打开通知并将客户端置于前台,并使用当前客户端调用onNotificationOpen (无需重新加载)

剩下的唯一一件事就是让通知立即发送给客户端,而无需打开,如果可能的话(还没有研究过)。

我是一个 Android 菜鸟,所以可能会有一些改进,但它似乎工作正常,所以我想我会分享。

OnNotificationOpe nReceiver:onReceive现在只需调用

FirebasePlugin.onBroadcastReceive(context, intent);

FirebasePlugin更改如下

  • 从 callbackContext 中删除 WeakReference
  • 添加 onBroadcastReceive 方法,将意图数据传递给 onNotificationOpen
  • 添加 onNewIntent 方法,将意图数据传递给 onNotificationOpen
  • 恢复旧版本的 onNotificationOpen 并修改如下

    • 删除弱参考线

    • 更改回调以使用 PluginResult 并在结果上调用 setKeepCallback(true) 以防止回调在第一次调用后被删除

    private static CallbackContext callbackContext;
    // ...
    private void registerOnNotificationOpen(final CallbackContext callbackContext) {
        FirebasePlugin.callbackContext = callbackContext;
    }

    // called when in foreground
    public static void onBroadcastReceive(Context context, Intent intent) {
        Log.d("FirebasePlugin", "onBroadcastReceive");
        Bundle data = intent.getExtras();
        FirebasePlugin.onNotificationOpen(data);
    }

    // called when in background
    <strong i="32">@Override</strong>
    public void onNewIntent(Intent intent) {
        Log.d(TAG, "new intent " + intent);
        super.onNewIntent(intent);
        FirebasePlugin.onNotificationOpen(intent.getExtras());
    }

    public static void onNotificationOpen(Bundle bundle) {
        if (FirebasePlugin.callbackContext == null ) {
            Log.d("FirebasePlugin", "no callback context, onNotificationOpen ignored");
            return;
        }
        if (callbackContext != null && bundle != null) {
            JSONObject json = new JSONObject();
            Set<String> keys = bundle.keySet();
            for (String key : keys) {
                try {
                    json.put(key, bundle.get(key));
                } catch (JSONException e) {
                    Log.d("FirebasePlugin", "onNotificationOpen: json exception");
                    PluginResult result = new PluginResult(PluginResult.Status.JSON_EXCEPTION, e.getMessage());
                    result.setKeepCallback(true);
                    callbackContext.sendPluginResult(result);
                    return;
                }
            }
            Log.d("FirebasePlugin", "onNotificationOpen: send notification to javascript");
            PluginResult result = new PluginResult(PluginResult.Status.OK, json);
            result.setKeepCallback(true);
            callbackContext.sendPluginResult(result);
        }
    }

所有28条评论

同样的问题,在 android 通知到达但在应用程序内部没有调用回调。
v. 0.1.12

@voidbrain @Kibukita请从 repo 测试最新版本。 我试图改进打开通知。 谢谢。

@BugsBunnyBR我只是尝试更新到最新版本的 repo 并对其进行了测试。 在 Android 上它仍然没有执行 onNotificationOpen。

@superheroben ,您能否提供一个存储库,其中包含您如何调用插件代码的示例? 你是如何发送通知的? 我用主题消息进行了测试。

同样的问题在这里。
调用 getInstanceId() 回调,通知到达,但从未调用 onNotificationOpen()。

客户代码:

if (window.FirebasePlugin)
{
  window.FirebasePlugin.getInstanceId(
    function(token) {
        thiss.saveToken(token);
    }, 
    function(error) {
        console.log(error);
    }
  );

  window.FirebasePlugin.onNotificationOpen(
    function(notification) {                  
      alert("Yeah!!!");                  
    }, 
    function(error) {
      alert("Error!");
      console.error(error);
    }
  );

  window.FirebasePlugin.grantPermission();
}

我的通知数据结构:

(
    [to] => (device token)
    [notification] => Array
        (
            [title] => Title
            [text] => Test message
            [sound] => default
            [vibrate] => 1
            [badge] => 2
        )
)

我的服务器端代码(PHP):

$jsonData = json_encode($data);

$ch     = curl_init("https://fcm.googleapis.com/fcm/send");
$header = array(
    'Content-Type: application/json',
    "Authorization: key=".MY_GCM_API_KEY
);

curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
curl_setopt( $ch,CURLOPT_SSL_VERIFYPEER, true);
curl_setopt( $ch,CURLOPT_RETURNTRANSFER, true );

curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $jsonData);

$result = curl_exec($ch);
curl_close($ch);

在 Cordova Android 5.2.2 上工作。 用于测试的设备运行 Android 4.4.2。 插件版本 0.1.12。

@arivanbastos ,您是否尝试过指向 github 存储库?

从github安装部分解决了这个问题。 谢谢你。

cordova plugin remove cordova-plugin-firebase
cordova plugin add https://github.com/arnesson/cordova-plugin-firebase/

现在,当应用程序在后台时调用 onNotificationOpen() 回调。
当应用程序处于前台时,而不是文档说明,通知到达并且不调用 onNotificationOpen():

应用程序在前台:
用户在 JavaScript 回调中收到通知数据,设备本身没有任何通知(这是推送通知的正常行为,由您作为开发人员来通知用户)

如果您发送“通知”类型(没有数据主体)的推送,则当应用程序处于前台时,不应显示通知。

对不起,我没看懂。 我应该在我的通知数据中添加一个“数据”部分吗?

(
    [to] => (device token)
    [notification] => Array
        (
            [title] => Title
            [text] => Test message
        )
    [data] => Array
        (
            [test] => 1
        )
)

这并没有解决问题。

通过“数据”重命名“通知”部分会使应用程序在通知到达时崩溃(“应用程序已停止”):

(
    [to] => (device token)
    [data] => Array
        (
            [title] => Title
            [text] => Test message
        )
)

https://firebase.google.com/docs/cloud-messaging/android/receive
这里描述的很好。
如果应用程序在后台,您的通知将发送到系统托盘,如果应用程序在前台,您的通知将发送到 onMessageReceived()。
如果您的消息包含数据,则始终将其传递给 onMessageReceived()。

我觉得是onMessageReceived()的实现有问题。
当我查看代码时,我解释如下:

  • 提取数据
  • 使用 NotificationBuilder 构建通知
  • 通过 NotificationManager 通知

NotificationManager.notify(id, notification) 发布要在状态栏中显示的通知。

然而,对我来说,这似乎是预期的,每次我收到来自 FCM 的消息时,它都会在状态栏中显示一条通知。
我没有看到任何检查应用程序是否在前台,也没有看到对回调的任何调用。 我不是 Android 开发人员,所以也许我错了,但所描述的行为符合这一点。

好的,我找到了调用回调的代码段。
随着 BugsBunnyBR 的最后一次提交,OnNotificationOpenReceiver 发生了变化,这解释了 arivanbastos 在指向 github 存储库时执行他的回调。

但是,如果有文本或标题(在通知或数据中),通知只会发送(到 OnNotificationOpenReceiver 和 NotificationManager)。 这意味着不可能在不将通知发送到 NotificationManager 的情况下将数据发送到您的应用程序,该通知在状态栏中显示它。

@arivanbastos
我对你说错了。 对于那个很抱歉。
你试过指向这个 repo 版本吗?

@packowitz@robertarnesson 。 好的,我的实现将始终*尝试显示通知。 或者 Firebase 自动显示的通知或onMessageReceived的一个构建将被显示。
onMessageReceived被调用或通知同时具有数据和通知正文时,将调用onNotificationOpen回调。 在我介绍onNotificationOpen公关中,我试图解释通知类型的推送通知不会触发回调。 建议始终包含数据主体和通知主体,以便插件可以检测并触发回调。

我知道,总是显示通知不是标准的 Firebase 通知行为。

大多数 Android 应用程序开发人员希望他们的通知显示在系统托盘中,即使应用程序在前台也是如此。 我知道在某些情况下,例如聊天应用程序,这种行为不是一件好事。
当我开发 Android 通知功能时,我并不关心聊天应用程序的需求或遵守 Firebase。

可以做的是:
1)开发一个在应用程序打开时设置的标志,说“嘿,我希望你即使在应用程序打开时也显示通知”并用它来控制行为。 如果应用程序在打开时始终设置标志,则不需要将其保存在任何存储中。

2)只需注释此并在应用程序处于前台时禁用通知。

_Always_ -> 如果插件在通知正文中找到“文本”或“标题”。

@BugsBunnyBR我喜欢有一个标志来选择行为的想法。
我会将 NotificationManager 与回调您的 JS 回调的 OnNotificationOpenReceiver 分离。 我的建议是引入一个检查,如果消息中有数据,如果有,则使用数据调用回调。
对于通知,最好有标志。
谢谢你。

@BugsBunnyBR我刚刚测试切换到 github 存储库,发现点击通知会重新启动我的应用程序,即使它已经在运行。 即使应用程序在前台并且我点击通知也会发生。
但回调现在有效;)

同样在这里,对我来说,版本 0.1.13 导致我的应用程序在前台时重新启动。 0.1.12 版本运行良好。

通知在 repo 版本中无法正常工作。 原因是我认为,如果在打开通知之前调用onNotificationOpen ,它会被忽略。

https://github.com/arnesson/cordova-plugin-firebase/blob/master/src/android/FirebasePlugin.java#L123

registerOnNotificationOpen ,如果有notificationBundle等待,它只会注册回调

此外,如果已经打开,应用程序似乎重新加载的原因在OnNotificationOpenReceiver它明确指出

launchIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);

https://github.com/arnesson/cordova-plugin-firebase/blob/master/src/android/OnNotificationOpenReceiver.java#L17

这会强制客户端重新加载,当onNotificationOpen回调注册时notificationBundle可用时,客户端会收到通知。

我已经重新编写了整个onNotificationOpen处理,并且几乎可以按我的预期工作,即:

  • 通知与前台的客户端一起到达,打开通知并在当前客户端中调用onNotificationOpen (无需重新加载)
  • 通知在后台与客户端一起到达,打开通知并将客户端置于前台,并使用当前客户端调用onNotificationOpen (无需重新加载)

剩下的唯一一件事就是让通知立即发送给客户端,而无需打开,如果可能的话(还没有研究过)。

我是一个 Android 菜鸟,所以可能会有一些改进,但它似乎工作正常,所以我想我会分享。

OnNotificationOpe nReceiver:onReceive现在只需调用

FirebasePlugin.onBroadcastReceive(context, intent);

FirebasePlugin更改如下

  • 从 callbackContext 中删除 WeakReference
  • 添加 onBroadcastReceive 方法,将意图数据传递给 onNotificationOpen
  • 添加 onNewIntent 方法,将意图数据传递给 onNotificationOpen
  • 恢复旧版本的 onNotificationOpen 并修改如下

    • 删除弱参考线

    • 更改回调以使用 PluginResult 并在结果上调用 setKeepCallback(true) 以防止回调在第一次调用后被删除

    private static CallbackContext callbackContext;
    // ...
    private void registerOnNotificationOpen(final CallbackContext callbackContext) {
        FirebasePlugin.callbackContext = callbackContext;
    }

    // called when in foreground
    public static void onBroadcastReceive(Context context, Intent intent) {
        Log.d("FirebasePlugin", "onBroadcastReceive");
        Bundle data = intent.getExtras();
        FirebasePlugin.onNotificationOpen(data);
    }

    // called when in background
    <strong i="32">@Override</strong>
    public void onNewIntent(Intent intent) {
        Log.d(TAG, "new intent " + intent);
        super.onNewIntent(intent);
        FirebasePlugin.onNotificationOpen(intent.getExtras());
    }

    public static void onNotificationOpen(Bundle bundle) {
        if (FirebasePlugin.callbackContext == null ) {
            Log.d("FirebasePlugin", "no callback context, onNotificationOpen ignored");
            return;
        }
        if (callbackContext != null && bundle != null) {
            JSONObject json = new JSONObject();
            Set<String> keys = bundle.keySet();
            for (String key : keys) {
                try {
                    json.put(key, bundle.get(key));
                } catch (JSONException e) {
                    Log.d("FirebasePlugin", "onNotificationOpen: json exception");
                    PluginResult result = new PluginResult(PluginResult.Status.JSON_EXCEPTION, e.getMessage());
                    result.setKeepCallback(true);
                    callbackContext.sendPluginResult(result);
                    return;
                }
            }
            Log.d("FirebasePlugin", "onNotificationOpen: send notification to javascript");
            PluginResult result = new PluginResult(PluginResult.Status.OK, json);
            result.setKeepCallback(true);
            callbackContext.sendPluginResult(result);
        }
    }

嗯......我注意到当客户端没有运行(已被杀死)时,通知没有发送(到设备)。

尝试直接打开 firebase 提供的通知并查看行为。我猜他们重新启动了我认为是正确行为的主要活动。

抱歉耽搁了。 我尝试了 0.1.13,但我的应用程序在通知打开后重新启动。

任何新闻 ?

我无法在使用 0.1.17 的 android 上获得任何 onNotificationOpen 回调成功或失败。 使用有效负载通过 API 或 GUI 发送都不起作用。 有什么建议?

为什么我们不用@Mehuge发布的代码创建一个拉取请求?它对我来说就像 android 上的魅力一样。

我不得不更新 FirebasePlugin 中的 onNewIntent 以过滤掉正常的启动意图,所以我的 onNewIntent 代码现在看起来像这样

<strong i="6">@Override</strong>
public void onNewIntent(Intent intent) {
  Log.d(TAG, "new intent " + intent);
  super.onNewIntent(intent);
  Bundle data = intent.getExtras();
  if (data != null) {
    String id = data.getString("id");
    if (null != id) {
      FirebasePlugin.handleNotificationBundle(data);
    } else {
      Log.d(TAG, "Not a notification intent, ignored");
    }
  }
}

我对此并不完全满意。 它通过在我的服务器代码总是发送的意图包中查找 id 属性来工作。 似乎没有任何 GCM 或 FBM 可靠地添加到包中可用于将意图识别为通知/消息的内容。 有时我们会添加一些 google 属性(如果我们从托盘打开通知)但是对于在前台时直接传递给客户端的消息和通知,除了消息中的数据告诉您这是一个启动意图之外别无其他由于通知,至少我可以看到。

可能有更好的方法来处理这个问题。

@Mehuge你介意用你拥有的所有文件创建

好的,这里是https://gist.github.com/Mehuge/374ee24d9e18a6c7ccc171d3e521b7ad

但是请注意,其中有一些特定于我们的应用程序的位。 我最终将代码移到了我们的项目中,因为我对其进行了大量更改。 事后看来,我可能应该对插件进行分叉并以这种方式对其进行修改,但此时,我已经落后于计划并且对整个事情感到非常厌烦,所以我采取了最快的方式来让一些东西工作。 自定义位相当明显,因此应该很容易排除。

另请注意,我实现插件的方式,它需要知道客户端何时暂停(或更具体地说是未暂停),以便它可以决定是创建通知还是直接传递消息。 您可能需要也可能不需要该功能,但在我们的例子中,我们不希望客户端在前台时发送的通知来创建 android 通知,而是直接传递给客户端进行处理。 要通知插件客户端的暂停状态,请将以下代码添加到您的主要活动中。

<strong i="9">@Override</strong>
protected void onResume() {
    FirebasePlugin.setPaused(false);
    super.onResume();
}

<strong i="10">@Override</strong>
protected void onPause() {
    FirebasePlugin.setPaused(true);
    super.onPause();
}

您可能需要解决另一个问题,即如果通知在后台到达但用户直接启动应用程序,而不是通过打开 android 通知,您可能需要以某种方式处理该问题。 在我们的应用程序案例中,我可以清除任何未打开的通知。 您的情况可能有所不同。

我对最终结果并不完全满意,例如添加的一些额外键是实验性的,实际上并没有被使用,我只是没有时间删除它们。

会对任何反馈或建议的改进或指出任何缺陷感兴趣。 我特别感兴趣的是找到一种方法来更好地检测来自正常发射的 GCM 有效载荷的发射意图。 我发现 google 属性仅在某些情况下添加。 此外,我尝试检测不同类型的通知(is_push、is_notify、broadcast)并没有真正奏效。

见#108

对我来说,我可以解决提出这样的请求:

{
  "registration_ids": [...tokens],
  "notification" : {
        "title": "Notf title",
        "body": "Notification body"
     },
     "data": {
        "click_action": "/call/dwEugLJ9PTVdcFb064CX"
     }
}

但是我不得不将 click_action 作为参数并手动进行重定向(我使用的是带有 react 应用程序的cordova)。

此页面是否有帮助?
0 / 5 - 0 等级

相关问题

rolinger picture rolinger  ·  3评论

dhavalsoni2001 picture dhavalsoni2001  ·  5评论

ghost picture ghost  ·  3评论

jdla1990 picture jdla1990  ·  4评论

arunkatariaoodles picture arunkatariaoodles  ·  4评论