Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WP8 Support #53

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
106 changes: 74 additions & 32 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,16 @@ Pushmeup is an attempt to create an push notifications center that could send pu
- Windows Phone
- And many others

Currently we have only support for ``iOS``, ``Android`` and ``Kindle Fire`` but we are planning code for more plataforms.
Currently we have only support for ``iOS``, ``Android``, ``Kindle Fire`` and ``Windows Phone`` but we are planning code for more plataforms.

## Installation

$ gem install pushmeup

or add to your ``Gemfile``

gem 'pushmeup'

and install it with

$ bundle install
Expand All @@ -40,16 +40,16 @@ and install it with

3. After you have created your ``pem`` file. Set the host, port and certificate file location on the APNS class. You just need to set this once:

APNS.host = 'gateway.push.apple.com'
APNS.host = 'gateway.push.apple.com'
# gateway.sandbox.push.apple.com is default and only for development
# gateway.push.apple.com is only for production
APNS.port = 2195

APNS.port = 2195
# this is also the default. Shouldn't ever have to set this, but just in case Apple goes crazy, you can.

APNS.pem = '/path/to/pem/file'
# this is the file you just created

APNS.pass = ''
# Just in case your pem need a password

Expand All @@ -67,7 +67,7 @@ and install it with
n1 = APNS::Notification.new(device_token, 'Hello iPhone!' )
n2 = APNS::Notification.new(device_token, :alert => 'Hello iPhone!', :badge => 1, :sound => 'default')
APNS.send_notifications([n1, n2])

> All notifications passed as a parameter will be sent on a single connection, this is done to improve
> reliability with APNS servers.

Expand All @@ -77,26 +77,26 @@ and install it with
APNS.start_persistence

device_token = '123abc456def'

# Send single notifications
APNS.send_notification(device_token, 'Hello iPhone!' )
APNS.send_notification(device_token, :alert => 'Hello iPhone!', :badge => 1, :sound => 'default')

# Send multiple notifications
n1 = APNS::Notification.new(device_token, 'Hello iPhone!' )
n2 = APNS::Notification.new(device_token, :alert => 'Hello iPhone!', :badge => 1, :sound => 'default')
APNS.send_notifications([n1, n2])

...

# Stop persistence, from this point each new push will open and close connections
APNS.stop_persistence

#### Sending more information along

