Open elfeffe opened 8 years ago
Great question. Before I start explaining, please correct me if I'm wrong. I think I have enough experience with push notifications (Jasonette started out as something extracted out from a messaging app.
As far as I know, push notification in most cases is a server-side thing. Let me use a messaging app as an example:
device token
to the app's server.device token
under John's account for later reference.device token
.device token
.device token
, which is John's phone.Of course, there is a way to bypass this. For example if Jane's phone knows exactly what John's device token
is, then it can directly jump to step 7 and send a push to that device token
through APNS immediately. But in most cases this is not realistic since most push based apps need some sort of centralized way of storing and managing device tokens for their users.
That said, there are many ways to tackle this problem.
The project is not yet at a stage where I want to make a decision on whether I will build a dedicated push broker service (Option 3) or not. And honestly I think building Jasonette into something that's tightly coupled with a "special server" may limit its potential.
I think option 2 feels most rational at this point, since you still have a way to send device tokens to your server without touching any native code, but you're not tied to a specific push provider.
But again, let me know if you know a better solution. Otherwise I will soon start working on the 'option 2' and post an update here :)
An action for sending tokens and new system event which would be fired when a push message arrives would be cool.
I fully agree that writing yet another push service backend would bind jasonette too tightly to one implementation.
OTOH I see that both UA and MS Azure require hooking their own frameworks on the client (iOS) side. I think makes it very difficult to come up with a generic solution for a system event.
Here's the push notification branch: https://github.com/Jasonette/JASONETTE-iOS/compare/push_notification?expand=1
I've just tested it and it works on mine, but as is always with push notifications you need to jump through a couple of certificate hoops.
I'm assuming you have an apple developer account, since that's the only way to support push notifications. Anyway, to make this work, you should:
Capabilities
tab in XCode and enable Push Notifications => This will create an entitlements file automaticallyGeneral
tab in XCode and DISABLE "automatically manage signing" and manually set that to the production app profile you created from developer.apple.com. (I think this is a one of those bugs on Apple's end and have seen many other projects suffer from the same problem. If anyone knows how to get around this please share.)Note that these are not Jasonette related steps but something anyone who wants to implement push notification on iOS needs to go through.
Once you're all set up, this is how the new API should work:
$notification.register
action => Registers this device to Apple for push notification$notification.registered
event with $jason.device_token
set as the newly assigned device token$notification.remote
event. In this case the entire push payload will be stored inside $jason. you can utilize this value to run any other action. In this case we call a $util.banner. {
"$jason": {
"head": {
"title": "PUSH TEST",
"actions": {
"$load": {
"type": "$notification.register"
},
"$notification.registered": {
"type": "$network.request",
"options": {
"url": "https://myserver.com/register_device.json",
"data": {
"device_token": "{{$jason.device_token}}"
}
}
},
"$notification.remote": {
"type": "$util.banner",
"options": {
"title": "Message",
"description": "{{JSON.stringify($jason)}}"
}
}
}
}
}
}
One more thing, I'm attaching the server-side code (it's an AWS lambda function but you can do whatever you want) I used to get it to work just in case. It's all hard-coded because it's just for validating the API:
// This app downloads the p8.key file from my S3 everytime, you can try it with your own S3. But anyway, downloading push certificate everytime is needless overhead so please don't do this in production.
var AWS = require('aws-sdk');
var s3 = new AWS.S3();
var fs = require('fs');
var apn = require('apn');
var options = {
token: {
key: "/tmp/key.p8",
keyId: "[[REDACTED]]",
teamId: "[[REDACTED]]"
},
production: true
};
var run = function(payload, ctx){
var apnProvider = new apn.Provider(options);
var note = new apn.Notification();
note.expiry = Math.floor(Date.now() / 1000) + 3600; // Expires 1 hour from now.
note.sound = "pop.wav";
note.badge = 3;
note.alert = "\uD83D\uDCE7 \u2709 You have a new message";
note.payload = {'messageFrom': 'Ethan Gliechtenstein'};
note.topic = "[[YOUR APP BUNDLE ID]]";
// Normally this device token should be dynamically looked up but I hard coded it by finding out what the device token is. I used some JSON markup like this to email myself the device token:
// "actions": {"$notification.registered": {"type": "$href", "options": {"url": "mailto:ethan.gliechtenstein@gmail.com?subject={{$jason.device_token}}", "view": "app"}}}
apnProvider.send(note, "[[HARDCODED DEVICE TOKEN]]").then( (result) => {
// see documentation for an explanation of result
console.log(JSON.stringify(result));
ctx.succeed({ "response": "OK" })
});
};
exports.handle = function(e, ctx) {
// Need to download cert from S3 first
var file = require('fs').createWriteStream('/tmp/key.p8');
var key_dest = s3.getObject({Bucket: "jasonette", Key: "cert/key.p8"}).createReadStream();
key_dest.on("data", function(data){
file.write(data);
});
key_dest.on("end", function(data){
file.end();
run(e, ctx);
});
}
Oh WOW.
I will try it Thank you very much for this and for the whole project, this is a fantastic project.
Ok, so I allocated some time to get this working with Azure Notification Hub -- just because we happen to have some Azure stuff running internally. I probably need to hack the code a bit for that to work, will do on a separate branch.
Just wanted to mention that this code works beautifully. I think this issue could be closed now.
I also confirm that this works fine, but there's one thing that's been bothering me, which is why I didn't merge this to master yet: https://github.com/Jasonette/JASONETTE-iOS/issues/53
I hope some has a good solution for this!
I was able to use this branch and push notifications worked well! I did have to enable the 'capability' manually. Also, I am using Firebase for pushes, so I had to adjust the JasonAppDelegate to register with the proper endpoints.
this version seems to be missing file:// .... how do we reference local files from settings.plist?
Great project! What about push notifications?