Skip to content

Commit

Permalink
[BlackBerry10] Add support for BB10 platform
Browse files Browse the repository at this point in the history
This uses the exec proxy to wrap functionality from com.blackberry.push.

Documentation available here:
http://developer.blackberry.com/html5/documentation/v2_1/push_service.html
James Keshavarzi authored and purplecabbage committed Sep 26, 2014
1 parent d528eca commit f1fa935
Showing 3 changed files with 305 additions and 14 deletions.
64 changes: 56 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
# Cordova Push Notifications Plugin for Android, iOS, WP8, Windows8 and Amazon Fire OS

---
# Cordova Push Notifications Plugin for Android, iOS, WP8, Windows8, BlackBerry 10 and Amazon Fire OS

## DESCRIPTION

This plugin is for use with [Cordova](http://incubator.apache.org/cordova/), and allows your application to receive push notifications on Amazon Fire OS, Android, iOS, Windows Phone and Windows8 devices.
* The Amazon Fire OS implementation uses [Amazon's ADM(Amazon Device Messaging) service](https://developer.amazon.com/sdk/adm.html).
* The Android implementation uses [Google's GCM (Google Cloud Messaging) service](http://developer.android.com/guide/google/gcm/index.html).
* The BlackBerry 10 version uses [blackberry push service](https://developer.blackberry.com/devzone/develop/platform_services/push_service_overview.html).
* The iOS version is based on [Apple APNS Notifications](http://developer.apple.com/library/mac/#documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/ApplePushService/ApplePushService.html).
* The WP8 implementation is based on [MPNS](http://msdn.microsoft.com/en-us/library/windowsphone/develop/ff402558(v=vs.105).aspx).
* Windows8 uses [Microsoft WNS Notifications](http://msdn.microsoft.com/en-us/library/windows/apps/hh913756.aspx).
@@ -293,7 +292,7 @@ The plugin is based on [plugman](https://github.com/apache/cordova-plugman) and
plugman install --platform [PLATFORM] --project [TARGET-PATH] --plugin [PLUGIN-PATH]

where
[PLATFORM] = ios, amazon-fireos, android wp8 or windows8
[PLATFORM] = ios, amazon-fireos, android, wp8, windows8 or blackberry10
[TARGET-PATH] = path to folder containing your phonegap project
[PLUGIN-PATH] = path to folder containing this plugin
```
@@ -324,14 +323,26 @@ To be called as soon as the device becomes ready.
```js
$("#app-status-ul").append('<li>registering ' + device.platform + '</li>');
if ( device.platform == 'android' || device.platform == 'Android' || device.platform == "amazon-fireos" ){

pushNotification.register(
successHandler,
errorHandler,
{
"senderID":"replace_with_sender_id",
"ecb":"onNotification"
});
} else if ( device.platform == 'blackberry10'){
pushNotification.register(
successHandler,
errorHandler,
{
invokeTargetId : "replace_with_invoke_target_id",
appId: "replace_with_app_id",
ppgUrl:"replace_with_ppg_url", //remove for BES pushes
ecb: "pushNotificationHandler",
simChangeCallback: replace_with_simChange_callback,
pushTransportReadyCallback: replace_with_pushTransportReady_callback,
launchApplicationOnPush: true
});
} else {
pushNotification.register(
tokenHandler,
@@ -345,14 +356,17 @@ if ( device.platform == 'android' || device.platform == 'Android' || device.plat
}
```

On success, you will get a call to tokenHandler (iOS), onNotification (Android and Amazon Fire OS), or onNotificationWP8 (WP8), allowing you to obtain the device token or registration ID, or push channel name and Uri respectively. Those values will typically get posted to your intermediary push server so it knows who it can send notifications to.
On success, you will get a call to tokenHandler (iOS), onNotification (Android and Amazon Fire OS), onNotificationWP8 (WP8) or successHandler (Blackberry10), allowing you to obtain the device token or registration ID, or push channel name and Uri respectively. Those values will typically get posted to your intermediary push server so it knows who it can send notifications to.

***Note***

- **Amazon Fire OS**: "ecb" MUST be provided in order to get callback notifications. If you have not already registered with Amazon developer portal,you will have to obtain credentials and api_key for your app. This is described more in detail in the [Registering your app for Amazon Device Messaging (ADM)](#registering_for_adm) section below.

- **Android**: If you have not already done so, you'll need to set up a Google API project, to generate your senderID. [Follow these steps](http://developer.android.com/guide/google/gcm/gs.html) to do so. This is described more fully in the **Testing** section below. In this example, be sure and substitute your own senderID. Get your senderID by signing into to your [google dashboard](https://code.google.com/apis/console/). The senderID is found at *Overview->Dashboard->Project Number*.

- **BlackBerry10**: "ecb" MUST be provided to get notified of incoming push notifications. Also note, if doing a public consumer (BIS) push, you need to manually add the _sys_use_consumer_push permission to config.xml. `<rim:permit system="true">_sys_use_consumer_push</rim:permit>`. In order to receieve notifications, an invoke target must be [setup](http://developer.blackberry.com/html5/documentation/v2_1/rim_invoke-target.html) for push. See [BlackBerry Push Service](http://developer.blackberry.com/html5/apis/v2_1/blackberry.push.pushservice.html) for additional information about blackberry push options.




#### successHandler
@@ -422,8 +436,8 @@ function onNotification(e) {
if ( e.foreground )
{
$("#app-status-ul").append('<li>--INLINE NOTIFICATION--' + '</li>');
// on Android soundname is outside the payload.

// on Android soundname is outside the payload.
// On Amazon FireOS all custom attributes are contained within payload
var soundfile = e.soundname || e.payload.sound;
// if the notification contains a soundname, play it.
@@ -459,6 +473,27 @@ function onNotification(e) {
}
}
```

```js
// BlackBerry10
function pushNotificationHandler(pushpayload) {
var contentType = pushpayload.headers["Content-Type"],
id = pushpayload.id,
data = pushpayload.data;//blob

// If an acknowledgement of the push is required (that is, the push was sent as a confirmed push
// - which is equivalent terminology to the push being sent with application level reliability),
// then you must either accept the push or reject the push
if (pushpayload.isAcknowledgeRequired) {
// In our sample, we always accept the push, but situations might arise where an application
// might want to reject the push (for example, after looking at the headers that came with the push
// or the data of the push, we might decide that the push received did not match what we expected
// and so we might want to reject it)
pushpayload.acknowledge(true);
}
};
```

Looking at the above message handling code for Android/Amazon Fire OS, a few things bear explanation. Your app may receive a notification while it is active (INLINE). If you background the app by hitting the Home button on your device, you may later receive a status bar notification. Selecting that notification from the status will bring your app to the front and allow you to process the notification (BACKGROUND). Finally, should you completely exit the app by hitting the back button from the home page, you may still receive a notification. Touching that notification in the notification tray will relaunch your app and allow you to process the notification (COLDSTART). In this case the **coldstart** flag will be set on the incoming event. You can look at the **foreground** flag on the event to determine whether you are processing a background or an in-line notification. You may choose, for example to play a sound or show a dialog only for inline or coldstart notifications since the user has already been alerted via the status bar.

For Amazon Fire OS, offline message can also be received when app is launched via carousel or by tapping on app icon from apps. In either case once app delivers the offline message to JS, notification will be cleared.
@@ -739,6 +774,19 @@ You can see how to create one from MSDN Samples:
- [Send Raw Notification (MSDN Sample)](http://msdn.microsoft.com/en-us/library/windowsphone/develop/hh202977(v=vs.105).aspx#BKMK_RunningtheRawNotificationSample)


### Sending push notifications on BlackBerry10
If doing a BES push, ensure the device has been enterprise activated, has network access (wifi or sim) and your app is installed in the work permiter. You also need to make sure the _sys_use_consumer_push permission is NOT specified in the config.xml. This permission is meant only for public consumer BIS pushes and will cause an error when registering.

If doing a public consumer BIS push, please ensure the _sys_use_consumer_push permission is added to the config.xml.

Both types of pushes require the use of a Push Initiator.

- [App based BIS Initiator](https://github.com/blackberry/BB10-WebWorks-Samples/tree/master/pushCaptureBasics/pushInitiator)
- [Web based BIS Initiator (Push Service SDK)](https://developer.blackberry.com/services/push/)
- [Web based BES Initiator](https://github.com/blackberry/BES10-WebWorks/tree/master/SimplePushTest/WW2.0/server)

For additional information on BlackBerry Push see https://developer.blackberry.com/services/push/.

### Troubleshooting and next steps
If all went well, you should see a notification show up on each device. If not, make sure you are not being blocked by a firewall, and that you have internet access. Check and recheck the token id, the registration ID and the certificate generating process.

25 changes: 19 additions & 6 deletions plugin.xml
Original file line number Diff line number Diff line change
@@ -2,6 +2,7 @@
<plugin xmlns="http://www.phonegap.com/ns/plugins/1.0"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:amazon="http://schemas.android.com/apk/lib/com.amazon.device.ads"
xmlns:rim="http://www.blackberry.com/ns/widgets"
id="com.phonegap.plugins.PushPlugin"
version="2.3.1">

@@ -76,7 +77,7 @@
<preference name="showmessageinnotification" value="true" />
<preference name="defaultnotificationmessage" value="You have a new message." />
</config-file>

<config-file target="AndroidManifest.xml" parent="/manifest">
<!-- This permission ensures that no other application can intercept your ADM messages. "[YOUR PACKAGE NAME]" is your package name as defined in your <manifest> tag. -->
<permission android:name="$PACKAGE_NAME.permission.RECEIVE_ADM_MESSAGE" android:protectionLevel="signature" />
@@ -100,13 +101,13 @@
<action android:name="com.amazon.device.messaging.intent.RECEIVE" />
<category android:name="$PACKAGE_NAME" />
</intent-filter>
</receiver>
</receiver>
</config-file>

<source-file src="src/amazon/PushPlugin.java" target-dir="src/com/amazon/cordova/plugin" />
<source-file src="src/amazon/ADMMessageHandler.java" target-dir="src/com/amazon/cordova/plugin" />
<source-file src="src/amazon/ADMHandlerActivity.java" target-dir="src/com/amazon/cordova/plugin" />

</platform>

<!-- ios -->
@@ -126,8 +127,20 @@

</platform>

<!-- wp8 -->
<platform name="wp8">
<!-- blackberry10 -->
<platform name="blackberry10">
<dependency id="com.blackberry.push" />
<dependency id="com.blackberry.invoked" />
<config-file target="www/config.xml" parent="/widget">
<feature name="PushPlugin" value="PushPlugin" />
</config-file>
<js-module src="www/blackberry10/PushPluginProxy.js" name="PushPluginProxy" >
<runs />
</js-module>
</platform>

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

<config-file target="config.xml" parent="/*">
<feature name="PushPlugin">
230 changes: 230 additions & 0 deletions www/blackberry10/PushPluginProxy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,230 @@
/*
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/

var pushServiceObj,
ecb;

function createChannel(success, error) {
if (pushServiceObj) {
pushServiceObj.createChannel(function(result, token) {
if (result == blackberry.push.PushService.SUCCESS) {
if (success) {
success({
status: result,
token: token
});
}
} else {
if (result == blackberry.push.PushService.INTERNAL_ERROR) {
error("Error: An internal error occurred during the create channel. Try registering again.");
} else if (result == blackberry.push.PushService.CREATE_SESSION_NOT_DONE) {
error("Error: No call to blackberry.push.PushService.create "
+ "was done before creating the channel. It usually means a programming error.");
} else if (result == blackberry.push.PushService.MISSING_PORT_FROM_PPG) {
error("Error: A port could not be obtained from the "
+ "PPG during the create channel. Try registering again.");
} else if (result == blackberry.push.PushService.INVALID_DEVICE_PIN) {
// This error code only applies to a consumer application using the public/BIS PPG
error("Error: The PPG obtained the device's PIN during "
+ "the create channel and considered it invalid. Try registering again.");
} else if (result == blackberry.push.PushService.INVALID_PROVIDER_APPLICATION_ID) {
// This error code only applies to a consumer application using the public/BIS PPG
error("Error: The application ID was considered invalid or missing during the create channel.");
} else if (result == blackberry.push.PushService.INVALID_PPG_SUBSCRIBER_STATE) {
// This error code only applies to a consumer application using the public/BIS PPG
error("Error: The subscriber on the PPG end reached an "
+ "invalid state. Report this issue to the BlackBerry support team.");
} else if (result == blackberry.push.PushService.EXPIRED_AUTHENTICATION_TOKEN_PROVIDED_TO_PPG) {
// This error code only applies to a consumer application using the public/BIS PPG
error("Error: An expired authentication token was"
+ "passed to the PPG internally during the create channel. Try registering again.");
} else if (result == blackberry.push.PushService.INVALID_AUTHENTICATION_TOKEN_PROVIDED_TO_PPG) {
// This error code only applies to a consumer application using the public/BIS PPG
error("Error: An invalid authentication token was passed "
+ "to the PPG internally during the create channel. Report this issue to the BlackBerry support team.");
} else if (result == blackberry.push.PushService.PPG_SUBSCRIBER_LIMIT_REACHED) {
// This error code only applies to a consumer application using the public/BIS PPG
error("Error: Too many devices have already peformed a "
+ "create channel for this application ID. Contact BlackBerry to increase the subscription limit for this app.");
} else if (result == blackberry.push.PushService.INVALID_OS_VERSION_OR_DEVICE_MODEL_NUMBER) {
// This error code only applies to a consumer application using the public/BIS PPG
error("Error: This device was found to have an invalid OS "
+ " version or device model number during the create channel. Consider updating the OS on the device.");
} else if (result == blackberry.push.PushService.MISSING_PPG_URL) {
// This error code only applies to a consumer application using the public/BIS PPG
error("Error: The PPG URL was considered "
+ "invalid or missing during the create channel.");
} else if (result == blackberry.push.PushService.PUSH_TRANSPORT_UNAVAILABLE) {
// This error code only applies to a consumer application using the public/BIS PPG
error("Error: Create channel failed as the push transport "
+ "is unavailable. Verify your mobile network and/or Wi-Fi are turned on. If they are on, you will "
+ "be notified when the push transport is available again.");
} else if (result == blackberry.push.PushService.PPG_SERVER_ERROR) {
// This error code only applies to a consumer application using the public/BIS PPG
error("Error: Create channel failed as the PPG is "
+ "currently returning a server error. You will be notified when the PPG is available again.");
} else if (result == blackberry.push.PushService.MISSING_SUBSCRIPTION_RETURN_CODE_FROM_PPG) {
// This error code only applies to a consumer application using the public/BIS PPG
error("Error: There was an internal issue obtaining "
+ "the subscription return code from the PPG during the create channel. Try registering again.");
} else if (result == blackberry.push.PushService.INVALID_PPG_URL) {
// This error code only applies to a consumer application using the public/BIS PPG
error("Error: The PPG URL was considered invalid during the create channel.");
} else {
error("Error: Received error code (" + result + ") when creating channel");
}
}


});
}


}

function onInvoked(invokeRequest) {
var pushPayload,
pushCallback;

if (invokeRequest.action && invokeRequest.action == "bb.action.PUSH") {
if (ecb) {
pushCallback = eval(ecb);

if (typeof pushCallback === "function") {
pushPayload = pushServiceObj.extractPushPayload(invokeRequest);
pushCallback(pushPayload);
}
}
}
}

module.exports = {

register: function(success, error, args) {
var ops = args[0],
simChangeCallback = ops.simChangeCallback,
pushTransportReadyCallback = ops.pushTransportReadyCallback,
launchApplicationOnPush = ops.launchApplicationOnPush !== undefined ? ops.launchApplicationOnPush : true;

ecb = ops.ecb;

blackberry.push.PushService.create(ops, function(obj) {
pushServiceObj = obj;

// Add an event listener to handle incoming invokes
document.addEventListener("invoked", onInvoked, false);
pushServiceObj.launchApplicationOnPush(launchApplicationOnPush , function (result) {
if (result != blackberry.push.PushService.SUCCESS ) {
if (result == blackberry.push.PushService.INTERNAL_ERROR) {
error("Error: An internal error occurred while calling launchApplicationOnPush.");
} else if (result == blackberry.push.PushService.CREATE_SESSION_NOT_DONE) {
error("Error: Called launchApplicationOnPush without an "
+ "existing session. It usually means a programming error.");
} else {
error("Error: Received error code (" + result + ") after calling launchApplicationOnPush.");
}
}
});

createChannel(success, error);
}, function(result) {
if (result == blackberry.push.PushService.INTERNAL_ERROR) {
error("Error: An internal error occurred while calling "
+ "blackberry.push.PushService.create. Try restarting the application.");
} else if (result == blackberry.push.PushService.INVALID_PROVIDER_APPLICATION_ID) {
// This error only applies to consumer applications that use a public/BIS PPG
error("Error: Called blackberry.push.PushService.create with a missing "
+ "or invalid appId value. It usually means a programming error.");
} else if (result == blackberry.push.PushService.MISSING_INVOKE_TARGET_ID) {
error("Error: Called blackberry.push.PushService.create with a missing "
+ "invokeTargetId value. It usually means a programming error.");
} else if (result == blackberry.push.PushService.SESSION_ALREADY_EXISTS) {
error("Error: Called blackberry.push.PushService.create with an appId or "
+ "invokeTargetId value that matches another application. It usually means a "
+ "programming error.");
} else {
error("Error: Received error code (" + result + ") after "
+ "calling blackberry.push.PushService.create.");
}
}, simChangeCallback, pushTransportReadyCallback);
},

unregister: function(success, error, args) {
if (pushServiceObj) {
pushServiceObj.destroyChannel(function(result) {

document.removeEventListener("invoked", onInvoked, false);

if (result == blackberry.push.PushService.SUCCESS ||
result == blackberry.push.PushService.CHANNEL_ALREADY_DESTROYED ||
result == blackberry.push.PushService.CHANNEL_ALREADY_DESTROYED_BY_PROVIDER ||
result == blackberry.push.PushService.CHANNEL_SUSPENDED_BY_PROVIDER ||
result == blackberry.push.PushService.PPG_SUBSCRIBER_NOT_FOUND ||
result == blackberry.push.PushService.CREATE_CHANNEL_NOT_DONE) {

success( { status: result } );
} else {
if (result == blackberry.push.PushService.INTERNAL_ERROR) {
error("Error: An internal error occurred during "
+ "the destroy channel. Try unregistering again.");
} else if (result == blackberry.push.PushService.CREATE_SESSION_NOT_DONE) {
error("Error: No call to blackberry.push.PushService.create "
+ "was done before destroying the channel. It usually means a programming error.");
} else if (result == blackberry.push.PushService.INVALID_DEVICE_PIN) {
// This error code only applies to a consumer application using the public/BIS PPG
error("Error: The PPG obtained the device's PIN during "
+ "the destroy channel and considered it invalid. Try unregistering again.");
} else if (result == blackberry.push.PushService.INVALID_PROVIDER_APPLICATION_ID) {
// This error code only applies to a consumer application using the public/BIS PPG
error("Error: The application ID was considered invalid or missing during the destroy channel.");
} else if (result == blackberry.push.PushService.INVALID_PPG_SUBSCRIBER_STATE) {
// This error code only applies to a consumer application using the public/BIS PPG
error("Error: The subscriber on the PPG end reached an "
+ "invalid state. Report this issue to the BlackBerry support team.");
} else if (result == blackberry.push.PushService.EXPIRED_AUTHENTICATION_TOKEN_PROVIDED_TO_PPG) {
// This error code only applies to a consumer application using the public/BIS PPG
error("Error: An expired authentication token was"
+ "passed to the PPG internally during the destroy channel. Try unregistering again.");
} else if (result == blackberry.push.PushService.INVALID_AUTHENTICATION_TOKEN_PROVIDED_TO_PPG) {
// This error code only applies to a consumer application using the public/BIS PPG
error("Error: An invalid authentication token was passed "
+ "to the PPG internally during the destroy channel. Report this issue to the BlackBerry support team.");
} else if (result == blackberry.push.PushService.PUSH_TRANSPORT_UNAVAILABLE) {
// This error code only applies to a consumer application using the public/BIS PPG
error("Error: Destroy channel failed as the push transport "
+ "is unavailable. Verify your mobile network and/or Wi-Fi are turned on. If they are on, you will "
+ "be notified when the push transport is available again.");
} else if (result == blackberry.push.PushService.PPG_SERVER_ERROR) {
// This error code only applies to a consumer application using the public/BIS PPG
error("Error: Destroy channel failed as the PPG is "
+ "currently returning a server error. You will be notified when the PPG is available again.");
} else if (result == blackberry.push.PushService.INVALID_PPG_URL) {
// This error code only applies to a consumer application using the public/BIS PPG
error("Error: The PPG URL was considered invalid during the destroy channel.");
} else {
error("Error: Received error code (" + result + ") from the destroy channel.");
}
}
});
}
}
};
require("cordova/exec/proxy").add("PushPlugin", module.exports);

0 comments on commit f1fa935

Please sign in to comment.