Catch FCM notification message in service worker after click_action triggered - firebase-cloud-messaging

The issue, I am facing with notification messages is, that a new tab is opened, whenever the complete URL of the defined click_action is not matching any opened tab.
Assuming click_action equals mydomain.com and there is an opened tab with the URL mydomain.com/anyroute. A new tab is opened, because the URLs do not match. But I would like the already opened tab to be focused instead of opening a new tab.
Can a notification message be catched by the service worker after a user clicks on the message or is there any other possibility?
EDIT: So far, the service worker's events like onBackgroundMessage or notificationclickare not passed, since the push notification is if type notification_message.

You can use the on like explained here.
messaging.onBackgroundMessage((payload) => {
console.log(
"[firebase-messaging-sw.js] Received background message ",
payload
);
// Customize notification here
const notificationTitle = "Background Message Title";
const notificationOptions = {
body: "Background Message body.",
icon: "/firebase-logo.png",
};
// Loop trough all clients controled by the SW
self.clients.matchAll(options).then(function (clients) {
// Let's see if we already have a chat window open:
const url = new URL(client.url);
if (url.pathname == "/custom_url/") {
// Excellent, let's use it!
client.focus();
}
// do something with your clients list
});
self.registration.showNotification(notificationTitle, notificationOptions);
});
Where you can use self.clients to loop trough all tabs/clients of your app that are controled by the SW. You can focus to a specfic client if the url/patch matches.

Related

React Native How to redirect on page when click on notification

I’m using react-native-push-notification on a page with a timer. If the application is in the background after 5 minutes, I’m notified that time has passed. When I click on the notification, it goes to this page. But when I close the application completely and after 5 minutes I click on the notification, it goes to the start page. Now the question is how to make it go to this page?
//
let remainingTime = (this.state.minute * 60 + this.state.seconds) * 1000;
let date = new Date(Date.now() + remainingTime);
PushNotification.localNotificationSchedule({
message: "Message",
date,
soundName: "rush"
});
When any notification is opened or received the callback onNotification is called passing an object with the notification data.
Notification object example:
{
foreground: false, // BOOLEAN: If the notification was received in foreground or not
userInteraction: false, // BOOLEAN: If the notification was opened by the user from the notification area or not
message: 'My Notification Message', // STRING: The notification message
data: {}, // OBJECT: The push data
}
So when onNotification is triggered you can get data object and based on its value you can write your logic of redirection.
To be more clear you can have this code on your start screen or main file
var PushNotification = require('react-native-push-notification');
PushNotification.configure({
// (optional) Called when Token is generated (iOS and Android)
onRegister: function(token) {
console.log( 'TOKEN:', token );
},
// (required) Called when a remote or local notification is opened or received
onNotification: function(notification) {
console.log( 'NOTIFICATION:', notification );
// process the notification
}
});

Outlook Web App add in Dialog Api messageParent not working

