diff --git a/.gitignore b/.gitignore
index 0202b51..c615632 100644
--- a/.gitignore
+++ b/.gitignore
@@ -12,8 +12,9 @@ test/tmp
test/version_tmp
tmp
example/.sass-cache
+.env
# YARD artifacts
.yardoc
_yardoc
-doc/
\ No newline at end of file
+doc/
diff --git a/README.md b/README.md
index 158bce4..6c1b010 100644
--- a/README.md
+++ b/README.md
@@ -77,6 +77,7 @@ Bundler.require
run Helios::Application.new do
service :data, model: 'path/to/DataModel.xcdatamodel'
service :push_notification, apn_certificate: 'path/to/apple_push_notification.pem', apn_environment: 'development'
+ service :gcm, gcm_api_key: 'xxxxxxx'
service :in_app_purchase
service :passbook
end
@@ -103,6 +104,7 @@ Helios can be run as Rails middleware by adding this to the configuration block
config.middleware.use Helios::Application do
service :data, model: 'path/to/DataModel.xcdatamodel'
service :push_notification, apn_certificate: 'path/to/apple_push_notification.pem', apn_environment: 'development'
+ service :gcm, gcm_api_key: 'xxxxxxx'
service :in_app_purchase
service :passbook
end
@@ -157,15 +159,39 @@ Each entity in the specified data model will have a `Sequel::Model` subclass cre
Endpoints
- PUT /devices/:token
+ PUT /push_notification/devices/:token
Register or update existing device for push notifications
- DELETE /devices/:token
+ DELETE /push_notification/devices/:token
Unregister a device from receiving push notifications
- POST /message
+ POST /push_notification/message
+ Send out a push notification to some devices
+
+
+
+---
+
+`gcm`: Adds Android push notification(Google Cloud Messaging) registration / unregistration endpoints.
+
+**Associated Classes**
+
+- `Rack::GCM::Device`
+
+
+ Endpoints
+
+ PUT /gcm/devices/:token
+ Register or update existing device for push notifications
+
+
+ DELETE /gcm/devices/:token
+ Unregister a device from receiving push notifications
+
+
+ POST /gcm/message
Send out a push notification to some devices
@@ -274,7 +300,13 @@ To run Helios in development mode on `localhost`, run the `server` command:
Once you have registered a device and set up your certificate, try this:
- $ curl -X POST -d 'payload={"aps": {"alert":"Blastoff!"}}' http://localhost:5000/message
+ $ curl -X POST -d 'payload={"aps": {"alert":"Blastoff!"}}' http://localhost:5000/push-notification/message
+
+### Testing Android Push Notifications(Google Cloud Messaging)
+
+Once you have registered a device and set up your certificate, try this:
+
+ $ curl -X POST -d 'payload={"alert":"Blastoff!"}' http://localhost:5000/gcm/message
### Running the Helios Console
@@ -336,6 +368,13 @@ Now covert the p12 file to a pem file:
$ openssl pkcs12 -in cert.p12 -out apple_push_notification.pem -nodes -clcerts
+## Integrating with an Android Application
+
+### Google Cloud Messaging Registration
+
+See more detail [Google Cloud Messaging Tutorial](http://developer.android.com/google/gcm/gs.html)
+
+
## Coming Attractions
There's still a lot to do to make Helios even better. Here are some ideas that are at the top of the list:
@@ -346,7 +385,7 @@ There's still a lot to do to make Helios even better. Here are some ideas that a
- Better RubyMotion integration
- Support for multiple schema definitions (not just Core Data)
- Send push notifications from the UI
-- Support for additional platforms (Android, WP7)
+- Support for additional platforms (WP7)
---
diff --git a/example/Gemfile b/example/Gemfile
index f8388ac..2afef97 100644
--- a/example/Gemfile
+++ b/example/Gemfile
@@ -3,3 +3,4 @@ source "https://rubygems.org"
gem 'helios', path: File.join(__FILE__, "../..")
gem 'unicorn'
gem 'pg'
+gem 'thin'
diff --git a/example/config.ru b/example/config.ru
index afe2e92..aa00d76 100644
--- a/example/config.ru
+++ b/example/config.ru
@@ -3,7 +3,8 @@ Bundler.require
app = Helios::Application.new do
service :data, model: Dir['*.xcdatamodel*'].first, only: [:create, :read]
- service :push_notification, frontend: false
+ service :push_notification, frontend: true
+ service :gcm, gcm_api_key: ENV['GCM_API_KEY']
service :in_app_purchase
service :passbook
service :newsstand, storage: ({
@@ -33,4 +34,4 @@ end
# }
# end
-run app
+run app
\ No newline at end of file
diff --git a/helios.gemspec b/helios.gemspec
index 5f0b1f1..d4e6798 100644
--- a/helios.gemspec
+++ b/helios.gemspec
@@ -36,6 +36,8 @@ Gem::Specification.new do |s|
s.add_dependency "rails-database-url", "~> 1.0"
s.add_dependency "fog", "~> 1.10"
s.add_dependency "houston", "~> 0.2"
+ s.add_dependency "rack-gcm", "~> 0.0.2"
+ s.add_dependency "sanjose", "~> 0.0.3"
s.add_development_dependency "rake"
s.add_development_dependency "rspec"
diff --git a/lib/helios/backend.rb b/lib/helios/backend.rb
index aec7a17..8dd41e2 100644
--- a/lib/helios/backend.rb
+++ b/lib/helios/backend.rb
@@ -62,3 +62,4 @@ def constantize(identifier)
require 'helios/backend/passbook'
require 'helios/backend/push-notification'
require 'helios/backend/newsstand'
+require 'helios/backend/gcm'
diff --git a/lib/helios/backend/gcm.rb b/lib/helios/backend/gcm.rb
new file mode 100644
index 0000000..0aff596
--- /dev/null
+++ b/lib/helios/backend/gcm.rb
@@ -0,0 +1,106 @@
+require 'rack/gcm'
+
+require 'sinatra/base'
+require 'sinatra/param'
+
+require 'sanjose'
+
+class Helios::Backend::Gcm < Sinatra::Base
+ helpers Sinatra::Param
+ attr_reader :gcm_api_key
+
+ def initialize(app, options = {}, &block)
+ super(Rack::GCM.new)
+
+ @api_key = options[:gcm_api_key] || ENV['GCM_API_KEY']
+ end
+
+ before do
+ content_type :json
+ end
+
+ get '/devices/?' do
+ param :q, String
+
+ devices = ::Rack::GCM::Device.dataset
+ devices = devices.filter("tsv @@ to_tsquery('english', ?)", "#{params[:q]}:*") if params[:q] and not params[:q].empty?
+
+ if params[:page] or params[:per_page]
+ param :page, Integer, default: 1, min: 1
+ param :per_page, Integer, default: 100, in: (1..100)
+
+ {
+ devices: devices.limit(params[:per_page], (params[:page] - 1) * params[:per_page]),
+ page: params[:page],
+ total: devices.count
+ }.to_json
+ else
+ param :limit, Integer, default: 100, in: (1..100)
+ param :offset, Integer, default: 0, min: 0
+
+ {
+ devices: devices.limit(params[:limit], params[:offset])
+ }.to_json
+ end
+ end
+
+ get '/devices/:token/?' do
+ record = ::Rack::GCM::Device.find(token: params[:token])
+
+ if record
+ {device: record}.to_json
+ else
+ status 404
+ end
+ end
+
+ head '/message' do
+ status 503 and return unless client
+
+ status 204
+ end
+
+ post '/message' do
+ status 503 and return unless client
+
+ param :payload, String, empty: false
+ param :tokens, Array, empty: false
+
+ tokens = params[:tokens] || ::Rack::GCM::Device.all.collect(&:token)
+
+ options = JSON.parse(params[:payload])
+ puts tokens.inspect
+ puts options
+
+ # Create a notification that alerts a message to the user.
+ notification = Sanjose::Notification.new(devices: tokens)
+ notification.data = options
+
+ begin
+ results = client.push(notification)
+
+ status 204
+ rescue => error
+ status 500
+
+ {error: error}.to_json
+ end
+
+ status 200
+ end
+
+ private
+
+ def client
+ begin
+ return nil unless api_key
+
+ client = Sanjose::Client.new
+ client.gcm_api_key = api_key
+
+ return client
+ rescue
+ return nil
+ end
+ end
+end
diff --git a/lib/helios/frontend.rb b/lib/helios/frontend.rb
index 7bd7f1c..a151599 100644
--- a/lib/helios/frontend.rb
+++ b/lib/helios/frontend.rb
@@ -25,31 +25,31 @@ class Frontend < Sinatra::Base
serve '/fonts', from: '/fonts'
js :application, '/javascripts/application.js', [
- 'javascripts/vendor/jquery.js',
- 'javascripts/vendor/jquery/jquery.ui.widget.js',
- 'javascripts/vendor/jquery/jquery.fileupload.js',
- 'javascripts/vendor/jquery/jquery.fileupload-ui.js',
- 'javascripts/vendor/underscore.js',
- 'javascripts/vendor/backbone.js',
- 'javascripts/vendor/backbone.paginator.js',
- 'javascripts/vendor/backbone.datagrid.js',
- 'javascripts/vendor/codemirror.js',
- 'javascripts/vendor/codemirror.javascript.js',
- 'javascripts/vendor/foundation.js',
- 'javascripts/vendor/foundation/foundation.dropdown.js',
- 'javascripts/vendor/foundation/foundation.reveal.js',
- 'javascripts/vendor/date.js',
- 'javascripts/vendor/linkheaders.js',
- 'javascripts/helios.js',
- 'javascripts/helios/models.js',
- 'javascripts/helios/collections.js',
- 'javascripts/helios/templates.js',
- 'javascripts/helios/views.js',
- 'javascripts/helios/router.js',
+ '/javascripts/vendor/jquery.js',
+ '/javascripts/vendor/jquery/jquery.ui.widget.js',
+ '/javascripts/vendor/jquery/jquery.fileupload.js',
+ '/javascripts/vendor/jquery/jquery.fileupload-ui.js',
+ '/javascripts/vendor/underscore.js',
+ '/javascripts/vendor/backbone.js',
+ '/javascripts/vendor/backbone.paginator.js',
+ '/javascripts/vendor/backbone.datagrid.js',
+ '/javascripts/vendor/codemirror.js',
+ '/javascripts/vendor/codemirror.javascript.js',
+ '/javascripts/vendor/foundation.js',
+ '/javascripts/vendor/foundation/foundation.dropdown.js',
+ '/javascripts/vendor/foundation/foundation.reveal.js',
+ '/javascripts/vendor/date.js',
+ '/javascripts/vendor/linkheaders.js',
+ '/javascripts/helios.js',
+ '/javascripts/helios/models.js',
+ '/javascripts/helios/collections.js',
+ '/javascripts/helios/templates.js',
+ '/javascripts/helios/views.js',
+ '/javascripts/helios/router.js',
]
css :application, '/stylesheets/application.css', [
- 'stylesheets/screen.css'
+ '/stylesheets/screen.css'
]
end
@@ -64,3 +64,12 @@ class Frontend < Sinatra::Base
end
end
end
+
+
+# Workaround for Sinatra::Assetpack bug
+# See https://github.com/helios-framework/helios/issues/68
+class Sinatra::AssetPack::Package
+ def to_production_html(path_prefix, options={})
+ to_development_html(path_prefix, options)
+ end
+end
diff --git a/lib/helios/frontend/javascripts/helios.coffee b/lib/helios/frontend/javascripts/helios.coffee
index 69e589b..16f18bb 100644
--- a/lib/helios/frontend/javascripts/helios.coffee
+++ b/lib/helios/frontend/javascripts/helios.coffee
@@ -63,6 +63,8 @@ $ ->
Helios.services['newsstand'] = href
when "Helios::Backend::PushNotification"
Helios.services['push-notification'] = href
+ when "Helios::Backend::Gcm"
+ Helios.services['gcm'] = href
when "Helios::Backend::Passbook"
Helios.services['passbook'] = href
diff --git a/lib/helios/frontend/javascripts/helios/collections.coffee b/lib/helios/frontend/javascripts/helios/collections.coffee
index 1c6c84f..621ce57 100644
--- a/lib/helios/frontend/javascripts/helios/collections.coffee
+++ b/lib/helios/frontend/javascripts/helios/collections.coffee
@@ -67,7 +67,6 @@ class Helios.Collections.Devices extends Helios.Collection
comparator: (device) ->
device.get('token')
-
class Helios.Collections.Receipts extends Helios.Collection
model: Helios.Models.Receipt
diff --git a/lib/helios/frontend/javascripts/helios/router.coffee b/lib/helios/frontend/javascripts/helios/router.coffee
index 26e642c..8b221ce 100644
--- a/lib/helios/frontend/javascripts/helios/router.coffee
+++ b/lib/helios/frontend/javascripts/helios/router.coffee
@@ -13,6 +13,7 @@ class Helios.Routers.Root extends Backbone.Router
routes:
'': 'index'
'data': 'data'
+ 'gcm': 'gcm'
'push-notification': 'push_notification'
'in-app-purchase': 'in_app_purchase'
'passbook': 'passbook'
@@ -25,6 +26,12 @@ class Helios.Routers.Root extends Backbone.Router
Helios.entities.fetch(type: 'OPTIONS')
@views.entities.render()
+ gcm: ->
+ @android_devices ?= new Helios.Collections.Devices
+ @android_devices.paginator_core.url = Helios.services['gcm'] + '/devices'
+ @views.andoid_devices ?= new Helios.Views.AndroidDevices(collection: @android_devices)
+ @views.andoid_devices.render()
+
push_notification: ->
@devices ?= new Helios.Collections.Devices
@devices.paginator_core.url = Helios.services['push-notification'] + '/devices'
diff --git a/lib/helios/frontend/javascripts/helios/views.coffee b/lib/helios/frontend/javascripts/helios/views.coffee
index a2eb4c4..d25d0a9 100644
--- a/lib/helios/frontend/javascripts/helios/views.coffee
+++ b/lib/helios/frontend/javascripts/helios/views.coffee
@@ -71,6 +71,35 @@ class Helios.Views.Devices extends Backbone.View
@collection.query = $(e.target).val()
@collection.fetch()
+class Helios.Views.AndroidDevices extends Backbone.View
+ template: JST['gcm/devices']
+ el: "[role='main']"
+
+ events:
+ 'keyup form.filter input': 'filter'
+
+ initialize: ->
+ @datagrid = new Backbone.Datagrid({
+ collection: @collection,
+ columns: @collection.fields,
+ paginated: true,
+ perPage: 20
+ })
+
+ render: =>
+ @$el.html(@template())
+
+ # @composeView ?= new Helios.Views.Compose()
+ # @composeView.render()
+ @$el.find("#datagrid").html(@datagrid.el)
+
+ @
+
+ filter: (e) ->
+ e.preventDefault()
+ @collection.query = $(e.target).val()
+ @collection.fetch()
+
class Helios.Views.Compose extends Backbone.View
template: JST['push-notification/compose']
el: "#compose-modal"
diff --git a/lib/helios/frontend/stylesheets/_fonts.sass b/lib/helios/frontend/stylesheets/_fonts.sass
index 21a8a48..885defe 100644
--- a/lib/helios/frontend/stylesheets/_fonts.sass
+++ b/lib/helios/frontend/stylesheets/_fonts.sass
@@ -70,6 +70,9 @@ i.heroku:before
i.push-notification:before
content: "\6f"
+i.gcm:before
+ content: "\6f"
+
i.passbook:before
content: "\78"
diff --git a/lib/helios/frontend/templates/gcm/compose.jst.tpl b/lib/helios/frontend/templates/gcm/compose.jst.tpl
new file mode 100644
index 0000000..bed38a3
--- /dev/null
+++ b/lib/helios/frontend/templates/gcm/compose.jst.tpl
@@ -0,0 +1,70 @@
+
+ Send a Google Cloud Message
+
+
+
+
+
+
+
+ ▁
+ Carrier
+ 100%
+
+
+
+ 9:04
+ Thursday, November 29
+
+
+
+
+ App Name
+
+
+
+
+
diff --git a/lib/helios/frontend/templates/gcm/devices.jst.tpl b/lib/helios/frontend/templates/gcm/devices.jst.tpl
new file mode 100644
index 0000000..9b3d0f1
--- /dev/null
+++ b/lib/helios/frontend/templates/gcm/devices.jst.tpl
@@ -0,0 +1,17 @@
+
+
Devices
+
+
+
+
+ <% if (false) { %>
+ Compose
+ <% } %>
+
+
+
+
+
diff --git a/lib/helios/frontend/templates/navigation.jst.tpl b/lib/helios/frontend/templates/navigation.jst.tpl
index 2f2a3f4..6292ac5 100644
--- a/lib/helios/frontend/templates/navigation.jst.tpl
+++ b/lib/helios/frontend/templates/navigation.jst.tpl
@@ -11,6 +11,12 @@
<% } %>
+ <% if(Helios.services['gcm']) { %>
+
+ Google Cloud Message
+
+ <% } %>
+
<% if(Helios.services['in-app-purchase']) { %>
In-App Purchase
diff --git a/lib/helios/version.rb b/lib/helios/version.rb
index 7917f5b..d6897e1 100644
--- a/lib/helios/version.rb
+++ b/lib/helios/version.rb
@@ -1,3 +1,3 @@
module Helios
- VERSION = "0.2.3"
+ VERSION = "0.2.4"
end