ngCordova/Ionic Push Notifications when application is in the background - push-notification

I'm currently building an android application using ionic/ngcordova. I'm at the point of implementing push notifications. I've implemented push notifications as a service which is injected at app.run(function(){..}) stage. The registration part works and I receive a callback containing the regid. Also, when the application is in the active state, the event is raised and the notification is received.
The problem I'm having is that when the application goes into the background, the notifications are not received at all. I would expect that a local notification would be raised when the app isn't running or something similar, but absolutely nothing happens, which is weird.
I've trawled the web for the last couple of days looking for a solution but I've been unable to find anything which kind of indicates to me that it should just work.
The following is my notificationService.js inside my app
app.factory('notificationService', ['$cordovaPush', function($cordovaPush){
var dataFactory = {};
//
// When the device is ready and this service has been plumbed in...
document.addEventListener("deviceready", function(){
console.log("initializing push notifications...");
_register();
}, false);
//
// Registers the device for push notifications...
var _register = function(){
var config = {};
if ( device.platform == 'android' || device.platform == 'Android' || device.platform == "amazon-fireos" ){
// TODO: centralise this value as it can change...
config = {
senderID: "448168747432",
ecb: "onNotificationGCM"
};
}else {
// iOS
config = {
"badge":"true",
"sound":"true",
"alert":"true"
};
// Can add the following property to the config object to raise a callback with the information if need be...
// "ecb": "onNotificationRegisterAPN"
}
$cordovaPush.register(config).then(function(result){
//
// Typically returns "ok" for android and devicetoken for iOS
console.log(result);
});
};
window.onNotificationGCM = function(result){
console.log(result);
/*
I get called when the app is in the foreground, but nothing happens when the app is in the background.
*/
};
dataFactory.register = _register;
return dataFactory;
}]);
If it helps, I'm using PushSharp via a .net application in order to deliver the notifications. Any help would be greatly appreciated.
UPDATE: I'm using the following frameworks/libs:
Ionic Framework 1.2.14-beta6
Cordova 4.2.0
PushPlugin

