I've been struggling with this for a few days and am stuck. I am using Azure Mobile Services and have two scheduler scripts defined. One is very simple and just sends all device tokens for User ID #1 a test push notification:
function SendTestNotification() {
sendPushNotification(1, 'SendTestNotification # ' + new Date());
function sendPushNotification(userId, body) {
var users = tables.getTable('NotificationTokens');
users.where({
User_Id: userId
}).read({
success: function(tokens) {
tokens.forEach(function(token) {
var alert = {
badge: 0,
alert: body,
sound: 'default'
};
push.apns.send(token.Token, alert,
{
error : function(err) {
console.error(err);
}
});
});
},
error: function(error) {
console.error(error)
return;
}
});
}
}
I have a second scheduler script which is much more elaborate and contains the actual push notification logic for my app. It contains the exact same sendPushNotification() function shown above. This 2nd script also contains an additional call to send me a "test" notification.
So all told, with these two scripts setup and scheduled, my iOS devices should get a total of 3 push notifications every 15 minutes. I have them timestamped as well so that they show when the notification was sent from the server.
However, when I run these scripts either manually or just let them run on their own every 15 minutes, I almost never get all of the notifications. Sometimes I get none. Sometimes I only get the first test notification. Sometimes I get the first test notification, the "real" notification, but not the 2nd test notification (which should have been sent by the exact same code that sent the "real" notification).
I have checked the logs on the portal and there are no errors coming back from APNS. I know the logging is working as I've seen errors for invalid device tokens in the past.
I should also state that I've sent these devices push notifications via APNS using a simple C# application with absolutely no problem.
Can anyone give any suggestions or see what I may be doing wrong? I have an app waiting to be reviewed and would love to get this issue taken care of.
Last time this happened to me I changed the scale from Free to Basic, and all notification were sent.
You said that there is no error, but just remember, if an error occurs you have to start over again from the point you stopped because the apns close the connection once an error occurs.
Related
My app is implemented in React Native and is using Firebase for notifications. We have webhooks on the web app that are triggered on certain events. Those webhooks then send a request to the respective Firebase Cloud Function. With information from the request's header they get the topic they must send the notification to; from the request's body it gathers the information to be sent as data to the device. They are sent as data notifications only, the handler (using the React Native FCM API) then shows a local notification already translated with i18n using the react-native-push-notifications package. Everything works fine until I hit the weird situation described below.
Everything was doing alright both on Android and iOS until I launched the app on Test Flight for internal testing and then it stopped working after some time on iOS. Eventually, I noticed that when more than one iPhone subscribed to the same topic it eventually lead to inconsistencies in the delivery of the data notifications. The first iPhone to subscribe to the topic usually worked, the others didn't, the first one most of the time eventually stopped working as well or sometimes it just kept working while the others still didn't. I used the Firebase Console to send some test notification to the subscribed devices and it they actually received it. I then changed my Cloud Functions' code to avoid sending any data and just send some example body and title and it turns out the problem was here. As soon as I send something through the data field in the admin.messaging.Message object to be sent as argument to the admin.messaging().send method, they aren't received by the iPhone devices subscribed to the topic (or it's received by one or two max, the first ones to currently subscribe to the topic. But they usually stop receiving them after a while as well).
This is really really weird and being so inconsistent makes it practically impossible to debug with my current knowledge. Some things to keep in mind:
All Android devices still receive the notifications without a problem
I've watched the iPhone's console through Xcode to see if there was some error when processing the notification, in case they were actually getting the notification but they it failed before it was shown to the user. But nothing is logged by the SpringBoard process, making me conclude the notifications aren't actually getting to the device
I've manually sent notifications with cURL to APNs (with this guide). They were received fine
All notifications without data, regardless of the iOS specific apn headers, payload, etc, are received
What can be the cause of the problem? Or there's something in my code causing this strange behavior (which I doubt, since it works fine on Android and works fine in iOS as well on specific scenarios), there's some type of bug on Firebase's side causing some notifications to not be sent or, finally, there's some error on Apple's APNs side causing this. Highly doubt the last one, if the fault lays on any exterior factor it probably should be on Firebase's handling of topics.
Really would appreciate some help. Thanks in advance. Sorry If I didn't gave enough information, I actually never had the need to do a question on Stack Overflow. I'll leave below an example of a cloud function as well.
exports.orderPending = functions
.region("europe-west2")
.https.onRequest((req, res) => {
if (req.method == "POST") {
res.status("200").send("Webhook successful");
const topic = req.headers["code"];
const message = {
data: {
id: JSON.stringify(req.body.order.id),
event: "orderPending",
order: JSON.stringify(req.body.order),
},
topic,
android: {
priority: "high",
},
apns: {
payload: {
aps: {
contentAvailable: true,
},
},
headers: {
"apns-push-type": "background",
"apns-priority": "5",
"apns-topic": "APP BUNDLE ID HERE",
},
},
};
functions.logger.log(req.body.order.id);
functions.logger.log(topic);
admin.messaging().send(message)
.then((response) => {
console.log("Successfully sent message: ", response);
})
.catch((error) => {
console.log("Error sending message: ", error);
});
}
});
Turns out the data payload was exceeding the 4KB APNs limit but since when you send by topic it doesn't show any errors at all I had no way of knowing. So yeah, add this to your checklist
Im trying to find a way to de-authorise users for push notifications when they log out from an app Ive found this function UIApplication.shared.unregisterForRemoteNotifications() which aparently works however I never see notifications being disabled, I also read in the documentation that it should not be used often or something to that effect, I basically want to have a toggle button in my app where the user clicks it one way and gets the standard enable notifications popup and another way to disable notifications on the fly, Im not a native swift developer so any pointers welcome
Also is it possible to attach a callback to this to know if it executes successfully, Im trying the following but get the error Argument passed to call that takes no arguments
UIApplication.shared.unregisterForRemoteNotifications() { (result, error) in
if let error = error {
call.error("Error", error)
} else if let result = result {
call.success([
"deregister": true
])
}
}
Edit: I found this which says its not possible to toggle on and off Change push notifications programmatically in Swift
With that in mind does this mean that the standard for devices is that:
1) when a user log out of their account they can still receive notifications.
2) When a user creates a new account on the same app it uses the same token and so receives notifications from the old account ?
3) when a user sells their phone and another guy/gal downloads the same app that they will receive notifications from that other users account (in terms of 3rd party push service one signal, aparently you dont need to refresh the player id)
I am having an issue with Parse Push on AWS. We have the adapter configured per these specifications and can seem to broadcast to one specific user (don't know how or why that user) using the curl method, but I am confused how (or if) I can use this to send user to user push notifications. For example, "X liked Y's Z" Where X is the liker, Y is the liked and Z is the object being liked.
in parse you have multiple options to send push notifications.
Push notifications can be sent to one or more users by providing a query with all the installations that you like to send the push to. You can also send push notifications for specific channel that the user subscribed to, this is very good for marketing or maybe if your app have different type of users (for example: sellers, buyers etc.)
The reason that a push is being sent to installations and not to users is because that one users can have multiple installations (e.g. iphone,ipad,other device etc.)
like i said there are multiple options to send push but i recommend to send a push using one of the following approaches:
From cloud code - you can create cloud code function that will be triggered by the client and this cloud code function will first create a query of all the installations that you need to send the push to and will execute the function that will actually send the push. This cloud code function can receive multiple parameters that can contain any data that needs to be processed before you sending the push, such data can be array of users, channel name and more.
the following cloud code snippets show how to send a push for all users who successfully subscribed and have device token:
Parse.Cloud.afterSave("SendPush", function(request) {
var query = new Parse.Query(Parse.Installation);
query.exists("deviceToken");
var payload = {
alert: "after save push"
};
Parse.Push.send({
data: payload,
where: query
}, {
useMasterKey: true
})
.then(function() {
response.success("Push Sent!");
}, function(error) {
response.error("Error while trying to send push " + error.message);
});
});
and then from your iOS SDK you call this cloud code function in the following way:
NSDictionary * parameters = # {}; // put parameters if required
[PFCloud callFunctionInBackground: #"SendPush"
withParameters: parameters block: ^ (id _Nullable object, NSError * _Nullable error) {
// callback result
}
];
From iOS SDK - if you don't want to send your push from cloud code you can do it directly from your iOS. I think it's better to do it in cloud code because in cloud code you write ones and then you can trigger this function from any SDK and also from the REST API.
In Parse docs you can find a lot of examples on how to send push from iOS SDK all the examples can be found here:
http://parseplatform.github.io/docs/ios/guide/#push-notifications
but like i said the best is to do it with cloud code.
Answer is similar if you're using AWS services without Parse. A better architecture is where the mobile device invokes business logic in the cloud (i.e., in an AWS Lambda function) and that code sends the push notifications. This allows you to build a more secure solution because you can control content and control who can send to whom (i.e., you must be on someone's friend list to send) within your business logic. If you open permissions to publish directly from the device, then you make system vulnerable to attacks where someone uses the app's credentials and publishes harmful content (potentially to all your app's users).
Example of sending push notification from an AWS Lambda function...
Can you send SNS push notification from lambda function in Amazon AWS?
I have spent hours deleting certificates and remaking them. I've followed this tutorial https://developers.arcgis.com/en/geotrigger-service/guide/ios-push-notifications/ many times and I still cannot get push notifications to work. I was using the geoloqi.com API but they were bought by esri and just released a new api. I had push working with geoloqi.
The only thing questionable about that tutorial is where it says "Paste the pem file in the box" I just copied from finder and pasted it like it said but it's weird because usually there's a browse for file button and then you upload. I don't know, thats probably not the problem but I thought I'd bring it up.
With this test code:
[[AGSGTApiClient sharedClient] postPath:#"device/notify"
parameters:#{#"text": #"Push notifications are working!", #"url": #"http://developers.esri.com"}
success:^(id res) {
NSLog(#"device/notify success: %#", res);
}
failure:^(NSError *err) {
NSLog(#"device/notify failure: %#", err.userInfo);
}];
I get:
device/notify success: {
devices = {
TKhqTzrTSQI0DGBa = queued;
};
But I never receive the push. Does anybody have a suggestion I can try next because I am lost?
The first thing you'll want to check is whether you have the proper certificates configured for your application. The best way to do this is completely outside the Geotrigger API so that it's not adding more steps to the mix. There are any number of ways you can do this, but we have also written a guide you can follow here: https://github.com/Esri/pushlet/tree/master/client
If you are familiar with Node.js, you can run the Pushlet server yourself and send test notifications to your device. If you are not familiar with Node.js, you can follow the first two steps, Set up the Certificates and Test the Connection.
Once you have verified you are not getting any SSL errors communicating with APNS, and you have verified you can use the certificates to send a push notification to your device directly, if you're still having trouble with sending a push notification through the Geotrigger API, you can contact our support at geotrigger-support#esri.com.
Was not able to figure out how to get hold of the launch options (if its even possible). Want to understand how to figure out the app launch mechanism - that is to say whether the app was launched by the user directly, or because of a notification. It would even be helpful when using the new Safari smart app banners.
Anybody with similar problem ? Any workaround or solutions to this ?
Cheers!
I use this code to find out if my Trigger.io app was opened by a Parse push notification:
var appLastResumed = new Date();
window.forge.event.appResumed.addListener(function() {
window.appLastResumed = new Date();
// additional code that runs when the app is resumed
});
window.forge.event.messagePushed.addListener(function() {
// this event fires every time a user clicks on a push notification
// no matter whether the app is already opened or not
// so we need to detect whether this happened right after an appResumed event
setTimeout( function() { // make sure the appResumed event is fired first
if (new Date().getTime() - window.appLastResumed.getTime() < 1000) {
// app was opened by a push notification
// insert your code here
}
}, 50);
});
You can detect when the app has been opened by a push notification or using a custom url.
1) Push notifications - use our event module in conjunction with our integration with Parse to write codes that runs when a push notification is received with the app open, or when it is opened by a push:
http://docs.trigger.io/en/v1.4/modules/event.html#messagepushed-addlistener
2) Custom urls - use our urlhandler module to assign a listener:
http://docs.trigger.io/en/v1.4/modules/urlhandler.html