APNS.send_notification(device_token, :alert => 'Hello iPhone!', :badge => 1, :sound => 'default',
APNS.send_notification(device_token, :alert => 'Hello iPhone!', :badge => 1, :sound => 'default',
:other => {:sent => 'with apns gem', :custom_param => "value"})

this will result in a payload like this:

{"aps":{"alert":"Hello iPhone!","badge":1,"sound":"default"},"sent":"with apns gem", "custom_param":"value"}
Expand All @@ -106,13 +106,13 @@ this will result in a payload like this:
- (void)applicationDidFinishLaunching:(UIApplication *)application {
// Register with apple that this app will use push notification
...

[[UIApplication sharedApplication] registerForRemoteNotificationTypes:(UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeBadge)];

...

}

- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
// Show the device token obtained from apple to the log
NSLog("deviceToken: %", deviceToken);
Expand All @@ -130,7 +130,7 @@ this will result in a payload like this:

GCM.key = "123abc456def"
# this is the apiKey obtained from here https://code.google.com/apis/console/

### Usage

#### Sending a single notification:
Expand Down Expand Up @@ -161,17 +161,17 @@ for more information on parameters check documentation: [GCM | Android Developer

data1 = {:key => "value", :key2 => ["array", "value"]}
# must be an hash with all values you want inside you notification

options1 = {:collapse_key => "placar_score_global", :time_to_live => 3600, :delay_while_idle => false}
# options for the notification

n1 = GCM::Notification.new(destination1, data1, options1)
n2 = GCM::Notification.new(destination2, data2)
n3 = GCM::Notification.new(destination3, data3, options2)

GCM.send_notifications( [n1, n2, n3] )
# In this case, every notification has his own parameters

for more information on parameters check documentation: [GCM | Android Developers](http://developer.android.com/guide/google/gcm/gcm.html#request)

#### Getting your Android device token (regId)
Expand All @@ -180,7 +180,7 @@ Check this link [GCM: Getting Started](http://developer.android.com/guide/google

### (Optional) You can add multiple keys for GCM

You can use multiple keys to send notifications, to do it just do this changes in the code
You can use multiple keys to send notifications, to do it just do this changes in the code

#### Configure

Expand Down Expand Up @@ -216,10 +216,10 @@ You can use multiple keys to send notifications, to do it just do this changes i

FIRE.client_id = "amzn1.application-oa2-client.12345678sdfgsdfg"
# this is the Client ID obtained from your Security Profile Management on amazon developers

FIRE.client_secret = "fkgjsbegksklwr863485245ojowe345"
# this is the Client Secret obtained from your Security Profile Management on amazon developers
# this is the Client Secret obtained from your Security Profile Management on amazon developers

### Usage

#### Sending a single notification:
Expand Down Expand Up @@ -250,27 +250,70 @@ for more information on parameters check documentation: [Amazon Messaging | Deve

data1 = {:key => "value", :key2 => ["array", "value"]}
# must be an hash with all values you want inside you notification

options1 = {:consolidationKey => "placar_score_global", :expiresAfter => 3600}
# options for the notification

n1 = FIRE::Notification.new(destination1, data1, options1)
n2 = FIRE::Notification.new(destination2, data2)
n3 = FIRE::Notification.new(destination3, data3, options2)

FIRE.send_notifications( [n1, n2, n3] )
# In this case, every notification has his own parameters

for more information on parameters check documentation: [Amazon Messaging | Developers](https://developer.amazon.com/public/apis/engage/device-messaging/tech-docs/06-sending-a-message#Request Format)

#### Getting your Kindle Fire device token (regId)

Check this link [Amazon Messaging: Getting Started](https://developer.amazon.com/public/apis/engage/device-messaging)

=======
## MPNS (Microsoft Push Notification Service)

#### Sending a single notification:

destination = "device_url"
# must be a string containing the device push url's of the device you want to push to

data = { title: "Title", message: "New Message" }
# must be an hash with all values you want inside your custom notification data

MPNS.send_notification( destination, data, type: :toast )
# Notification with toast type

MPNS.send_notification( destination, { count: 1, title: "Hello" }, type: :tile )
# Notification with tile type

MPNS.send_notification( destination, "<root><value1>hello</value1><value2>wp8</value2></root>" )
# Notification with raw type

for more information on parameters check documentation: [Windows Phone Dev Center](http://msdn.microsoft.com/en-us/library/windowsphone/develop/hh202945)

#### Sending multiple notifications:

n1 = MPNS::Notification.new("device_url_1", data, type: :toast )
n2 = MPNS::Notification.new("device_url_2", data, type: :toast )
n3 = MPNS::Notification.new("device_url_3", data, type: :toast )

MPNS.send_notifications( [n1, n2, n3] )
# In this case, every notification has his own parameters

for more information on parameters check documentation: [Windows Phone Dev Center](http://msdn.microsoft.com/en-us/library/windowsphone/develop/hh202945)

#### Authenticating your web service

MPNS.pem = '/path/to/pem/file'

Unauthenticated web services, are throttled at a rate of 500 push notifications per subscription per day. For more info, see [Setting up an authenticated web service to send push notifications for Windows Phone 8.](http://msdn.microsoft.com/pt-br/library/windows/apps/ff941099)

#### Getting your Microsoft Push Notification device url (device_url)

Check this link [Windows Phone dev center](http://msdn.microsoft.com/en-us/library/windowsphone/develop/hh202940)
and this for a detailed example [Windows Phone dev center](http://msdn.microsoft.com/en-us/library/windowsphone/develop/hh202967)

## Status

#### Build Status
#### Build Status
[![Build Status](https://travis-ci.org/NicosKaralis/pushmeup.png?branch=master)](https://travis-ci.org/NicosKaralis/pushmeup)
[![Code Climate](https://codeclimate.com/github/NicosKaralis/pushmeup.png)](https://codeclimate.com/github/NicosKaralis/pushmeup)

Expand All @@ -290,4 +333,3 @@ http://www.opensource.org/licenses/MIT


[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/NicosKaralis/pushmeup/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

1 change: 1 addition & 0 deletions lib/pushmeup.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
require "pushmeup/apple"
require "pushmeup/android"
require "pushmeup/amazon"
require "pushmeup/windows_phone"
88 changes: 88 additions & 0 deletions lib/pushmeup/mpns/core.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
require 'httparty'

module MPNS
include HTTParty

BASEBATCH = { :tile => 1, :toast => 2, :raw => 3 }
BATCHADDS = { :delay450 => 10, :delay900 => 20 }
WP_TARGETS = { :toast => "toast", :tile => "token" }

@pem = nil

class << self
attr_accessor :pem
end

def self.send_notification(device_url, data = {}, options = {})
n = MPNS::Notification.new(device_url, data, options)
self.send_notifications([n])
end

def self.send_notifications(notifications)
responses = []
notifications.each do |n|
responses << self.send(n)
end
responses
end

protected

def self.send(n)
wp_type = n.type.to_s.capitalize
notification_class = calculate_delay n.type, n.delay

headers = { 'Content-Type' => 'text/html', 'X-NotificationClass' => notification_class.to_s }
headers['X-WindowsPhone-Target'] = WP_TARGETS[n.type] unless n.type == :raw

body = "<?xml version='1.0' encoding='utf-8'?>"
unless n.type == :raw
body << "<wp:Notification xmlns:wp='WPNotification'><wp:#{wp_type}>"
case n.type
when :toast
body << "<wp:Text1>#{n.data[:title]}</wp:Text1>" +
"<wp:Text2>#{n.data[:message]}</wp:Text2>"
body << "<wp:Param>#{n.data[:param]}</wp:Param>" if n.data[:param]
when :tile
body << "<wp:BackgroundImage>#{n.data[:image]}</wp:BackgroundImage>" if n.data[:image]
body << "<wp:Count>#{n.data[:count].to_s}</wp:Count>" if n.data[:count]
body << "<wp:Title>#{n.data[:title]}</wp:Title>" if n.data[:title]
body << "<wp:BackBackgroundImage>#{n.data[:back_image]}</wp:BackBackgroundImage>" if n.data[:back_image]
body << "<wp:BackTitle>#{n.data[:back_title]}</wp:BackTitle>" if n.data[:back_title]
body << "<wp:BackContent>#{n.data[:back_content]}</wp:BackContent>" if n.data[:back_content]
end
body << "</wp:#{wp_type}></wp:Notification>"
else
body = n.data
end

return self.send_to_server(n.device_url,headers, body)
end

def self.send_to_server(host, headers, body)
params = {:headers => headers, :body => body}
params[:pem] = File.read(self.pem) if self.pem
response = self.post(host, params)
return build_response(response)
end

def self.build_response(response)
case response.code
when 200
{:response => 'success', :body => response.body, :headers => response.headers, :status_code => response.code}
when 401
{:response => 'There was an error authenticating the sender account.', :status_code => response.code}
when 404
{:response => 'Url not found.', :status_code => response.code}
when 500
{:response => 'There was an internal error in the GCM server while trying to process the request.', :status_code => response.code}
when 503
{:response => 'Server is temporarily unavailable.', :status_code => response.code}
end
end

def self.calculate_delay(type, delay)
BASEBATCH[type] + (BATCHADDS[delay] || 0)
end

end
14 changes: 14 additions & 0 deletions lib/pushmeup/mpns/notification.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
module MPNS
class Notification
attr_accessor :device_url, :data, :type, :delay

def initialize(device_url, data, options = {})
self.device_url = device_url
self.data = data

self.type = options[:type] || :raw
self.delay = options[:delay]
end

end
end
2 changes: 2 additions & 0 deletions lib/pushmeup/windows_phone.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
require "pushmeup/mpns/core"
require "pushmeup/mpns/notification"