I am developing a Outlook add in and was checking out the authentication flow (Microsoft login) for my app. I tried using the dialog api to achieve this but was not able to pass message from the dialog to the task pane after successful sign in.
index.js:
var fullUrl = 'https://localhost:3000/src/templates/auth.html'
Office.context.ui.displayDialogAsync(fullUrl,
{height: 40, width: 40}, function (result) {
console.log("Dialog has initialized. Wiring up events");
_dlg = result.value;
console.log(result.status);
_dlg.addEventHandler(Office.EventType.DialogMessageReceived, function(responseMessage){ console.log(responseMessage);});
});
Dialog box:
Office.initialize = function (reason) {
$(document).ready(function () {
Office.context.ui.messageParent("Message 1");
}
}
In the dialog console I get this,
outlook-web-16.01.debug.js:4587 Failed to execute 'postMessage' on
'DOMWindow': The target origin provided ('https://outlook.live.com')
does not match the recipient window's origin
('https://localhost:3000').
Any idea what could be the problem?

Service Worker - Wait for clients.openWindow to complete before postMessage

I am using service worker to handle background notifications. When I receive a message, I'm creating a new Notification using self.registration.showNotification(title, { icon, body }). I'm watching for the click event on the notification using self.addEventListener('notificationclick', ()=>{}). On click I'm checking to see if any WindowClient is open, if it is, I'm getting one of those window clients and calling postMessage on it to send the data from the notification to the app to allow the app to process the notification. Incase there is no open window I'm calling openWindow and once that completes I'm sending the data to that window using postMessage.
event.waitUntil(
clients.matchAll({ type: 'window' }).then((windows) => {
if (windows.length > 0) {
const window = windows[0];
window.postMessage(_data);
window.focus();
return;
}
return clients.openWindow(this.origin).then((window) => {
window.postMessage(_data);
return;
});
})
);
The issue I am facing is that the postMessage call inside the openWindow is never delivered. I'm guessing this is because the postMessage call on the WindowClient happens before the page has finished loading, so the eventListener is not registered to listen for that message yet? Is that right?
How do I open a new window from the service worker and postMessage to that new window.
I stumble this issue as well, using timeout is anti pattern and also might cause delay larger then the 10 seconds limit of chrome that could fail.
what I did was checking if I need to open a new client window.
If I didn't find any match in the clients array - which this is the bottle neck, you need to wait until the page is loaded, and this can take time and postMessage will just not work.
For that case I created in the service worker a simple global object that is being populated in that specific case for example:
const messages = {};
....
// we need to open new window
messages[randomId] = pushData.message; // save the message from the push notification
await clients.openWindow(urlToOpen + '#push=' + randomId);
....
In the page that is loaded, in my case React app, I wait that my component is mounted, then I run a function that check if the URL includes a '#push=XXX' hash, extracting the random ID, then messaging back to the service worker to send us the message.
...
if (self.location.hash.contains('#push=')) {
if ('serviceWorker' in navigator && 'Notification' in window && Notification.permission === 'granted') {
const randomId = self.locaiton.hash.split('=')[1];
const swInstance = await navigator.serviceWorker.ready;
if (swInstance) {
swInstance.active.postMessage({type: 'getPushMessage', id: randomId});
}
// TODO: change URL to be without the `#push=` hash ..
}
Then finally in the service worker we add a message event listener:
self.addEventListener('message', function handler(event) {
if (event.data.type === 'getPushMessage') {
if (event.data.id && messages[event.data.id]) {
// FINALLY post message will work since page is loaded
event.source.postMessage({
type: 'clipboard',
msg: messages[event.data.id],
});
delete messages[event.data.id];
}
}
});
messages our "global" is not persistent which is good, since we just need this when the service worker is "awaken" when a push notification arrives.
The presented code is pseudo code, to point is to explain the idea, which worked for me.
clients.openWindow(event.data.url).then(function(windowClient) {
// do something with the windowClient.
});
I encountered the same problem. My error was that I registered event handler on the window. But it should be registered on service worker like this:
// next line doesn't work
window.addEventListener("message", event => { /* handler */ });
// this one works
navigator.serviceWorker.addEventListener('message', event => { /* handler */ });
See examples at these pages:
https://developer.mozilla.org/en-US/docs/Web/API/Clients
https://developer.mozilla.org/en-US/docs/Web/API/Client/postMessage
UPD: to clarify, this code goes into the freshly opened window. Checked in Chromium v.66.

Showing fcm notification message in JSON format when app is killed or in background in react-native-fcm

I am using react-native-fcm library for android device. I am getting notification properly when my application is running, but when my application is in the background or killed then I am getting notification data in JSON format similarly in an image I shared here.
componentDidMount() {
// iOS: show permission prompt for the first call. later just check permission in user settings
// Android: check permission in user settings
FCM.requestPermissions().then(()=>console.log('granted')).catch(()=>console.log('notification permission rejected'));
/*FCM.getFCMToken().then(token => {
console.log('Token',token)
// store fcm token in your server
});*/
this.notificationListener = FCM.on(FCMEvent.Notification, async(notif) => {
console.log('FCM notification', notif)
this.sendRemote(notif)
});
// initial notification contains the notification that launchs the app. If user launchs app by clicking banner, the banner notification info will be here rather than through FCM.on event
// sometimes Android kills activity when app goes to background, and when resume it broadcasts notification before JS is run. You can use FCM.getInitialNotification() to capture those missed events.
// initial notification will be triggered all the time even when open app by icon so send some action identifier when you send notification
/*FCM.getInitialNotification().then(notif => {
console.log('FCM', notif)
this.sendRemote(notif)
//console.log('Initial Notification',notif)
});*/
FCM.getInitialNotification().then((notif: any) => {
// for android/ios app killed state
console.log("ifAny",notif)
if (notif) {
console.log("Any",notif)
// there are two parts of notif. notif.notification contains the notification payload, notif.data contains data payload
}
});
}
sendRemote(notif) {
var data = notif.fcm.body;
var title = notif.fcm.title;
FCM.presentLocalNotification({
title: 'App Name',
body: title,
big_text: title,
large_icon: 'ic_launcher',
priority: 'high',
sound: "default",
click_action: this.clickActions(notif),
show_in_foreground: true,
wake_screen: true,
local: true,
param: notif.notify_about,
paramData: data
});
}
notify_about:'',
fcm:{action:null,
body:"{data:'',time:''}",
color:null,
icon: '',
tag:null,
title:"Notification title"}
this is my data format which I am sending from the server.
Here I want to show only data body. But when the app is killed or in the background, it shows the complete body in the notification.And Its working fine when the app is running.

titanium appcelerator cloudpush tray notification not showing

Iam developing an application that uses push notifications.
Iam using ti.cloudpush module 3.2X and titanium sdk 3.2X
When i tries to recieve notification it deos not showing on tray.
I can read message inside application but it is not creating on notification tray.
here is my sample code
var CloudPush = require('ti.cloudpush');
CloudPush.enabled = true;
CloudPush.showTrayNotificationsWhenFocused = true;
CloudPush.showTrayNotification = true;
CloudPush.focusAppOnPush = false;
CloudPush.retrieveDeviceToken({
success : function deviceTokenSuccess(e) {
alert('Device Token: ' + e.deviceToken);
deviceToken = e.deviceToken;
},
error : function deviceTokenError(e) {
alert('Failed to register for push! ' + e.error);
}
});
CloudPush.addEventListener('callback', function(evt) {
alert(evt.payload);
//alert(JSON.stringify(evt.payload));
});
CloudPush.addEventListener('trayClickLaunchedApp', function(evt) {
Ti.API.info('Tray Click Launched App (app was not running)');
});
CloudPush.addEventListener('trayClickFocusedApp', function(evt) {
Ti.API.info('Tray Click Focused App (app was already running)');
});
Thanks in advance
Assuming you have set up the PushNotifications.subscribe correctly the default properties of this module are used until you set a property for the first time.
Because the properties are persisted to the device settings (via Titanium.App.Properties), the most recent value you set will always be used.
Do a Build > Clean to make sure you have not overwritten one of these properties by accident.
Then double check what they are set to with quick logging check -
Ti.API.log(Ti.App.Properties.getString('oneofthecloudproperties');
You should then be able to see if it's an issue with the subscribe event or how you have set the push notification properties.