For anyone else who's been pulling their hair out for a couple of days like I have, the solution was really simple...I was missing two properties in my Pushsharp QueueNotification request. So using the example given on the PushSharp github repo here: https://github.com/Redth/PushSharp#sample-code
push.QueueNotification(new GcmNotification().ForDeviceRegistrationId("DEVICE-REGISTRATION-ID-HERE").WithJson("{\"alert\":\"Hello World!\",\"badge\":7,\"sound\":\"sound.caf\"}"));
Needs to be updated to add the missing properties:
push.QueueNotification(new GcmNotification().ForDeviceRegistrationId("DEVICE REGISTRATION ID HERE")
.WithJson(#"{""alert"":""This is the future"",""badge"":7,""sound"":""sound.caf"",""title"":""Status Bar title"",""message"":""Some text you want to display to the user""}"));
Otherwise if your app happens to be developed using Cordova and its not currently in the foreground, nothing, repeat nothing will happen.
Tip my hat to gdelavald with his comment on PushPlugin for pointing me in the right direction here:
https://github.com/phonegap-build/PushPlugin/issues/212

Related

Telegram WebApp sendData method doesn't work on MacOS

I am trying to figure out how to correctly work with WebApp added to Telegram API.
So, I have a simple setup of a React app and Bot. React app has counter and all I need is send counter data back to bot using sendData method.
Bot returns keyboard button, as mentioned in telegram docs with link to my web-app
private async returnButton(ctx: Context<Update>): Promise<void | object> {
ctx.reply('Enter number', Markup.keyboard([
Markup.button.webApp('Open counter', 'https://75bc-185-115-37-241.eu.ngrok.io')
]).resize())
return {};
}
Here's part of React app:
useEffect(() => {
Telegram.WebApp.ready();
Telegram.WebApp.MainButton.isVisible = true;
setDebug(Telegram.WebApp.sendData.toString());
}, [])
useEffect(() => {
Telegram.WebApp.onEvent('mainButtonClicked', () => {
Telegram.WebApp.MainButton.text = 'Clicked!';
try {
Telegram.WebApp.sendData(JSON.stringify({ counter }));
setDebug(`Sent`);
} catch (e) {
setDebug(`${e}, ${JSON.stringify(e)}`)
}
})
}, [counter])
I've added setDebug(Telegram.WebApp.sendData.toString()) just to
make sure method is present. I didn't find any good ways for debugging, as I have no
access to smth like devtools in webapp window
So below gif shows what happens when I click button on Mac client. Debug data set to Sent and no errors pops out. But modal doesn't close as it should and most importantly bot doesn't receive any data from webapp.
Though using iOS/ipadOS telegram flow works fine. Window closes and data sent to bot.
I have tried to reinstall Telegram client, but still no changes. Did I miss something or this is Mac client bug?
to get data from the main button you need to open the app with your keyboard. This will not work with an inline keyboard.

Nativescript Push Notification not triggering navigation

I'm using the Firebase plugin to create push notifications, and it works well. The idea is that I receive the notification - when I click on the notification the app opens with a dialog, and when you click on one of the options, you navigate to a page. However, when the app is minimized or closed and I receive a notification, the navigation doesn't works successfully. I'm using Nativescript 6.3.1 with Angular 8
onMessageReceivedCallback: (message: firebase.Message) => {
let meterNumber = message.data.meter;
let peid = message.data.peid;
let entid = message.data.entid;
this.mainService.listMeterNumbers(peid, true).subscribe((res) => {
let options = {
title: "Don't remind me about '" + message.data.meter + "' within -",
message: "",
cancelButtonText: "Cancel",
actions: ["1 Day", "1 Week", "1 Month", "1 Year"]
}
action(options).then((snooze)=> {
this.mainService.setMeterNotificationReminder(entid, snooze).subscribe(() => {
if(snooze !== 'Cancel') {
this.loading.navigateFromNotification = true;
this.loading.navigatedMeterNumber = meterNumber;
this.loading.navigatedMeterNumberParentEntityId = peid;
setTimeout(()=>{ // i've tried several different things here
this.ngZone.run(() => { // and here
this.loading.showNotificationList = false; // to do this - this was at first a .navigate(['newpage'], id)
});
}, 1000)
}
});
});
});
Please any help would be appreciated
There are two main states in which a push notification may be received by your application:
1.) Application is in Foreground.
2.) Application is in Background.
In the background state tho, there is a possibility that:
A. Your app is not in view (hence in the background) but is not closed and still fully running. Eg. you are on a different app.
B. Your app is not in view (still background) but is fully closed and not fully running. Only the Push Notification subscription service is running.
In your case, the reason why your code handling on onMessageReceivedCallback doesn't fully work is because the app is closed (case B) and thus some context of the code here are undefined.
For example, your this.mainService is undefined and this service might only be constructed when you run the application or the application is open.
There are various work around for this, but main thing is that on your onMessageReceivedCallback you should separate your code handling by:
if (message.foreground) {
... do stuff when app is foreground ...
}
else {
... handling if app is closed or in background. this code is executed when the user taps on the notification ...
}
You'll have to route the user to the correct page in onMessageReceivedCallback. Probably in an 'app loaded' event.
You can get more ideas here.

React Native: managing notification on RNFirebase

I have successfully implemented a basic notification feature using react-native-firebase library, everything is working as expected, information is properly received and ready to be used for a purpose I have yet to determine. My code currently look like this for the notification handling part:
componentDidMount() {
/**
* When app on foreground, rewrap received notification and re-send it as notification using channelId
* A workaround because channelId never set by default by FCM API so we need to rewrap to make sure it is
* shown on user's notification tray
*/
this.notificationListener = firebase.notifications().onNotification((notification) => {
//data object must have channelId props as a workaround for foreground notification on Android
console.log('Notif ', notification);
notification.android.setChannelId(notification.data.channelId);
firebase.notifications().displayNotification(notification);
});
//On Notification tapped, be it from foreground or background
this.notificationOpen = firebase.notifications().onNotificationOpened((notificationOpen) => {
//body and title lost if accessed from background, taking info from data object by default
const notification = notificationOpen.notification;
console.log('Open ', notification)
Alert.alert(notification.data.title, notification.data.body);
});
//When notification received when app is closed
this.initialNotification = firebase.notifications().getInitialNotification()
.then((notificationOpen) => {
//body and title lost if accessed this way, taking info from data object where info will persist
if (notificationOpen) {
const notification = notificationOpen.notification;
console.log('Initial ', notification)
Alert.alert(notification.data.title, notification.data.body);
}
});
}
componentWillUnmount() {
this.notificationListener();
this.initialNotification()
this.notificationOpen();
}
The above code let me use any information I sent from firebase console or a php server set up by my colleague from within the above scope (not sure how the server side implementation was done, but it gives me the exact same notification object on my end).
So that's good and all, but the problem is when I set badge on IOS from firebase console, the badge doesn't go away once I opened the notification.
I have been trying to figure out if there's any extra bit I have to add to the above block to programatically decrement the badge counter, but have no luck so far.
So if anyone here can show me how to manage these notification objects properly (especially explaining the nature and lifecycle of these objects -- i.e. which data on which property/method persists or is static within the scope of the notification object) on both Android and IOS, that would be greatly appreciated :)
Turns out a simple firebase.notifications().setBadge(0) on root componentDidMount() clears out the badge count whenever the app is opened.
May need to use firebase.notifications().removeAllDeliveredNotifications() or firebase.notifications().cancelAllNotifications() to remove them from notification tray too.
May be you have to set code for badge while creating a notification
this.notificationListener = firebase.notifications().onNotification((notification) => {
const localNotification = new firebase.notifications.Notification()
.setNotificationId(notification.notificationId)
.setTitle(notification.title)
.setSubtitle(notification.subtitle)
.setBody(notification.body)
.setData(notification.data)
.ios.setBadge(notification.ios.badge);
firebase.notifications()
.displayNotification(localNotification)
.catch(err => console.error(err));
}
Put this line in code .ios.setBadge(notification.ios.badge); while building a notification and try again

User based notifications with the Bluemix Push Notification service

Currently developing a Cordova app and wanted to use the IBM Bluemix Push Notification service to send user based push notifications.
According to the documentation here, seems like the first step is to call MFPPush.initialize(appGuid, clientSecret), which I tried to do. But this function is not present in the plugin interface and therefore I get an 'undefined' error when running the app.
Moreover, the doc also talks about calling MFPPush.registerDevice({},success,failure,userId). However, when I look at the plugin javascript interface, it only takes 3 parameters.
Could someone please give some advice to help me sort this out?
Thanks.
I just ran the Bluemix Cordova hellopush sample which should help you out. Make sure you follow the directions in the README, and make sure to change the route and guid in your index.js (it should look something like this):
route: "http://imfpush.ng.bluemix.net",
guid: "djkslk3j2-4974-4324-8e82-421c02ce847c",
You will be able to find the route and guid in your Push Notifications service credentials.
After running it by following the directions (and ensuring that you have GCM / APNS set up correctly for whatever platform you are using), you should be greeted with this screen after clicking register:
#johan #joe Cordova app can use the IBM Bluemix Push Notification service to send user based push notifications. Please follow the below example using BMSPush to register for Push Notifications.
// initialize BMSCore SDK
BMSClient.initialize("Your Push service region");
// initialize BMSPush SDK
var appGUID = "Your Push service appGUID";
var clientSecret = "Your Push service clientSecret";
// Initialize for normal push notifications
var options = {}
BMSPush.initialize(appGUID,clientSecret,options);
// Initialize for iOS actionable push notifications and custom deviceId
var options ={"categories":{
"Category_Name1":[
{
"IdentifierName":"IdentifierName_1",
"actionName":"actionName_1",
"IconName":"IconName_1"
},
{
"IdentifierName":"IdentifierName_2",
"actionName":"actionName_2",
"IconName":"IconName_2"
}
]},
"deviceId":"mydeviceId"
};
BMSPush.initialize(appGUID, clientSecret, options);
var success = function(response) { console.log("Success: " + response); };
var failure = function(response) { console.log("Error: " + response); };
// Register device for push notification without UserId
BMSPush.registerDevice(options, success, failure);
// Register device for push notification with UserId
var options = {"userId": "Your User Id value"};
BMSPush.registerDevice(options, success, failure);
Please go through the Bluemix Cordova Plugin Push SDK doc link.

How do I use Meteor and a Cordova BLE plugin to connect to a BLE device

I'm trying to use Meteor and this Cordova plugin -https://github.com/don/cordova-plugin-ble-central - added to my project using meteor add cordova in order to connect to a Bluetooth LE device (TI Sensortag). All I want to do to begin with is, when a link is clicked, to connect to the device and show a message.
I have the following code in the events section of my template javascript.
Template.measure.events({'click [data-action=scan-connect-stream]':
function(event, template) {
event.preventDefault();
if (Meteor.isCordova) {
Meteor.startup(function () {
ble.connect('24:09:00:DE:00:42',
function(){
alert('Connect success');
return;
},
function(){
alert('Connect failed');
return;
});
});
}
}
});
My problem is that sometimes the code works and I get a 'Connect success' alert but more often than not it it fails to connect and shows the 'Connect failed' alert. Before I added the return statements in the success and fail callbacks it didn't work at all.
I'm debugging this on an android device (meteor run android-device --verbose) and can see via adb logcat that the BLE Connect event in the Cordova plugin is firing but then doesn't connect. I get the same issue debugging on two different phones and when using a BLE device that isn't a TI Sensortag so I'm guessing this is an problem with the way the plugin is interacting with Meteor (maybe Meteor isn't waiting long enough for a success callback?).
Has anyone used this plugin successfully with Meteor or can anyone provide any clue as to what I'm doing wrong? Should I try wrapping it in a Meteor package or is there any way I can give the plugin more time to respond before the success or fail callbacks fire? Any help would be much appreciated!
For anyone who's having similar issues this is what sorted it for me. I put the ble.connect call into the success callback of the ble.scan function. Not sure why but scanning for a few seconds first does the job.
Template.measure.events({
'click [data-action=scan-connect-stream]': function(event, template) {
event.preventDefault();
if (Meteor.isCordova) {
Meteor.startup(function () {
device_id = '24:09:00:DE:00:42';
ble.scan([], 5,
function(peripherals){
connectDevice(device_id);
},
function(){
alert('No devices found');
}
);
});
}
}
});
var connectDevice = function (device_id) {
ble.connect(device_id,
function(){
alert('Device ' + device_id + ' connnected');
},
function(){
alert('Couldn\'t connect to device ' + device_id);
});
}
If anyone can explain why the ble.connect won't work on its own that'd be great!
EDIT: Looking at the Android code it seems that the plugin is designed in such a way that ble.scan has to be called before calling ble.connect. The ble.scan causes a LinkedHashMap in the Android code to be populated with any discovered devices. Only once the device is listed in the LinkedHashMap can you then connect to it using ble.connect.

Resources