Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 164 lines (108 sloc) 8.707 kb
de8cf54 @niclasmeier initial commit
niclasmeier authored
1 # A clojure Apple Push Notification library
2
3 This small library provides a simple facility to send push messages to the
0f345ed @niclasmeier FInished conversion to Netty 4 and added new error handling model.
niclasmeier authored
4 [Apple push notification](https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/WhatAreRemoteNotif.html)
04e2bf0 @niclasmeier - converted links from textile to markdown
niclasmeier authored
5 service. The library uses [netty](http://netty.io) for the asynchronous communication with the server.
de8cf54 @niclasmeier initial commit
niclasmeier authored
6
0f345ed @niclasmeier FInished conversion to Netty 4 and added new error handling model.
niclasmeier authored
7 **Warning:** The 0.5.x versions have a major change in behaviour. The connection instance in the 0.2.x versions tried to re-connect when it was closed, e.g. after disconnect by Apple due to a faulty message.
8 The connection in the 0.5.x instance will stay closed and you have to create a new one manually. This is motivated by the error handling which is new to the 0.5.x series. See _Error handling_ for more information.
de8cf54 @niclasmeier initial commit
niclasmeier authored
9
10 ## Build
11
12 To build the api-doc plugin you'll have to clone the git repository.
13
14 git clone git(at)github.com:HEROLABS/herolabs-apns.git
15
04e2bf0 @niclasmeier - converted links from textile to markdown
niclasmeier authored
16 Assuming that you have [Leiningen](https://github.com/technomancy/leiningen) already installed. Simply execute
de8cf54 @niclasmeier initial commit
niclasmeier authored
17
18 lein install
19
20 to install the plugin into your local plugin repository.
21
22 ## Usage
23
24 To integrate the library in you project simply add this to your `project.clj`:
25
0f345ed @niclasmeier FInished conversion to Netty 4 and added new error handling model.
niclasmeier authored
26 :dependencies [[herolabs/apns "0.5.0"]]
de8cf54 @niclasmeier initial commit
niclasmeier authored
27
0f345ed @niclasmeier FInished conversion to Netty 4 and added new error handling model.
niclasmeier authored
28 Sending a push message is quite easy. First we create the message. It's - more or less - a simple clojure map, but you also may use some builder/helper functions from `herolabs.apns.message`. When you use the builder function to may also supply informations like the recipent (`to`) or other meta-informations like the priority or the expiry date.
de8cf54 @niclasmeier initial commit
niclasmeier authored
29
0f345ed @niclasmeier FInished conversion to Netty 4 and added new error handling model.
niclasmeier authored
30 (-> (to "SOME_APS_TOKEN")
31 (with-loc-key "GAME_PLAY_REQUEST_FORMAT")
32 (with-loc-args ["Jenna" "Frank"]))
de8cf54 @niclasmeier initial commit
niclasmeier authored
33
34 Will create a message like this:
35
36 {:aps {:alert {:loc-args ["Jenna" "Frank"], :loc-key "GAME_PLAY_REQUEST_FORMAT"}}}
37
0f345ed @niclasmeier FInished conversion to Netty 4 and added new error handling model.
niclasmeier authored
38 Meta data like the recipient, etc. will be stored as Clojure meta-data on the map.
39
de8cf54 @niclasmeier initial commit
niclasmeier authored
40 The next important step is to create a connecion. The connection will act as proxy for the real connection
41 to the Apple service. You don't need to open, close or maintain it. The underlying connection management
42 is handeled by the library and netty.
43
cc38041 @niclasmeier - updated version number
niclasmeier authored
44 ## Creating a connection
de8cf54 @niclasmeier initial commit
niclasmeier authored
45 To create a connection we will need a `ssl-context` and an `address` of the Apple servers. The `address` is the easy part.
46 You may need the `dev-address` or the `prod-address` to obtain the addresses used by Apple.
47
cc38041 @niclasmeier - updated version number
niclasmeier authored
48 To create the `ssl-context` you may use the functions in `herolabs.apns.ssl`. First create a Files or URLs to your
49 certificate and key files. Then you can use the `keystore` function to create a transient keystore containing the key and the certificate.
de8cf54 @niclasmeier initial commit
niclasmeier authored
50
cc38041 @niclasmeier - updated version number
niclasmeier authored
51 (let [key-file (resource "files/my-project.p12")
52 cert-file (resource "files/my-project.cer")
53 store (ssl/keystore :key-path key-
54 :key-pass "verysecretkeypass"
55 :cert-path cert-file)]
0f345ed @niclasmeier FInished conversion to Netty 4 and added new error handling model.
niclasmeier authored
56 ...
cc38041 @niclasmeier - updated version number
niclasmeier authored
57 )
58
de8cf54 @niclasmeier initial commit
niclasmeier authored
59
60 Unfortunately the certificates used by Apple are not signed by a major (known by the JRE) authority. So the connection
61 would not be established by the JRE. You have to choices: a) import the Apple certificates into the JRE keystores (secure)
62 b) override the trust manager so that he accepts the certificate (not so secure). In this example I chose b.
63
cc38041 @niclasmeier - updated version number
niclasmeier authored
64 Now lets have a look how to create the context and connection:
de8cf54 @niclasmeier initial commit
niclasmeier authored
65
cc38041 @niclasmeier - updated version number
niclasmeier authored
66 (let [silly-trust-managers (naive-trust-managers :trace true)
67 ctx (ssl/ssl-context :keystore store :trust-managers silly-trust-managers)
68 connection (push/create-connection (dev-address) ctx)]
0f345ed @niclasmeier FInished conversion to Netty 4 and added new error handling model.
niclasmeier authored
69 ...
cc38041 @niclasmeier - updated version number
niclasmeier authored
70 )
de8cf54 @niclasmeier initial commit
niclasmeier authored
71
72
73 Now lets send a message:
74
0f345ed @niclasmeier FInished conversion to Netty 4 and added new error handling model.
niclasmeier authored
75 (send connection message)
de8cf54 @niclasmeier initial commit
niclasmeier authored
76
0f345ed @niclasmeier FInished conversion to Netty 4 and added new error handling model.
niclasmeier authored
77 Due to the nature of the protocol the feedback is very "limitied". The 0.5.x-Series uses the most recent protocol version of the Apple service, so the feedback got better.
de8cf54 @niclasmeier initial commit
niclasmeier authored
78
79
0f345ed @niclasmeier FInished conversion to Netty 4 and added new error handling model.
niclasmeier authored
80 ### Error Handling
81 The error handling is new to the 0.5.x version series and a little more manual/explicit than before.
cc38041 @niclasmeier - updated version number
niclasmeier authored
82
0f345ed @niclasmeier FInished conversion to Netty 4 and added new error handling model.
niclasmeier authored
83 Some good news first, you are able to provide some handling functions for almost every event Netty is providing. E.g. a `:disconnect-handler` to write something when the connection was disconnected:
cc38041 @niclasmeier - updated version number
niclasmeier authored
84
0f345ed @niclasmeier FInished conversion to Netty 4 and added new error handling model.
niclasmeier authored
85 (push/create-connection (dev-address) ctx :disconnect-handler (fn [_ _] (println "disconnected.")))
cc38041 @niclasmeier - updated version number
niclasmeier authored
86
0f345ed @niclasmeier FInished conversion to Netty 4 and added new error handling model.
niclasmeier authored
87 Simply supply the the addional parameter on connection creation.
cc38041 @niclasmeier - updated version number
niclasmeier authored
88
0f345ed @niclasmeier FInished conversion to Netty 4 and added new error handling model.
niclasmeier authored
89 The most intersting handler to supply are the `:channel-inactive-handler` and the `:error-handler` - which is something APS specific.
cc38041 @niclasmeier - updated version number
niclasmeier authored
90
0f345ed @niclasmeier FInished conversion to Netty 4 and added new error handling model.
niclasmeier authored
91 The `:channel-inactive-handler` is called when the connection is closed and the underlying channel ist disconnected from the Netty EventLoop. You max pass an arity 2 function which will receive the `ChannelHandlerContext` and a list of messages which where sent to the APS service but should be re-sent. For details [look at the APS dokumentation](https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/WhatAreRemoteNotif.html) and continue reading.
cc38041 @niclasmeier - updated version number
niclasmeier authored
92
0f345ed @niclasmeier FInished conversion to Netty 4 and added new error handling model.
niclasmeier authored
93 The `:error-handler` is a more convenient `:channel-read-handler` (therefore you may only supply one or the other when creating a connection). The only response Apple sends is an error response before disconnecting. The error handler will be called when receiving the error message from apple. You may supply an one argument function which will get a map like this:
cc38041 @niclasmeier - updated version number
niclasmeier authored
94
0f345ed @niclasmeier FInished conversion to Netty 4 and added new error handling model.
niclasmeier authored
95 {:status :invalid-token :id 3892 :faulty {:aps { ... }} :resent ()}
cc38041 @niclasmeier - updated version number
niclasmeier authored
96
0f345ed @niclasmeier FInished conversion to Netty 4 and added new error handling model.
niclasmeier authored
97 * `status`: The status flag of the response from Apple
98 * `id`: The internal ID of the message in the context of the current connection
99 * `faulty`: The message which caused the error
100 * `resent`: The messages which are propably lost at Apple and should be re-sent.
cc38041 @niclasmeier - updated version number
niclasmeier authored
101
0f345ed @niclasmeier FInished conversion to Netty 4 and added new error handling model.
niclasmeier authored
102 One more word on this messages that gone missing. Apple does not process any message after the faulty one. So the connection remembers (and forgets them after 15 seconds) of all messages sent. When the error message is received all messages before the faulty will also removed, so you get the ones which where sent and possibily not processed.
de8cf54 @niclasmeier initial commit
niclasmeier authored
103
0f345ed @niclasmeier FInished conversion to Netty 4 and added new error handling model.
niclasmeier authored
104 So how to do the error handling:
105
106 (def ^:private aps-connection (atom nil))
107
108 (declare connection)
15d1545 @niclasmeier - added some further instructions.
niclasmeier authored
109
0f345ed @niclasmeier FInished conversion to Netty 4 and added new error handling model.
niclasmeier authored
110 (defn- resent-handler []
111 (fn resent-handler-fn [_ re-sent]
112 (doseq [msg re-sent] (push/sent (connection) msg))))
15d1545 @niclasmeier - added some further instructions.
niclasmeier authored
113
0f345ed @niclasmeier FInished conversion to Netty 4 and added new error handling model.
niclasmeier authored
114 (defn- error-handler [error]
115 (swap! aps-connection (fn [_] nil))
116 (let [status (:status error)
117 faulty (:faulty error)
118 device-token (:devive-token (meta faulty))]
119 (when (and (= :invalid-token status) device-token)
120 (delete-token-from-somewhere token))))
15d1545 @niclasmeier - added some further instructions.
niclasmeier authored
121
0f345ed @niclasmeier FInished conversion to Netty 4 and added new error handling model.
niclasmeier authored
122 (def connection []
123 (or @aps-connection
124 (swap! aps-connection (fn [_]
125 (when-let [ssl-context (get-ssl-context)]
126 (let [address (if (= :prod mode) (push/prod-address) (push/dev-address))]
127 (push/create-connection address ssl-context
128 :channel-inactive-handler (resent-handler edition-id)
129 :error-handler error-handler)))
130 )))))
de8cf54 @niclasmeier initial commit
niclasmeier authored
131
0f345ed @niclasmeier FInished conversion to Netty 4 and added new error handling model.
niclasmeier authored
132 I defined two handler functions. One which handle the re-sending of the messages and the other removes the cached connection and e.g. deletes tokens from my database when the token is invalid.
de8cf54 @niclasmeier initial commit
niclasmeier authored
133
0f345ed @niclasmeier FInished conversion to Netty 4 and added new error handling model.
niclasmeier authored
134 ## Feedback Service
135 To use the push notifications correctly you'll have to check for feedback in a regular fashion. The feedback service
136 provides a list of device tokens and timestamps of the devices that have your application no longer installed.
de8cf54 @niclasmeier initial commit
niclasmeier authored
137
0f345ed @niclasmeier FInished conversion to Netty 4 and added new error handling model.
niclasmeier authored
138 Using this service is also pretty simple:
de8cf54 @niclasmeier initial commit
niclasmeier authored
139
0f345ed @niclasmeier FInished conversion to Netty 4 and added new error handling model.
niclasmeier authored
140 (doseq [[token timestamp] (feedback (dev-address) ssl-context)]
141 (deregister-device token))
de8cf54 @niclasmeier initial commit
niclasmeier authored
142
0f345ed @niclasmeier FInished conversion to Netty 4 and added new error handling model.
niclasmeier authored
143 The `feedback` function returns a lazy collection that reads the data from the service. The `herolabs.apns.feedback`
144 also contain the `dev-address` or the `prod-address` functions to contain the addresses. Be aware that they differ from
145 the ones used by the push service.
de8cf54 @niclasmeier initial commit
niclasmeier authored
146
147
148
149 ## License
150
151 Copyright (c) 2012 HEROLABS GmbH. All rights reserved.
152
153 The use and distribution terms for this software are covered by the
154 Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
155 which can be found in the file epl-v10.html at the root of this distribution.
156 By using this software in any fashion, you are agreeing to be bound by
157 the terms of this license.
158 You must not remove this notice, or any other, from this software.
159
160 Unless required by applicable law or agreed to in writing, software
161 distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
162 WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
163 License for the specific language governing permissions and limitations under
164 the License.
Something went wrong with that request. Please try again.