Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 144 lines (80 sloc) 8.526 kb
a86a96d Updating readme w/ current status
Kali Donovan authored
1 == UPDATE Sept 19, 2011: current status
2
3 The project I built this for was cancelled months ago, which means I don't have valid PEM keys or any infrastructure in place to test. I hope to start a new iOS app as soon as the jQuery Mobile team releases their 1.0 release, but in the meantime you're better off looking at the community for help with any issues that come up. Sorry for the inconvenience, and hopefully I'll be able to dive back into this soon!
4
5 -----
6
b5a539b @kdonovan Touching up documentation, monit config, and daemon.
kdonovan authored
7 == Synopsis
a0b2747 @kdonovan yajl somehow destroyed to_s and to_json on certain models when this g…
kdonovan authored
8
b5a539b @kdonovan Touching up documentation, monit config, and daemon.
kdonovan authored
9 Need to send background notifications to an iPhone application over a <em>persistent</em> connection in Ruby? Keep reading...
10
11 == The Story
12
91ff205 @kdonovan Minor README changes
kdonovan authored
13 So you're building the server component of an iPhone application in Ruby. And you want to send background notifications through the Apple Push Notification servers, which doesn't seem too bad at first. But then you read in the {Apple Documentation}[https://developer.apple.com/iphone/library/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/WhatAreRemoteNotif/WhatAreRemoteNotif.html#//apple_ref/doc/uid/TP40008194-CH102-SW7] that Apple's servers may treat non-persistent connections as a Denial of Service attack, and you realize that Rails has no easy way to maintain a persistent connection internally, and things start looking more complicated.
b5a539b @kdonovan Touching up documentation, monit config, and daemon.
kdonovan authored
14
15 The apn_sender gem includes a background daemon which processes background messages from your application and sends them along to Apple <em>over a single, persistent socket</em>. It also includes the ability to query the Feedback service, helper methods for enqueueing your jobs, and a sample monit config to make sure the background worker is around when you need it.
a0b2747 @kdonovan yajl somehow destroyed to_s and to_json on certain models when this g…
kdonovan authored
16
b5a539b @kdonovan Touching up documentation, monit config, and daemon.
kdonovan authored
17 == Yet another ApplePushNotification interface?
cdbb386 @kdonovan Tweaked README
kdonovan authored
18
b5a539b @kdonovan Touching up documentation, monit config, and daemon.
kdonovan authored
19 Yup. There's some great code out there already, but we didn't like the idea of getting banned from the APN gateway for establishing a new connection each time we needed to send a batch of messages, and none of the libraries I found handled maintaining a persistent connection.
cdbb386 @kdonovan Tweaked README
kdonovan authored
20
b5a539b @kdonovan Touching up documentation, monit config, and daemon.
kdonovan authored
21 == Current Status
cdbb386 @kdonovan Tweaked README
kdonovan authored
22
b5a539b @kdonovan Touching up documentation, monit config, and daemon.
kdonovan authored
23 This gem has been in production use since early May, 2010. There are no guarantees of complete functionality, of course, but it's working for us. :)
91ff205 @kdonovan Minor README changes
kdonovan authored
24 ** UPDATE: our site is now defunct (for completely-unrelated reasons), but the many forks and watchers make me think something's going right. **
26f0566 @kdonovan Initial commit to apple_push_notification.
kdonovan authored
25
f4aaa2c @kdonovan Basic functionality in place
kdonovan authored
26 == Usage
27
a760a88 @kdonovan Better notification sending. Added Feedback Service support.
kdonovan authored
28 === 1. Queueing Messages From Your Application
f4aaa2c @kdonovan Basic functionality in place
kdonovan authored
29
cdbb386 @kdonovan Tweaked README
kdonovan authored
30 To queue a message for sending through Apple's Push Notification service from your Rails application:
f4aaa2c @kdonovan Basic functionality in place
kdonovan authored
31
1ec459d @kdonovan Renamed gem to apn_sender, lib to apn.
kdonovan authored
32 APN.notify(token, opts_hash)
f4aaa2c @kdonovan Basic functionality in place
kdonovan authored
33
1ec459d @kdonovan Renamed gem to apn_sender, lib to apn.
kdonovan authored
34 where +token+ is the unique identifier of the iPhone to receive the notification and +opts_hash+ can have any of the following keys:
f4aaa2c @kdonovan Basic functionality in place
kdonovan authored
35
1ec459d @kdonovan Renamed gem to apn_sender, lib to apn.
kdonovan authored
36 # :alert #=> The alert to send
37 # :badge #=> The badge number to send
38 # :sound #=> The sound file to play on receipt, or true to play the default sound installed with your app
711b466 @kdonovan Readme tweak - no more :custom key.
kdonovan authored
39
40 If any other keys are present they'll be be passed along as custom data to your application.
f4aaa2c @kdonovan Basic functionality in place
kdonovan authored
41
a760a88 @kdonovan Better notification sending. Added Feedback Service support.
kdonovan authored
42 === 2. Sending Queued Messages
f4aaa2c @kdonovan Basic functionality in place
kdonovan authored
43
cdbb386 @kdonovan Tweaked README
kdonovan authored
44 Put your <code>apn_development.pem</code> and <code>apn_production.pem</code> certificates from Apple in your <code>RAILS_ROOT/config/certs</code> directory.
45
46 Once this is done, you can fire off a background worker with
47
48 $ rake apn:sender
49
50 For production, you're probably better off running a dedicated daemon and setting up monit to watch over it for you. Luckily, that's pretty easy:
51
b5a539b @kdonovan Touching up documentation, monit config, and daemon.
kdonovan authored
52 # To generate daemon
53 ./script/generate apn_sender
54
55 # To run daemon. Pass --help to print all options
56 ./script/apn_sender --environment=production --verbose start
cdbb386 @kdonovan Tweaked README
kdonovan authored
57
4df180a @kdonovan Adding :full_cert_path, which allows explicitly specifying custom cer…
kdonovan authored
58 Note the --environment must be explicitly set (separately from your <code>Rails.env</code>) to production in order to send messages via the production APN servers. Any other environment sends messages through Apple's sandbox servers at <code>gateway.sandbox.push.apple.com</code>.
cdbb386 @kdonovan Tweaked README
kdonovan authored
59
d91d0eb @kdonovan README tweaks
kdonovan authored
60 Also, there are two similar options: <code>:cert_path</code> and <code>:full_cert_path</code>. The former specifies the directory in which to find the .pem file (either apn_production.pem or apn_development.pem, depending on the environment). The latter specifies a .pem file explicitly, allowing customized certificate names if needed.
4df180a @kdonovan Adding :full_cert_path, which allows explicitly specifying custom cer…
kdonovan authored
61
62 Check <code>logs/apn_sender.log</code> for debugging output. In addition to logging any major errors there, apn_sender hooks into the Resque::Worker logging to display any verbose or very_verbose worker output in apn_sender.log file as well.
b5a539b @kdonovan Touching up documentation, monit config, and daemon.
kdonovan authored
63
64
a760a88 @kdonovan Better notification sending. Added Feedback Service support.
kdonovan authored
65 === 3. Checking Apple's Feedback Service
66
67 Since push notifications are a fire-and-forget sorta deal, where you get no indication if your message was received (or if the specified recipient even exists), Apple needed to come up with some other way to ensure their network isn't clogged with thousands of bogus messages (e.g. from developers sending messages to phones where their application <em>used</em> to be installed, but where the user has since removed it). Hence, the Feedback Service.
68
69 It's actually really simple - you connect to them periodically and they give you a big dump of tokens you shouldn't send to anymore. The gem wraps this up nicely -- just call:
70
4df180a @kdonovan Adding :full_cert_path, which allows explicitly specifying custom cer…
kdonovan authored
71 # APN::Feedback accepts the same optional :environment and :cert_path / :full_cert_path options as APN::Sender
a760a88 @kdonovan Better notification sending. Added Feedback Service support.
kdonovan authored
72 feedback = APN::Feedback.new()
73
74 tokens = feedback.tokens # => Array of device tokens
75 tokens.each do |token|
76 # ... custom logic here to stop you app from
77 # sending further notifications to this token
78 end
79
80 If you're interested in knowing exactly <em>when</em> Apple determined each token was expired (which can be useful in determining if the application re-registered with your service since it first appeared in the expired queue):
81
82 items = feedback.data # => Array of APN::FeedbackItem elements
83 items.each do |item|
84 item.token
85 item.timestamp
86 # ... custom logic here
87 end
88
b5a539b @kdonovan Touching up documentation, monit config, and daemon.
kdonovan authored
89 The Feedback Service works as a big queue. When you connect it pops off all its data and sends it over the wire at once, which means connecting a second time will return an empty array, so for ease of use a call to either +tokens+ or +data+ will connect once and cache the data. If you call either one again it'll continue to use its cached version (rather than connecting to Apple a second time to retrieve an empty array, which is probably not what you want).
a760a88 @kdonovan Better notification sending. Added Feedback Service support.
kdonovan authored
90
91 Forcing a reconnect is as easy as calling either method with the single parameter +true+, but be sure you've already used the existing data because you'll never get it back.
92
93
94 ==== Warning: No really, check Apple's Feedback Service occasionally
95
91ff205 @kdonovan Minor README changes
kdonovan authored
96 If you're sending notifications, you should definitely call one of the <code>receive</code> methods periodically, as Apple's policies require it and they apparently monitor providers for compliance. I'd definitely recommend throwing together a quick rake task to take care of this for you (the {whenever library}[http://github.com/javan/whenever] provides a nice wrapper around scheduling tasks to run at certain times (for systems with cron enabled)).
a760a88 @kdonovan Better notification sending. Added Feedback Service support.
kdonovan authored
97
e6e3556 @kdonovan Documentation tweaks + strip illegal characters from token
kdonovan authored
98 Just for the record, this is essentially what you want to have whenever run periodically for you:
99
100 def self.clear_uninstalled_applications
101 feedback_data = APN::Feedback.new(:environment => :production).data
102
103 feedback_data.each do |item|
104 user = User.find_by_iphone_token( item.token )
105
106 if user.iphone_token_updated_at && user.iphone_token_updated_at > item.timestamp
107 return true # App has been reregistered since Apple determined it'd been uninstalled
108 else
109 user.update_attributes(:iphone_token => nil, :iphone_token_updated_at => Time.now)
110 end
111 end
112 end
a760a88 @kdonovan Better notification sending. Added Feedback Service support.
kdonovan authored
113
114
115
116
cdbb386 @kdonovan Tweaked README
kdonovan authored
117 === Keeping Your Workers Working
118
7e41bc1 @kdonovan Successful receipt of messages verified from IRB and rake.
kdonovan authored
119 There's also an included sample <code>apn_sender.monitrc</code> file in the <code>contrib/</code> folder to help monit handle server restarts and unexpected disasters.
120
f4aaa2c @kdonovan Basic functionality in place
kdonovan authored
121
cdbb386 @kdonovan Tweaked README
kdonovan authored
122 == Installation
f4aaa2c @kdonovan Basic functionality in place
kdonovan authored
123
1ec459d @kdonovan Renamed gem to apn_sender, lib to apn.
kdonovan authored
124 APN is built on top of {Resque}[http://github.com/defunkt/resque] (an awesome {Redis}[http://code.google.com/p/redis/]-based background runner similar to {delayed_job}[http://github.com/collectiveidea/delayed_job]). Read through the {Resque README}[http://github.com/defunkt/resque#readme] to get a feel for what's going on, follow the installation instructions there, and then run:
f4aaa2c @kdonovan Basic functionality in place
kdonovan authored
125
91ff205 @kdonovan Minor README changes
kdonovan authored
126 $ gem install apn_sender
f4aaa2c @kdonovan Basic functionality in place
kdonovan authored
127
91ff205 @kdonovan Minor README changes
kdonovan authored
128 In your Rails app, add (2.3.x):
f4aaa2c @kdonovan Basic functionality in place
kdonovan authored
129
faec50b @kdonovan Tweaking documentation, tasks
kdonovan authored
130 config.gem 'apn_sender', :lib => 'apn'
131
91ff205 @kdonovan Minor README changes
kdonovan authored
132 or (3.x) to your Gemfile:
133
134 gem 'apn_sender', :require => 'apn'
135
faec50b @kdonovan Tweaking documentation, tasks
kdonovan authored
136 To add a few useful rake tasks for running workers, add the following line to your Rakefile:
137
138 require 'apn/tasks'
139
26f0566 @kdonovan Initial commit to apple_push_notification.
kdonovan authored
140
141 == Copyright
142
143 Copyright (c) 2010 Kali Donovan. See LICENSE for details.
Something went wrong with that request. Please try again.