Parse.Push plugin for Cordova/Phonegap/ionic. Works for both hosted Parse.com and open source parse-server.
Works with Parse.com and parse-server
cordova plugin add https://github.com/taivo/parse-push-plugin
- Set app id, server URL, and keys as
config.xml
preference
tags. - Done! No fuss with Objective C, AndroidManifest, or Java
- getInstallationId( successCB, errorCB )
- getSubscriptions( successCB, errorCB )
- subscribe( channel, successCB, errorCB )
- unsubscribe( channel, successCB, errorCB )
- resetBadge( successCB, errorCB )
- register( successCB, errorCB ) //optional, see Advanced Configuration
Handle openPN, receivePN, receivePN:customEvt
anywhere in your javascript code.
ParsePushPlugin.on('receivePN', function(pn){
console.log('yo i got this push notification:' + JSON.stringify(pn));
});
//
// Use custom events to simulate separate communication channels using push notification.
// Just set an 'event' key in the push payload made from your server. If you set {event: "x"},
// you'll be able to catch it via "receivePN:x"
//
ParsePushPlugin.on('receivePN:chat', function(pn){
console.log('yo i can also use custom event to keep things like chat modularized');
});
ParsePushPlugin.on('receivePN:system-maintenance', function(pn){
console.log('yo, here is a system maintenance payload');
});
//
// When you open a notification from the system tray, `openPN` is also triggered.
// You can use it to do things like navigating to a different page or refreshing data.
ParsePushPlugin.on('openPN', function(pn){
//you can do things like navigating to a different view here
console.log('Yo, I get this when the user taps open a notification from the tray');
});
Android: to prevent flooding the notification tray, this plugin retains only the last PN with the same title
field. For messages without the title
field, the application name is used. A count of unopened PNs is shown.
You can override this feature, however, by adding the following to config.xml
:
<preference name="ParseMultiNotifications" value="true" />
Android: Mimic the iOS behavior and create a notification in the system tray when app is off or in background. When app is in foreground, PN payloads are forwarded via the receivePN
and receivePN:customEvt
events.
iOS: Forward the PN payload to javascript in foreground mode. When app inactive or in background, iOS holds PNs in the tray. Only when the user opens these PNs would we have access and forward them to javascript.
-
Open Source parse-server
-
Setup
parse-server
There are plenty of guides out there to help you get started on popular hosting services like Heroku and AWS. If you want to setup parse-server on your laptop for local development, here's a quick-start guide.
-
Once you have a working
parse-server
, generate your push credentials:- iOS
- Create SSL push certificate with Apple. You may find this tutorial useful. All steps prior to adding code to your iOS application are applicable.
- Place the
p12
certificate file from the previous step on your server.
- Android
- Get the sender id (your project number) from your google developer console. It's a long integer.
- Enable GCM for your project on google developer console and generate a server API key.
- iOS
-
Update your
parse-server
configuration to use the push credentials. Here is an example:{ "appId": "MY_APP_ID", "masterKey": "SUPER_SECRET", "cloud": "./myCloudDir/main.js", "push": { "android":{ "senderId": "SENDER_ID_AKA_PROJECT_NUMBER", "apiKey": "SERVER_API_KEY_FROM_GOOGLE_DEVELOPER_CONSOLE" }, "ios":{ "pfx": "my-push-certificate.p12", "bundleId": "com.company.myapp", "production": false } } }
-
Restart your
parse-server
for the new settings to take effect.
-
-
Hosted Parse.com
- iOS
- Create SSL push certificate with Apple. You may find this tutorial useful. All steps prior to adding code to your iOS application are applicable.
- Use Parse Dashboard to upload the generated
p12
push certificate.
- Android - no need for certificate setup. Parse.com uses its own push credentials.
- iOS
cordova plugin add https://github.com/taivo/parse-push-plugin
Create the following tags in config.xml
:
- For open source parse-server
<preference name="ParseAppId" value="your-parse-app-id" />
<preference name="ParseServerUrl" value="http://your-parse-server:1337/parse/" />
<!-- If your parse-server config requires a client key, set this.
If not, skip this preference -->
<preference name="ParseClientKey" value="your-parse-client-key" />
<!-- required for Android push notification
To get your GCM sender ID, enable GCM for your Android project in the Google Developer Console.
The sender id is your project number, and should be a large integer like 123427208255.
This is the same "senderId" to be used in your parse-server push configuration.
-->
<preference name="ParseGcmSenderId" value="gcm-sender-id" />
<!-- As standard, this plugin only shows the most recent PN in
the android notifications tray along with a count of unopened
PNs. If you would like to override this behaviour and show all
PNs in the tray, then add this preference.
If not, skip this preference -->
<preference name="ParseMultiNotifications" value="true" />
- For legacy Parse.com
<preference name="ParseAppId" value="your-parse-app-id" />
<preference name="ParseClientKey" value="your-parse-client-key" />
<!-- Do not replace this string value. It must be "PARSE_DOT_COM"-->
<preference name="ParseServerUrl" value="PARSE_DOT_COM" />
<!-- As standard, this plugin only shows the most recent PN in
the android notifications tray along with a count of unopened
PNs. If you would like to override this behaviour and show all
PNs in the tray, then add this preference.
If not, skip this preference -->
<preference name="ParseMultiNotifications" value="true" />
You're all set. The plugin takes care of initializing Parse platform using the config.xml
preferences mentioned above. It also saves your installation to the database automatically.
To customize push notifications, initialize Parse platform yourself, or use your own MainApplication.java
in Android, see the Advanced Configuration section.
When your app starts, ParsePushPlugin automatically obtains and stores necessary device tokens to your native ParseInstallation
. It also registers a javascript callback that will be triggered when a push notification is opened or received.
Anywhere in your code, you can set a listener for notification events using the ParsePushPlugin object.
$ionicPlatform.ready(function(){
if(window.ParsePushPlugin){
ParsePushPlugin.on('receivePN', function(pn){
alert('yo i got this push notification:' + JSON.stringify(pn));
});
//
//you can also listen to your own custom events
// Note: to push custom event, include 'event' key in your push payload,
// e.g. {alert: "sup", event:'chat'}
ParsePushPlugin.on('receivePN:chat', chatEventHandler);
ParsePushPlugin.on('receivePN:serverMaintenance', serverMaintenanceHandler);
//
// When the app is off or in background, push notifications get added
// to the notification tray. When a user open a notification, you
// can catch it via openPN
ParsePushPlugin.on('openPN', function(pn){
alert('a notification was opened:' + JSON.stringify(pn));
});
}
});
$ionicPlatform.ready(function(){
if(window.ParsePushPlugin){
ParsePushPlugin.getInstallationId(function(id) {
// note that the javascript client has its own installation id,
// which is different from the device installation id.
alert("device installationId: " + id);
}, function(e) {
alert('error');
});
ParsePushPlugin.getSubscriptions(function(subscriptions) {
alert(subscriptions);
}, function(e) {
alert('error');
});
ParsePushPlugin.subscribe('SampleChannel', function(msg) {
alert('OK');
}, function(e) {
alert('error');
});
ParsePushPlugin.unsubscribe('SampleChannel', function(msg) {
alert('OK');
}, function(e) {
alert('error');
});
}
});
If your app is already on (or in the background), you can simply perform page switching in javascript. Just add a urlHash
field in your PN payload that contains either a url hash, i.e. #myhash, or a url parameter string, i.e. ?param1=a¶m2=b. Then catch that field via the openPN
event and go from there.
ParsePushPlugin.on('openPN', function(pn){
if(pn.urlHash){
window.location.hash = hash;
}
});
For cold start, you can also let your cordova app finish loading and use javascript to handle page switching. Carry out this type of page switching while the spashscreen is still visible for a better user experience.
Directly launching a non-default url via native code is also possible. Here are some hints on how to do that:
Android: If urlHash
starts with "#" or "?", this plugin will pass it along as an extra in the android intent to launch your MainActivity. You can then launch the custom url in MainActivity.onCreate
this way:
@Override
public void onCreate(Bundle savedInstanceState)
{
//
// your code...
//
String urlHash = intent.hasExtra("urlHash") ? intent.getStringExtra("urlHash") : "";
loadUrl(launchUrl + urlHash);
}
iOS: On cold start via notification, didFinishLaunchingWithOptions
and this plugin's didLaunchViaNotification
have access to the payload. Those 2 functions are good starting points for launching custom url.
For Android, a silent notification can be sent by omitting the title
and alert
fields in the JSON payload. This means the push notification will not be shown in the system tray, but its JSON payload will still be delivered to your receivePN
and receivePN:customEvt
handlers.
The actual code that handles Parse platform initialization is in ParsePushApplication.java.
Android knows to use this class due to the attribute android:name
in <application>
in 'platforms/android/app/src/main/AndroidManifest.xml'.
To preserve your customizations, this plugin sets android:name="github.taivo.parsepushplugin.ParsePushApplication"
if and only if android:name
is not already defined. It does this during plugin installation. Similarly, when the plugin is
uninstalled, android:name
will be removed only if its content matches github.taivo.parsepushplugin.ParsePushApplication
exactly.
If you use your own Application class, don't forget to update android:name
to point to it.
Optional: Write your own MainApplication and/or initialize Parse yourself: Look at ParsePushApplication.java. The comments contain all the explanations and hints you will need. Mimic the code to write your own customized implementation.
Optional: Customize background color for the push notification icon in Android Lollipop: Go to your platforms/android/res/values
folder and create a file named colors.xml
. Paste the following content in it and replace the hex color value of the form #AARRGGBB
to your liking.
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="parse_push_icon_color">#ff112233</color>
</resources>
You can provide a property ParseNotificationIcon
in config.xml
to provide a custom android notification icon for Android Lollipop and above like this:
<preference name="ParseNotificationIcon" value="android_notification_icon" />
The icon has to be in folder resources
in project root and with extension .png
. The icon is then copied to platforms/android/app/src/main/res/drawable/<PROVIDED-NAME>.png
. For details, how to design the icon have a look at https://clevertap.com/blog/fixing-notification-icon-for-android-lollipop-and-above/
By default, ParsePushPlugin
automatically registers your device for push notification on app startup. This means
your app will ask for push notification permission at the very beginning of the first app start. For UX reason,
you may want to delay asking the user for that permission until you absolutely need it. To do so,
add <preference name="ParseAutoRegistration" value="false" />
to config.xml
and manually call ParsePushPlugin.register(successCB, errorCB)
in your javascript.
If you want to completely customize your notification settings, use the method didFinishLaunchingWithOptions
in AppDelegate+parsepush.m as a guide to modify the same method in
your platforms/ios/ProjectName/Classes/AppDelegate.m
.
When you initialize Parse from your own platforms/ios/ProjectName/Classes/AppDelegate.m
, this plugin will
skip it's version of Parse initialization and notification setup, that way it won't override your customization.
-
Parse uses the term "client key" to specify a key for both Android and iOS. This is different from the Javascript key. In the javascript portion of your Cordova/Phonegap/Ionic app, use the Javascript key. This has nothing to do with the plugin. In the
config.xml
preferenceParseClientKey
, use the Android and iOS client key. Note that for open source parse-server, these keys are optional. -
For legacy Parse.com, the appropriate key is required depending on your client platform, e.g., Javascript, Android or iOS client, dotNet, REST. For open source parse-server, a key is only required if you have configured your server with it. In the past, our Android users have reported strange errors in their logcat relating to missing permission declarations. It turns out those error messages were red herrings. The real problem involved a parse-server that required client keys and a missing
ParseClientKey
preference inconfig.xml
.
-
If you run into this error during build
> Could not resolve all dependencies for configuration ':_debugCompile'. > Could not find any version that matches com.android.support:support-v4:+. Searched in the following locations: https://repo1.maven.org/maven2/com/android/support/support-v4/maven-metadata.xml https://repo1.maven.org/maven2/com/android/support/support-v4/ Required by: :android:unspecified
Update your android SDK installation to include android-extra:
android update sdk --no-ui --filter extra
-
Starting with the Parse Android SDK v1.10.1 update, your app may crash at start and the log says something about a missing method in OkHttpClient. Just update the cordova libs of your project via
cordova platform update android
. If your previous cordova libs are old, you may run into further compilation errors that has to do with the new cordova libs setting your android target to be 22 or higher. Look at fileplatforms/android/project.properties
and make sure that is consistent with yourconfig.xml
This plugin takes advantage of the cordova.exec
bridge. If calls to cordova.exec
only gets triggered after pressing your device's Home button, try inspecting your Content-Security-Policy. Your frame-src
must allow gap:
because the cordova bridge on iOS works via Iframe.