With Hybrid Messaging you are able to deliver messages to any phone number via SMS or Push. When the end users phone number has your app or our free Notifire app installed, the platform can deliver your message via push which is 50% of the SMS price. If the end user on the phone number does not have your app or Notifire installed, the message will automatically be send as an SMS.
HTTP POST
Endpoint URL: https://sgw01.cm.nl/gateway.ashx
Full SMS Gateway docs can be found here.
Prerequisites:
<?xml version="1.0"?>
<MESSAGES>
<AUTHENTICATION>
<PRODUCTTOKEN>00000000-0000-0000-0000-000000000000</PRODUCTTOKEN>
</AUTHENTICATION>
<MSG>
<FROM>Company</FROM>
<TO>00447911123456</TO>
<APPKEY>00000000-0000-0000-0000-000000000000</APPKEY>
<BODY>This message will be delivered as a push message.</BODY>
</MSG>
</MESSAGES>
Allowed channels
The allowed channels field forces a message to only use certain routes. In this field you can define a list of which channels you want your message to use. Not defining any channels will be interpreted als allowing all channels.
The channels available are:
The example request below has the allowed channel "Push" and does not contain "SMS". This means the message will be restricted to only taking "Push" routes.
XML Post:
<?xml version="1.0"?>
<MESSAGES>
<AUTHENTICATION>
<PRODUCTTOKEN>00000000-0000-0000-0000-000000000000</PRODUCTTOKEN>
</AUTHENTICATION>
<MSG>
<FROM>Company</FROM>
<TO>00447911123456</TO>
<APPKEY>00000000-0000-0000-0000-000000000000</APPKEY>
<ALLOWEDCHANNELS>Push</ALLOWEDCHANNELS>
<BODY>This message will be delivered as a push message.</BODY>
</MSG>
</MESSAGES>
JSON Post:
{
"messages": {
"authentication": {
"producttoken": "00000000-0000-0000-0000-000000000000"
},
"msg": [ {
"from": "SenderName",
"to": [{
"number": "00447911123456"
}],
"body": {
"content": "This message will be delivered as a push message"
},
"allowedChannels": ["Push"],
"appKey": "00000000-0000-0000-0000-000000000000"
}
]
}
}
Hybrid Messaging now allows you use different fallback-to-SMS behaviour in the same App. The HTTP Gateway now supports the appMessageType to set a specific messaging type per message.
By default Hybrid Messaging is using the messaging type you define in the APP Manager
However in the API you can now overrule the "default" messaging type per message. You can select one of the following options:
For bulk, marketing etc. Messages have unlimited lifetime (as long as the telecom or push service provides). If the user has the App installed we’ll deliver the message as a push notification even if the user is offline. The system will fall back on SMS to send the message only if the push message cannot be delivered (delivery status: failed i.e. no app installed or phone number not verified in the App).
SMS Fall Back: limited fallback behavior
One Time Passwords, message lifetime is 30 seconds. If the push does not arrive and you manually decide to send an SMS to your end-user instead, the push message will be terminated to avoid double messages (this is a parameter you can define in the API).
SMS Fall Back: Manual fallback
Use this in case the messages are of extreme high priority. It guarantees delivery of your message with a SMS fall back when a push message is sent to a device and it does not respond to the push notification. i.e. app is closed or there is no internet connection.
SMS Fall Back: Automatic fallback if no interaction with the push message
Automatic fall back on SMS after 30 seconds to ensure the message is being delivered. This might result in double messages. (receiving both SMS and Push notification)
XML Post:
<?xml version="1.0"?>
<MESSAGES>
<AUTHENTICATION>
<PRODUCTTOKEN>00000000-0000-0000-0000-000000000000</PRODUCTTOKEN>
</AUTHENTICATION>
<MSG>
<FROM>SenderName</FROM>
<TO>00447911123456</TO>
<APPKEY>00000000-0000-0000-0000-000000000000</APPKEY>
<APPMESSAGETYPE>Critical</APPMESSAGETYPE>
<BODY>This message will use the critical messaging type.</BODY>
</MSG>
</MESSAGES>
JSON Post:
{
"messages": {
"authentication": {
"producttoken": "00000000-0000-0000-0000-000000000000"
},
"msg": [ {
"from": "Hybrid Test",
"to": [{
"number": "00447911123456"
}],
"body": {
"content": "This is a critical message"
},
"appmessagetype": "critical" ,
"appKey": "00000000-0000-0000-0000-000000000000"
}
]
}
}
The iOS SDK contains the following things:
CocoaPods is a dependency manager for Objective-C, which automates and simplifies the process of using 3rd-party libraries like HybridMessaging in your projects. See http://cocoapods.org for more information on how to install and use CocoaPods.
platform :ios, '7.0'
pod 'HybridMessagingSDK', '~> 1.2'
The HybridMessaging SDK can be added to your application by dragging the HybridMessaging.h and libHybridMessaging.a file into your project in Xcode. Make sure to enable “Copy items if needed” in the “Choose options for adding these files” dialog.
#import <HybridMessaging.h>
application:didFinishLaunchingWithOptions:
method- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[HybridMessaging configureWithKey:@"YOUR_APPLICATION_KEY"
secret:@"YOUR_APPLICATION_SECRET"];
[HybridMessaging enable];
}
Notes: the "enable" method triggers a dialog to the user to request permission to sent push notifications. You may want to call the method at a later time to increase the likelihood that the user will accept the notifications. The permission dialog is only triggered once. When the user has denied the request it can be enabled again from the Settings menu.
Set the device development mode (defaults to production)
+ (void)setDevelopment:(BOOL)yesOrNo;
When this value is set to YES, the device registration is marked as a development device, and our server automatically uses the development push certificate (if configured) while sending a push notification to the device.
Set this value before calling any device verification methods, preferably at the start of the application in - (BOOL)application:didFinishLaunchingWithOptions:
Note: Remember to set this value to NO in a production build or remove the method call
The central class in the Hybrid Messaging SDK is called HybridMessaging and holds references to methods for notifications and authentication functionality. All methods calls are static.
The HybridMessaging
class also contains a method for the Device ID and Push Token:
+ (NSString *)deviceId;
+ (NSString *)pushToken;
+ (NSString *)msisdn;
+ (NSString *)version;
+ (void)requestPhoneVerification:(NSString *)msisdn
handler:(void (^)(HMDeviceRegistrationStatus status))statusHandler;
+ (void)requestPhoneVerificationVoiceCall:(NSString *)msisdn
handler:(void (^)(BOOL success))statusHandler;
+ (void)requestPinVerification:(NSString *)pin
handler:(void (^)(HMDeviceRegistrationStatus status))statusHandler;
+ (void)requestVerificationStatus:(void(^)(HMDeviceRegistrationStatus status))statusHandler;
The device registration status can have one of the following values:
- HMDeviceRegistrationStatusUnknown
- HMDeviceRegistrationStatusUnverified
- HMDeviceRegistrationStatusWaitingForPin
- HMDeviceRegistrationStatusLastPinVerificationFailed
- HMDeviceRegistrationStatusPinVerified
- HMDeviceRegistrationStatusInvalid
Notes: Phone number is in MSISDN format and must start with the country code: e.g. 0031 for the Netherlands.
[HybridMessaging requestPhoneVerification:phoneNumberTextField.text
handler:^(HMDeviceRegistrationStatus status) {
if (status == HMDeviceRegistrationStatusWaitingForPin
|| status == HMDeviceRegistrationStatusLastPinVerificationFailed) {
// Show PIN view
} else {
// Handle error
}
}];
Set the user notification types (optional). Defaults to Alert, Badge and Sound.
+ (void)setUserNotificationTypes:(HMUserNotificationType)types;
Get the current notification types
+ (HMUserNotificationType)userNotificationTypes;
All available notification types:
- HMUserNotificationTypeNone // the application may not present any UI upon a notification being received
- HMUserNotificationTypeBadge // the application may badge its icon upon a notification being received
- HMUserNotificationTypeSound // the application may play a sound upon a notification being received
- HMUserNotificationTypeAlert // the application may display an alert upon a notification being received
Notes: Make sure to set the notification types before calling the +enable method.
[HybridMessaging setUserNotificationTypes:(HMUserNotificationTypeBadge |
HMUserNotificationTypeAlert |
HMUserNotificationTypeSound)];
Enable push notification.
+ (void)enable;
Disable push notification.
+ (void)disable;
You may set the following blocks in your application to react to the push notification events.
[HybridMessaging setDidReceiveRemoteNotificationBlock:^(NSDictionary *userInfo) {
NSLog(@"%@", userInfo);
}];
Called when a push notification is received
[HybridMessaging setDidRegisterForRemoteNotificationsWithDeviceTokenBlock:^(NSData *deviceToken) {
NSLog(@"%@", [deviceToken description]);
}];
Called when a push token is received
[HybridMessaging setDidFailToRegisterForRemoteNotificationsWithErrorBlock:^(NSError *error) {
NSLog(@"%@", error);
}];
Called when the push registration fails
Methods to receive the messages that have been sent by the Hybrid Messaging.
+ (void)messages:(void (^)(NSArray *messages, NSError *error))handler;
+ (void)messagesWithLimit:(NSInteger)limit handler:(void (^)(NSArray *messages, NSError *error))handler;
+ (void)messagesWithLimit:(NSInteger)limit offset:(NSInteger)offset handler:(void (^)(NSArray *messages, NSError *error))handler;
Get the last 100 messages
[HybridMessaging messagesWithLimit:100 handler:^(NSArray *messages, NSError *error) {
if (error) {
// Handle error
} else {
for (NSDictionary *message in messages) {
NSString *id = message[@"ID"];
NSString *body = message[@"Body"];
NSString *dateTime = message[@"DateTime"];
NSString *sender = message[@"Sender"];
// Do something with message
}
}
}];
Get geolocation information about the app user.
+ (void)requestGeoIpInfo:(void(^)(NSDictionary *info))handler;
Sets a callback to be executed when the carrier has changed.
+ (void)setDeviceDidUpdateCarrierBlock:(void(^)(CTCarrier *carrier))block;
The library is hosted in the Maven repository Bintray. All required changes (permissions, services and receivers) will automatically be merged as they're included in the Android Archive (AAR).
Add the dependency to your build.gradle
:
dependencies {
compile 'com.cm.hybridmessagingsdk:hybridmessagingsdk:2.2.0'
}
The heart of the SDK is the HybridMessaging
class. It contains all the functionality (like registering, messaging and notification settings) and is the only class needed to communicate with the SDK.
Initialization is required before calling any other method in HybridMessaging
Initialize the Hybrid Messaging SDK. Initialization is required before calling any other method in HybridMessaging
. The initialization process should happen as early as possible, initializing in the Application
class ensures the SDK is always initialized.
There's two ways to initialize the Hybrid Messaging SDK:
Add this metadata to the <application />
tag in your Android Manifest:
<meta-data
android:name="com.cm.hybridmessaging.api_key"
android:value="your_hybridmessaging_key" />
<meta-data
android:name="com.cm.hybridmessaging.secret"
android:value="your_hybridmessaging_secret" />
<meta-data
android:name="com.cm.hybridmessaging.projectid"
android:value="@string/project_id" />
Add the GCM Sender ID to your strings.xml
:
<string name="project_id">your_gcm_sender_id</string>
And call the initialize method:
HybridMessaging.initialize(Context context)
The keys will be read from the Android Manifest, so there's no need to provide them programmatically.
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
// initialize the Hybrid Messaging SDK
HybridMessaging.initialize(this);
}
}
Declare your Application
class in the <application />
tag in the Android Manifest:
<application [icon, label, theme, etc.] android:name=".MyApplication" />
Provide the keys programmatically, do this if you can't or prefer not to use metadata.
HybridMessaging.initialize(Context context, String apiKey, String apiSecret, String senderId)
public class MyApplication extends Application {
private static final String API_KEY = "your_hybridmessaging_key";
private static final String API_SECRET = "your_hybridmessaging_secret";
private static final String SENDER_ID = "your_gcm_sender_id";
@Override
public void onCreate() {
super.onCreate();
// initialize the Hybrid Messaging SDK
HybridMessaging.initialize(this, API_KEY, API_SECRET, SENDER_ID);
}
}
Declare your Application
class in the <application />
tag in the Android Manifest:
<application [icon, label, theme, etc.] android:name=".MyApplication" />
Google Play Services is required to receive push notifications. This is required by the Hybrid Messaging SDK in order to function. It's recommended to check if it's available through Google's API, so the user's guaranteed to be able to receive push notifications. Check this preferably in the startup activity.
Check if the Google Play Services is available. If it's not, a dialog with a solution will be shown if possible.
private boolean checkPlayServices() {
GoogleApiAvailability apiAvailability = GoogleApiAvailability.getInstance();
int resultCode = apiAvailability.isGooglePlayServicesAvailable(this);
if (resultCode != ConnectionResult.SUCCESS) {
if (apiAvailability.isUserResolvableError(resultCode)) {
apiAvailability.getErrorDialog(this, resultCode, REQUEST_GOOGLE_PLAY_SERVICES).show();
} else {
Log.w(TAG, "This device does not support the required Google Play Services.");
// show the user an error message
}
return false;
}
return true;
}
And handle the result from the error dialog.
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case REQUEST_GOOGLE_PLAY_SERVICES:
// if Play Services is available now, re-init the SDK and continue
HybridMessaging.initialize(getApplicationContext());
default:
super.onActivityResult(requestCode, resultCode, data);
}
}
REQUEST_GOOGLE_PLAY_SERVICES
is the request code used to indentify the request in the onActivityResult(...)
callback. Its value may be any number, but should be unique: no other requests should use the same value. For example:
private static final int REQUEST_GOOGLE_PLAY_SERVICES = 1;
Normal registration flow:
Phone numbers are in MSISDN format and have to start with the country code. Example: the country code for the Netherlands is
0031
, the MSISDN will look like0031612345678
.
Get the status of the verification/registration of the user.
HybridMessaging.getVerificationStatus(OnVerificationStatus listener)
OnVerificationStatus
interface:
void onVerificationStatus(VerificationStatus status);
void onError(Throwable throwable);
The enum VerificationStatus
has four values:
VerificationStatus | Meaning |
---|---|
Unverified |
The user is not registered |
Verified |
The user is registered and the phone number is verified |
LastPinVerificationFailed |
The user is registered, but the last provided pin was invalid |
WaitingForPin |
The user is registered, but hasn't provided a pin |
HybridMessaging.getVerificationStatus(new OnVerificationStatus() {
@Override
public void onVerificationStatus(VerificationStatus status) {
switch (status) {
case Unverified:
// show registration screen
break;
case Verified:
// already registered
break;
case LastPinVerificationFailed:
case WaitingForPin:
// show pin input
break;
}
}
@Override
public void onError(Throwable throwable) {
Log.e("MainActivity", "Error getting verification status", throwable);
}
});
Register a new user.
HybridMessaging.registerNewUser(String msisdn, OnRegistrationListener listener)
The user will receive an SMS message containing a validation PIN.
OnRegistrationListener
interface:
void onReceivedRegistration(Registration registration);
void onError(Throwable throwable);
HybridMessaging.registerNewUser(msisdn, new OnRegistrationListener() {
@Override
public void onReceivedRegistration(Registration registration) {
// ask user to enter verification PIN
}
@Override
public void onError(Throwable throwable) {
Log.e("MainActivity", "Error registering new user", throwable);
}
});
Confirm the MSISDN by providing the verification PIN sent to the phone number when the user was registered.
HybridMessaging.registerUserByPincode(String verificationCode, OnVerificationStatus listener)
See Check verification status for information about this listener.
HybridMessaging.registerUserByPincode(verificationCode, new OnVerificationStatus() {
@Override
public void onVerificationStatus(VerificationStatus status) {
switch (status) {
case Verified:
// verification was successful
break;
case LastPinVerificationFailed:
// provided PIN was invalid
break;
}
}
@Override
public void onError(Throwable throwable) {
Log.e("MainActivity", "Error registering user by PIN", throwable);
}
});
When the user wants the PIN re-sent.
HybridMessaging.requestNewVerificationPin(String msisdn, OnRegistrationListener listener)
See Register new user for information about this listener.
HybridMessaging.requestNewVerificationPin(msisdn, new OnRegistrationListener() {
@Override
public void onReceivedRegistration(Registration registration) {
// ask user to enter verification pin
}
@Override
public void onError(Throwable throwable) {
Log.e("MainActivity", "Error sending new PIN", throwable);
}
});
If the user prefers the PIN to be provided over a voice call, the user will be called in the language the device is set to.
HybridMessaging.doVoiceCall(String msisdn, VoiceCallListener listener)
listener
is optional
VoiceCallListener
interface:
void onSuccess();
void onError(Throwable throwable);
HybridMessaging.doVoiceCall(msisdn, new VoiceCallListener() {
@Override
public void onSuccess() {
// user is being called
}
@Override
public void onError(Throwable throwable) {
Log.e("MainActivity", "Error requesting PIN over voice call", throwable);
}
});
Check if the user is registered.
HybridMessaging.hasRegistration() : boolean
Note: this does not replace checking the verification status, as this methods only checks the registration locally.
Remove the registration, so a new user could be registered.
HybridMessaging.resetLogin()
Get the MSISDN of the registration.
HybridMessaging.getMsisdn() : String
Get the Device ID of the registration.
HybridMessaging.getDeviceId() : String
Get all messages.
HybridMessaging.getMessages(OnMessageListener listener)
Get a certain amount
of messages.
HybridMessaging.getMessages(int amount, OnMessageListener listener)
skip
a certain number and get a certain amount
of messages.
HybridMessaging.getMessages(int skip, int amount, OnMessageListener listener)
Get all messages after a given date.
HybridMessaging.getMessagesFromDate(long dateInMillisec, OnMessageListener listener)
dateInMillisec
: date formatted as a UNIX timestamp in milliseconds
Get messages filtered by a custom filter.
HybridMessaging.getMessagesWithFilter(Filter filter, OnMessageListener listener)
You can add one or more options to the
Filter
. The filter works with OData. Filter options:OPTION_EXPAND
,OPTION_FILTER
,OPTION_ORDER_BY
,OPTION_SELECT
,OPTION_SKIP
andOPTION_TOP
.
Filter filter = new Filter();
filter.addFilter(Filter.OPTION_SELECT, "ID,Body,DateTime,Sender,UpdateIDs");
filter.addFilter(Filter.OPTION_SKIP, "10");
filter.addFilter(Filter.OPTION_TOP, "5");
filter.addFilter(Filter.OPTION_FILTER, "DateTime gt DateTime'2016-01-01T12:00:00.000");
OnMessageListener
interface:
void onReceivedMessages(int statusCode, Headers headers, Message[] messages);
void onError(Throwable throwable);
int skip = 10;
int amount = 5;
HybridMessaging.getMessages(skip, amount, new OnMessageListener() {
@Override
public void onReceivedMessages(int statusCode, Headers headers, Message[] messages) {
// show messages
}
@Override
public void onError(Throwable throwable) {
Log.e("MainActivity", "Error getting messages", throwable);
}
});
Mark a message as read by the recipient at the current date.
HybridMessaging.markMessageAsRead(Message message, MarkAsReadListener listener)
listener
is optional
Mark a message as read by the recipient at the specified date.
HybridMessaging.markMessageAsRead(Message message, Date date, MarkAsReadListener listener)
listener
is optional
MarkAsReadListener
interface:
void onSuccess();
void onError(Throwable throwable);
HybridMessaging.markMessageAsRead(message, new MarkAsReadListener() {
@Override
public void onSuccess() {
// message is successfully marked as read
}
@Override
public void onError(Throwable throwable) {
Log.e("MainActivity", "Error marking message as read", throwable);
}
});
The SDK automatically shows notifications in the status bar with the default settings.
Default title: The application name Default icon: The application icon Both are retrieved from the
<application />
tag in theAndroidManifest.xml
Set a custom title for default notifications.
title
: passnull
to reset it to its default (application name).
HybridMessaging.setNotificationTitle(String title)
Set a custom icon for default notifications.
HybridMessaging.setNotificationIcon(int resourceId)
resourceId
: a drawable resource ID, pass0
to reset it to its default (application icon).
HybridMessaging.setNotificationIcon(R.drawable.ic_notification);
Change the behaviour of the SDK showing notifications. By default, the SDK shows notifications when receiving a message.
HybridMessaging.fireNotificationsByDefault(boolean showNotifications)
This is best to be used in conjunction with notification listener and show custom notifications.
If you want to be notified when a new Notification
is received, you could register a listener for this. For example, when you want to show custom notifications.
HybridMessaging.setHybridNotificationListener(HybridNotificationListener listener)
Note: if you want to show custom notifications, default notifications should be disabled
HybridNotificationListener
interface:
void onReceiveHybridNotification(Context context, Notification notification);
NotificationCompat.Builder notifBuilder = new NotificationCompat.Builder(context)
.setContentTitle("Hybrid Messaging SDK Example")
.setSmallIcon(R.drawable.ic_notification)
.setContentText(notification.getMessage())
.setAutoCancel(true);
// gets an instance of the NotificationManager service
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(notificationId, notifBuilder.build());
Users have the ability to disable notifications for apps, the SDK can detect if the user has disabled notifications for this app. When notifications are disabled, SMS messages will be sent instead of push messages, so the user will still receive Hybrid messages.
Enable or disable automatic detection.
HybridMessaging.setDetectDisabledNotifications(boolean enable)
Get if automatic detection is enabled.
HybridMessaging.getDetectDisabledNotifications() : boolean
By default, automatic detection is enabled.
If a device has a different SIM card, chances are the phone number has changed. As Hybrid Messaging is about phone numbers, it's a good idea to check if a user's phone number has changed. The Hybrid Messaging SDK is able to detect a replaced SIM card and could notify you. When a SIM card change is detected, it's recommended to reset the registration and let the user verify its phone number again.
HybridMessaging.setOnSimChangedListener(OnSimcardChangedListener listener)
Note: to be able to detect SIM card changes, the permission
READ_PHONE_STATE
is required.Add this to the
<manifest />
tag of your Android Manifest:<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
Interface OnSimcardChangedListener
:
void onSimcardChanged(boolean isChanged, String simState);
In any Activity
override the Activity.onResume()
and Activity.onPause()
and call them on the SDK. This will make it start and stop listening for changes to respect the Activity
lifecycle.
HybridMessaging.onResume()
HybridMessaging.onPause()
Recommended: call
onResume()
andonPause()
in everyActivity
shown after the user is registered.
HybridMessaging.setOnSimChangedListener(new OnSimcardChangedListener() {
@Override
public void onSimcardChanged(boolean isChanged, String simState) {
if (isChanged) {
// reset the registration
}
}
});
public class MainActivity extends Activity {
@Override
protected void onResume() {
super.onResume();
HybridMessaging.onResume();
}
@Override
protected void onPause() {
super.onPause();
HybridMessaging.onPause();
}
}
It's also possible to check for SIM card changes manually.
HybridMessaging.didSimStateChange() : boolean
Get the current version of the Hybrid Messaging SDK.
HybridMessaging.getSDKVersion() : String
To customize the user agent sent to the Hybrid Messaging servers with every call, obtain the UserAgent
instance. It's possible to change the app name, app version and language. By default, these properties will be read from the app.
HybridMessaging.getUserAgent() : UserAgent
In order to set a custom timeout value for all http(s) traffic from within the SDK, the setConnectionTimeout method can be called with an argument expressing the timeout value in seconds. By default, a timeout of 10 seconds will be used by the SDK in all http(s) communication.
HybridMessaging.setConnectionTimeout(int timeoutInSeconds)
Since 2.0.0 are all required permissions, receivers and services declared in the library's Android Manifest. All required changes to the Android Manifest will automatically be merged.
More info: Include library
Remove the permissions:
<!--Necessary for all outgoing internet connections-->
<uses-permission android:name="android.permission.INTERNET" />
<!--Necessary for connecting with the play store and retrieving registration id-->
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<!--Keep the service awake during processing incoming notifications-->
<uses-permission android:name="android.permission.WAKE_LOCK" />
<!--Receive notifications from the CCS/GCM platform of google-->
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
Remove receivers:
<receiver android:name="com.cm.hybridmessagingsdk.receivers.GcmBroadcastReceiver"
android:permission="com.google.android.c2dm.permission.SEND">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<category android:name="com.cm.hybridmessaging" />
</intent-filter>
</receiver>
Remove services:
<service android:name="com.cm.hybridmessagingsdk.GCMNotificationIntentService" />
Upgrade the dependency to version 2.2.0 in your build.gradle
:
dependencies {
compile 'com.cm.hybridmessagingsdk:hybridmessagingsdk:2.2.0'
}
More info: Include library
Due to switching from Apache HttpClient to OkHttp, the signature of the onReceivedMessages(...)
method in the OnMessageListener
has changed.
Previous:
void onReceivedMessages(int statusCode, Header[] headers, Message[] messages);
Now:
void onReceivedMessages(int statusCode, Headers headers, Message[] messages);
More info: Get messages
Deprecated method | Replacement |
---|---|
HybridMessaging#HybridMessaging(Context) |
HybridMessaging.initialize(Context) |
HybridMessaging.setUserAgent() : UserAgent |
HybridMessaging.getUserAgent() : UserAgent |
Message#getUpdateId() : String |
Message#getUpdateIds() : String[] |
Message#setUpdateId(String) : void |
Message#setUpdateIds(String[]) : void |
Notification#getNotificationId() : String |
Notification#getId() : int |
HybridMessaging.getMsisdn()
doesn't try to read the MSISDN from the SIM card anymore, as this is unreliable on certain devices. It now only reads it from the preferences.execute within the target Cordova project:
cordova plugin add https://github.com/CMTelecom/cm-plugin-hybridmessaging.git#1.0.0
OR
<plugin name="cm-plugin-hybridmessaging" spec="https://github.com/CMTelecom/cm-plugin-hybridmessaging.git#1.0.0" />
to the config.xml
file of the project.The plugin intialization consists of two steps, namely:
Service configuration is performed by the means of the hybridmessaging.configureService(config)
call. This configures the hybrid messaging service with API key, API secret, Android sender ID , a callback for handling incoming push notification content and finally, a callback for handling SIM card/carrier changes.
Parameters
Object
, (required) - config object with format:{
appKey : 'string',
appSecret : 'string',
senderId : 'string', (required on Android only)
notificationCallback : 'function',
deviceCarrierUpdateCallback : 'function'
}
Example
var config = {
appKey : YOUR_APP_KEY,
appSecret : YOUR_APP_SECRET,
senderId : YOUR_ANDROID_SENDER_ID,
notificationCallback: notificationCallback,
deviceCarrierUpdateCallback: deviceCarrierUpdateCallback
};
window.hybridmessaging.configureService(config);
function notificationCallback(pushPayload) {
console.log(pushPayload);
#push payload is raw platform-specific payload including keys such as 'alert' on iOS and 'message' on Android.
var message = pushPayload.alert ? pushPayload.alert : pushPayload.message;
$cordovaDialogs.alert(message, 'Push message', 'OK');
}
function deviceCarrierUpdateCallback() {
console.log('Device carrier has changed');
}
IMPORTANT: the configureService
method should be called as early in the application's life cycle as possible and prior to executing any other call related to hybrid messaging. All hybrid messaging methods called prior to service configuration will return with an error.
The hybrid messaging service is started by calling hybridmessaging.startMessagingService(successCallback, errorCallback)
. This prepares the client for receiving hybrid messages.
Parameters
successCallback: function
, (required) - callback function to be called upon successfully started messaging service
failureCallback: function
, (optional) - callback function to be called upon error
Example
window.hybridmessaging.startMessagingService(function() {
console.log('Messaging service has started successfully');
}, function(error) {
console.log('Failed to start messaging service: ' + error);
});
IMPORTANT: the startMessagingService
method should be called after executing the configureService
method and should complete with success prior to executing any other call related to hybrid messaging. All hybrid messaging methods called prior to successful service starting (except for configureService
which should be called before it and as early in the application life cycle as possible) will return with an error.
In order for the user to be able to receive hybrid notifications, the user's phone number (MSISDN) needs to be confirmed at least once in the life time of the mobile application. This is performed by requesting verification via the requestVerification(msisdn, successCallback, errorCallback)
which triggers an SMS with a one-time PIN to be sent to the user's device:
Parameters
msisdn: string
, (required) - phone number to verify
successCallback: function
, (required) - callback function to be called upon successfully requesting number verification.
failureCallback: function
, (optional) - callback function to be called upon error
Example
var msisdn = '0031612345678';
window.hybridmessaging.requestVerification(msisdn, function(status) {
console.log(status);
}, function(error) {
console.log('Phone number verification failed: ' + error);
});
Once successfully received on the user's device, the one-time PIN code should be passed back to the hybrid messaging plugin for verification. This is performed using the verifyPin(pin, successCallback, errorCallback)
call.
Parameters
pin: string
, (required) - pin to verify
successCallback: function
, (required) - callback function to be called upon successfully executing PIN verification (with verification either passed or failed, but in any case correctly executed)
errorCallback: function
, (optional) - callback function to be called upon error
Example
var pin = '0785';
window.hybridmessaging.verifyPin(pin, function(status) {
console.log(status);
}, function(error) {
console.log('Failed to verify pin: ' + error);
});
In case if the default SMS-based number verification failed, the user can request the one time PIN code to be passed to them using an alternative method, namely via requestVerificationVoiceCall(successCallback, errorCallback)
. The requested voice call, if successful, will provide the same PIN code as was originally sent via SMS for verification.
Parameters
successCallback: function
, (required) - callback function to be called upon successfully requesting PIN voice call
errorCallback: function
, (optional) - callback function to be called upon error
Example
window.hybridmessaging.requestVerificationVoiceCall(function() {
console.log('Successfully performed a voice call');
}, function(error) {
console.log('Failed to perform a voice call: ' + error);
});
IMPORTANT: Due to its fallback nature the requestVerificationVoiceCall
method should only be called after regular SMS-based verification has been requested using the requestVerification
method. Calling requestVerificationVoiceCall
before attempting at least one requestVerification call in the application's lifetime will result in an error.
Each of the methods used in phone number verification returns upon successful execution (so through its respective successCallback
) a status code which represents one of the discrete statuses from the DeviceRegistrationStatus
enumeration:
DeviceRegistrationStatus.UNVERIFIED,
DeviceRegistrationStatus.WAITING_FOR_PIN,
DeviceRegistrationStatus.LAST_PIN_VERIFICATION_FAILED,
DeviceRegistrationStatus.PIN_VERIFIED,
DeviceRegistrationStatus.INVALID,
DeviceRegistrationStatus.UNKNOWN
Additionally, at any point in the application flow, independently of the method calls decribed above, it is possible to explicitly call the getVerificationStatus(successCallback, errorCallback)
method which upon success will also deliver the current status of the verification.
Parameters
successCallback: function
, (required) - callback function to be called upon successfully fetching the current status
errorCallback: function
, (optional) - callback function to be called upon error
Example
window.hybridmessaging.getVerificationStatus(function(status) {
console.log(status);
}, function(error) {
console.log('Failed to get verification status: ' + error);
});
In order to fetch all previously received hybrid messages, the getMessages(limit, offset, successCallback, errorCallback)
can be used.
Parameters
limit: number
, (optional) - amount of messages to retrieve
offset: number
, (optional) - offset from which messages to retrieve
successCallback: function
, (required) - callback to be called upon successful message retrieval
errorCallback: function
, (optional) - callback function to be called upon error
Example
var limit = 5;
var offset = 10;
window.hybridmessaging.getMessages(limit, offset, function(messages) {
console.log(messages);
}, function(error) {
console.log('Failed to retrieve messages: ' + error);
});
It is possible to programmatically obtain the device ID value which is used by the hybrid messaging system in order to uniquely identify a device of a user. For this, the getDeviceIdValue(successCallback, errorCallback)
call can be used.
Parameters
successCallback: function
, (required) - callback function to be called upon successfully fetching device ID
errorCallback: function
, (optional) - callback function to be called upon error
Example
window.hybridmessaging.getDeviceIdValue(function(deviceId) {
console.log('Device id is ' + deviceId);
}, function(error) {
console.log('Failed to fetch device id: ' + error);
});
It is possible to programmatically obtain the device's phone (MSISDN) number as long as only it has ever been registered with the hybrid messaging system during the mobile application's life time. For this, the getMsisdnValue(successCallback, errorCallback)
call can be used.
Parameters
successCallback: function
, (required) - callback function to be called upon successfully fetching theMSISDN
errorCallback: function
, (optional) - callback function to be called upon error
window.hybridmessaging.getMsisdnValue(function(msisdn) {
console.log('MSISDN is ' + msisdn);
}, function(error) {
console.log('Failed to fetch MSISDN: ' + error);
});
In case when it's desired to use the Apple Push Notification Service (APNS) development sandbox instead of the actual APNS production system, a setDevelopment(enableDevelopment)
call should be executed client side in order to notify the hybrid messaging server about the need for using an appropriate APNS endpoint.
Parameters
boolean
, (required)window.hybridmessaging.setDevelopment(true);
Apps that register with and retrieve messages from CM’s Hybrid Messaging platform use a REST API to communicate. This document is a guide on how to use the API. There are some prerequisites (like authorization) for every request. These are explained in chapter 2.
In chapter 3 we explain how to register and chapter 4 is all about receiving messages. As this API is a RESTful interface, we use HTTP verbs to define an action:
More information on REST: http://en.wikipedia.org/wiki/Representational\_state\_transfer#Applied\_to\_web\_services
The data format is JSON. More information on JSON: http://www.json.org
The Authorization header is used to verify requests from your app are originating from the app. The app 'signs' the request with a calculated OAuth 2.0 Message Authentication Code (MAC) signature and the REST API will check this by calculating the same signature itself and comparing this calculated signature with the mac value in the Authorization header.
The Authorization header needs three values:
The value of the Authorization header will look like this:
MAC kid="8eda08f7-5249-40c2-9ef7-ce573f3a8dca" mac="rqaxTHoMFpvaMc7i9Yau8mtN2zw=" ts="1534409510"
In this example the appSecret: secret
is used.
The message authentication code (mac) is calculated by using hmac-sha-1 on a string representing the request. The string representing the request looks like this:
GET /v1.0/messages HTTP/1.1
api.cmtelecom.com
1534409510
The query string, if used, should also be included:
POST /v1.0/messages?$top=100 HTTP/1.1
api.cmtelecom.com
1534409510
If authorization fails, the server will respond with HTTP Status 401 Unauthorized.
Your app also needs to include a User-Agent header. This contains information about the app, the hybrid messaging library used and the device. It should at least contain the mobile platform (iOS, Android or WindowsPhone). Other information is optional. It is useful to include the operating system, app name, user name, device brand name, device model name, user language and/or the app version.
Android example:
MyApp/1.0 (Android 6.0.1; LGE; Nexus 5X; en_US)
If the UserAgent is not correct or missing, the server responds with HTTP Code 400 Bad Request.
To uniquely identify the app install on the device, the Hybrid Messaging platform generates a globally unique identifier (GUID). After you’ve retrieve a DeviceID as reply on the first device registration request, you need to include a DeviceID header on every request with this GUID as its value. It’s mandatory for every request, except when creating a new device registration.
If the DeviceID is not correct, the server responds with HTTP Code 400 Bad Request.
Do not mistake the DeviceID with the deviceID from your phone.
The API uses the ISO 8601 Date/Time format, with a T between the date and the time. In short, this is the format:
YYYY-MM-DDTHH:mm:ss.ms
Do not use local time, but always use UTC time.
A full HTTP request will look like this:
PUT /v1.0/deviceregistrations HTTP/1.1
Host: api.cmtelecom.com
Authorization: MAC kid="8eda08f7-5249-40c2-9ef7-ce573f3a8dca" ts="1464242891" mac="dkViwAV9Pi5xiab39VRUq+gU4Co="
Content-Type: application/json
User-Agent: MyApp/1.0 (Android 6.0.1; LGE; Nexus 5X; en_US)
DeviceID: 0c6bf13c-8d1c-474c-ab66-74dadb1c3d7d
{
"Msisdn": "0031600000000"
}
A "device registration" in the context of this API is an install of an app on a device.
To get information about the apps device registration, simply send a GET request to /v1.0/deviceregistrations
and you get the following response:
{
"DeviceID":"9386b95d-d31b-49bd-8bf8-f203bed9236e",
"Msisdn":"0031600000000",
"Platform":"Android",
"RegistrationStatus":"Unverified",
"Created":"2016-05-22T18:02:45.427",
"RegisteredForPushNotification":false,
"AppKey":"73838e3f-186c-433a-a8e1-e73c88856abc",
"AppName":"MyApp",
"UserAgent":"MyApp/1.0 (Android 6.0.1; LGE; Nexus 5X; en_US)"
}
RegistrationStatus can have the following values:
When the device registration is not found, the server returns HTTP Code 404 Not found.
To register a new device registration, you send a POST request to /v1.0/deviceregistrations
. You can even send a request without any field, but you still have to provide an empty object:
{}
You can also choose to include the push token and/or MSISDN already:
{
"PushToken":"3b19403cc169950f61471bec7fb21722e9a26f5e35c70a"
}
PushToken is the token that the app retrieves from a push notification cloud service like Windows Notification Services, Google Cloud Messaging or Apple Push Notification Server.
To update an existing device registration, you send a PUT request to /v1.0/deviceregistrations
with any field you want to update. You can leave out any field you don’t want to update.
{
"PushToken":"3b12be3456ea60b82b71bec7fb21722e9a26f5e35c70a",
"Msisdn":"0031600000000"
}
Msisdn is the mobile subscriber identification number. A internationally formatted phone number starting with the country prefix with leading zeroes.
When a device registration request contains an MSISDN (phone number) which is not verified yet, the platform will automatically send a verification SMS message to that MSISDN.
You need to give your user a way to put in the verification code, after which your app sends a PUT request to /v1.0/deviceregistrations
with the appropriate code:
{
"VerificationCode":"1234"
}
If the code is correct, the server will respond with:
{
...
"RegistrationStatus":"PinVerified",
"RegisteredForPushNotification":true,
...
}
If the code is not correct, the server responds with:
{
...
"RegistrationStatus":"LastPinVerificationFailed",
"RegisteredForPushNotification":false,
...
}
To retrieve all messages for the app, send a GET request to /v1.0/messages
. The response looks like this:
[
{
"ID":"7af65395-2dc9-45c4-aa58-a7f53e33c4f3",
"UpdateID":"6509643555",
"Recipient":"0031600000000",
"Sender":"MyApp",
"Body":"Your first message!",
"DateTime":"2016-05-22T23:41:28.563",
"Status":"Delivered"
},
{
"ID":"807256bb-01ca-43f3-8d07-d3d91a675f14",
"UpdateID":"6509643556",
...
}
]
Status can contain the following values:
The ID is a globally unique identifier (GUID) that uniquely identifies the message. The UpdateID is only guaranteed to be unique for 24 hours. This ID is needed to notify the platform that a message is retrieved by an app or read by the user, which is explained in the next paragraph.
DateTime is the time the message arrived at the Hybrid Messaging platform.
The messages API supports the ODATA Query language. You can specify $select, $top, $skip, $filter and $orderby to make your result set more specific.
See chapter 5 of this page for more information: http://www.odata.org/documentation/odata-version-3-0/url-conventions
When your app retrieve a message as a push notification, it should notify the platform about this event. To do so, send the following PUT request to the server:
{
"UpdateID":"6509643556",
"Status":"Delivered"
}
When your app displayed the message to a user, it should notify the platform using a Date/Time in the ReadByRecipient field.
{
"UpdateID":"6509643556",
"Status":"Delivered",
"ReadByRecipient":"2016-05-22T23:41:28.563"
}
Messages sent from the HybridMessaging platform make use of the XMPP Android protocol. This allow us to monitor if a message is received on the device of the user. When receiving the message a connection from Google will be made with the phone of the user. This connection can be reused to send an ACK back to the originated address. In order to make HybridMessaging properely work on Android we need to know if a notification is received on the phone. If not a message will be send twice since we don't know for sure if the message was received correctly or on time. Follow the steps below to send back ACKS when succesfully receiving messages.
To receive messages from hybrid messaging you should first create a WakefulBroadcastReceiver
with an IntentService
capable of listening to incoming notifications.
In the IntentService you are able to retrieve the contents of the message and send an Ack back to the server over the XMPP protocol. In order to send the Ack back to the server you have to instantiate a GoogleCloudMessaging object and retrieve the message type.
final GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(this);
String messageType = gcm.getMessageType(intent);
Also retrieve the bundle from the intent to retrieve the message
Bundle extras = intent.getExtras();
To send a message back to the server, make sure you wait a very short time. Let the Thread sleep for a very short while otherwise the Ack will not be send back to the server.
Afterwards retrieve the bundle contents from the Extras received through the Intent. Important are time_to_live and messageId that need to be send back to the server. Send an ACK back to the server over the same GCM connection with as destination your Google project ID including an address as following: YOUR_PROJECT_ID + "@gcm.googleapis.com
Example:
public class GCMNotificationIntentService extends IntentService {
public GCMNotificationIntentService() {
super("com.your.project.GCMNotificationIntentService");
}
@Override
protected void onHandleIntent(Intent intent) {
Bundle extras = intent.getExtras();
final GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(this);
String messageType = gcm.getMessageType(intent);
if (extras != null) {
if (!extras.isEmpty()) {
if (GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE.equals(messageType)) {
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(200);
}
catch (InterruptedException e) {}
}
String messageId = null;
long ttl = 30L;
Bundle bundle = intent.getExtras();
messageId = bundle.getString("message_id");
String notificationId = bundle.getString("from");
String message = bundle.getString("message");
String tempttl = bundle.getString("time_to_live");
if(tempttl != null) {
ttl = Long.valueOf(bundle.getString("time_to_live"));
}
// ## Send ACK back to server containing the following KEY and VALUE ## //
Bundle dataBundle = new Bundle();
dataBundle.putString("message_type", "DLR");
try {
if(tempttl != null) {
gcm.send(PROJECT_ID + "@gcm.googleapis.com", messageId, ttl, dataBundle);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
GcmBroadcastReceiver.completeWakefulIntent(intent); // Close the service
}
}
important: Make sure to send "message_type" along with "DLR" back to the server