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 CHANGED
@@ -1 +1,2 @@
1
1
  .DS_Store
2
+ pkg
@@ -0,0 +1,8 @@
1
+ == 0.1.1 released 2009-11-10
2
+
3
+ * Moved from model to "acts_as_pushable".
4
+ * Updated readme for new interface.
5
+
6
+ == 0.1.0 released 2009-11-10
7
+
8
+ * Initial release.
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2009 Fabien Penso, Sam Soffes
1
+ Copyright (c) 2009 Sam Soffes
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person
4
4
  obtaining a copy of this software and associated documentation
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", "Fabien Penso"]
33
+ gemspec.authors = ["Sam Soffes"]
34
34
  end
35
35
  Jeweler::GemcutterTasks.new
36
36
  rescue LoadError
@@ -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
- ## Installing
38
+ ## Environment
21
39
 
22
- Install as a gem:
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
- # Add to config/environment.rb:
25
- config.gem "apple_push_notification", :source => "http://gemcutter.org/"
42
+ ApplePushNotification.enviroment = Rails.env.to_sym
26
43
 
27
- # At command prompt:
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
- or as a plugin:
46
+ ## Usage
31
47
 
32
- $ script/plugin install git://github.com/samsoffes/apple_push_notification.git
48
+ You can use ApplePushNotification with an ActiveRecord model, standalone, or on any object.
33
49
 
34
- Once you have installed apple\_push\_notification, run the following command:
50
+ ### ActiveRecord
35
51
 
36
- $ rake apn:migrate
52
+ Just add `acts_as_pushable` to your model.
37
53
 
38
- ## Environment
54
+ class Device < ActiveRecord::Base
55
+ acts_as_pushable
56
+ end
39
57
 
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.
58
+ You can then send a notification like this
41
59
 
42
- ApplePushNotification.enviroment = Rails.env.to_sym
60
+ d.send_notification :alert => "I heart Rails"
43
61
 
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.
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
- ## Example
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
- $ ./script/console
49
- >> a = ApplePushNotification.new
50
- >> a.device_token = "XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX"
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 Fabien Penso. Released under the MIT license. Modified by [Sam Soffes](http://samsoff.es).
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
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 File.join(File.dirname(__FILE__), "app", "models", "apple_push_notification.rb")
2
-
3
- %w{ models }.each do |dir|
4
- path = File.join(File.dirname(__FILE__), 'app', dir)
5
- $LOAD_PATH << path
6
- puts "Adding #{path}"
7
- ActiveSupport::Dependencies.load_paths << path
8
- ActiveSupport::Dependencies.load_once_paths.delete(path)
9
- end
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
@@ -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.1.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/db/migrate/20090406132059_create_apple_push_notifications.rb
36
- - tasks/apple_push_notification_tasks.rake
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
@@ -1 +0,0 @@
1
- # Uninstall hook code here