-
Notifications
You must be signed in to change notification settings - Fork 71
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Custom Events (push notification, websocket, geolocation, etc) #77
Comments
Mostly LGTM. Main point I wanted to raise though is about background processing. This is Android specific, I don't know enough about how iOS does background processing these days. Taking push-notifications as a first example, whats not covered yet here is how things will work when a push message is received while Jasonette app is not in the foreground. Normally you would want this (eg. think chat client) to display a std OS notification UI that a new message is available. The user then has the option to press on the notification and expects to be taken to the relevant part of the apps UI. In regards to the "problem" I think this should be handled internally by each action that implements an event. |
Wouldn't this be ambiguous? The "registered" event is something we also receive from the server side. Note that we don't have to go with the
I understand it can be a bit confusing, but I did try to make it consistent somewhat, so let me explain. Basically whenever there's a
In this example, Basically I've been using the That said, we did experiment with using a
Wow you really thought far ahead into this! I totally forgot to mention this. There are two parts to this question:
Let me go through each: 1. what to do when user opens the notification?OK fortunately we have an clean solution to this by utilizing a couple of already existing features of Jasonette:
Combining these two, we can send a push notification with an
and it would open that view when the user slides open that notification. Of course, we could express it using
This way we don't have to register anything anywhere. In fact, the iOS version has already implemented half of this (just the href part) Jasonette/JASONETTE-iOS@8610338 The reason I didn't implement an 2. Is it possible to customize the push notification behavior while app is in the background?Both iOS and Android have "rich push notifications" which allows for more customized view of the notification itself, as well as allowing users to interact with the notification in custom ways: From my own personal usage and looking at how most people interact with push notifications, I personally think of these as gimmicky features at this point and may not be worth spending time to standardize into a JASON syntax, especially considering how both Apple and Google have vested interest to create differentiated experiences to the lock screen going forward. That said this may change in the future when the lock screen UI somehow ends up becoming as standardized as typical app UIs AND they provide some significant value for end users. This is why I don't think it's a good idea to implement rich notifications at the core level. Maybe someone can create an extension if they really wanted these features. Finally, I realize Android has much more powerful features to handle push notifications in custom ways compared to iOS, but this wouldn't be cross platform, which is why the core doesn't implement it. Again this could be added on as an extension in the future if someone wants to do some crazy stuff with push notifications on Android. So for now, I think it's good enough to implement regular push notifications that:
Agreed. Basically abstracting out the exception handling so that the user doesn't have to know, I think that's better for now. The only reason I was cautious about this was maybe sometimes users may want to handle things differently depending on the state, but we can just add the state feature later if this is necessary. For now I can't think of when someone would want to manually handle these things so agree it's better to start simple. |
@gliechtenstein thanks for such a detailed followup! Re: "$", sorry I wasnt thinking about extensions correctly from Jasonette users pov, makes perfect sense now. Re: JSON in notification payloads: excellent idea! Didnt spot that in the iOS implementation. I like supporting actions as well as href. Re: "Rich Notifications UI" yes agree don't need this right now, BUT... This makes me think I should point out something that I noticed from working alongside iOS dev's inthe past that seems quite diff between the 2 platforms: on Android the "notification ui" is about much more than just push notifications. Its actual an integral part of apps local functionality, nothing to do with APN,GCM, etc. So notifications are used a lot, from simple useful cases eg. large file upload continues in background after the app doing the upload leaves the foreground, with the notification showing a progress bar. Through to the annoying: game registers an alarm that triggers after X days and if you haven't played the game, shows a notification remind you to play it. None of the above have anything to do with push-notifications but things like background audio or file uploading are very useful and I could see myself needing to use them in Jasonette apps right now. On Android ongoing notifications are also linked to lockscreen, but thats only a recent thing on newer versions of Android, on-going notifications have been around much longer. Hope the above makes sense, like I said, all of the above doesn't directly affect this proposal except to keep it in mind in terms of future functionality for core jasonette as well as extensions. |
Currently on Jasonette, actions can be triggered by:
action
attached to the same button is run)This post is related to 3.
Preface: How Events Work Today
The only way to make use of system events is to define their handlers under
$jason.head.actions
. For example:Here we are listening for the
$load
system event and have attached an action handler, which makes a$network.request
and$render
s its content.There are limited number of these built-in system events (
$load
,$show
,$foreground
,$pull
) at the moment.Going Beyond Default System Events
Being able to listen to events is very useful, but what if we could go further and listen to other types of events?
We could listen to other background events that we aren't capturing at the moment, such as location (geofencing), time (local notifications), and remote events (remote push notifications), etc.
Custom Events
Unlike events such as
$show
and$foreground
which are automatically triggered by the system, when it comes to custom events, the system has no prior knowledge, and it may be wasteful to listen to all of those events even when not in use, so we need to manually register to listen to them. Normally a lifecycle for custom events looks like the following:In fact we already have an implementation for this, which is the push notification module. This feature is only implemented on iOS at the moment and not even documented because I wanted to take some time to decide if this was the best way to handle this, but I think it's time that we establish an official way to implement these custom events and move forward, officially rolling out all the long-overdue features such as push notification.
Push Notification Example
I'll use the push notification example to describe each step.
Basically We can package all of the four steps into a single
Jason*Action
class.1. Register
$notification.register
: This is not an event, but an action. Sends a token registration request to APNS server.We can implement this as a
register()
method underJasonNotificationAction
class.2. Listen (for register success event)
Then it waits for a response back from APNS.
3. Trigger (on register success)
The first thing that happens after the registration is APNS returns with a
"$notification.registered"
event. This is a one time event that only gets triggered right after $notification.register action to APNS returns success. It returns thedevice token
assigned by APNS. We need to store this token somewhere so we can reuse it later (normally on a server).4. Listen (for actual notifications)
Now everything is set to go. The app goes back to doing its thing, but this time it keeps listening to APNS for any incoming push notifications.
5. Trigger (on every new push notification message)
When someone sends a POST request to APNS pointing to this device's
device_token
, APNS will send a push notification to this device, and a "$notification.remote" event will be triggered on this device.We can attach any handler action here to handle the notification, as seen below.
(May want to change the event name to something that's more intuitive, like
$notification.onmessage
or$notification.message
. Feedback appreciated)6. Unregister
In case of push notification this is not really necessary so this part is ommitted. But I can imagine some action/events requiring this, such as location tracking.
Example Scenario
Jasonette is a view-oriented framework--we write a JSON markup to describe a view, just like how web browsers work. This means there currently isn't a way to describe something outside the context of a view.
So far with push notifications this hasn't been a big problem because we can simply attach different event handlers for different views.
For example if we have a chat app, we may have
Whenever there's an incoming push notification from APNS or GCM,
A. In the chatroom view we may want to:
$render
.$util.banner
B. In the lobby view:
We probably just want to dispaly
$util.banner
all the time, since there is no chat going on in the lobby itself.So far from experience, it looks like attaching event handlers to the view (instead of globally) seems to cover all use cases while keeping it consistent with the existing, view-oriented JASON syntax. (But please share feedback if there seems to be a hole)
Implementation Spec
Bringing all this together here's a spec for implementing these custom events:
A. 4 phases
There are four steps to dealing with custom events:
$notification.registered
), or on a view level (like$load
).B. Implement as a single Jason*Action class.
Sometimes this may not be 100% feasible but we should strive to put everything into a single class as much as possible in order to keep features modular.
This class would consist of:
"type": "$notification.register"
, which callsJasonNotificationAction.register()
)call
(iOS / Android). Then all that's left is to just define an event handler under$jason.head.actions
that will handle these events.Problem
What I described above kind of works, with a caveat.
I talked about the
$notification.register
action as if it works without any problem, but there is a small issue I didn't mention--"registration" is not something we should be doing all the time.The code above would register for notification every time this view is loaded. In some cases this may not be desirable because it's redundant.
Using a more relevant case to explain this, let's say we're using this method to implement
websocket
. We may want to start a session once when the app launches and keep that session around throughout the entire lifecycle of the app instead of reinitializing the session everytime a view is loaded.Solutions?
We need some way to deal with this problem. (The current iOS push notification implementation doesn't address this problem) Some ideas I have so far involve keeping track of state (registered vs. not registered), probably keep it as a member variable of say,
JasonWebsocketAction
.Solution 1. Action based
Maybe implement an action called
$notification.token
which returns as eithersuccess
orerror
callback (if the app already has registered for push, the$notification.register
action should have stored it somewhere and would return the token throughsuccess
callback, as$jason
)This seems clean because we make use of the
success
anderror
callbacks,Solution 2. Variable based
Introduce a new variable for each of these cases (for example
$notification.token
) and use template expression to selectively execute.Implementation-wise this is more complex because now we have to touch variables and templates. Might be challenging to keep it modular.
Solution 3?
Any ideas or suggestions?
The text was updated successfully, but these errors were encountered: