From c8156ccecd006d8b3e148c0d33f9f93c2ce488fe Mon Sep 17 00:00:00 2001 From: lazaronixon Date: Wed, 31 Dec 2014 20:49:47 -0200 Subject: [PATCH] WP8 Support Implementation for WPNS, raw, toasts and tiles notifications. --- README.md | 106 +++++++++++++++++++++--------- lib/pushmeup.rb | 1 + lib/pushmeup/mpns/core.rb | 88 +++++++++++++++++++++++++ lib/pushmeup/mpns/notification.rb | 14 ++++ lib/pushmeup/windows_phone.rb | 2 + 5 files changed, 179 insertions(+), 32 deletions(-) create mode 100644 lib/pushmeup/mpns/core.rb create mode 100644 lib/pushmeup/mpns/notification.rb create mode 100644 lib/pushmeup/windows_phone.rb diff --git a/README.md b/README.md index 9adcf4e..b30d5f8 100644 --- a/README.md +++ b/README.md @@ -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 @@ -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 @@ -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. @@ -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"} @@ -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); @@ -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: @@ -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) @@ -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 @@ -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: @@ -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, "hellowp8" ) + # 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) @@ -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") - diff --git a/lib/pushmeup.rb b/lib/pushmeup.rb index 33c6465..bc80811 100644 --- a/lib/pushmeup.rb +++ b/lib/pushmeup.rb @@ -2,3 +2,4 @@ require "pushmeup/apple" require "pushmeup/android" require "pushmeup/amazon" +require "pushmeup/windows_phone" diff --git a/lib/pushmeup/mpns/core.rb b/lib/pushmeup/mpns/core.rb new file mode 100644 index 0000000..e2e6b52 --- /dev/null +++ b/lib/pushmeup/mpns/core.rb @@ -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 = "" + unless n.type == :raw + body << "" + case n.type + when :toast + body << "#{n.data[:title]}" + + "#{n.data[:message]}" + body << "#{n.data[:param]}" if n.data[:param] + when :tile + body << "#{n.data[:image]}" if n.data[:image] + body << "#{n.data[:count].to_s}" if n.data[:count] + body << "#{n.data[:title]}" if n.data[:title] + body << "#{n.data[:back_image]}" if n.data[:back_image] + body << "#{n.data[:back_title]}" if n.data[:back_title] + body << "#{n.data[:back_content]}" if n.data[:back_content] + end + body << "" + 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 diff --git a/lib/pushmeup/mpns/notification.rb b/lib/pushmeup/mpns/notification.rb new file mode 100644 index 0000000..b423689 --- /dev/null +++ b/lib/pushmeup/mpns/notification.rb @@ -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 diff --git a/lib/pushmeup/windows_phone.rb b/lib/pushmeup/windows_phone.rb new file mode 100644 index 0000000..7fb542b --- /dev/null +++ b/lib/pushmeup/windows_phone.rb @@ -0,0 +1,2 @@ +require "pushmeup/mpns/core" +require "pushmeup/mpns/notification"