iOS Push notifications failing on Azure app - ios

i have a ASP.NET Web API hosted as app on Azure and one of the APIs is to send notifications to users on iOS.
i am facing a strange issue on Azure. Sometimes the push notifications work and randomly stop after. I am using PushSharp and not NotificationHub or anything.
the code basically loops over device tokens and makes calls to APNS.
this seems to work fine locally but fails on Azure.
any ideas what i am missing? the error just says multiple errors.
thanks in advance.
var broker = new ApnsServiceBroker(config);
broker.OnNotificationFailed += (notification, exception) =>
{
callback(new Result { status = "FAIL", message = exception.Message });
Console.WriteLine("failed");
};
broker.OnNotificationSucceeded += (notification) =>
{
callback(new Result { status = "Success", message = "" });
Console.WriteLine("pass");
};
broker.Start();
broker.QueueNotification(new ApnsNotification
{
DeviceToken = userDeviceToken,
Payload = JObject.Parse("{ \"aps\" : { \"alert\" : \"" + message + "\", \"sound\":\"default\", \"badge\":0 },\"notification\":" + json + " }")
});
broker.Stop();

Related

How to prepare APN for production

Im trying to deploy my app with notifications but it's giving me the biggest headache in the world. All other questions ive seen with regards to this seem outdated.
I set up APNs to be sent from a nodeJS script that I have running. When running in my sandbox everything was working well. As soon as I sent my app to TestFlight, notifications stopped sending. My script is still Successfully sending to the Notification Id registered with my phone but im assuming its not the correct production Id. If anyone canhelp get me sending production notifications it would be greatly appreciated! Thank you
APN Server code
var options = {
token: {
key: "AuthKey_6V27D43P5R.p8",
keyId: "3Z6SEF7GE5",
teamId: "ASQJ3L7765"
},
production: true
};
var apnProvider = new apn.Provider(options);
function SendIOSNotification(token, message, sound, payload, badge){
var deviceToken = token; //phone notification id
var notification = new apn.Notification(); //prepare notif
notification.topic = 'com.GL.Greek-Life'; // Specify your iOS app's Bundle ID (accessible within the project editor)
notification.expiry = Math.floor(Date.now() / 1000) + 3600; // Set expiration to 1 hour from now (in case device is offline)
notification.badge = badge; //selected badge
notification.sound = sound; //sound is configurable
notification.alert = message; //supports emoticon codes
notification.payload = {id: payload}; // Send any extra payload data with the notification which will be accessible to your app in didReceiveRemoteNotification
apnProvider.send(notification, deviceToken).then(function(result) { //send actual notifcation
// Check the result for any failed devices
var subToken = token.substring(0, 6);
console.log("Succesfully sent message to ", subToken);
}).catch( function (error) {
console.log("Faled to send message to ", subToken);
})
}

Ajax request fail over https on iOS browser but not through http

Hi thanks in advance for the help.
We're running a mobile web app that has been working fine on all browsers when it originally went live earlier this year.
About the app:
Running on IIS 8.5.
Certificate is from LetsEnctrypt.org
REST web service is running on .NET Web API 2.
Front end is AngularJS
Sample Ajax Call:
$http.post('/api/User/Validate', loginData)
.then(function (response) {
alert("_login.Success: " + JSON.stringify(response, null, 4));
if (response.data.StatusCode == 200) {
//console.log("Successfult Validate" + response);
var token = response.data.Data[0].Token;
var authData = {
token: token.TokenStr,
expiryDate: token.ExpiryDate,
companyId: response.data.Data[0].CompanyId,
userId: response.data.Data[0].UserId
};
_setAuthData(authData);
deferred.resolve(response.data);
}
else {
console.log("Error while validating ", response);
deferred.resolve(response.data);
}
}, function (err, status) {
alert("_login.Error: " + JSON.stringify(err, null, 4) + " " + status);
_logOut();
deferred.reject(err);
});
I've added debug logging to troubleshoot this and i see the request hit that backend without any errors that i can see but when the browser gets the request the error callback function gets executed instead of the success one. If i try the same code through http it works perfectly.
Thoughts?
Thanks!

iOS and Android Push Notifications from server Java

