Overview
When Cordial's mobile SDK is initialized in your app, it automatically captures the device data necessary for device identification and routing of mobile app messages to your contacts. One of the most reliable ways to obtain up-to-date mobile device data is through the SDK while contacts interact with your app. But this method relies on your contacts having a version of the app installed that contains the Cordial SDK.
To ensure that you can send mobile app messages to your existing contacts—no matter which version of the app they have installed—you can use Cordial's Data Jobs and an externally hosted data file to migrate device data to Cordial.
In this article, we'll break down the logic of a sample Smarty script that is designed to prepare device data from your import file and import it to your Cordial account.
Example mobile app object
Mobile app channel object
{ "channels": { "push": { "address": { "5c98d21q-b3o8-42bc-9dac-e9d3c00e34e1": { "app": "1.0.0-MobileApp", "os": "android", "pushEnabled": true, "sdk": "1.0", "token": "do4-_NCZRbiKTo_l-8jVKy...", "v": "10",
"valid": "true" } }, "subscribedAt": "2020-04-16T20:52:21+0000", "unsubscribedAt": "", "subscribeStatus": "subscribed" } } }
Parameter details
The push channel key may differ depending on your account configuration.
Parameter | Description |
---|---|
channels.push.address | A unique identifier for the registered device (deviceID). Cordial's mobile SDK generates this value when contacts begin using your app for the first time after the SDK is initialized, but this value can also be generated using Smarty. Multiple unique devices can be associated with a single contact record. |
channels.push.address.deviceID.app | The version of your app installed on the device. |
channels.push.address.deviceID.os | Device operating system (iOS or Android). |
channels.push.address.deviceID.pushEnabled | Indicates whether push notifications are enabled (true of false). |
channels.push.address.deviceID.sdk | The version of Cordial's SDK in your app. |
channels.push.address.deviceID.token | APNS (Apple) or FCM (Android) issued device token. |
channels.push.address.deviceID.v | Device operating system version. |
channels.push.address.deviceID.valid | Shows that as of the last send, this device still had the app installed. |
channels.push.unsubscribedAt | The most recent date contact unsubscribed from the push channel. |
channels.push.subscribedAt | The most recent date contact subscribed to the push channel. |
channels.push.subscribeStatus | Contact's current push channel subscribe status. |
In order to receive mobile app messages, contacts must be subscribed at the mobile app channel level, and, optionally, push notifications must be enabled at the device level to receive push notifications.
The deviceID is a unique identifier that distinguishes devices from one another in the Cordial database. The device token is a unique app identifier issued by APNS or FCM and used by Cordial to send notifications to the specific app instance installed on the contact's device (similar to an email address or a phone number).
Import code breakdown
This is our sample Smarty code in its entirety. You can scroll the code box or copy its contents for easier viewing in a different application.
{* Sample Row: - token - The Device Token (required) - device_type - The Device Platform (required) - alias - The Email Address (optional) - opt_in - Are Push Notifications Enabled (optional) *} {*Edit these variables as needed*} {$channelKey = 'push'} {$token = $dataRecord.token} {$device_type = $dataRecord.device_type} {$opt_in = $dataRecord.opt_in} {$alias = $dataRecord.alias} {*Prevents editing of data. Set to false when ready to test editing data and importing*} {$debug = true} {*Don't edit these variables*} {$deviceId = null} {$device = null} {$waitForResult = true} {*If the token or device_type is empty, skip this record*} {if !empty($token) && !empty($device_type)} {if $utils-strContains("ios", $device_type, false)} {*For iOS tokens, we need to lowercase them before proceeding*} {$token = $token|lower} {/if} {*Search by token to see if the device already exists*} {$foundContact = $utils-getContactByDeviceToken($channelKey, $token)} {* If a contact was found, you can skip or perform other data operations on the record *} {if $foundContact} {*Do nothing as the device already exists, probably came in naturally via an app update with Cordial SDK*} {if $debug} Existing Contact Found {$utils-jsonPrettyPrint($foundContact)} {/if} {else} {*Device doesn't exist yet, we need to import it*} {*Generate a new DeviceID*} {$deviceId = $utils-generateUUID4()} {* Preparing a payload, required fields: 'os', 'pushEnabled', 'token', optional fields: 'sdk', 'app', 'v' *} {*Setting values to 0 for now to signal these were imported*} {$device = ['os' = $device_type, 'token' = $token, 'v' = '0', 'sdk' = '0', 'app' = '0']} {*If we aren't given a value for pushEnabled, we will default to true as we will get feedback on the next send*} {*We need to do some string comparisons as well since PHP will treat any non-null string as true*} {if isset($opt_in) && (!$opt_in || $utils-strContains("false", $opt_in, false))} {$device['pushEnabled'] = false} {else} {$device['pushEnabled'] = true} {/if} {*Add the device to the devices array to upsert*} {$payload["channels.$channelKey.address"] = [$deviceId = $device]} {*Set the secondary key to create a cID + device contact*} {$pk = "{$channelKey}:{$token}"} {*If an email is provided, we will use that as the secondary key so it updates an existing contact if the email exists*} {if !empty($alias)} {$payload["channels.email.address"] = $alias} {$pk = "email:{$alias}"} {/if} {if !$debug} {$c = $utils-upsertContact($payload, $pk, true)} {*Also call update contact to update the subscribe status*} {$contact = $utils-setcontact("cID:{$c._id}")} {$c = $utils-updateContact(["channels.$channelKey.subscribeStatus" = "subscribed"], $waitForResult, true, true)} {else} Payload to Upsert {$utils-jsonPrettyPrint($payload)} {/if} {/if} {/if}
Skip devices without device token and OS
Depending on how your import file was compiled, it may contain device data without the required device token and device OS values. A common reason these values may be missing is due to them being removed by the previous push provider when your app is uninstalled from the contact's device.
{*If the token or device_type is empty, skip this record*} {if !empty($token) && !empty($device_type)}
Our script will skip device records without these values and continue uninterrupted.
Check if device token is associated with an existing contact record
Your import file could contain device data that already exists in Cordial if some of your contacts have been using a version of your app with Cordial's SDK installed. We're using the getContactByDeviceToken Smarty utility to check if any of the device tokens in the import file are associated with an existing contact record in your Cordial account.
{*Search by token to see if the device already exists*} {$foundContact = $utils->getContactByDeviceToken($channelKey, $token)} {* If a contact was found, you can skip or perform other data operations on the record *} {if $foundContact} {*Do nothing as the device already exists, probably came in naturally via an app update with Cordial SDK*}
Device data added via Cordial's SDK while contacts are using your app is usually current and may not need to be changed during migration. Our script does not update this data, but you could perform any number of operations on the incoming data prior to updating existing records.
Insert new device data
This part of the script will insert new device data from the import file.
{else}
{*Device doesn't exist yet, we need to import it*}
{*Generate a new DeviceID*}
{$deviceId = $utils->generateUUID4()}
{* Preparing a payload, required fields: 'os', 'pushEnabled', 'token', optional fields: 'sdk', 'app', 'v' *}
{*Setting values to 0 for now to signal these were imported*}
{$device = ['os' => $device_type, 'token' => $token, 'v' => '0', 'sdk' => '0', 'app' => '0']}
{*If we aren't given a value for pushEnabled, we will default to true as we will get feedback on the next send*}
{*We need to do some string comparisons as well since PHP will treat any non-null string as true*}
{if isset($opt_in) && (!$opt_in || $utils->strContains("false", $opt_in, false))}
{$device['pushEnabled'] = false}
{else}
{$device['pushEnabled'] = true}
{/if}
{*Add the device to the devices array to upsert*}
{$payload["channels.$channelKey.address"] = [$deviceId => $device]}
To successfully insert new device data, the script will look for the required data fields within the import file. Some of the required values may be set by the script.
Required data fields
Parmeter | Source |
---|---|
channels.push.address | Our script will generate unique deviceID values using the generateUUID4 Smarty utility. |
channels.push.address.deviceID.os | Import file. |
channels.push.address.deviceID.pushEnabled | Import file. If not provided, the script will default this value to true. |
channels.push.address.deviceID.token | Import file. |
Setting the pushEnabled
value to true does not set the push opt-in status of the actual device. Only contacts can opt-in and out of receiving push notifications by changing push settings on their device. This value is set to true so the next time you send a notification to those contacts, APNS or FCM will respond and verify if the device token is valid.
The optional values for device OS version, SDK version, and app version will default to 0 and can be updated at a later time as your contacts begin using the version of your app with Cordial's SDK initialized.
Use email address as secondary contact identifier
Some of your records may contain an email address. When this is the case, our script will use the email value as the secondary contact key to identify and update contact records:
{*If an email is provided, we will use that as the secondary key so it updates an existing contact if the email exists*}
{if !empty($alias)}
{$payload["channels.email.address"] = $alias}
{$pk = "email:{$alias}"}
{/if}
Finally, we import the record and set the subscription status to subscribed since even if the device is opted-out of push notifications, they can still receive In-App and Inbox messages.
If the $debug
flag at the top of the script is set to true
, then no imports will happen and instead the payload that would be imported is printed out for testing purposes.
{if !$debug}
{$c = $utils->upsertContact($payload, $pk, true)}
{*Also call update contact to update the subscribe status*}
{$contact = $utils->setcontact("cID:{$c._id}")}
{$c = $utils->updateContact(["channels.$channelKey.subscribeStatus" => "subscribed"], $waitForResult, true, true)}
{else}
Payload to Upsert
{$utils->jsonPrettyPrint($payload)}
{/if}
Cordial's mobile SDK alongside other providers
Cordial's mobile SDK is capable of running alongside other SDKs on the same app. In this scenario, Cordial's SDK assumes more of a listener role, waiting for your instructions on when and how to handle mobile app messages and other events.
This is a reliable way to test the SDK installation because it lets you selectively allow the new SDK to handle device and event data. After some time of testing and reaching satisfactory integration results, you can transition to letting Cordial's mobile SDK handle mobile app messages and events automatically.
Learn more by accessing Cordial's mobile SDK developer documentation on GitLab:
Initializing multiple SDKs within your app requires careful planning and can be demanding on your development team. Although it has many advantages over outright switching to the new SDK, the feasibility of this approach is dependent on the available resources at your disposal.
Comments
0 comments
Please sign in to leave a comment.