APNS

A plugin/Gem for the Apple Push Notification Service.

The connections to Apple are done on demand (per process) and last until they are either closed by the system or are timed out. This is the prefered way for communicating with Apple’s push servers.

Works in Ruby on Rails 3.

Install


sudo gem install apns
  or
rails plugin install git://...
  

Setup:

Convert your certificates

In Keychain access export your push certificate(s) as a .p12. Then run the following command to convert each .p12 to a .pem


openssl pkcs12 -in cert.p12 -out cert.pem -nodes -clcerts
  

After you have your .pem files, copy them to a place where APNS can access them. You will need to register them with APNS before being able to send Notifications

In a Rails project, you can add an initializer to configure the pem(s), with for example:


In file ./config/initializers/APNS.rb:

# Initialize the APNS environment
APNS.pem = Rails.root.join("config", Rails.env + ".pem") # => ./config/{development,production}.pem

  

Creating a Payload:

Sending a push notification is sending a Payload to Apple’s servers.

You may create payloads with APNS::Payload.new( [,]) A payload is composed of a device-token and a message all mixed and encoded together. Payload message can either just be a alert string or a hash that lets you specify the alert, badge, sound and any custom field.


device_token = '123abc456def'
p1 = APNS::Payload.new(device_token, 'Hello iPhone!')
p2 = APNS::Payload.new(device_token, :alert => 'Hello iPhone!', :badge => 1, :sound => 'default')
p3 = APNS::Payload.new(device_token).badge(4).alert("Hello iPhone!").sound('bird.aiff')

# with custom data:
p4 = APNS::Payload.new(device_token, :badge => 2, :my_custom_field => 'blah')
p5 = APNS::Payload.new(device_token, :badge => 2).custom(:my_custom_field => 'blah')

Truncating payload informations

Only valid Payloads will be sent to Apple. From APNS point of view, a valid payload has a size lesser or equal to 256 bytes. REM: Apple may find a APNS valid payload invalid because it doesn’t contain mandatory fields in the message part. For instance, a message must at least contain a non empty badge or sound or alert.

You can check whether a payload is valid with the Payload#valid? method. In case you know a payload message field is too large and wish to have it truncated you can either use Payload#payload_with_truncated_alert or a more generic Payload#payload_with_truncated_string_at_keypath. These two method will try to truncate the value of the alert field or any custom field at a keypath.

Truncate the alert field:


p = APNS::Payload.new("a-device-token", "A very long message "*15)
p.valid?
=> false
p.size
=> 331
p.payload_with_truncated_alert.size
=> 256
p.payload_with_truncated_alert.valid?
=> true    
  

Truncate a custom field:


p = APNS::Payload.new("a-device-token", :alert => "Hello from APNS", :custom => {:foo => "Bar "*80})
p.valid?
=> false
p.size
=> 387
p.payload_with_truncated_string_at_keypath("custom.foo").size
=> 256
p.payload_with_truncated_string_at_keypath("custom.foo").valid?
=> true
	

Sending Notifications to a single application:

Before sending notifications, you must have setup the pem file(s) so that Apple knows which application you are sending a notification to.


APNS.pem = "/path/to/my/development.pem"

Now we can send some payloads either with:

  • APNS.send_payloads()
  • APNS.send() # same as APNS.send_payloads

APNS.send(p1, p2, p3)

Sending Notifications to multiple applications:

You may want to handle push notifications for many applications at once. In this case you have to setup multiple pem streams:


@streams = [:voodoo, :child]

@streams.each do |stream|
	APNS.pem(stream, "/path/to/#{stream}/development.pem"
end
  

Now you can send the notifications to any stream with:

* APNS.send_stream(, )


APNS.send_stream(@streams.first, p1, p2, p3)
APNS.send_stream(@streams.last, p4, p5)

Feedback queue:

You should check the feedback queue of your application on Apple’s servers to avoid sending notifications to obsolete devices

For single pem:


APNS.feedback.each do |time, token|
	# remove the device registered with this token ?
end

For multiple pems:


APNS.feedback(@streams.first).each do |time, token|
	# remove the device registered with this token ?
end

Getting your iPhone’s device token

After you setup push notification for your application with Apple. You need to ask Apple for you application specific device token.

In the UIApplicationDelegate


- (void)applicationDidFinishLaunching:(UIApplication *)application {    
	[[UIApplication sharedApplication] registerForRemoteNotificationTypes:
		(UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeBadge)];	
}</p>
<p>- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
	// Do something with the device token
}