am using spring boot & spring project
i have developed one rest call &
FCM_URL = https://fcm.googleapis.com/fcm/send
Server Key = My Firebase Key
#RequestMapping(value = "/push/notification")
public void sendNotification(#RequestParam String Mobiletoken, #org.springframework.web.bind.annotation.RequestBody FcmRequestObject message) throws JsonParseException, JsonMappingException, IOException {
OkHttpClient client = new OkHttpClient();
ObjectMapper mapper = new ObjectMapper();
JSONObject obj = new JSONObject(message);
System.out.println("Here sending notification request/...");
RequestBody body = new FormBody.Builder().add("to", tokens).add("data", obj.toString()).build();
System.out.println(obj.toString());
Request request = new Request.Builder().url(ApplicationConstants.FCM_URL)
.addHeader("Authorization", "key=" + ApplicationConstants.FCM_SERVER_KEY).addHeader("Content-Type", "application/json").post(body)
.build();
try {
Response response = client.newCall(request).execute();
System.out.println(response.isSuccessful() + " - " + response.code());
} catch (IOException e) {
e.printStackTrace();
}
}
Input : Device Token & json body
Android Devices able to get Notifications
But IOS Devices not able to get notifications [we have tested from firebase console with server key & device token its working, only from server they not able to get]
need to any changes in Rest Call for IOS?
in PHP have
$arrayToSend = array('to' => $token, 'notification' => $notification,'priority'=>'high');
Help on this and save my Days, if any changes in rest and can you give sample..
thank you in advance..
I too faced this problem.
As -AL suggested, I used attribute "notification" in place of "data" and it worked for me.
Sample push message for iOS:
"{"notification":{"title":"Title of notification","body":"Your message","attribute3":"vale","attribute4":"vale"....},"to":"Device Token","priority":"high"}"
In the above payload, attribute 3 and 4 are extra attributes that we can add to do perform any action or event like navigating to any particular screen based on the notification.

Send notification from web to android device using Firebase

I am trying for a while now to implement this flow: When user adds some files on server app, notification should trigger and send from server to FCM and that from there to pass message saying something like: 'New file has been added'.
Basically I want to inform mobile device user that something on server has been changed.
I have tried many things, but nothing seems to work as I would expect, at least.
On the mobile side I have set up Firebase inside my Xamarin.Android project, and when I am sending notifications directly from Firebase console, I get notifications, and everything is good.
But I don't want to send notifications via Firebase console, I would rather send notification from server (which is ASP.NET MVC project) to Firebase console and then pass it from there to android device.
My first question would be: Has anybody got an idea how can I inform web app about device_id? Is there some way that android device send this information on server? And maybe from there I can store that data and update it occasionally, since it is basically a refresh token.
My second problem is this: Even when I hard code current device_id of an active android device and try to send a message from server whit this code:
public class FirebaseService : IFirebaseService
{
public void SendMessageToClientApplication(string message, string serverApiKey, string senderId, string deviceId)
{
AndroidFCMPushNotificationStatus result = new AndroidFCMPushNotificationStatus();
try
{
result.Successful = false;
result.Error = null;
deviceId = "eMk6mD8P8Dc:APA91bG5Lmqn4Hwb4RZJ1Mkdl8Rf_uYQsQCEfDJK334tzSvIGzdao7o2X6VmtcTEp_Li0mG8iUoUT7-_RnZxQKocHosZwx6ITWdpmQyCwUv60IIIy0vxNlEaccT6RqK6c-cE1C6I3FTT";
var value = message;
WebRequest tRequest = WebRequest.Create("https://fcm.googleapis.com/fcm/send");
tRequest.Method = "post";
tRequest.ContentType = "application/x-www-form-urlencoded;charset=UTF-8";
tRequest.Headers.Add(string.Format("Authorization: key={0}", serverApiKey));
tRequest.Headers.Add(string.Format("Sender: id={0}", senderId));
string postData = "collapse_key=score_update&time_to_live=108&delay_while_idle=1&data.message="
+ value + "&data.time=" + DateTime.Now.ToString() + "&registration_id=" + deviceId + "";
Byte[] byteArray = Encoding.UTF8.GetBytes(postData);
tRequest.ContentLength = byteArray.Length;
using (Stream dataStream = tRequest.GetRequestStream())
{
dataStream.Write(byteArray, 0, byteArray.Length);
using (WebResponse tResponse = tRequest.GetResponse())
{
using (Stream dataStreamResponse = tResponse.GetResponseStream())
{
using (StreamReader tReader = new StreamReader(dataStreamResponse))
{
String sResponseFromServer = tReader.ReadToEnd();
result.Response = sResponseFromServer;
}
}
}
}
}
catch (Exception ex)
{
result.Successful = false;
result.Response = null;
result.Error = ex;
}
}
}
I get nothing both in Firebase console and of course nothing on device as well.
I have tried to implement Firebase web as javascript on my server app like this:
<script>
var config = {
apiKey: "mykey",
authDomain: "myauthdomain",
databaseURL: "mydatabaseurl",
projectId: "myprojectid",
storageBucket: "mystoragebucket",
messagingSenderId: "mysenderid"
};
window.onload = function () {
firebase.initializeApp(config);
const messaging = firebase.messaging();
messaging.requestPermission()
.then(function () {
console.log('Notification permission granted.');
return messaging.getToken()
})
.then(function (token) {
console.log(token);
})
.catch(function (err) {
console.log('Unable to get permission to notify.', err);
});
messaging.onMessage(function (payload) {
console.log('onMessage: ', payload);
});
}
</script>
But this code gets some kind of a different device_id(aka token), probably one generated for that server machine.
Does anybody has experience with sending device_id to server app and from there sending notification message to Firebase console? I would appreciate some code examples, tutorials or anything that can help, since I was unable to find something useful during my google search.
My first question would be: Has anybody got an idea how can I inform web app about device_id?
The most common approach is to store the list of device tokens (each device that uses FCM has such a token) in a database, such as the Firebase Database. There is an example of this in the Cloud Functions for Firebase documentation. In this example the devices receiving the messages are web pages, but the approach is the same for iOS and Android.
I also recommend reading Sending notifications between Android devices with Firebase Database and Cloud Messaging. In this article, instead of sending to a device token, each user subscribes to a topic. That prevents having to manage the device tokens in your code.

