Cordova-plugin-firebase: (Android) При нажатии на уведомление не запускается обратный вызов onNotificationOpen

Созданный на 21 сент. 2016  ·  28Комментарии  ·  Источник: arnesson/cordova-plugin-firebase

Кордова 6.3.1
Плагин Phonegap Firebase 0.1.12
Устройство: LG G5 с Android 6.0.1

Это код, который я использую:
`var app = {
// Конструктор приложения
инициализировать: function () {
this.bindEvents ();
},
// Связываем слушателей событий
//
// Связываем любые события, которые требуются при запуске. Общие события:
// 'load', 'deviceready', 'offline' и 'online'.
bindEvents: function () {
document.addEventListener ('deviceready', this.onDeviceReady, ложь);
},
// Обработчик событий deviceready
//
// Область действия this - событие. Чтобы вызвать «receiveEvent»
// функция, мы должны явно вызвать app.receivedEvent (...);
onDeviceReady: function () {
console.log ("Estamos en onDeviceReady");
if (navigator.connection.type == Connection.NONE) {
navigator.notification.alert («Se Requiere conexión a Internet»);
} еще {
window.FirebasePlugin.onNotificationOpen (функция (уведомление) {
console.log (уведомление);
navigator.notification.alert («Рецибидо»);
}, функция (ошибка) {
console.log (ошибка);
});
}
},

};
app.initialize (); `

Я получаю уведомления на панели задач во всех ситуациях: приложение в фоновом режиме, на переднем плане и закрыто, и когда я нажимаю на уведомление, приложение открывается в трех случаях, но обратный вызов не запускается.

Что-то не так в коде?

Заранее спасибо.

Самый полезный комментарий

Я переписал всю обработку onNotificationOpen и теперь она работает почти так, как я ожидал, а именно:

  • Уведомление поступает с клиентом в режиме «forground», открытое уведомление и onNotificationOpen вызывается в текущем клиенте (без перезагрузки)
  • Уведомление приходит с клиентом в фоновом режиме, открытое уведомление и клиент переводится в рабочий режим, и onNotificationOpen вызывается текущим клиентом (без перезагрузки)

Единственное, что осталось, - это немедленно доставить уведомление клиенту, не открывая его, если это вообще возможно (еще не изучил).

Я немного новичок в Android, поэтому могут быть внесены некоторые улучшения, но, похоже, все работает нормально, поэтому подумал, что поделюсь.

OnNotificationOpe nReceiver: onReceive теперь просто вызывает

FirebasePlugin.onBroadcastReceive(context, intent);

Изменен FirebasePlugin следующим образом

  • удалить WeakReference из callbackContext
  • добавить метод onBroadcastReceive, передает данные о намерениях в onNotificationOpen
  • добавить метод onNewIntent, передает данные о намерениях в onNotificationOpen
  • восстановил старую версию onNotificationOpen и изменил ее следующим образом

    • удалена строка WeakReference

    • Измените обратные вызовы, чтобы использовать 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-уведомления приходят, но внутри приложения не вызывается обратный вызов.
Версия 0.1.12

@voidbrain @Kibukita, пожалуйста, протестируйте последнюю версию из репо. Пытался улучшить открытое уведомление. Спасибо.

@BugsBunnyBR Я просто попробовал обновить репо до последней версии и просто протестировал ее. На 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 , вы пробовали указывать на

Установка с гитхаба частично решила проблему. Спасибо.

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

Теперь обратный вызов onNotificationOpen () вызывается, когда приложение находится в фоновом режиме.
Когда приложение находится на переднем плане, а не в документации, приходит уведомление и onNotificationOpen () не вызывается:

Приложение на переднем плане:
Пользователь получает данные уведомления в обратном вызове JavaScript без каких-либо уведомлений на самом устройстве (это нормальное поведение push-уведомлений, уведомление пользователя зависит от вас, разработчика)

Если вы отправляете push типа «уведомление» (без тела данных), уведомление не должно отображаться, когда приложение находится на переднем плане.

Извините, я не поняла. Должен ли я просто добавить раздел «данные» в мои данные уведомления?

