Commit e5ecdc65 authored by EddyVerbruggen's avatar EddyVerbruggen
Browse files

Added WP8 support

parent dc9d4952
Loading
Loading
Loading
Loading
+2 −1
Changes for .gitignore: 2 added lines, 1 removed line.
Original line number Diff line number Diff line

*.iml
.idea
.DS_Store
+78 −11
Changes for README.md: 78 added lines, 11 removed lines.
Original line number Diff line number Diff line
# Cordova Push Notifications Plugin for Android and iOS
# Cordova Push Notifications Plugin for Android, iOS and WP8

---

@@ -39,13 +39,13 @@ This plugin is for use with [Cordova](http://incubator.apache.org/cordova/), and
1) copy the contents of **src/android/com/** to your project's **src/com/** folder.
   copy the contents of **libs/** to your **libs/** folder.
   copy **{android_sdk_path}/extras/android/support/v13/android-support-v13.jar** to your **libs/** folder.
   The final hirearchy will likely look something like this;
   The final hierarchy will likely look something like this:

	{project_folder}
		libs
			gcm.jar
			android-support-v13.jar
			cordova-2.7.0.jar
			cordova-3.4.0.jar
		src
			com
				plugin
@@ -86,7 +86,9 @@ This plugin is for use with [Cordova](http://incubator.apache.org/cordova/), and
4) Modify your **res/xml/config.xml** to include the following line in order to tell Cordova to include this plugin and where it can be found: (See the Sample_config.xml file in the Example folder)

```xml
<plugin name="PushPlugin" value="com.plugin.gcm.PushPlugin" />
<feature name="PushPlugin">
  <param name="android-package" value="com.plugin.gcm.PushPlugin" />
</feature>
```

5) Add the **PushNotification.js** script to your assets/www folder (or javascripts folder, wherever you want really) and reference it in your main index.html file. This file's usage is described in the **Plugin API** section below.
@@ -109,7 +111,9 @@ PushPlugin.m
Add a reference for this plugin to the plugins section in **config.xml**:

```xml
<gap:plugin name="com.phonegap.plugins.PushPlugin"/>
<feature name="PushPlugin">
  <param name="ios-package" value="PushPlugin" />
</feature>
```

Add the **PushNotification.js** script to your assets/www folder (or javascripts folder, wherever you want really) and reference it in your main index.html file.
@@ -118,6 +122,27 @@ Add the **PushNotification.js** script to your assets/www folder (or javascripts
<script type="text/javascript" charset="utf-8" src="PushNotification.js"></script>
```

## Manual Installation for WP8

Copy the following files to your project's Commands folder and add it to the VS project:

```
PushPlugin.cs
```

Add a reference to this plugin in **config.xml**:

```xml
<feature name="PushPlugin">
  <param name="wp-package" value="PushPlugin" />
</feature>
```

Add the **PushNotification.js** script to your assets/www folder (or javascripts folder, wherever you want really) and reference it in your main index.html file.
```html
<script type="text/javascript" charset="utf-8" src="PushNotification.js"></script>
```

## Automatic Installation
This plugin is based on [plugman](https://github.com/apache/cordova-plugman). to install it to your app,
simply execute plugman as follows;
@@ -131,15 +156,17 @@ where
	[PLUGIN-PATH] = path to folder containing this plugin
```

Alternatively this plugin can be installed using the Phonegap CLI.

1) Navigaate to the root folder for your phonegap project.
2) Run the command.
Alternatively this plugin can be installed using the Phonegap CLI:

```sh

phonegap local plugin add https://github.com/phonegap-build/PushPlugin.git

```

or the Cordova CLI:

```sh
cordova plugin add https://github.com/phonegap-build/PushPlugin.git

```

@@ -210,7 +237,7 @@ function errorHandler (error) {
}
```

**tokenHandler (iOS ony)** - called when the device has registeredwith a unique device token.
**tokenHandler (iOS only)** - called when the device has registered with a unique device token.

```js
function tokenHandler (result) {
@@ -302,6 +329,46 @@ Looking at the above message handling code for Android, a few things bear explai

Also make note of the **payload** object. Since the Android notification data model is much more flexible than that of iOS, there may be additional elements beyond **message**, **soundname**, and **msgcnt**. You can access those elements and any additional ones via the **payload** element. This means that if your data model should change in the future, there will be no need to change and recompile the plugin.

##### wp8
Register as

```js
pushNotification = window.plugins.pushNotification;
pushNotification.register(successHandler, errorHandler, {"channelName":"your_channel_name","ecb":"onNotification"});

function successHandler(result) {
  console.log('registered###' + result.uri);
  // send uri to your notification server
}
```

onNotification is fired if the app is running when you receive the toast notification

```js
function onNotification (e) {
  navigator.notification.alert(e.text2, function(){}, e.text1);
}
```

When not using PhoneGap Build, you can control the launch page when the user taps on your toast notification when the app is not running. Add the following code to your MainPage.xaml.cs:

```
  protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
  {
      base.OnNavigatedTo(e);
      try
      {
          if (this.NavigationContext.QueryString["NavigatedFrom"] == "toast") // this is set on the server
          {
              this.CordovaView.StartPageUri = new Uri("//www/index.html#notification-page", UriKind.Relative);
          }
      }
      catch (KeyNotFoundException)
      {
      }
  }
```

#### unregister
You will typically call this when your app is exiting, to cleanup any used resources. Its not strictly necessary to call it, and indeed it may be desireable to NOT call it if you are debugging your intermediarry push server. When you call unregister(), the current token for a particular device will get invalidated, and the next call to register() will return a new token. If you do NOT call unregister(), the last token will remain in effect until it is invalidated for some reason at the GCM side. Since such invalidations are beyond your control, its recommended that, in a production environment, that you have a matching unregister() call, for every call to register(), and that your server updates the devices' records each time.

+23 −2
Changes for plugin.xml: 23 added lines, 2 removed lines.
Original line number Diff line number Diff line
@@ -2,13 +2,16 @@
<plugin xmlns="http://www.phonegap.com/ns/plugins/1.0"
    xmlns:android="http://schemas.android.com/apk/res/android"
    id="com.phonegap.plugins.PushPlugin"
    version="2.1.1">
    version="2.2.0">

  <name>PushPlugin</name>
	<author>Bob Easterday</author>

	<description>
		This plugin allows your application to receive push notifications on both Android and iOS devices. The Android implementation uses Google Cloud Messaging whereas the iOS version is based on Apple APNS Notifications
		This plugin allows your application to receive push notifications on Android, iOS and WP8 devices.
    Android uses Google Cloud Messaging.
    iOS uses Apple APNS Notifications.
    WP8 uses Microsoft MPNS Notifications.
	</description>

	<license>MIT</license>
@@ -77,4 +80,22 @@
		<header-file src="src/ios/PushPlugin.h" />

	</platform>

  <!-- wp8 -->
  <platform name="wp8">

    <config-file target="config.xml" parent="/*">
      <feature name="PushPlugin">
        <param name="wp-package" value="PushPlugin"/>
      </feature>
    </config-file>

    <config-file target="Properties/WMAppManifest.xml" parent="/Deployment/App/Capabilities">
      <Capability Name="ID_CAP_PUSH_NOTIFICATION"/>
    </config-file>

    <source-file src="src/wp8/PushPlugin.cs" />

  </platform>

</plugin>

src/wp8/PushPlugin.cs

0 → 100644
+169 −0
Changes for src/wp8/PushPlugin.cs: 169 added lines, 0 removed lines.
Original line number Diff line number Diff line
using Microsoft.Phone.Controls;
using Microsoft.Phone.Notification;
using System;
using System.Diagnostics;
using System.Text;
using System.Threading;
using System.Runtime.Serialization;
using System.Windows;

namespace WPCordovaClassLib.Cordova.Commands
{
    public class PushPlugin : BaseCommand
    {
        private HttpNotificationChannel pushChannel;
        private string channelName;
        private string toastCallback;

        public void register(string options)
        {
            Options pushOptions;

            try
            {
                string[] args = JSON.JsonHelper.Deserialize<string[]>(options);
                pushOptions = JSON.JsonHelper.Deserialize<Options>(args[0]);
                this.channelName = pushOptions.ChannelName;
                this.toastCallback = pushOptions.NotificationCallback;
            }
            catch (Exception)
            {
                DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
                return;
            }

            pushChannel = HttpNotificationChannel.Find(channelName);
            if (pushChannel == null)
            {
                pushChannel = new HttpNotificationChannel(channelName);
                pushChannel.ChannelUriUpdated += new EventHandler<NotificationChannelUriEventArgs>(PushChannel_ChannelUriUpdated);
                pushChannel.ErrorOccurred += new EventHandler<NotificationChannelErrorEventArgs>(PushChannel_ErrorOccurred);
                pushChannel.ShellToastNotificationReceived += new EventHandler<NotificationEventArgs>(PushChannel_ShellToastNotificationReceived);
                pushChannel.Open();
                pushChannel.BindToShellToast();
            }
            else
            {
                pushChannel.ChannelUriUpdated += new EventHandler<NotificationChannelUriEventArgs>(PushChannel_ChannelUriUpdated);
                pushChannel.ErrorOccurred += new EventHandler<NotificationChannelErrorEventArgs>(PushChannel_ErrorOccurred);
                pushChannel.ShellToastNotificationReceived += new EventHandler<NotificationEventArgs>(PushChannel_ShellToastNotificationReceived);

                RegisterResult result = new RegisterResult();
                result.ChannelName = this.channelName;
                result.Uri = pushChannel.ChannelUri.ToString();
                this.DispatchCommandResult(new PluginResult(PluginResult.Status.OK, result));
            }
        }

        void PushChannel_ChannelUriUpdated(object sender, NotificationChannelUriEventArgs e)
        {
            // return uri to js
            RegisterResult result = new RegisterResult();
            result.ChannelName = this.channelName;
            result.Uri = pushChannel.ChannelUri.ToString();
            this.DispatchCommandResult(new PluginResult(PluginResult.Status.OK, result));
        }

        void PushChannel_ErrorOccurred(object sender, NotificationChannelErrorEventArgs e)
        {
            // call error handler and return uri
            RegisterError err = new RegisterError();
            err.Code = e.ErrorCode.ToString();
            err.Message = e.Message;
            this.DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, err));
        }

        void PushChannel_ShellToastNotificationReceived(object sender, NotificationEventArgs e)
        {
            StringBuilder message = new StringBuilder();
            string relativeUri = string.Empty;

            Toast toast = new Toast();
            if (e.Collection.ContainsKey("wp:Text1"))
            {
                toast.Title = e.Collection["wp:Text1"];
            }
            if (e.Collection.ContainsKey("wp:Text2"))
            {
                toast.Subtitle = e.Collection["wp:Text2"];
            }
            if (e.Collection.ContainsKey("wp:Param"))
            {
                toast.Param = e.Collection["wp:Param"];
            }

            PluginResult result = new PluginResult(PluginResult.Status.OK, toast);

            Deployment.Current.Dispatcher.BeginInvoke(() =>
            {
                PhoneApplicationFrame frame = Application.Current.RootVisual as PhoneApplicationFrame;
                if (frame != null)
                {
                    PhoneApplicationPage page = frame.Content as PhoneApplicationPage;
                    if (page != null)
                    {
                        CordovaView cView = page.FindName("CordovaView") as CordovaView; // was: PGView
                        if (cView != null)
                        {
                            cView.Browser.Dispatcher.BeginInvoke((ThreadStart)delegate()
                            {
                                try
                                {
                                    cView.Browser.InvokeScript("execScript", this.toastCallback + "(" + result.Message + ")");
                                }
                                catch (Exception ex)
                                {
                                    Debug.WriteLine("ERROR: Exception in InvokeScriptCallback :: " + ex.Message);
                                }

                            });
                        }
                    }
                }
            });
        }

        [DataContract]
        public class Toast
        {
            [DataMember(Name = "text1", IsRequired = false)]
            public string Title { get; set; }

            [DataMember(Name = "text2", IsRequired = false)]
            public string Subtitle { get; set; }

            [DataMember(Name = "param", IsRequired = false)]
            public string Param { get; set; }
        }

        [DataContract]
        public class Options
        {
            [DataMember(Name = "channelName", IsRequired = true)]
            public string ChannelName { get; set; }

            [DataMember(Name = "ecb", IsRequired = false)]
            public string NotificationCallback { get; set; }
        }

        [DataContract]
        public class RegisterResult
        {
            [DataMember(Name = "uri", IsRequired = true)]
            public string Uri { get; set; }

            [DataMember(Name = "channel", IsRequired = true)]
            public string ChannelName { get; set; }
        }

        [DataContract]
        public class RegisterError
        {
            [DataMember(Name = "code", IsRequired = true)]
            public string Code { get; set; }

            [DataMember(Name = "message", IsRequired = true)]
            public string Message { get; set; }
        }
    }
}
 No newline at end of file