Cordova/Phonegap iOS Parse-Push Plugin

I have spent lot of time to find correct cordova plugin for parse push notifications for both Android & iOS platforms.
My requirements are:
To receive parse push notification (in both android & iOS)
Able to store all the incoming push notifications in mobile local storage Sqlite.
I have tried all the below parse push cordova plugins for both Android & iOS platforms.
https://github.com/avivais/phonegap-parse-plugin
https://github.com/taivo/parse-push-plugin
https://github.com/campers/parse-push-plugin
https://github.com/manishiitg/parse-push-plugin
For Android: All the above plugins are working perfectly to fulfill my above mentioned requirements.
For iOS: Only 1st plugin i.e https://github.com/avivais/phonegap-parse-plugin is working. And that too i was not able to save the notifications in local storage sqlite. That means only my 1st requirement is fulfilled but not my 2nd requirement.
All the github pages of remaining plugins (i.e 2nd, 3rd, 4th) states that:
"Please note that I've only worked on the Android aspect of this fork. The iOS side is not yet up to date."
Is there any plugin which will work for both Android & iOS platforms to fulfill my 2 requirements?
(or)
If there is no common plugin for both the platforms, then how can I store the incoming plugins in iOS sqlite?
Please help me. Thanks in advance.
I happen to maintain https://github.com/taivo/parse-push-plugin
It looks like you caught my fork at its infancy. I picked it up when the upstream fork seemed stagnant for a while and at that time I was only addressing the Android aspect. Since then I've provided full iOS support. And it works for parse-server as well as the out-going parse.com. I also did one better and made installation just a matter of
cordova add https://github.com/taivo/parse-push-plugin
and writing a few config.xml tags to indicate server url, and app id.
That should take out the big pain of manually messing with Android Manifest, Java, and Objective C when setting up the plugin.
It should now meet or exceed your requirement. To receive push notification and store in sqlite, all you have to do is set an event handler in javascript. Be sure to wrap it with some sort of device ready or platform ready event handler to ensure the plugin has properly loaded.
$ionicPlatform.ready(function(){
if(window.ParsePushPlugin){
ParsePushPlugin.on('receivePN', function(pn){
console.log('yo i got this notif:' + JSON.stringify(pn) );
//
// do your sqlite storage here
//
});
}
});
You just might be interested in the Azure Push Notifications. It combines both Push notification services so you can send messages to both devices from one central point.
I quote:
Notification Hubs A scalable, cross-platform solution for sending push
notifications to mobile devices, Notification Hubs works well with
Cordova apps. Notification Hubs manages the registrations with each
PNS. More important, Notification Hubs lets you create template
registrations so you can send messages to all registered devices,
regardless of platform, with only a single line of code. You can also
use tags to send targeted notifications only to devices with specific
registrations. For more information about Notification Hubs, see the
Azure Web site at aka.ms/nkn4n4.
Here i have a helper class for registering your device with the pushnotification service. For sending push notifications, you can use an azure portal and send styled push notifications in json format.
var Pushman = {
Initialize: function (hubConnString, hubName, gcmSenderId, callbackRegistered, callbackUnRegistered, callbackInlineNotification, callbackBackgroundNotification, callbackError) {
//store connection and callback information on app startup for Push Registration later
Pushman.HubConnectionString = hubConnString;
Pushman.HubName = hubName;
Pushman.GcmSenderId = gcmSenderId;
//callbacks
Pushman.RegisteredCallback = callbackRegistered;
Pushman.UnRegisteredCallback = callbackUnRegistered;
Pushman.NotificationForegroundCallback = callbackInlineNotification;
Pushman.NotificationBackgroundCallback = callbackBackgroundNotification;
Pushman.ErrorCallback = callbackError;
},
RegisterForPushNotifications: function (tags) {
//setup Azure Notification Hub registration
Pushman.Hub = new WindowsAzure.Messaging.NotificationHub(Pushman.HubName, Pushman.HubConnectionString, Pushman.GcmSenderId);
Pushman.Hub.registerApplicationAsync(tags).then(Pushman.onRegistered, Pushman.onError);
//setup PushPlugin registration
Pushman.Push = window.PushNotification;
var push;
//register depending on device being run
if (device.platform == 'android' || device.platform == 'Android' || device.platform == "amazon-fireos") {
//android
push = Pushman.Push.init(
{ "android": { "senderID": Pushman.GcmSenderId } }
);
push.on('registration', Pushman.onRegistered);
push.on('notification', Pushman.onAndroidNotification);
push.on('error', Pushman.onError);
} else {
//iOS
push = Pushman.Push.init(
{ "ios": { "alert": "true", "badge": "true", "sound": "true" } }
);
push.on('registration', Pushman.onRegistered);
push.on('notification', Pushman.onIOSNotification);
push.on('error', Pushman.onError);
}
},
UnRegisterForPushNotifications: function () {
if (Pushman.Hub != null) {
//dont pass through error handler
//unreg azure
Pushman.Hub.unregisterApplicationAsync()
.then(Pushman.onUnRegistered, null);
//unreg native
Pushman.Push.unregister(Pushman.onUnRegistered, null);
}
},
onRegistered: function (msg) {
Pushman.log("Registered: " + msg.registrationId);
//only call callback if registrationId actually set
if (msg.registrationId.length > 0 && Pushman.RegisteredCallback != null) {
Pushman.RegisteredCallback(msg);
}
},
onUnRegistered: function () {
Pushman.log("UnRegistered");
if (Pushman.UnRegisteredCallback != null) {
Pushman.UnRegisteredCallback();
}
},
onInlineNotification: function (msg) {
Pushman.log("OnInlineNotification: " + msg);
if (Pushman.NotificationForegroundCallback != null) {
Pushman.NotificationForegroundCallback(msg);
}
},
onBackgroundNotification: function (msg) {
Pushman.log("OnBackgroundNotification: " + msg);
if (Pushman.NotificationBackgroundCallback != null) {
Pushman.NotificationBackgroundCallback(msg);
}
},
onColdStartNotification: function (msg) {
Pushman.log("OnColdStartNotification: " + msg);
if (Pushman.NotificationBackgroundCallback != null) {
Pushman.NotificationBackgroundCallback(msg);
}
},
onError: function (error) {
Pushman.log("Error: " + error);
if (Pushman.ErrorCallback != null) {
Pushman.ErrorCallback(error);
}
},
onAndroidNotification: function (e) {
switch (e.event) {
case 'registered':
if (e.regid.length > 0) {
Pushman.onRegistered("Registered");
}
break;
case 'message':
if (e.foreground) {
//if this flag is set, this notification happened while app in foreground
Pushman.onInlineNotification(e.payload.message);
} else {
//otherwise app launched because the user touched a notification in the notification tray.
if (e.coldstart) {
//app was closed
Pushman.onColdStartNotification(e.payload.message);
}
else {
//app was minimized
Pushman.onBackgroundNotification(e.payload.message);
}
}
break;
case 'error':
Pushman.onError(e.msg);
break;
default:
Pushman.onError("Unknown message");
break;
}
},
onIOSNotification: function (event) {
//TODO: not sure how ios works re cold start vs inline msg types?
if (event.alert) {
navigator.notification.alert(event.alert);
}
if (event.badge) {
Push.setApplicationIconBadgeNumber(app.successHandler, app.errorHandler, event.badge);
}
},
tokenHandler: function (result) {
// iOS - not sure its use though appears somewhat important
// Your iOS push server needs to know the token before it can push to this device
// here is where you might want to send it the token for later use.
alert('device token = ' + result);
},
log: function (msg) {
console.log(msg);
},
}
///"class" variables - not sure how to put them into the js "class"
Pushman.Push = null;
Pushman.Hub = null;
Pushman.HubConnectionString = null;
Pushman.HubName = null;
Pushman.GcmSenderId = null;
Pushman.NotificationForegroundCallback = null;
Pushman.NotificationBackgroundCallback = null;
Pushman.RegisteredCallback = null;
Pushman.UnRegisteredCallback = null;
Pushman.ErrorCallback = null;
I did not write this myself, all credit goes to this guy.
Then you just need to initialize the plugin when the application starts:
//azure notificationshub connection information
notificationHubPath = "notificationhub name";
connectionString = "notificatin hub connectionstring";
//sender id for google cloud services
var senderIdGCM = "sender id from google gcm";
//tag registration (csv string), can be empty but not undefined
var registrationTagsCsv = ""; //test1, test2
var app = {
Initialize: function () {
//reg for onload event
this.AppStart();
},
AppStart: function () {
"use strict";
document.addEventListener('deviceready', app.onLoad, false);
document.addEventListener('deviceready', onDeviceReady.bind(this), false);
function onDeviceReady() {
// Handle the Cordova pause and resume events
document.addEventListener('pause', onPause.bind(this), false);
document.addEventListener('resume', onResume.bind(this), false);
// TODO: Cordova has been loaded. Perform any initialization that requires Cordova here.
};
function onPause() {
// TODO: This application has been suspended. Save application state here.
};
function onResume() {
// TODO: This application has been reactivated. Restore application state here.
};
},
onLoad: function () {
app.log("Initializing...");
//setup push notifications
Pushman.Initialize(connectionString, notificationHubPath, senderIdGCM,
app.onNotificationRegistered, app.onNotificationUnRegistered,
app.onNotificationInline, app.onNotificationBackground, app.onNotificationError);
//hookup cmd buttons
app.registerForPush();
//$("#register").click(app.registerForPush);
//$("#unregister").click(app.unRegisterForPush);
app.onAppReady();
},
registerForPush: function (a, c) {
app.log("Registering...");
//register for tags
Pushman.RegisterForPushNotifications(registrationTagsCsv);
},
unRegisterForPush: function (a, c) {
app.log("UnRegistering...");
//register for tags
Pushman.UnRegisterForPushNotifications();
},
onAppReady: function () {
app.log("Ready");
},
onNotificationRegistered: function (msg) {
app.log("Registered: " + msg.registrationId);
},
onNotificationUnRegistered: function () {
app.log("UnRegistered");
},
onNotificationInline: function (data) {
app.log("Inline Notification: " + data);
},
onNotificationBackground: function (data) {
app.log("Background Notification: " + data);
},
onNotificationError: function (error) {
app.log("Error: " + error);
},
log: function (msg) {
console.log(msg);
},
};
If you want to store the messages then you just need to add your code for storing to sql where the messages get received. You'll need an azure account to make this work, here you can get a free trail. It will allow you to send up to 1 million push notifications a month free of charge.
I think this article may be of use, it has more of a direct native workaround for your hybrid app to work
http://www.hiddentao.com/archives/2015/04/10/parse-push-notifications-for-your-android-and-ios-cordova-app/.
I'm working on a Cordova android app, and this seems to be a working solution

Resources