apple_push_notification 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/CHANGELOG.rdoc +8 -0
- data/LICENSE +1 -1
- data/Rakefile +1 -1
- data/Readme.markdown +64 -25
- data/VERSION +1 -1
- data/apple_push_notification.gemspec +53 -0
- data/init.rb +1 -0
- data/lib/apple_push_notification.rb +101 -9
- data/lib/apple_push_notification/acts_as_pushable.rb +14 -0
- data/rails/init.rb +1 -0
- metadata +5 -7
- data/install.rb +0 -0
- data/lib/app/models/apple_push_notification.rb +0 -101
- data/lib/db/migrate/20090406132059_create_apple_push_notifications.rb +0 -18
- data/tasks/apple_push_notification_tasks.rake +0 -10
- data/uninstall.rb +0 -1
data/.gitignore
CHANGED
data/CHANGELOG.rdoc
ADDED
data/LICENSE
CHANGED
data/Rakefile
CHANGED
@@ -30,7 +30,7 @@ begin
|
|
30
30
|
gemspec.description = "Rails plugin for Apple Push Notifications"
|
31
31
|
gemspec.email = "sam@samsoff.es"
|
32
32
|
gemspec.homepage = "http://github.com/samsoffes/apple_push_notification"
|
33
|
-
gemspec.authors = ["Sam Soffes"
|
33
|
+
gemspec.authors = ["Sam Soffes"]
|
34
34
|
end
|
35
35
|
Jeweler::GemcutterTasks.new
|
36
36
|
rescue LoadError
|
data/Readme.markdown
CHANGED
@@ -2,6 +2,24 @@
|
|
2
2
|
|
3
3
|
This plugin helps you use the Apple Push Notification system.
|
4
4
|
|
5
|
+
## Installing
|
6
|
+
|
7
|
+
Install as a gem:
|
8
|
+
|
9
|
+
# Add to config/environment.rb:
|
10
|
+
config.gem "apple_push_notification", :source => "http://gemcutter.org/"
|
11
|
+
|
12
|
+
# At command prompt:
|
13
|
+
$ sudo rake gems:install
|
14
|
+
|
15
|
+
or as a plugin:
|
16
|
+
|
17
|
+
$ script/plugin install git://github.com/samsoffes/apple_push_notification.git
|
18
|
+
|
19
|
+
Once you have installed ApplePushNotification, run the following command:
|
20
|
+
|
21
|
+
$ rake apn:migrate
|
22
|
+
|
5
23
|
## Converting Your Certificate
|
6
24
|
|
7
25
|
Once you have the certificate from Apple for your application, export your key
|
@@ -17,46 +35,67 @@ Now covert the p12 file to a pem file:
|
|
17
35
|
|
18
36
|
Put `apn_development.pem` in `config/certs` in your rails app. For production, name your certificate `apn_production.pem` and put it in the same directory. See the environment section for more about environments.
|
19
37
|
|
20
|
-
##
|
38
|
+
## Environment
|
21
39
|
|
22
|
-
|
40
|
+
By default, the development environment will always be used. This makes it easy to test your app in production before your iPhone application is approved and your production certificate is active. You can easily override this by adding this line in an initializer or environment file.
|
23
41
|
|
24
|
-
|
25
|
-
config.gem "apple_push_notification", :source => "http://gemcutter.org/"
|
42
|
+
ApplePushNotification.enviroment = Rails.env.to_sym
|
26
43
|
|
27
|
-
|
28
|
-
$ sudo rake gems:install
|
44
|
+
You can also simply set `ApplePushNotification.enviroment` to `:development` or `:production`. Setting the `ApplePushNotification.enviroment` chooses the appropriate certificate in your `certs` folder and Apple push notification server.
|
29
45
|
|
30
|
-
|
46
|
+
## Usage
|
31
47
|
|
32
|
-
|
48
|
+
You can use ApplePushNotification with an ActiveRecord model, standalone, or on any object.
|
33
49
|
|
34
|
-
|
50
|
+
### ActiveRecord
|
35
51
|
|
36
|
-
|
52
|
+
Just add `acts_as_pushable` to your model.
|
37
53
|
|
38
|
-
|
54
|
+
class Device < ActiveRecord::Base
|
55
|
+
acts_as_pushable
|
56
|
+
end
|
39
57
|
|
40
|
-
|
58
|
+
You can then send a notification like this
|
41
59
|
|
42
|
-
|
60
|
+
d.send_notification :alert => "I heart Rails"
|
43
61
|
|
44
|
-
|
62
|
+
The `send_notification` method accepts a hash of options for the notification parameters. See the Parameters section for more information.
|
63
|
+
|
64
|
+
Your model must have a `device_token` attribute. If you wish to change this to something else (like `device` for example), simply pass it like this `acts_as_pushable :device`.
|
65
|
+
|
66
|
+
### Standalone
|
45
67
|
|
46
|
-
|
68
|
+
Simply call `ApplePushNotification.send_notification` and pass the device token as the first parameter and the hash of notification options as the second (see the Parameters section for more information).
|
47
69
|
|
48
|
-
$
|
49
|
-
>>
|
50
|
-
>>
|
51
|
-
>> a.badge = 5
|
52
|
-
>> a.sound = true
|
53
|
-
>> a.alert = "Hello world"
|
54
|
-
>> a.send_notification
|
70
|
+
$ script/console
|
71
|
+
>> token = "XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX"
|
72
|
+
>> ApplePushNotification.send_notification token, :alert => "Hello World!", :badge => 5, :sound => true
|
55
73
|
=> nil
|
56
74
|
|
75
|
+
### Any Object
|
76
|
+
|
77
|
+
You can extend ApplePushNotification with any class. It will look for the `device_token` method when sending the notification. When ApplePushNotification is extended, if `device_token=` isn't defined, getters and setters are generated.
|
78
|
+
|
79
|
+
$ script/console
|
80
|
+
>> token = "XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX"
|
81
|
+
>> d = Object.new
|
82
|
+
>> d.extend ApplePushNotification
|
83
|
+
>> d.device_token = token
|
84
|
+
>> d.send_notification :alert => "So flexible"
|
85
|
+
=> nil
|
86
|
+
|
87
|
+
See the Parameters section for more information on what `send_notification` accepts.
|
88
|
+
|
89
|
+
## Parameters
|
90
|
+
|
91
|
+
The following notification parameters can be defined in the options hash:
|
92
|
+
|
93
|
+
* `alert` - text displayed to the use
|
94
|
+
* `sound` - this can be the filename (i.e. `explosion.aiff`) or `true` which will play the default notification sound
|
95
|
+
* `badge` - this must be an integer
|
96
|
+
|
57
97
|
### Notes
|
58
98
|
|
59
|
-
* The spaces in `device_token` are optional.
|
60
|
-
* The `sound` can be the filename (i.e. `explosion.aiff`) or `true` which will play the default notification sound.
|
99
|
+
* The spaces in `device_token` are optional and will be ignored.
|
61
100
|
|
62
|
-
Copyright (c) 2009
|
101
|
+
Copyright (c) 2009 [Sam Soffes](http://samsoff.es). Released under the MIT license. Forked from Fabien Penso.
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.2.0
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{apple_push_notification}
|
8
|
+
s.version = "0.2.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Sam Soffes"]
|
12
|
+
s.date = %q{2009-11-10}
|
13
|
+
s.description = %q{Rails plugin for Apple Push Notifications}
|
14
|
+
s.email = %q{sam@samsoff.es}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE"
|
17
|
+
]
|
18
|
+
s.files = [
|
19
|
+
".gitignore",
|
20
|
+
"CHANGELOG.rdoc",
|
21
|
+
"LICENSE",
|
22
|
+
"Rakefile",
|
23
|
+
"Readme.markdown",
|
24
|
+
"VERSION",
|
25
|
+
"apple_push_notification.gemspec",
|
26
|
+
"init.rb",
|
27
|
+
"lib/apple_push_notification.rb",
|
28
|
+
"lib/apple_push_notification/acts_as_pushable.rb",
|
29
|
+
"rails/init.rb",
|
30
|
+
"test/apple_push_notification_test.rb",
|
31
|
+
"test/test_helper.rb"
|
32
|
+
]
|
33
|
+
s.homepage = %q{http://github.com/samsoffes/apple_push_notification}
|
34
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
35
|
+
s.require_paths = ["lib"]
|
36
|
+
s.rubygems_version = %q{1.3.5}
|
37
|
+
s.summary = %q{Rails plugin for Apple Push Notifications}
|
38
|
+
s.test_files = [
|
39
|
+
"test/apple_push_notification_test.rb",
|
40
|
+
"test/test_helper.rb"
|
41
|
+
]
|
42
|
+
|
43
|
+
if s.respond_to? :specification_version then
|
44
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
45
|
+
s.specification_version = 3
|
46
|
+
|
47
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
48
|
+
else
|
49
|
+
end
|
50
|
+
else
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
data/init.rb
CHANGED
@@ -0,0 +1 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/rails/init.rb"
|
@@ -1,9 +1,101 @@
|
|
1
|
-
require
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
1
|
+
require 'socket'
|
2
|
+
require 'openssl'
|
3
|
+
|
4
|
+
module ApplePushNotification
|
5
|
+
|
6
|
+
def self.extended(base)
|
7
|
+
# Added device_token attribute if not included by acts_as_pushable
|
8
|
+
unless base.respond_to?(:acts_as_push_options)
|
9
|
+
base.class_eval do
|
10
|
+
attr_accessor :device_token
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
APN_PORT = 2195
|
16
|
+
@@apn_cert = nil
|
17
|
+
@@apn_host = nil
|
18
|
+
|
19
|
+
def self.apn_enviroment
|
20
|
+
@@apn_enviroment
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.apn_development?
|
24
|
+
@@apn_enviroment != :production
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.apn_production?
|
28
|
+
@@apn_enviroment == :production
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.apn_enviroment= enviroment
|
32
|
+
@@apn_enviroment = enviroment.to_sym
|
33
|
+
@@apn_host = self.apn_production? ? "gateway.push.apple.com" : "gateway.sandbox.push.apple.com"
|
34
|
+
cert = self.apn_production? ? "apn_production.pem" : "apn_development.pem"
|
35
|
+
path = File.join(File.expand_path(RAILS_ROOT), "config", "certs", cert)
|
36
|
+
@@apn_cert = File.exists?(path) ? File.read(path) : nil
|
37
|
+
raise "Missing apple push notification certificate in #{path}" unless @@apn_cert
|
38
|
+
end
|
39
|
+
|
40
|
+
self.apn_enviroment = :development
|
41
|
+
|
42
|
+
def send_notification options
|
43
|
+
raise "Missing apple push notification certificate" unless @@apn_cert
|
44
|
+
|
45
|
+
ctx = OpenSSL::SSL::SSLContext.new
|
46
|
+
ctx.key = OpenSSL::PKey::RSA.new(@@apn_cert)
|
47
|
+
ctx.cert = OpenSSL::X509::Certificate.new(@@apn_cert)
|
48
|
+
|
49
|
+
s = TCPSocket.new(@@apn_host, APN_PORT)
|
50
|
+
ssl = OpenSSL::SSL::SSLSocket.new(s, ctx)
|
51
|
+
ssl.sync = true
|
52
|
+
ssl.connect
|
53
|
+
|
54
|
+
ssl.write(self.apn_message_for_sending(options))
|
55
|
+
ssl.close
|
56
|
+
s.close
|
57
|
+
rescue SocketError => error
|
58
|
+
raise "Error while sending notifications: #{error}"
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.send_notification token, options = {}
|
62
|
+
d = Object.new
|
63
|
+
d.extend ApplePushNotification
|
64
|
+
d.device_token = token
|
65
|
+
d.send_notification options
|
66
|
+
end
|
67
|
+
|
68
|
+
protected
|
69
|
+
|
70
|
+
def apn_message_for_sending options
|
71
|
+
json = ApplePushNotification::apple_json_array options
|
72
|
+
message = "\0\0 #{self.device_token_hexa}\0#{json.length.chr}#{json}"
|
73
|
+
raise "The maximum size allowed for a notification payload is 256 bytes." if message.size.to_i > 256
|
74
|
+
message
|
75
|
+
end
|
76
|
+
|
77
|
+
def device_token_hexa
|
78
|
+
# Use `device_token` as the method to get the token from
|
79
|
+
# unless it is overridde from acts_as_pushable
|
80
|
+
apn_token_field = "device_token"
|
81
|
+
if respond_to?(:acts_as_push_options)
|
82
|
+
apn_token_field = acts_as_push_options[:device_token_field]
|
83
|
+
end
|
84
|
+
token = send(apn_token_field.to_sym)
|
85
|
+
raise "Cannot send push notification without device token" if !token || token.empty?
|
86
|
+
[token.delete(' ')].pack('H*')
|
87
|
+
end
|
88
|
+
|
89
|
+
def self.apple_json_array options
|
90
|
+
result = {}
|
91
|
+
result['aps'] = {}
|
92
|
+
result['aps']['alert'] = options[:alert].to_s if options[:alert]
|
93
|
+
result['aps']['badge'] = options[:badge].to_i if options[:badge]
|
94
|
+
result['aps']['sound'] = options[:sound] if options[:sound] and options[:sound].is_a? String
|
95
|
+
result['aps']['sound'] = 'default' if options[:sound] and options[:sound].is_a? TrueClass
|
96
|
+
result.to_json
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
|
101
|
+
require File.dirname(__FILE__) + "/apple_push_notification/acts_as_pushable"
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module ApplePushNotification
|
2
|
+
module ActsAsPushable
|
3
|
+
end
|
4
|
+
end
|
5
|
+
|
6
|
+
ActiveRecord::Base.class_eval do
|
7
|
+
def self.acts_as_pushable(device_token_field = :device_token)
|
8
|
+
class_inheritable_reader :acts_as_push_options
|
9
|
+
write_inheritable_attribute :acts_as_push_options, {
|
10
|
+
:device_token_field => device_token_field
|
11
|
+
}
|
12
|
+
include ApplePushNotification
|
13
|
+
end
|
14
|
+
end
|
data/rails/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "apple_push_notification"
|
metadata
CHANGED
@@ -1,11 +1,10 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: apple_push_notification
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sam Soffes
|
8
|
-
- Fabien Penso
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
@@ -24,19 +23,18 @@ extra_rdoc_files:
|
|
24
23
|
- LICENSE
|
25
24
|
files:
|
26
25
|
- .gitignore
|
26
|
+
- CHANGELOG.rdoc
|
27
27
|
- LICENSE
|
28
28
|
- Rakefile
|
29
29
|
- Readme.markdown
|
30
30
|
- VERSION
|
31
|
+
- apple_push_notification.gemspec
|
31
32
|
- init.rb
|
32
|
-
- install.rb
|
33
|
-
- lib/app/models/apple_push_notification.rb
|
34
33
|
- lib/apple_push_notification.rb
|
35
|
-
- lib/
|
36
|
-
-
|
34
|
+
- lib/apple_push_notification/acts_as_pushable.rb
|
35
|
+
- rails/init.rb
|
37
36
|
- test/apple_push_notification_test.rb
|
38
37
|
- test/test_helper.rb
|
39
|
-
- uninstall.rb
|
40
38
|
has_rdoc: true
|
41
39
|
homepage: http://github.com/samsoffes/apple_push_notification
|
42
40
|
licenses: []
|
data/install.rb
DELETED
File without changes
|
@@ -1,101 +0,0 @@
|
|
1
|
-
require 'socket'
|
2
|
-
require 'openssl'
|
3
|
-
|
4
|
-
class ApplePushNotification < ActiveRecord::Base
|
5
|
-
|
6
|
-
attr_accessor :paylod, :sound, :badge, :alert
|
7
|
-
attr_accessible :device_token
|
8
|
-
|
9
|
-
PORT = 2195
|
10
|
-
|
11
|
-
cattr_accessor :enviroment
|
12
|
-
self.enviroment = :development
|
13
|
-
|
14
|
-
validates_uniqueness_of :device_token
|
15
|
-
|
16
|
-
def send_notification
|
17
|
-
raise "Missing cert: #{_path}" unless @@cert
|
18
|
-
|
19
|
-
ctx = OpenSSL::SSL::SSLContext.new
|
20
|
-
ctx.key = OpenSSL::PKey::RSA.new(@@cert)
|
21
|
-
ctx.cert = OpenSSL::X509::Certificate.new(@@cert)
|
22
|
-
|
23
|
-
s = TCPSocket.new(@@host, PORT)
|
24
|
-
ssl = OpenSSL::SSL::SSLSocket.new(s, ctx)
|
25
|
-
ssl.sync = true
|
26
|
-
ssl.connect
|
27
|
-
|
28
|
-
ssl.write(self.apn_message_for_sending)
|
29
|
-
|
30
|
-
ssl.close
|
31
|
-
s.close
|
32
|
-
|
33
|
-
rescue SocketError => error
|
34
|
-
raise "Error while sending notifications: #{error}"
|
35
|
-
end
|
36
|
-
|
37
|
-
def self.enviroment= enviroment
|
38
|
-
@@enviroment = enviroment.to_sym
|
39
|
-
@@host = self.production? ? "gateway.push.apple.com" : "gateway.sandbox.push.apple.com"
|
40
|
-
cert = self.production? ? "apn_production.pem" : "apn_development.pem"
|
41
|
-
path = File.join(File.expand_path(RAILS_ROOT), "config", "certs", cert)
|
42
|
-
@@cert = File.exists?(path) ? File.read(path) : nil
|
43
|
-
end
|
44
|
-
|
45
|
-
def self.development?
|
46
|
-
@@enviroment != :production
|
47
|
-
end
|
48
|
-
|
49
|
-
def self.production?
|
50
|
-
@@enviroment == :production
|
51
|
-
end
|
52
|
-
|
53
|
-
def self.send_notifications(notifications)
|
54
|
-
ctx = OpenSSL::SSL::SSLContext.new
|
55
|
-
ctx.key = OpenSSL::PKey::RSA.new(@@cert)
|
56
|
-
ctx.cert = OpenSSL::X509::Certificate.new(@@cert)
|
57
|
-
|
58
|
-
s = TCPSocket.new(@@host, PORT)
|
59
|
-
ssl = OpenSSL::SSL::SSLSocket.new(s, ctx)
|
60
|
-
ssl.sync = true
|
61
|
-
ssl.connect
|
62
|
-
|
63
|
-
for notif in notifications do
|
64
|
-
ssl.write(notif.apn_message_for_sending)
|
65
|
-
end
|
66
|
-
|
67
|
-
ssl.close
|
68
|
-
s.close
|
69
|
-
rescue SocketError => error
|
70
|
-
raise "Error while sending notifications: #{error}"
|
71
|
-
end
|
72
|
-
|
73
|
-
protected
|
74
|
-
|
75
|
-
def to_apple_json
|
76
|
-
json = self.apple_array.to_json
|
77
|
-
logger.debug "Sending #{json}"
|
78
|
-
json
|
79
|
-
end
|
80
|
-
|
81
|
-
def apn_message_for_sending
|
82
|
-
json = self.to_apple_json
|
83
|
-
message = "\0\0 #{self.device_token_hexa}\0#{json.length.chr}#{json}"
|
84
|
-
raise "The maximum size allowed for a notification payload is 256 bytes." if message.size.to_i > 256
|
85
|
-
message
|
86
|
-
end
|
87
|
-
|
88
|
-
def device_token_hexa
|
89
|
-
[self.device_token.delete(' ')].pack('H*')
|
90
|
-
end
|
91
|
-
|
92
|
-
def apple_array
|
93
|
-
result = {}
|
94
|
-
result['aps'] = {}
|
95
|
-
result['aps']['alert'] = alert if alert
|
96
|
-
result['aps']['badge'] = badge.to_i if badge
|
97
|
-
result['aps']['sound'] = sound if sound and sound.is_a? String
|
98
|
-
result['aps']['sound'] = 'default' if sound and sound.is_a? TrueClass
|
99
|
-
result
|
100
|
-
end
|
101
|
-
end
|
@@ -1,18 +0,0 @@
|
|
1
|
-
class CreateApplePushNotifications < ActiveRecord::Migration
|
2
|
-
def self.up
|
3
|
-
# This is used to store the device UID informations
|
4
|
-
create_table :apple_push_notifications do |t|
|
5
|
-
t.string :device_token, :size => 71
|
6
|
-
t.integer :errors_nb, :default => 0 # used for storing errors from apple feedbacks
|
7
|
-
t.string :device_language, :size => 5 # if you don't want to send localized strings
|
8
|
-
|
9
|
-
t.timestamps
|
10
|
-
end
|
11
|
-
|
12
|
-
add_index :apple_push_notifications, :device_token
|
13
|
-
end
|
14
|
-
|
15
|
-
def self.down
|
16
|
-
drop_table :apple_push_notifications
|
17
|
-
end
|
18
|
-
end
|
@@ -1,10 +0,0 @@
|
|
1
|
-
namespace :apn do
|
2
|
-
desc "migrates ugin's migration files into the database."
|
3
|
-
task :migrate => :environment do
|
4
|
-
|
5
|
-
ActiveRecord::Migration.verbose = ENV["VERBOSE"] ? ENV["VERBOSE"] == "true" : true
|
6
|
-
ActiveRecord::Migrator.migrate(File.expand_path(File.dirname(__FILE__) + "/../lib/db/migrate"), ENV["VERSION"] ? ENV["VERSION"].to_i : nil)
|
7
|
-
|
8
|
-
Rake::Task["db:schema:dump"].invoke if ActiveRecord::Base.schema_format == :ruby
|
9
|
-
end
|
10
|
-
end
|
data/uninstall.rb
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
# Uninstall hook code here
|