dr-apns 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/MIT-LICENSE +22 -0
- data/README.textile +153 -0
- data/Rakefile +53 -0
- data/lib/apns/core.rb +239 -0
- data/lib/apns.rb +24 -0
- metadata +50 -0
data/MIT-LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2009 James Pozdena, 2010 Justin.tv
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person
|
4
|
+
obtaining a copy of this software and associated documentation
|
5
|
+
files (the "Software"), to deal in the Software without
|
6
|
+
restriction, including without limitation the rights to use,
|
7
|
+
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
copies of the Software, and to permit persons to whom the
|
9
|
+
Software is furnished to do so, subject to the following
|
10
|
+
conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be
|
13
|
+
included in all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
17
|
+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
19
|
+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
20
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
21
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
22
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
data/README.textile
ADDED
@@ -0,0 +1,153 @@
|
|
1
|
+
h1. JTV-APNS
|
2
|
+
|
3
|
+
Jtv-apns is a gem for accessing the Apple Push Notification Service that allows
|
4
|
+
both sending notifications and reading from apple's feedback service. This gem
|
5
|
+
is based heavily on the work of James Pozdena (http://github.com/jpoz/APNS).
|
6
|
+
|
7
|
+
h2. Install
|
8
|
+
|
9
|
+
<pre>
|
10
|
+
sudo gem install jtv-apns
|
11
|
+
</pre>
|
12
|
+
|
13
|
+
h2. Setup:
|
14
|
+
|
15
|
+
First, you will need to export your development/production iphone push service
|
16
|
+
certificate and key from your keychain. To do this select the private key and
|
17
|
+
certificate, and select File -> Export from your keychain. By default a .p12
|
18
|
+
file will be generated containing certificate and key.
|
19
|
+
|
20
|
+
Next, run the following command to convert this .p12 file into a .pem file.
|
21
|
+
<pre>
|
22
|
+
openssl pkcs12 -in cert.p12 -out cert.pem -nodes -clcerts
|
23
|
+
</pre>
|
24
|
+
|
25
|
+
This pem file should be stored somewhere secure that your application can access. Next, set the jtv-apns configuration parameters:
|
26
|
+
|
27
|
+
<pre>
|
28
|
+
###################
|
29
|
+
# Hosts Config
|
30
|
+
###################
|
31
|
+
|
32
|
+
# Push Notification Service:
|
33
|
+
#
|
34
|
+
# (default: gateway.sandbox.push.apple.com is)
|
35
|
+
# Set as below for a production install
|
36
|
+
APNS.host = 'gateway.push.apple.com'
|
37
|
+
|
38
|
+
# (default: 2195)
|
39
|
+
# APNS.port = 2195
|
40
|
+
|
41
|
+
# Feedback Service:
|
42
|
+
#
|
43
|
+
# (default: feedback.sandbox.push.apple.com)
|
44
|
+
APNS.feedback_host = 'feedback.push.apple.com'
|
45
|
+
|
46
|
+
# (default: 2196)
|
47
|
+
# APNS.feedback_port = 2196
|
48
|
+
|
49
|
+
####################
|
50
|
+
# Certificate Setup
|
51
|
+
####################
|
52
|
+
|
53
|
+
# Path to the .pem file created earlier
|
54
|
+
APNS.pem = '/path/to/pem/file'
|
55
|
+
|
56
|
+
# Password for decrypting the .pem file, if one was used
|
57
|
+
APNS.pass = 'xxxx'
|
58
|
+
|
59
|
+
####################
|
60
|
+
# Connection Mgmt
|
61
|
+
####################
|
62
|
+
|
63
|
+
# Cache open connections when sending push notifications
|
64
|
+
# this will force the gem to keep 1 connection open per
|
65
|
+
# host/port pair, and reuse it when sending notifications
|
66
|
+
|
67
|
+
# (default: false)
|
68
|
+
# APNS.cache_connections = true
|
69
|
+
</pre>
|
70
|
+
|
71
|
+
h2. Example (Single notification):
|
72
|
+
|
73
|
+
Then to send a push notification you can either just send a string as the alert or give it a hash for the alert, badge and sound.
|
74
|
+
|
75
|
+
<pre>
|
76
|
+
device_token = '123abc456def'
|
77
|
+
|
78
|
+
APNS.send_notification(device_token, 'Hello iPhone!')
|
79
|
+
APNS.send_notification(device_token, :aps => {:alert => 'Hello iPhone!', :badge => 1, :sound => 'default'})
|
80
|
+
</pre>
|
81
|
+
|
82
|
+
h2. Example (Multiple notifications):
|
83
|
+
|
84
|
+
You can also send multiple notifications using the same connection to Apple:
|
85
|
+
|
86
|
+
<pre>
|
87
|
+
device_token = '123abc456def'
|
88
|
+
|
89
|
+
n1 = [device_token, :aps => { :alert => 'Hello...', :badge => 1, :sound => 'default' }
|
90
|
+
n2 = [device_token, :aps => { :alert => '... iPhone!', :badge => 1, :sound => 'default' }]
|
91
|
+
|
92
|
+
APNS.send_notifications([n1, n2])
|
93
|
+
</pre>
|
94
|
+
|
95
|
+
|
96
|
+
h2. Send other info along with aps
|
97
|
+
|
98
|
+
Application-specific information can be included along with the alert by
|
99
|
+
passing it along with the "aps" key in the message hash.
|
100
|
+
|
101
|
+
<pre>
|
102
|
+
APNS.send_notification(device_token, :aps => { :alert => 'Hello iPhone!', :badge => 1, :sound => 'default'},
|
103
|
+
:sent_by => 'Justin.tv')
|
104
|
+
</pre>
|
105
|
+
|
106
|
+
h2. Pre-establishing connections
|
107
|
+
|
108
|
+
If connection caching is enabled, you can tell the gem to establish connections before sending any notifications.
|
109
|
+
|
110
|
+
<pre>
|
111
|
+
APNS.establish_notification_connection
|
112
|
+
# ...
|
113
|
+
if APNS.has_notification_connection?
|
114
|
+
APNS.send_notification(device_token, "It works!")
|
115
|
+
end
|
116
|
+
</pre>
|
117
|
+
|
118
|
+
h2. Accessing the feedback service
|
119
|
+
|
120
|
+
jtv-apns provides a simple api to access Apple's feedback service. Below is an example for setting the feedback time on an ActiveRecord object corresponding to a device token.
|
121
|
+
|
122
|
+
<pre>
|
123
|
+
# APNS.feedback_each returns an array of Hash objects with the following keys
|
124
|
+
# :feedback_on => (Time) Time Apple considers app unregistered from device
|
125
|
+
# :length => (Fixnum) Length of :device_token, currently always 32 (bytes)
|
126
|
+
# :device_token => (String) hex-encoded device token
|
127
|
+
APNS.feedback.each do |feedback|
|
128
|
+
d = RegisteredDevices.find(:first, :conditions => { :device_token = feedback.device_token })
|
129
|
+
unless d.nil?
|
130
|
+
d.feedback_on = feedback.feedback_on
|
131
|
+
end
|
132
|
+
end
|
133
|
+
</pre>
|
134
|
+
|
135
|
+
h2. Getting your iPhone's device token
|
136
|
+
|
137
|
+
After you setup push notification for your application with Apple. You need to ask Apple for you application specific device token.
|
138
|
+
|
139
|
+
ApplicationAppDelegate.m
|
140
|
+
<pre>
|
141
|
+
- (void)applicationDidFinishLaunching:(UIApplication *)application {
|
142
|
+
// Register with apple that this app will use push notification
|
143
|
+
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:(UIRemoteNotificationTypeAlert |
|
144
|
+
UIRemoteNotificationTypeSound | UIRemoteNotificationTypeBadge)];
|
145
|
+
}
|
146
|
+
|
147
|
+
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
|
148
|
+
// Show the device token obtained from apple to the log
|
149
|
+
NSLog(@"deviceToken: %@", deviceToken);
|
150
|
+
}
|
151
|
+
</pre>
|
152
|
+
|
153
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake/gempackagetask'
|
3
|
+
require 'rubygems/specification'
|
4
|
+
require 'date'
|
5
|
+
require 'spec/rake/spectask'
|
6
|
+
|
7
|
+
GEM = 'apns'
|
8
|
+
GEM_NAME = 'apns'
|
9
|
+
GEM_VERSION = '0.9.0'
|
10
|
+
AUTHORS = ['James Pozdena']
|
11
|
+
EMAIL = "jpoz@jpoz.net"
|
12
|
+
HOMEPAGE = "http://github.com/jpoz/apns"
|
13
|
+
SUMMARY = "Simple Apple push notification service gem"
|
14
|
+
|
15
|
+
spec = Gem::Specification.new do |s|
|
16
|
+
s.name = GEM
|
17
|
+
s.version = GEM_VERSION
|
18
|
+
s.platform = Gem::Platform::RUBY
|
19
|
+
s.has_rdoc = true
|
20
|
+
s.extra_rdoc_files = ["MIT-LICENSE"]
|
21
|
+
s.summary = SUMMARY
|
22
|
+
s.description = s.summary
|
23
|
+
s.authors = AUTHORS
|
24
|
+
s.email = EMAIL
|
25
|
+
s.homepage = HOMEPAGE
|
26
|
+
s.require_path = 'lib'
|
27
|
+
s.autorequire = GEM
|
28
|
+
s.files = %w(MIT-LICENSE README.textile Rakefile) + Dir.glob("{lib}/**/*")
|
29
|
+
end
|
30
|
+
|
31
|
+
task :default => :spec
|
32
|
+
|
33
|
+
desc "Run specs"
|
34
|
+
Spec::Rake::SpecTask.new do |t|
|
35
|
+
t.spec_files = FileList['spec/**/*_spec.rb']
|
36
|
+
t.spec_opts = %w(-fs --color)
|
37
|
+
end
|
38
|
+
|
39
|
+
Rake::GemPackageTask.new(spec) do |pkg|
|
40
|
+
pkg.gem_spec = spec
|
41
|
+
end
|
42
|
+
|
43
|
+
desc "install the gem locally"
|
44
|
+
task :install => [:package] do
|
45
|
+
sh %{sudo gem install pkg/#{GEM}-#{GEM_VERSION}}
|
46
|
+
end
|
47
|
+
|
48
|
+
desc "create a gemspec file"
|
49
|
+
task :make_spec do
|
50
|
+
File.open("#{GEM}.gemspec", "w") do |file|
|
51
|
+
file.puts spec.to_ruby
|
52
|
+
end
|
53
|
+
end
|
data/lib/apns/core.rb
ADDED
@@ -0,0 +1,239 @@
|
|
1
|
+
# Copyright (c) 2009 James Pozdena, 2010 Justin.tv
|
2
|
+
#
|
3
|
+
# Permission is hereby granted, free of charge, to any person
|
4
|
+
# obtaining a copy of this software and associated documentation
|
5
|
+
# files (the "Software"), to deal in the Software without
|
6
|
+
# restriction, including without limitation the rights to use,
|
7
|
+
# copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
# copies of the Software, and to permit persons to whom the
|
9
|
+
# Software is furnished to do so, subject to the following
|
10
|
+
# conditions:
|
11
|
+
#
|
12
|
+
# The above copyright notice and this permission notice shall be
|
13
|
+
# included in all copies or substantial portions of the Software.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
17
|
+
# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
19
|
+
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
20
|
+
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
21
|
+
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
22
|
+
# OTHER DEALINGS IN THE SOFTWARE.
|
23
|
+
|
24
|
+
module APNS
|
25
|
+
require 'socket'
|
26
|
+
require 'openssl'
|
27
|
+
require 'json'
|
28
|
+
|
29
|
+
# Host for push notification service
|
30
|
+
# production: gateway.push.apple.com
|
31
|
+
# development: gateway.sandbox.apple.com
|
32
|
+
@host = 'gateway.sandbox.push.apple.com'
|
33
|
+
@port = 2195
|
34
|
+
|
35
|
+
# Host for feedback service
|
36
|
+
# production: feedback.push.apple.com
|
37
|
+
# development: feedback.sandbox.apple.com
|
38
|
+
@feedback_host = 'feedback.sandbox.push.apple.com'
|
39
|
+
@feedback_port = 2196
|
40
|
+
|
41
|
+
# openssl pkcs12 -in mycert.p12 -out client-cert.pem -nodes -clcerts
|
42
|
+
@pem = nil # this should be the path of the pem file not the contentes
|
43
|
+
@pass = nil
|
44
|
+
|
45
|
+
@cache_connections = false
|
46
|
+
@connections = {}
|
47
|
+
|
48
|
+
class << self
|
49
|
+
attr_accessor :host, :port, :feedback_host, :feedback_port, :pem, :pass, :cache_connections
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.establish_notification_connection
|
53
|
+
if @cache_connections
|
54
|
+
begin
|
55
|
+
self.get_connection(self.host, self.port, self.pem)
|
56
|
+
return true
|
57
|
+
rescue
|
58
|
+
end
|
59
|
+
end
|
60
|
+
return false
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.has_notification_connection?
|
64
|
+
return self.has_connection?(self.host, self.port)
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.send_notification(device_token, message)
|
68
|
+
self.with_notification_connection do |conn|
|
69
|
+
conn.write(self.packaged_notification(device_token, message))
|
70
|
+
conn.flush
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def self.send_notifications(notifications)
|
75
|
+
self.with_notification_connection do |conn|
|
76
|
+
notifications.each do |n|
|
77
|
+
conn.write(self.packaged_notification(n[0], n[1]))
|
78
|
+
end
|
79
|
+
conn.flush
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def self.feedback
|
84
|
+
apns_feedback = []
|
85
|
+
self.with_feedback_connection do |conn|
|
86
|
+
# Read buffers data from the OS, so it's probably not
|
87
|
+
# too inefficient to do the small reads
|
88
|
+
while data = conn.read(38)
|
89
|
+
apns_feedback << self.parse_feedback_tuple(data)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
return apns_feedback
|
94
|
+
end
|
95
|
+
|
96
|
+
protected
|
97
|
+
|
98
|
+
# Each tuple is in the following format:
|
99
|
+
#
|
100
|
+
# timestamp | token_length (32) | token
|
101
|
+
# bytes: 4 (big-endian) 2 (big-endian) | 32
|
102
|
+
#
|
103
|
+
# timestamp - seconds since the epoch, in UTC
|
104
|
+
# token_length - Always 32 for now
|
105
|
+
# token - 32 bytes of binary data specifying the device token
|
106
|
+
#
|
107
|
+
def self.parse_feedback_tuple(data)
|
108
|
+
feedback = data.unpack('N1n1H64')
|
109
|
+
{:feedback_at => Time.at(feedback[0]), :length => feedback[1], :device_token => feedback[2] }
|
110
|
+
end
|
111
|
+
|
112
|
+
def self.packaged_notification(device_token, message)
|
113
|
+
pt = self.packaged_token(device_token)
|
114
|
+
pm = self.packaged_message(message)
|
115
|
+
[0, 0, 32, pt, 0, pm.size, pm].pack("ccca*cca*")
|
116
|
+
end
|
117
|
+
|
118
|
+
def self.packaged_token(device_token)
|
119
|
+
[device_token.gsub(/[\s|<|>]/,'')].pack('H*')
|
120
|
+
end
|
121
|
+
|
122
|
+
def self.packaged_message(message)
|
123
|
+
if message.is_a?(Hash)
|
124
|
+
message.to_json
|
125
|
+
elsif message.is_a?(String)
|
126
|
+
'{"aps":{"alert":"'+ message + '"}}'
|
127
|
+
else
|
128
|
+
raise "Message needs to be either a hash or string"
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def self.with_notification_connection(&block)
|
133
|
+
self.with_connection(self.host, self.port, self.pem, &block)
|
134
|
+
end
|
135
|
+
|
136
|
+
def self.with_feedback_connection(&block)
|
137
|
+
# Explicitly disable the connection cache for feedback
|
138
|
+
cache_temp = @cache_connections
|
139
|
+
@cache_connections = false
|
140
|
+
|
141
|
+
self.with_connection(self.feedback_host, self.feedback_port, self.pem, &block)
|
142
|
+
|
143
|
+
ensure
|
144
|
+
@cache_connections = cache_temp
|
145
|
+
end
|
146
|
+
|
147
|
+
private
|
148
|
+
|
149
|
+
def self.open_connection(host, port, pem)
|
150
|
+
raise "The path to your pem file is not set. (APNS.pem = /path/to/cert.pem)" unless self.pem
|
151
|
+
raise "The path to your pem file does not exist!" unless File.exist?(self.pem)
|
152
|
+
|
153
|
+
context = OpenSSL::SSL::SSLContext.new
|
154
|
+
context.cert = OpenSSL::X509::Certificate.new(File.read(self.pem))
|
155
|
+
context.key = OpenSSL::PKey::RSA.new(File.read(self.pem), self.pass)
|
156
|
+
|
157
|
+
retries = 0
|
158
|
+
begin
|
159
|
+
sock = TCPSocket.new(host, port)
|
160
|
+
ssl = OpenSSL::SSL::SSLSocket.new(sock, context)
|
161
|
+
ssl.connect
|
162
|
+
return ssl, sock
|
163
|
+
rescue SystemCallError
|
164
|
+
if (retries += 1) < 5
|
165
|
+
sleep 1
|
166
|
+
retry
|
167
|
+
else
|
168
|
+
# Too many retries, re-raise this exception
|
169
|
+
raise
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
def self.has_connection?(host, port, pem)
|
175
|
+
@connections.has_key?([host,port,pem])
|
176
|
+
end
|
177
|
+
|
178
|
+
def self.create_connection(host, port, pem)
|
179
|
+
@connections[[host, port, pem]] = self.open_connection(host, port, pem)
|
180
|
+
end
|
181
|
+
|
182
|
+
def self.find_connection(host, port, pem)
|
183
|
+
@connections[[host, port, pem]]
|
184
|
+
end
|
185
|
+
|
186
|
+
def self.remove_connection(host, port, pem)
|
187
|
+
if self.has_connection?(host, port, pem)
|
188
|
+
ssl, sock = @connections.delete([host, port, pem])
|
189
|
+
ssl.close
|
190
|
+
sock.close
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
def self.reconnect_connection(host, port, pem)
|
195
|
+
self.remove_connection(host, port, pem)
|
196
|
+
self.create_connection(host, port, pem)
|
197
|
+
end
|
198
|
+
|
199
|
+
def self.get_connection(host, port, pem)
|
200
|
+
if @cache_connections
|
201
|
+
# Create a new connection if we don't have one
|
202
|
+
unless self.has_connection?(host, port, pem)
|
203
|
+
self.create_connection(host, port, pem)
|
204
|
+
end
|
205
|
+
|
206
|
+
ssl, sock = self.find_connection(host, port, pem)
|
207
|
+
# If we're closed, reconnect
|
208
|
+
if ssl.closed?
|
209
|
+
self.reconnect_connection(host, port, pem)
|
210
|
+
self.find_connection(host, port, pem)
|
211
|
+
else
|
212
|
+
return [ssl, sock]
|
213
|
+
end
|
214
|
+
else
|
215
|
+
self.open_connection(host, port, pem)
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
def self.with_connection(host, port, pem, &block)
|
220
|
+
retries = 0
|
221
|
+
begin
|
222
|
+
ssl, sock = self.get_connection(host, port, pem)
|
223
|
+
yield ssl if block_given?
|
224
|
+
|
225
|
+
unless @cache_connections
|
226
|
+
ssl.close
|
227
|
+
sock.close
|
228
|
+
end
|
229
|
+
rescue Errno::ECONNABORTED, Errno::EPIPE, Errno::ECONNRESET
|
230
|
+
if (retries += 1) < 5
|
231
|
+
self.remove_connection(host, port, pem)
|
232
|
+
retry
|
233
|
+
else
|
234
|
+
# too-many retries, re-raise
|
235
|
+
raise
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
data/lib/apns.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# Copyright (c) 2009 James Pozdena, 2010 Justin.tv
|
2
|
+
#
|
3
|
+
# Permission is hereby granted, free of charge, to any person
|
4
|
+
# obtaining a copy of this software and associated documentation
|
5
|
+
# files (the "Software"), to deal in the Software without
|
6
|
+
# restriction, including without limitation the rights to use,
|
7
|
+
# copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
# copies of the Software, and to permit persons to whom the
|
9
|
+
# Software is furnished to do so, subject to the following
|
10
|
+
# conditions:
|
11
|
+
#
|
12
|
+
# The above copyright notice and this permission notice shall be
|
13
|
+
# included in all copies or substantial portions of the Software.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
17
|
+
# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
19
|
+
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
20
|
+
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
21
|
+
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
22
|
+
# OTHER DEALINGS IN THE SOFTWARE.
|
23
|
+
|
24
|
+
require 'apns/core'
|
metadata
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: dr-apns
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.3
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Dongri Jin
|
9
|
+
autorequire: apns
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-06-10 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: Simple Apple push notification service gem
|
15
|
+
email: dongriab@gmail.com
|
16
|
+
executables: []
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files:
|
19
|
+
- MIT-LICENSE
|
20
|
+
files:
|
21
|
+
- MIT-LICENSE
|
22
|
+
- README.textile
|
23
|
+
- Rakefile
|
24
|
+
- lib/apns/core.rb
|
25
|
+
- lib/apns.rb
|
26
|
+
homepage: http://github.com/dongriab/APNS
|
27
|
+
licenses: []
|
28
|
+
post_install_message:
|
29
|
+
rdoc_options: []
|
30
|
+
require_paths:
|
31
|
+
- lib
|
32
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
requirements: []
|
45
|
+
rubyforge_project:
|
46
|
+
rubygems_version: 1.8.24
|
47
|
+
signing_key:
|
48
|
+
specification_version: 3
|
49
|
+
summary: Simple Apple push notification service gem
|
50
|
+
test_files: []
|