Merge lp:~chipaca/ubuntu-push/tutorial into lp:ubuntu-push/automatic

Proposed by John Lenton on 2014-12-09
Status: Work in progress
Proposed branch: lp:~chipaca/ubuntu-push/tutorial
Merge into: lp:ubuntu-push/automatic
Diff against target: 382 lines (+369/-4)
2 files modified
docs/Makefile (+15/-4)
docs/tutorial.txt (+354/-0)
To merge this branch: bzr merge lp:~chipaca/ubuntu-push/tutorial
Reviewer Review Type Date Requested Status
Ubuntu Push Hackers 2014-12-09 Pending
Review via email: mp+244179@code.launchpad.net
To post a comment you must log in.

Unmerged revisions

357. By John Lenton on 2014-12-09

added tutorial

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'docs/Makefile'
2--- docs/Makefile 2014-09-25 16:48:18 +0000
3+++ docs/Makefile 2014-12-09 16:58:23 +0000
4@@ -1,4 +1,15 @@
5-all: *txt *svg
6- rst2html --link-stylesheet highlevel.txt highlevel.html
7- rst2html --link-stylesheet lowlevel.txt lowlevel.html
8-
9+COMMON= _common.txt \
10+ _description.txt \
11+ push.svg \
12+ example-client/helloHelper \
13+ example-client/manifest.json \
14+ example-client/helloHelper-apparmor.json \
15+ example-client/hello.json
16+
17+all: highlevel.html lowlevel.html
18+
19+highlevel.html: highlevel.txt $(COMMON)
20+lowlevel.html: lowlevel.txt $(COMMON)
21+
22+%.html: %.txt
23+ rst2html --link-stylesheet $< $@
24
25=== added file 'docs/tutorial.txt'
26--- docs/tutorial.txt 1970-01-01 00:00:00 +0000
27+++ docs/tutorial.txt 2014-12-09 16:58:23 +0000
28@@ -0,0 +1,354 @@
29+.. -*- rst -*-
30+
31+.. contents::
32+
33+Ubuntu Push Notifications
34+================================================================
35+
36+(a tutorial)
37+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
38+
39+This tutorial will walk you through the changes you'll need to do to
40+your application in order for it to receive push notifications on
41+Ubuntu.
42+
43+We'll start with a very simple client-server application: the server
44+generates events at random [*]_, and the client displays these events to
45+the user:
46+
47+ = ==== ====
48+ # date event title
49+ = ==== ====
50+ 1 now ``lp0`` on fire
51+ 2 pot Alas, poor Yorik!
52+ 3 qux Keyboard error. Press any key to continue.
53+ = ==== ====
54+
55+ (this'll be a screenshot once it stops looking so ugly)
56+
57+the user can then drill down into the event to find out more:
58+
59+ +---+-----------------------------------------+
60+ | 1 | ``lp0`` on fire |
61+ +===+=========================================+
62+ | |
63+ | I set one of the printers on fire. |
64+ | You probably want to do something about it. |
65+ | Silly human. |
66+ +---------------------------------------------+
67+
68+.. [*] Well, not at random, but in response to an external event that
69+ happens at an unpredictable time. Sure looks random from the outside.
70+
71+you can get the Qt Project for this app `here
72+<javascript:alert("not%20yet%20you%20can't")>`_.
73+
74+We'll assume you're building this app in the Ubuntu SDK, using an “App
75+with QML Extension Library” type project. So you'll have a main
76+``qml`` file under ``app/`` that has a ``MainView`` in it somewhere,
77+
78+.. code:: qml
79+ :number-lines:
80+
81+ MainView {
82+ objectName: "mainView"
83+ applicationName: "com.chipaca.pushtorial"
84+ automaticOrientation: true
85+ useDeprecatedToolbar: false
86+
87+ width: units.gu(100)
88+ height: units.gu(75)
89+
90+ ...
91+ }
92+
93+and a click manifest that looks something like this:
94+
95+.. code:: json
96+ :number-lines:
97+
98+ {
99+ "name": "@APP_ID@",
100+ "description": "description of pushtorial",
101+ "architecture": "@CLICK_ARCH@",
102+ "title": "@APP_NAME@",
103+ "hooks": {
104+ "pushtorial": {
105+ "apparmor": "pushtorial.apparmor",
106+ "desktop": "pushtorial.desktop"
107+ }
108+ },
109+ "version": "0.1",
110+ "maintainer": "Pushtorial Maintainers <pushtorial@chipaca.com>",
111+ "framework": "ubuntu-sdk-14.10"
112+ }
113+
114+
115+This very simple app has a problem: as soon as the screen goes off, or
116+the user switches to another application, they will no longer be
117+notified of the events. The application might even be reaped by the
118+lifecycle policy and no longer be running at all!
119+
120+
121+
122+Push notifications
123+----------------------------------------------------------------
124+
125+That's where push notifications come in: they allow you to alert the
126+user of server-side events, independently of whether your app is
127+running or not.
128+
129+So let's pretend your server sends the event information (sequential
130+id, title, and description) in a push message. We'll get into what
131+that means and how to set it up later, but for now, assume your app
132+somehow get handed a JSON document with that info on the
133+phone. Something like this:
134+
135+.. code:: json
136+ :number-lines:
137+
138+ { "id": 1,
139+ "title": "lp0 on fire",
140+ "description": "I set one of the printers on fire. You probably want to do something about it. Silly human."
141+ }
142+
143+The point where that is handed to you is in what we call the *push
144+helper*, which is a little program that runs with (a particular subset
145+of) your application's permissions, whose job it is to translate the
146+on-the-wire push notification (that JSON doc) into something you
147+present to the user. You'd want it to output something like
148+
149+.. code:: json
150+ :number-lines:
151+
152+ {
153+ "notification": {
154+ "tag": "1",
155+ "card": {
156+ "summary": "lp0 on fire",
157+ "body": "I set one of the printers on fire. ...",
158+ "popup": true,
159+ "persist": true,
160+ }
161+ "sound": true,
162+ "vibrate": true
163+ }
164+ }
165+
166+.. warning::
167+ This output format is expected to change, so it'll be easier for
168+ everyone if you don't make it your wire format also. Your wire
169+ format should make sense to your application domain, and the *push
170+ helper*'s job is to translate from from the application domain to
171+ this format. Otherwise you'll be stuck translating from one push
172+ format to another at some point soon, and that's going to *suck*.
173+
174+So, in this helper, after you've loaded the JSON from ``argv[1]`` into
175+a ``QJsonObject``, you'd pass it to something like
176+
177+.. code:: c++
178+ :number-lines:
179+
180+ QJsonObject postal(QJsonObject push) {
181+ QJsonObject card = QJsonObject();
182+ card["summary"] = push["title"];
183+ card["body"] = push["description"];
184+ card["popup"] = true;
185+ card["persist"] = true;
186+
187+ QJsonObject notif = QJsonObject();
188+ notif["card"] = card;
189+ notif["tag"] = push["id"];
190+ notif["sound"] = true;
191+ notif["vibrate"] = true;
192+
193+ QJsonObject postal = QJsonObject();
194+ postal["notification"] = notif;
195+
196+ return postal;
197+ }
198+
199+and write out the output of that to ``argv[2]``.
200+
201+Having that in your project, you'd need to tweak your manifest to
202+include an additional ``hook``,
203+
204+.. code:: json
205+ :number-lines:
206+
207+ {
208+ ...
209+ "hooks": {
210+ ...
211+ "helper": {
212+ "apparmor": "helper.apparmor",
213+ "push-helper": "helper.json"
214+ }
215+ },
216+ ...
217+ }
218+
219+and also include the referenced ``helper.apparmor`` file with apparmor bits for it,
220+
221+.. code:: json
222+ :number-lines:
223+
224+ {
225+ "template": "ubuntu-push-helper",
226+ "policy_groups": [
227+ "push-notification-client"
228+ ],
229+ "policy_version": 1.2
230+ }
231+
232+and the referenced ``helper.json`` pointing straight back at the
233+``helper`` executable:
234+
235+.. code:: json
236+ :number-lines:
237+
238+ {
239+ "exec": "helper"
240+ }
241+
242+That's everything that's needed to be able to test delivery of push
243+notifications to your app in place. Here's how you do that: in the
244+SDK, make sure you've selected your device, then build and run your
245+project. With the app running on your phone then you *swipe it to the
246+background*, shell into your phone, and
247+
248+.. code:: console
249+ :number-lines:
250+
251+ $ gdbus call -e -d com.ubuntu.Postal -o /com/ubuntu/Postal/com_2eexample_2epush \
252+ > --method com.ubuntu.Postal.Post com.example.push_push-test "'"'{"id": 1,
253+ > "title": "A Title", "description": "A Description"}'"'"
254+
255+If everything installed correctly you should see and hear the notification.
256+
257+.. note::
258+
259+ If you don't swipe your app to the background you won't see a
260+ thing, because notifications aren't presented for apps that are in
261+ the foreground. They will be signaled over DBus, and should respond
262+ appropriately to the signal. We'll get into that later.
263+
264+ After you've played around with things you'll need to swipe the app
265+ back into the foreground to let the SDK close it and clean it
266+ up. You'll remember about this, because unless the app is in the
267+ foreground you'll mash the stop button in the SDK to no effect.
268+
269+
270+
271+Registration
272+----------------------------------------------------------------
273+
274+Now that we've got the helper in place and working, let's get a token
275+from the push server so your app server can send push messages.
276+
277+This is a step called *registration*. This is handled automatically
278+for you; all you need to add is a little snippet to your QML (as well
279+as the appropriate ``import``):
280+
281+.. code:: qml
282+ :number-lines:
283+
284+ import Ubuntu.PushNotifications 0.1
285+
286+ MainView {
287+ ...
288+
289+ PushClient {
290+ id: pushClient
291+ appId: mainView.applicationName + "_pushtorial"
292+ onTokenChanged: {
293+ console.log(" Your push token is", token, "-- KEEP IT SECRET")
294+ }
295+ onError: {
296+ if (status==="bad auth") {
297+ console.log("EEE Tell the user to log in with U1 to get push notifications")
298+ } else {
299+ console.log("EEE Registration error:", status)
300+ }
301+ }
302+ }
303+ }
304+
305+and add the ``push-notification-client`` policy group to your app's
306+``apparmor``.
307+
308+Normally you'd do more user-friendly things in the ``onTokenChanged``
309+and ``onError`` handlers, mind.
310+
311+Anyway! Now you should be able to send push notifications to the
312+device! Excellent. Click the green arrow in the SDK, swipe the app to
313+the background, and
314+
315+.. code:: console
316+ :number-lines:
317+
318+ $ ./unicast -H push.ubuntu.com "YourToken++Seriously-its-a-password==" \
319+ > com.chipaca.pushtorial_pushtorial \
320+ > '{"id": 42, "title": "Hello", "description": "This just happened"}'
321+
322+you can download the ``unicast`` script from the push client's
323+loggerhead_.
324+
325+.. _loggerhead: http://bazaar.launchpad.net/~ubuntu-push-hackers/ubuntu-push/trunk/view/head:/scripts/unicast
326+
327+
328+
329+Missing minucia
330+----------------------------------------------------------------
331+
332+Two little thinigs that are probably bothering you right now if you've
333+made it this far.
334+
335+One, your notifications are missing the nice big icon on the left!
336+Just the little piddle app/secondary icon on the right. That's easy to
337+fix; just set the ``"icon"`` property in the JSON's ``card`` object to
338+something relevant.
339+
340+Remember, however, that the notification's main icon is supposed to
341+say something about the event itself, not about the system delivering
342+it. So it could be an alert level, or somebody's face, or the main
343+image of the news article, or the favicon of the rss feed. You get the
344+idea.
345+
346+The *other* thing that'll be bugging you is that when you touch the
347+notification nothing happens, and you probably want it to launch your
348+application.
349+
350+For that bit to work you need an ``actions`` entry in the ``card``
351+object. For now, simply set the value to an array containing just
352+``appid://com.chipaca.pushtorial/pushtorial/current-user-version``, and
353+read the `wiki page`_ about what this string means. Note that this
354+just launches the app (or brings it to foreground); we'll look into
355+*deep linking* later on.
356+
357+.. _wiki page: https://wiki.ubuntu.com/URLDispatcher
358+
359+-------
360+
361+writing mostly done to here
362+
363+Not being a spammy spammer (or, managing notification backlog)
364+----------------------------------------------------------------
365+
366+tags & clearpersistent`
367+
368+What things should look like (or, what options you have)
369+----------------------------------------------------------------
370+
371+* mention vibration and sound are more than just boolean; link to doc
372+
373+* screenshots for (both popup- and non-):
374+
375+ * icons
376+
377+ * title and desc
378+
379+ * emblem counter (explain how/when that one works)
380+
381+Deep Linking
382+----------------------------------------------------------------

Subscribers

People subscribed via source and target branches