(
    [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 (идентификатор, уведомление) отправляет уведомление, которое будет отображаться в строке состояния.

Однако мне кажется, что каждый раз, когда я получаю сообщение от FCM, в строке состояния будет отображаться уведомление.
Я не вижу никакой проверки, находится ли приложение на переднем плане, и я не вижу никаких вызовов обратного вызова. Я не разработчик Android, поэтому, возможно, я ошибаюсь, но описанное поведение подходит к этому.

Хорошо, я нашел фрагмент кода, который вызывает обратный вызов.
С последней фиксацией от BugsBunnyBR было изменение в OnNotificationOpenReceiver, которое объясняет, что arivanbastos запускает свой обратный вызов при указании на репозиторий github.

Но все же уведомление отправляется (в OnNotificationOpenReceiver и NotificationManager) только в том случае, если есть текст или заголовок (в уведомлении или в данных). Это означает, что невозможно отправить данные в ваше приложение, не получив уведомление, отправленное в NotificationManager, который показывает его в StatusBar.

@arivanbastos
Я сказал тебе что-то не так. Извини за это.
Вы пробовали указать на эту версию репо?

@packowitz и @robertarnesson . Хорошо, моя реализация ВСЕГДА * будет пытаться показать уведомление. Или будет отображаться автоматически отображаемое уведомление Firebase или одна сборка внутри onMessageReceived .
Обратный вызов onNotificationOpen будет вызываться при вызове onMessageReceived или когда уведомление имеет тела данных и уведомлений одновременно. В моем PR, который представил onNotificationOpen я пытался объяснить, что push-уведомления типа Notification не вызовут обратный вызов. Рекомендуется всегда включать тело данных и тело уведомления, чтобы плагин мог обнаруживать и запускать обратный вызов.

Я знаю, что постоянное отображение уведомления - это не стандартное поведение уведомлений Firebase.

Большинство разработчиков приложений для Android хотят, чтобы их уведомления отображались в системном трее, даже если приложение находится на переднем плане. Я знаю, что в приложениях для чата есть случаи, когда такое поведение нехорошо.
Когда я разрабатывал функцию уведомлений для Android, меня не волновали потребности приложений чата или соответствие Firebase.

Что можно сделать:
1) Разработайте флаг, который будет установлен, когда приложение открыто, говоря «эй, я хочу, чтобы вы показывали уведомление, даже когда приложение открыто», и используйте его для управления поведением. Его не нужно было бы сохранять в каком-либо хранилище, если бы приложение всегда устанавливало флаг при открытии.

2) Просто прокомментируйте эту строку и отключите уведомление, когда приложение находится на переднем плане.

_Всегда_ -> Если плагин находит «текст» или «заголовок» в теле уведомления.

@BugsBunnyBR Мне нравится идея иметь флаг для выбора поведения.
Я бы отделил NotificationManager от OnNotificationOpenReceiver, выполняя обратный вызов вашего JS-обратного вызова. Я рекомендую ввести проверку, есть ли данные в сообщении, и если да, то вызвать обратный вызов с данными.
Для уведомления хорошо бы иметь флаг.
Спасибо.

@BugsBunnyBR Я только что протестировал переключение на
Но теперь обратный вызов работает;)

То же самое и здесь, для меня версия 0.1.13 вызывает перезапуск моего приложения, когда оно находится на переднем плане. Версия 0.1.12 работает нормально.

Уведомления просто не работают разумно в репо-версии. Причина в том, что я думаю, что если 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

который заставляет клиента перезагружаться, когда доступен notificationBundle когда зарегистрирован обратный вызов onNotificationOpen поэтому клиент получает уведомление.

Я переписал всю обработку onNotificationOpen и теперь она работает почти так, как я ожидал, а именно:

  • Уведомление поступает с клиентом в режиме «forground», открытое уведомление и onNotificationOpen вызывается в текущем клиенте (без перезагрузки)
  • Уведомление приходит с клиентом в фоновом режиме, открытое уведомление и клиент переводится в рабочий режим, и onNotificationOpen вызывается текущим клиентом (без перезагрузки)

Единственное, что осталось, - это немедленно доставить уведомление клиенту, не открывая его, если это вообще возможно (еще не изучил).

Я немного новичок в Android, поэтому могут быть внесены некоторые улучшения, но, похоже, все работает нормально, поэтому подумал, что поделюсь.

OnNotificationOpe nReceiver: onReceive теперь просто вызывает

FirebasePlugin.onBroadcastReceive(context, intent);

Изменен FirebasePlugin следующим образом

  • удалить WeakReference из callbackContext
  • добавить метод onBroadcastReceive, передает данные о намерениях в onNotificationOpen
  • добавить метод onNewIntent, передает данные о намерениях в onNotificationOpen
  • восстановил старую версию onNotificationOpen и изменил ее следующим образом

    • удалена строка WeakReference

    • Измените обратные вызовы, чтобы использовать 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, но мое приложение перезапускается после открытия уведомления.

какие-нибудь Новости ?

Я не могу добиться успеха или сбоя обратного вызова onNotificationOpen на Android, используя 0.1.17. Ни отправка через API, ни GUI с полезной нагрузкой не работает. Какие-либо предложения?

Почему бы нам не создать пул-реквест с опубликованным кодом

Мне пришлось обновить onNewIntent в FirebasePlugin, чтобы отфильтровать обычные намерения запуска, поэтому мой код 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 Не могли бы вы создать gists со всеми имеющимися у вас файлами?

Хорошо, вот это 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 в качестве параметра и выполнить перенаправление вручную (я использовал cordova с приложением реакции).

Была ли эта страница полезной?
0 / 5 - 0 рейтинги

Смежные вопросы

ghost picture ghost  ·  3Комментарии

stephan-nordnes-eriksen picture stephan-nordnes-eriksen  ·  5Комментарии

rolinger picture rolinger  ·  5Комментарии

merbin2012 picture merbin2012  ·  4Комментарии

chrissterling picture chrissterling  ·  3Комментарии