RadiumOne's Frequently Asked Questions page is a central hub where its customers can always go to with their most common questions. These are the 34 most popular questions RadiumOne receives.
Within Mobile Analytics everything comes down to tracking events.
Each event in turn has a set of attributes that add dimensions and depth and which we can use to analyze them after the fact.
Some clients will have very strong ideas of what events they should be tracking and what attributes are important for each. Others will require more hand holding.
Anything that happens in the app code can be tracked as an event, not just user actions. So, for example, in a dating app a user might tap 'Like" on another users profile and that's obviously trackable as an action, but when the system recognizes that both users have clicked "Like" and sends them both notifications, sending the "Like" notification can also be tracked as an action.
If you are unsure, please bring in a Solution Engineer who can talk through the use cases with them.
Set of available events includes:
1) Automatic Events
The R1 Mobile Analytics SDK will automatically capture some generic events in order to get the most meaningful data on how users interact with your application. These events are triggered when the state of the application is changed, and therefore do not require any additional code to work out of the box:
Launch- emitted when the app starts
First Launch- emitted when the app starts for the first time
First Launch After Update- emitted when the app starts for the first time after a version upgrade
Application Opened- emitted when your app is opened after a message is sent.
Session Start- emitted when a new session starts
Session End- emitted when a session ends; includes a Session Length attribute with the session length in seconds
2) Standard Events
Standard Events cover all the main user flows (login, register, share, purchase...) in a standardized format for optimized reporting on the portal, providing a great foundation for your analytics strategy. They unlock great insights, particularly with respect to user lifetime value.
Login -Tracks a user login within the app
Registration -Records a user registration within the app
Facebook connect -Allows access to Facebook services
Twitter connect -Allows access to Twitter services
User Info -This event enables you to send user profiles to the backend.
Upgrade -Tracks an application version upgrade
Trial Upgrade -Tracks an application upgrade from a trial version to a full version
Screen View -Basically, a page view, it provides info about that screen
Transaction -A purchase
TransactionItem -Deprecated, use the Transaction event instead.
Delete Cart
Add To Cart
Delete From Cart
3)Custom Events
Custom events enable you to create and track specific events that are more closely aligned with your app. If planned and structured correctly, custom events can be strong indicators of user intent and behavior. Some examples include pressing the like button, playing a song, changing the screen mode from portrait to landscape, and zooming in or out of an image. These are all actions by the user that could be tracked with events.
Custom events can also be used to track things that happen in an app that do not involve direct user input. For instance a dating app could fire an event when the server matches two users based on interest and it sends them both notifications, even though neither end user has taken an action yet.
4) In-App Webview Events
By setting up in-app webview events, you can track events that begin inside your native application but are completed in the embedded browser. To do so, you will have to embed some JavaScript in the page that you will want to fire the event, and you need to properly trigger the webview in your application. These can include events in any of the three categories above.
Read More:
Implement event tracking in iOS Implement event tracking in Android
View ArticleThis guide is intended to summarize the available integration options so that you can easily plan your deployment.
The first thing to do is Sign up for a free account( http://connect.radiumone.com/register/ ). Note that each account is tied to a single email address at this time so you'll need to share access between your engineers who will build the integration and the people usingthe reporting. After integration is complete you can change the password on the account if desired.
Once you have your account, the integration steps are as follows:
Steps:
Plan your Integration
Identify events to measure your Key Performance indicators (KPI's)
Identify user groups you want to target with push notifications
Select an integration option
Software Development Kit (SDK)
API Integration from your app
Server to Server Integration via API
API integration from a third party tool
Testing and QA
Submit app
1. Plan your Integration:
Identify key events
RadiumOne Mobile Analytics is fundamentally based on tracking Events - things that happen in your app. Those things can be user actions like tapping a button or completing a purchase, or they can be something that happens on the app side such as one user being matched to another in a dating app.
RadiumOne Mobile Analytics will automatically track:
Launch - fired when the app starts
First Launch - fired when the app starts for the first time
First Launch After Update -fired when the app starts for the first time after a version upgrade
Application Opened - fired when your app is opened after a message is sent.
Session Start - fired when a new session starts
Session End - fired when a session ends; includes a Session Length attribute with the session length in seconds
What else should I track?
You can track any number of custom events in Mobile Analytics, but rather than just tracking everything and cluttering your dashboard with irrelevant data, we recommend stopping to consider what the Key Performance Indicators (KPI's) are for your app. These will vary considerably depending on your vertical and your particular approach and there is no one-size-fits-all solution.
To make it easier, we have standardized data formatting for a few very common events, these include:
Login: Tracks a user login within the app
Registration: Records a user registration within the app
Facebook connect: Track this when the user allows access to Facebook services
Twitter connect: Track this when the user allows access to Twitter services
User Info: This event enables you to send user profiles to the backend. Please do not send us personally identifiable information!
Upgrade: Tracks an application version upgrade
Trial Upgrade: Tracks an application upgrade from a trial version to a full version
Screen View: Basically, a page view, it provides info about that screen
Transaction: A purchase
Delete Cart
Add To Cart
Delete From Cart
You are not limited to these predefined events, however, and can add your own custom events as well.
Key things to consider about what to track:
What are the critical parts of the user experience in my app?
Where am I losing users? What features need improvement?
Does my user base spending a lot of time with one feature mean it is broken and a time suck for users or does it mean they love it and are very engaged? How can I tell the difference?
What will I learn by tracking this event?
How is it relevant to my KPI's?
What attributes of the event are important? For example, a Transaction event should at minimum include the value of the transaction and the names or ID's of the item or items purchased, but depending on your monetization model might benefit from other contextual info as well.
To get the best results, we recommend having all your stakeholders sit down and discuss what they want to know and whats important to them. Unlike many analytics solutions, we do not have a cap on the number of trackable events so you can be as comprehensive as you want.
If you are new to Analytics and need a hand figuring this out, please reach out to our support team and we will be happy to help make sure you get the data you need and are able to implement tracking quickly and easily.
2. Integration Options
SDK Installation
This is by far the most common route and the easiest for us to support and debug. Unlike some other tools, the RadiumOne Mobile Analytics SDK plays no role in the day to day functioning of your app - its not serving ads or in-app content - and is purely a reporting tool. That keeps the footprint incredibly lightweight and implementation simple. Key functionality includes offline queing of messages to our endpoint so youdon'tlose data when users go offline.
Basic SDK integration can be accomplished in a few hours. Beyond that, the time requirements are totally dependent on the tagging and event tracking you want to put in place.
The basic steps are outlined here: https://support.radiumone.com/hc/en-us/articles/218279063
For full step by step instructions, please refer to our documentation on Github.iOS: https://github.com/radiumone/r1-connect-demo-iOS
Android: https://github.com/radiumone/r1-connect-demo-Android
Windows: https://github.com/radiumone/r1-connect-demo-WP/tree/master/R1ConnectDemo
Phonegap: https://github.com/radiumone/r1-connect-demo-phonegap
Titanium: https://github.com/radiumone/r1-connect-titanium
API Integrations
In all of these scenarios, integration is accomplished by sending push notifications to the RadiumOne Mobile Analytics Event Tracker API.
Youll need to go through the normal setup steps, the same as if you were integrating the RadiumOne Mobile Analytics SDK.
Register App with RadiumOne Mobile Analytics and retrieve the application id from the RadiumOne Mobile Analytics Dashboard.
Set up your system to push event data to RadiumOne Mobile Analytics. This must include:
First launch of app for each end user as it occurs
Session data for end users
Any Event data that you wish to track and segment upon
Messages must follow the rules and structure laid out in the RadiumOne Mobile Analytics API doc: https://support.radiumone.com/hc/en-us/articles/207516263-RadiumOne-Mobile-Analytics-Event-Tracker-Endpoint-API-
There are three main flavors of API integration:
API Integration from the app
Many companies are wary of SDK implementations because theydon'twant to put someone elses software into their app. If that sounds like you, building your own integration that makes the same calls to our endpoint that would be made by our SDK can be an effective route to integration. Doing so is more work than integrating the SDK but gives your developers complete control over what data is sent and under what circumstances. It is essentially a 1 for 1 replacement of the SDK. Because of the extra work required, this is not recommended unless SDK integration is completely off the table and you lack the server infrastructure required for other API integrations.
This is an ideal solution in cases where:
You do not want to integrate an SDK
Your team has the technical expertise to manually handle message queing and other functionality normally handled by our SDK
You are not collecting useage data either on your own servers or via a third party OR you are collecting the data but do not have a way to dynamically send it to the RadiumOne Mobile Analytics API OR you want to avoid the cost of relaying messages through your own servers.
Server to Server API integration from your internal server
Perhaps you are already be collecting useage data for all the events you want to track in on your own servers and want to pass that data on to RadiumOne Mobile Analytics from that server for analysis and action. In this scenario, you simply fire messages to the RadiumOne Mobile Analytics endpoint for that useage data as it comes into your servers like a relay race.
This is an ideal solution in cases where:
You cannot integrate an SDK
You already have your own in-house data infrastructure set up that is already receiving data from end users about what they are doing.
Those servers are capable of pushing notifications about end user behavior to MAs API endpoints in real time.
Server to Server API integration from third party tool
This scenario is best for cases where you want to use the RadiumOne Mobile Analytics dashboard and functionality in addition to some other previously implemented external tool.
Available options here are:
Appsflyer
Kochava
TUNE
Segment
mParticle
Tealium Mobile
3. Testing and QA
RadiumOne Mobile Analyticsis a complex product with lots of moving parts. Depending which modules you are using, you may be able to omit some of these steps.
Testing Process
If you will be doing mediaattribution through Mobile Analytics, request tracking links or access for your test build from your RadiumOne account manager. Click the link on your test device.
Open the test build of your app
Perform each of the tracked actions at least once.
Wait half an hour and check reports to make sure all events have been recorded along with relevant attributes. We recommend using the Trends report to check that all the events have come through and the Segmentation report to easily check attributes.
If applicable, check to make sure the Track dashboard has successfully attributed your test installs.
4. App submission
For iOS you will need to check the box declaring that you are collecting IDFA in order to attribute ads displayed elsewhere. Full steps and detailed instructions are at https://support.radiumone.com/hc/en-us/articles/207311053-iOS-SDK-App-Submission
For Android there are no special submission requirements.
View ArticleOne of the areas in which Mobile Analytics is highly differentiated from other mobile analytics solutions is in its ability to leverage user behavior data to boost efficiency and ROI for your programmatic media campaigns.
At this time, custom audiences can be created from the Segmentation, Funnels, and Retention reports.
Please either contact your Account Manager or [email protected] to make sure your Mobile Analytics account is tied to your RadiumOne advertising account before starting this process.
Creating audiences from Segmentation report
Click the "New Segmentation" button on the Segmentation report to launch the configuration wizard or the "edit" link to leverage an existing segment. Note that once a report is tied to an Audience it can no longer be edited.
Name your segment using the text box at the top right.
Select the date range for your segment.
Select an operating system filter to target users on a single platform (iOS, Android, Windows) or leave the filter blank to include all users.
Select the event that will define the segment and any attributes. For example, on a Transaction event it would be common to select carrier_country, the item name, or the price. If you have demographic information in your attributes it might be useful as well. Depending on your industry and your app, the options selected can vary considerably. To ensure you have the data you will need here, we recommend consulting with our Solutions Engineering team ahead of implementation to make sure your bases are covered.
Pay careful attention to attributes since that is where all your context is found. The available data includes all of the automatically tracked event attributes, plus any custom attributes you may have added. This lets you narrow the focus of your audience for more precise targeting. For attributes that have multiple possible values, you can determine how many of those values to include by checking the appropriate boxes.
Once you have your Audience defined, click the button "+ Create Audience for Ad campaign" to push the audience to the RadiumOne DMP
Note that the Segmentation report has three main view types - Users (the set of users in your segment), Events (the number of times the event that the segment is built on happened), and Events per User (the number of times per end user that the segmenting event occurred). Changing this will change the data visualization shown in the dashboard because it shows a different part of the data set, but does not impact the Audience being defined.
Screenshot of Segment creation. Hit "Create Audience for Ad campaign" to make segment targetable.
Creating audiences from Funnels
Funnels are a classic form of user flow analysis and allow you to map out common user experiences and identify dropoff points. This report will show you what percent of the users who completed a particular action went on to complete some other specific action, out of the set that completed both how many completed a third, and so on. You can also segment each step of the funnel for more focused analysis
Creating Audiences from Funnels is powerful because it allows you to:
Run re-engagement campaigns aimed at users who have dropped off in order to bring them back in.Example: Use the Exclusion option to target users who have not completed the last step of your funnel with a deep-linked ad that takes them directly to the appropriate content.
Run retention campaigns against users who are engaged in order to build useage habits around your app.Example: Use the Inclusion option to target users who have completed the last step of your funnel and encourage them to take some other high-value action in your app. This helps reinforce useage habits and keeps those high-value users engaged.
Use lookalike targeting to acquire new users similar to the ones who have completed your funnel and proven their valueExample: Use the Inclusion option to identify high-value users (for instance, users who got all the way through your tutorial and made at least one purchase) so we can find users who share similar interests and useage patterns to target as part of your growth campaign.
How to:
Click the "New Funnel" button on the Funnels report to launch the configuration wizard or the "edit" link to update an existing Funnel. Note that once a report is tied to an Audience it can no longer be edited.
Name your Funnel using the text box at the top right
Select the date range for your Funnel.
Select an operating system filter to target users on a single platform (iOS, Android, Windows) or leave the filter blank to include all users.
Select at least two events and any attributes. You can add additional steps using the "+ Add Step" button at the bottom of the configuration screen.
Pay careful attention to attributes since that is where all your context is found. The available data includes all of the automatically tracked event attributes, plus any custom attributes you may have added. This lets you narrow the focus of your audience for more precise targetting. For attributes that have multiple possible values, you can check how many of those values to include.
Re-order the steps as needed using the Re-order buttons.
Once your funnel is complete, click "Create Funnel"
Once created, you can create and audience from a Funnel by clicking the "Create Audience for Ad-campaign" button at the bottom of the report.
Doing so reveals the audience creation tools which let you select a Campaign period and a Segment type that lets you choose either Inclusion or Exclusion to target or exclude users who completed the last step of the funnel. The end date for the campaign can be in the future.
Once created you can view these audiences but cannot alter them
Creating a Funnel: Setting up the steps, look back, platform, and segmentation.
Creating a Funnel: View of funnel, click "Create Audience for Ad-campaign" button to create a targetable audience.
Creating a Funnel: Select Campaign period and set Exclusion or Inclusion targeting.*
*Note that the set of users is defined by the lookback window, not just the start and end dates. So if my window is Feb 1 to Feb 8 and I have a 7 day look-back, my data set for day 1 includes everyone who completed the Funnel from January 25th to February 1st. Day two would be January 26th to February 2nd, and so on..
Creating audiences from Retention
The Retention tool is a powerful Cohorting tool that lets you view how many users who completed one event went on to complete a second event on each of the days following. That can include classic retention metrics like First Launch vs Session (to show how many new users who started on a given day opened the app on each of the following days) or more custom metrics that are specific to your app.
Creating Audiences from retention reports is powerful because it allows you to:
Run re-engagement campaigns aimed at users who have dropped off in order to bring them back in.Example: Use the Exclusion option to target users who have not completed the retention event with a deep-linked ad that takes them directly to the appropriate content.
Run retention campaigns against users who are engaged in order to build usage habits around your app.Example: Use the Inclusion option to target users who have completed your retention event and encourage them to do it again or take some other high-value action in your app. This helps reinforce useage habits and keeps those high-value users engaged.
Use lookalike targeting to acquire new users similar to the ones who meet your retention criteria.Example: Use the Inclusion option to identify high-value users (for instance, users who have made two purchases in a seven day period) so we can find users who share similar interests and useage patterns to target as part of your growth campaign.
How to:
Click the "New Retention" button on the Retention report to launch the configuration wizard or the "edit" link to leverage an existing Retention report. Note that once a report is tied to an Audience it can no longer be edited.
Name your Retention using the text box at the top right
Select the date range for your report.
Select an operating system filter to target users on a single platform (iOS, Android, Windows) or leave the filter blank to include all users.
Select the Population Event - the event that creates the initial set of users to analyze.
Select the Retention event - the event that will be used as your success metric.
Once you have your Audience defined, click the button "Create Audience for Ad campaign" to expand the Audience creation section of the page.
Select the Campaign period - the period of time during which you want users who meet your criteria to be added to this audience. The end date can be in the future.
Select the Lookback window. Your Lookback window is the number of days before the campaign start date that would be considered for the audience creation. This window will be incremented daily.
Select either Inclusion (to add people who have been retained to the audience) or Exclusion (to add people who have not completed the retention event during the window).
Select Single day (only users who qualified/disqualified on the last day) or Cumulative (all users who meet your criteria durign the lookback window) for Grouping.
Double check your selections and then hit button marked "Create Retention with Audience for Ad-campaign" to save the audience.
Retention: Pick events, platform, and date range.
Retention: Select duration of campaign, look back period, targeting, and grouping and then hit "Create Retention with Audience for Ad campaign.
Viewing your saved audiences
Saved audiences from all three reports can be accessed from the left navigation bar in the "Analyze" section of Mobile Analytics by clicking "View DMP Audiences". Doing so brings up a searchable list of all created audiences, along with the source report, audience ID, date created, and the appropriate details.
View ArticleIntroduction
RadiumOne currently has two mechanisms in order to track in-App mobile data and allow segmentation of that data into our DMP:
RadiumOne RadiumOne Mobile Analytics SDK ( iOS, Android )
RadiumOne Event Tracker EndPoint
If for some reason youcannot usethe RadiumOne RadiumOne Mobile Analytics SDK, this Endpoint provides an alternative path to integrate either directly from your app or server to server.
This endpoint accepts data that is formatted in a JSON format with well-defined parameters.
Registering your application in RadiumOne RadiumOne Mobile Analytics
In order to be able to track your application and make use of it, you need to register it in RadiumOne RadiumOne Mobile Analytics. It is easy to do.
You access RadiumOne RadiumOne Mobile Analytics here: connect.radiumone.com
Once you are registered, you can create a new app through the RadiumOne Mobile Analytics process. Then you can access the information that you will need from the settings view.
You will want to retrieve the application id field, as it is necessary for data to be processed. The format of the application id is a GUID and it will look like this: 8E19B036-3848-4AB7-A21A-536B70A5C0A6
Please note that the previous value is an example.
Endpoint information
In order to pass information to RadiumOne, you need to use the following endpoint:
Staging: https://rp-stg.gwallet.com/r1t/evt3/#{application_id}?v=2
Production: https://rp.gwallet.com/r1t/evt3/#{application_id}?v=2
{application_id} is the value that RadiumOne RadiumOne Mobile Analytics has assigned to you through the UI. All calls should be made to this dynamic endpoint. This will allow the data to flow into the system.
All data should be passed as POST and should be sent as HTTPS.
Responses
If the data passed via the POST query is correct, you will receive a 200 response with the message Well done or else you will see Bad Request
Event details
The system has several events that are defined by default. Any system put in place should replicate these events.
Here are the automatic events that the SDK supports:
Launch- emitted when the app starts
First Launch- emitted when the app starts for the first time
First Launch After Update- emitted when the app starts for the first time after a version upgrade
Application Opened- This event is very useful for push notifications and can measure when your app is opened after a message is sent.
Similarly, it is possible to create your own events based on the event data structure.
Each of these events will be detailed in Appendix A to explain how they should actually be filled.
Pre-conditions and System setup
Before you send any data, please ensure the following,
Utilize persistent HTTPS connections
Limit 1,000 QPS or 250 Mbps per connection
Combine multiple events from a given device into a single HTTPS POST message (up to 1MB in size)
The endpoint can support in the range of 50,000 QPS
Currently we do not support event de-duplication on the logger side, so it depends on how duplicate events are handled on the data processing side.
Rules for posting data
App UUID must be valid and the app must be active
source field is required
event_info - at least one event must be present
event_info.event_name must be non-empty
device_info.id_info - at least one device ID must be present
event_info.transaction_id is required
event_info.timestamp is required
event_info.key_value.key is required (if event_info.key_value is present)
RadiumOne Mobile Analytics Key Name
Type
Sample Value
Default behavior
Description
Mandatory
application_id
String
application_name (bundle_name)
If (null) ERROR
Combination of application name and bundle name
Y
application_name
String
MYAPP
null
This is the name of the application
Y
application_version
String
3.0.9.1
Null
This is the version number for your application
Y
bundle_name
String
com.bundlename
null
This is the name of the bundle
Y
carrier_country
String
fr
null
This is the ISO 3166-1 Alpha 2 code
Y
carrier_name
String
Free
null
This is the name of the cell phone carrier
Y
conn_type
String
WIFI
null
This is the type of data connection
N
device_info
JSON Object
null
This is the device information structure. The structure will be explained further down
N
event
JSON Object
null
This is the list of events that you are sending
N
screen_resolution
String
1024x768
null
This is the screen resolution of the device
N
sdk_version
String
partner ID value
null
This is the version of your SDK
Y
source
String
ADVERTISER_SDK
"ADVERTISER_SDK"
This is the source of the information contained in the payload. This parameter is MANDATORY
Y
user_language
String
fr
null
This is the ISO 3166-1 Alpha 2 code
N
viewport_size
String
400x300
null
This is the actual size of the viewport of the app
N
device_type
String
Handheld | Tablet
null
Device Type accepts 3 enums [ tablet, handheld, null ]
N
version
String
2
2
Version
Y
Device_info Mapping Table
Key Name
Type
Sample Value
Default value
Description
Mandatory
os
String
iPhone OS
null
This is the name of the OS running on the phone
Value MUST be "iOS","Android", or "Windows".
Y
Os_version
String
8.1.3
null
This is the version of the OS running on the phone
N
Os_language
String
fr
"en"
This is the ISO 3166-1 Alpha 2 code
N
Ip_v4
String
3.0.9.1
null
This is the ipv4 of the device
Y
Ip_v6
String
null
This is the ipv6 of the device
N
make
String
Apple
null
This is the name of the maker
Y
model
String
iPhone
null
This is the name of the device
Y
Timezone_offset
Integer
-25200
0
This is the timezone offset in seconds
N
country
String
fr
null
This is the ISO 3166-1 Alpha 2 code
Y
Id_info
JSON Object
null
This is the device information structure. The structure will be explained further down
Y
user_agent
String
"Mozilla/5.0 (iPad; CPU OS 9_1 like Mac OS X) "
null
This is a device user agent.
N
ID_info Mapping Table
Key Name
Type
Sample Value
Default values
Description
Mandatory
Dpid
String
9AEF8C48-91F3-47A9-A400-B474621CFC0D
null
This is the device id of the device (either idfa, aid, wpid)
Y
Dpid_sha1
String
897a26ccf206628432d1667845e11b0cec0fee21
null
This is the sha1 value for dpid
Y
Dpid_md5
String
163fb576035dd3cfb9c01dd43f0e862c
null
This is the md5 value for dpid
Y
aid
String
null
This is the Google Advertising Identifier (sometimes called GAID in the industry)
Y
Adv_id
String
null
This is android advertising id. Since Android ID is deprecated and the field is mandatory, most clients send GAID a second time.
Y
Idfa
String
9AEF8C48-91F3-47A9-A400-B474621CFC0D
null
This is the idfa value for Apple
Y
Idfv
String
EA8AA54A-8BDF-4D6F-B760-703CA1820BFB
null
This is the idfv value for Apple
Y
Opt_out
Boolean
false
false
Tells the system whether the user has opted out of tracking or not.
N
Bluetooth_status
String
null
This is the status of the Bluetooth code
N
Locale
String
En-US
En-US
This is the locale of the device
Event Mapping Table
Key Name
Type
Sample Value
Description
Mandatory
Event_name
String
MyEventName
This is the name of the event.
Y
Transaction_id
String
1222
This is the transaction id, must be unique per transaction.
Y
Timestamp
Long
1431582994837
Epoc timestamp (MUST BE MILLISECONDS)
Y
Key_value
JSON Array
{key_value:"title", string_value:"Intro to Analytics"}
This is the structure used to pass extra parameters.
Y
Lat
Long
nul
This is the latitude of the deviceOUTPUT = (lat X 1,000,000)
N
Lon
Long
null
This is the longitude of the deviceOUTPUT = (lon X 1,000,000)
N
Session_id
String
4E5C09B7-73E5-406F-8140-13751FB62B1B
This is the session id (GUID)
Y
Speed
String
null
This is the speed of the device
N
JSON payload structure
The JSON payload should have the following structure. Please note that some parameters are optional and dependent on the platform. The actual meaning of the parameters is explained later in a table. The JSON structure is also pretty complex and will be decomposed.
Actual examples will be provided as separate files with this document in order to make it clear. Here is the list of all elements at root level. Please note that when fields are not filled, they should be appearing with a null value. All parameters are also actual string except for one exception. Nested structures will be present in subsequent tables:
JSON format (example)
Comments after //, (M)= Mandatory fields, (O)= Optional fields
{
"application_id": "9E7662CA-2E05-41AB-8E4C-50E9F626FF49", // This is the ID available on Settings page on the Portal (M)
"application_name": "MyApp", // This is the name of your App (O)
"application_user_id": "", // This can be null (O)
"application_version": null, // This is the version of your App if available, or else null (O)
"bundle_name": "testbundle", // Please add the bundle id of your app or leave as test (O)
"carrier_country": null, // Please add carrier country if available, else null (O)
"carrier_name": null, // Please add carrier name if available, else null (O)
"conn_type": "WIFI", // Please add connection type if available, else null (O)
"device_info": {
"country": "US", // Please add the country of the App download (M)
"id_info": {
"adv_id": null, // Please add Android advertiser ID if Android, else null (O)
"aid": null, // Please add Android ID if Android, else null (O)
"dpid": "9B445DD3-8510-46C2-A534-4552F07BF942", // Please add IDFA if iOS, aid or Adv_id if Android (M)
"dpid_md5": null, // Please add md5 hash of dpid (O needed for Install Tracking)
"dpid_sha1": null, // Please add sha1 hash of dpid (O needed for Install Tracking)
"idfa": "9B445DD3-8510-46C2-A534-4552F07BF942", // Please add IDFA if iOS (O)
"idfv": null, // Please add IDFV if iOS and Opt out is true (O)
"opt_out": false, // Please add condition of user for tracking (M)
"production_live": null, // null for S2S
"r1_daid": null // null for S2s
},
"ip_v4": null, // Please add of IPv4 Address (O)
"make": null, // Please add make of device (O)
"model": null, // Please add model of device (O)
"os": "iPhone OS", // Please add OS of device (M)
"os_language": "en", // Please add OS Language of device (M)
"os_version": null, // Please add OS version of device (O)
"timezone_offset": null // Please add timezone offset (O)
},
"device_type": "HANDHELD", // Please add device type (O)
"event_info": [
{
"event_name": "Application Opened", // Please add event name (M)
"key_value": [
{
"key": "Engagement Type", // Please add key of custom attribute qualifying event (O)
"string_value": "Super High " // Please add value of custom attribute qualifying event (O)
}, // Use string_value if string, else double_value if double format
{
"key": "network_name", //The name of the ad network that drove the user'sinstall. This is required to be able to segment by attribution but can otherwise be left out.
"string_value": "RadiumOne" // Replace this with the nameof the DSP, network, or exchange. This is required to be able to segment by attribution but can otherwise be left out.
},
{
"key": "tracker_name", //The name of the campaign that this user's install was attributed to.This is required to be able to segment by attribution but can otherwise be left out.
"string_value": "Campaign name here" //This is required to be able to segment by attribution but can otherwise be left out.
},
{
"key": "site_id", // The name of the website or app where the ad that the end user clicked on before installing was placed.This is required to be able to segment by attribution but can otherwise be left out.
"string_value": "Site name here" //This is required to be able to segment by attribution but can otherwise be left out.
}
],
"lat": 340043, // Please add latitude if available (multiplied by 10000) (O)
"lon": -1184324, // Please add longitude if available (multiplied by 10000) (O)
"session_id": "AA", // Please add non null value for session id (M)
"timestamp": 1431579614885, // Please add epoch timestamp of client event generation (M)
"transaction_id": "1439830721" // Please add a non null value for transaction id (M)
}
],
"sdk_version": "S2S", // Please add sd_version as S2S always (M)
"source": "ADVERTISER_SDK", // Please add source as ADVERTISER_SDK always (M)
"user_language": "en", // Please add user language (O)
"version": "2", // Please add version as 2 (M)
"viewport_size": null // Please add viewport_size if available, else null (O)
}
If you post the above event to the endpoint you will receive a 200 response with the message well done!
View ArticleFor each end user's device we collect:
- IDFA, WPID (windows phone ID), or Android ID- advertising opt-out- mobile network- bluetooth status- mobile country code- locale- jailbroken status of the device- OS- OS version- OS language- ip- make- model- timezone- country- application version- device type- carrier name- carrier country- connection type- screen resolution- viewport size- installed app info (android only, and optional)- bundle name- user language
Optional when location is enabled:- lat (optional)- long (optional)- altitude (optional)- course (optional)- speed (optional)
Event data (for all users):
- Launch: applaunch, initiates session tracking.- First Launch: when the app starts for the first time- First Launch After Update:when the app starts for the first time after a version upgrade- Suspend: the app is put into the background state- Resume: the app returns from the background state- Application Opened: recorded when the app is opened and can measure when your app is opened after a message is sent- Session Start: a new session begins. Not displayed in portal but used to calculate session information which is displayed.- Session End:a session ends; includes a Session Length attribute with the session length in seconds. Not displayed in portal but used to calculate session information which is displayed.
Event data (custom):
We can track virtually anything that might happen in your app, but it's up to you to set up this custom tracking.
View ArticleWhat events should I track in Mobile Analytics?
Setting up event tracking is the single most important part of getting your Mobile Analytics instance up and running. It is imperative that your event tracking strategy be well thought out, as these events will form the foundation for all of your reporting going forward. This document outlines the process by which you should set up event tracking so you can make the most out of insights from your app.
Table of Contents:
Getting started with Mobile Analytics
Step 1: Map out your app goals and KPIs
Step 2: Identify all events and attributes to track
Key things to consider when creating your list of events and attributes
Step 3: Work with your developer to create events in Mobile Analytics
Creating Events
Default Events
Standard Events
Custom Events
Advanced setup for custom events:
Scenario 1: Tracking consistent events across multiple pages or screens
Scenario 2: Tracking events that are unique per page
Scenario 3: Omit attributes and values entirely
Getting started with Mobile Analytics
Step 1: Map out your app goals and KPIs
The very first step in setting up your Mobile Analytics solutions is to sit down with key stakeholders and your marketing/analytic teams to map out the Key Performance Indicators (KPI's) for your app.
Note: These goals/KPIs/reports will vary considerably depending on your vertical and your particular approach. There is no one-size-fits-all solution.
Step 2: Identify all events and attributes to track
Once you have an understanding of all your app KPIs, youll have a much better sense for what information you need to see and measure. Thinking about all the reports that will help you track KPIs, create a list of all the events you need to track (i.e.: user made a purchase) along with relevant attributes (i.e.: user spent $50).
Key things to consider when creating your list of events and attributes
What are the critical parts of the user experience in my app?
Where am I losing users? What features need improvement?
Does my user base spending a lot of time with one feature? This could mean something is broken and/or a time suck for users... but it could also mean they love the feature and are very engaged. Breaking out the tracking will help you tell the difference.
What will I learn by tracking this event?
How is it relevant to my KPI's?
What attributes of the event are important? For example, a Transaction event should at minimum include the value of the transaction and the names or ID's of the item or items purchased, but depending on your monetization model might benefit from other contextual info as well.
What events would define a valuable audience? What sort of segments do you want to push to your media campaigns?
What reports will I want to see? What information do I need to collect in order to produce those reports?
Step 3: Work with your developer to create events in Mobile Analytics
Once you have identified all the events and attributes you want to track, work with you app developer to create these events in Mobile Analytics. Note below that there are some events that will be tracked by default in your Mobile Analytics.
Creating Events
There are 3 types of events in Mobile Analytics:
Default events
Standard events
Custom events
Most integrations involve all three event types.
Default Events
Default events are tracked automatically. No further action needed to record the information below.
Launch - fired when the app starts
First Launch - fired when the app starts for the first time
First Launch After Update -fired when the app starts for the first time after a version upgrade
Application Opened - fired when your app is opened
Session Start - fired when a new session starts. Sessions are defined as a period of continuous activity so you may have multiple sessions tracked for a single app open if users frequently send your app to the background between uses instead of quitting out of it entirely.
Session End - fired when a session ends; includes a Session Length attribute with the session length in seconds
Note: Tracking only default events will be insufficient for virtually every deployment and will cripple your reporting. Per above, you should also be tracking standard and/or custom events that make sense for your particular apps KPIs.
Standard Events
To make reporting easier, we have standardized data formatting for a few very common events, these include:
Login: Tracks a user login within the app
Registration: Records a user registration within the app
Facebook connect: Track this when the user allows access to Facebook services
Twitter connect: Track this when the user allows access to Twitter services
User Info: This event enables you to send user profiles to the backend. Please do not send us personally identifiable information!
Upgrade: Tracks an application version upgrade
Trial Upgrade: Tracks an application upgrade from a trial version to a full version
Screen View: Basically, a page view, it provides info about that screen
Transaction: A purchase
Delete Cart
Add To Cart
Delete From Cart
Custom Events
You are not limited to these predefined events, and in fact virtually every deployment will have at least a few custom events. The key elements of custom event tracking are:
The Event name or label: this is label that will be used in the Analytics dashboard to refer to your events. It should be descriptive and give at least basic information about what is happening without being overly precise. For example, the event name "pageView" is too vague and doesn't provide any useful information about what the user is actually doing. A better event name would be "productPageView" which tells you that the end user is viewing a product.
Attribute label: Our mobile analytics dashboard allows you to input custom attributes about your events. These attributes are typically contextual information that add segmentation options. So, for example, if I'm tracking a "productPageView" event I might want the attribute label to be "productName"
Attribute values: The values of the attribute will be descriptive and correspond to the selected label. So if I set the attribute label to "productName" the value could be the actual name or id of the product being viewed.
This combination creates a record for an event named "productPageView" and in Segmentation, Funnels, Retention, and the other various reports I would be able to segment out instances of that productPageView event according to the name of the product being viewed.
Note that the you should never use variables that are unique per user in your naming of events, attributes, or values. Doing so will break the mobile analytics dashboard.
Advanced setup for custom events:
Every app is a bit different and so is every company's reporting requirements. Depending on those requirements you may want to customize your naming conventions for your custom events. Here are three different scenarios where this could be applicable.
Scenario 1: Tracking consistent events across multiple pages or screens
Do you have a few consistent events that are tracked across multiple pages and want to group your reports based on the action being completed instead of the page it is being completed from? In this case you might use the following:
Event name: the name of the action being completed
Attribute label: pageName
Attribute value: the name of the page where the user completed the action.
You would be able to generate a report of all the places where people clicked a button (for example) and then segment it by the pages that they did so from. Depending on the reporting you want, it might be a good thing to be able to lump together all clicks of a common button across multiple pages.
Scenario 2: Tracking events that are unique per page
If the buttons and interactions on each page are unique, you might instead lump all interactions on a page together in a single event and then segment out the specific events.
Event name: viewMore
Attribute label: actionsTaken
Attribute value: the name of the actions taken on the view more page.
Scenario 3: Omit attributes and values entirely
This has the advantage of surfacing all the pertinent info at the top level and making reporting setup a bit faster. The down side is that you would not be able to lump similar events together across pages the way you can with scenario 1 or lump together sets of events from a single page as in scenario 2.
Event name: Concatenate Page name + event name, so for example "productDetail_addToCart"
Attribute label: none
Attribute value: none
If you are new to Analytics and need a hand figuring this out, please reach out to our Sales Engineering team and we will be happy to help make sure you get the data you need and are able to implement tracking quickly and easily.
View ArticleThe process for integrating the Mobile Analytics SDK is very straightforward. The steps are as follows:
Create your RadiumOne Mobile Analytics account (if you have not already done so).
Create a profile for your app. Note that in our solution Android, iOS, and Windows versions of an app are part of the same app profile and that our reporting allows you to filter by platform or lump them all together as needed.
Import the library into your project
Initialize and configure the SDK using your Application ID from the RadiumOne dashboard. https://github.com/radiumone/r1-connect-titanium
Track in-app events - Do not skip this step! If you are unsure what to track, check out our guide to setting up tracking.
Track any web-view events that are initiated from within the app
Set up Attribution tracking, either via your existing attribution analytics provider or via our Kochava integration. This is only available to our media clients. If you want to use our Kochava integration please check with your RadiumOne account manager.
Set up Smart link initialization if you want to enable deferred deep linking from our Smart links solution.
Test the SDK implementation by opening your dev build of the app and performing all the tracked actions and then going to the RadiumOne dashboard and validating that the data appears. Note that there may be a delay of ~30 minutes for data to visualize in the dashboard.
For full step by step instructions, please refer to our documentation on Github.iOS: https://github.com/radiumone/r1-connect-demo-iOS
Android: https://github.com/radiumone/r1-connect-demo-Android
Windows: https://github.com/radiumone/r1-connect-demo-WP/tree/master/R1ConnectDemo
Phonegap: https://github.com/radiumone/r1-connect-demo-phonegap
Titanium:
View ArticleThe short answer is yes.
Connect gives you deep in-app analytics, full attribution data across all networks via our partnership with Kochava, push notification management, and sophisticated location analysis in a single tool. All of that functionality exists completely independent of our advertising products.
If youare using Activate, Connect provides fantastic targeting data that will make it more effective. Think of the two products as adjacent office towers with a bridge between them. They are independent but mutually reinforcing and you can send as much or as little data from one to the other as makes sense for your business.
View ArticleConnect has two fundamentally different methods to work with user actions.
Event tracking comes from the Analytics side of the product's pedigree and is fundamentally about tracking historical data. By contrast, Tagging in Connect comes from the Push Messaging side and is about what people are doing now.
So what does that mean for you as you set up your Connect implementation? Let's use some concrete examples to illustrate them.
Say a user is in your app and adds an item to their cart
View ArticleSystem Requirements
SDK Initialization
Import Files
Link the Static Library
Initialize the SDK
Advanced Settings
Analytics Activation
1. System Requirements
The R1 Connect SDK supports all mobile and tablet devices running iOS 6.0 or newer with a base requirement of Xcode 4.5 used for development (Xcode 6.0 or newer is recommended). The downloadable directory (see below " a. Import Files ") contains the library and headers for the R1 Connect SDK.
The library supports the following architectures (iOS version 6.0 and higher):
-arm7, arm7s, arm64 for deploying to physical devices
-i386, x86_64 for Simulator testing
2. SDK Initialization
a. Import Files
Download the r1connect lib files: git clone [email protected] :radiumone/r1-connect-demo-iOS.git
Open your iOS project in Xcode.
Select File -> Add Files to [YOUR XCODE PROJECT] project
Select all header files in the appropriate "Lib" Folder from the repo you just cloned. The "Bitcode Lib" is built for Xcode 7 version (with bitcode support). The "Non-Bitcode Lib" should only be used if you are building with Xcode 6.
When the dialog box appears, check the Copy Items into destination groups folder checkbox.
b. Link the Static Library
Go to "Build Phases" and make sure LibR1Connect.a file is set in the Link Binary With Libraries section. If absent, please add it.
Make sure you add:
libsqlite3.dylib
CoreLocation.framework
CoreBluetooth.framework
AdSupport.framework
CoreTelephony.framework
SystemConfiguration.framework
Verify that the Background Modes switch is turned on in the Capabilities tab for your target.
Also, it is important to add an entry to the 'Other Linker Flags' setting in your application's Build Settings in Xcode. Add '-ObjC' to the 'Other Linker Flags' setting if it is not already present. This is a common required flag when integrating static libraries with your code.
Integrate with your Swift project
If you are using Swift in your project and you want to use R1 Connect SDK in your swift code you should:
Open Build Settings for your project
Find Swift Compiler - Code Generation section
Add path to R1SDK-Bridging-Header.h file to Objective-C Bridging Header.
For example if SDK located in R1SDK folder inside your root project directory path will be $(PROJECT_DIR)/R1SDK/R1SDK-Bridging-Header.h
c. Initialize the SDK
You will need to initialize the R1 Connect Library in your App Delegate.
Import the required header files (Only for Objective C code)
At the top of your application delegate include any required headers:
#import "R1SDK.h"
#import "R1Emitter.h"
Initialize the R1Connect Instance
Note:The sdk.applicationID value is found in your RadiumOne Connect Dashboard under the Settings > Application tab. Do NOT use your Apple app ID, doing so will break your integration and prevent data from being sent.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
R1SDK *sdk = [R1SDK sharedInstance];
// Initialize SDK
sdk.applicationId = @"YOUR APPLICATION ID";
return YES;
}
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
let sdk = R1SDK.sharedInstance();
// Initialize SDK
sdk.applicationId = "YOUR APPLICATION ID";
return true
}
d.Feature Configuration
The following is a list of configuration parameters for the R1 Connect SDK. Most of these contain values that are sent to the tracking server to help identify your app on our platform and to provide analytics on sessions and location.
Configuration Parameters
applicationUserId
Optional current user identifier.
[R1SDK sharedInstance].applicationUserId = @"12345";
R1SDK.sharedInstance().applicationUserId = "12345";
cookieMapping
Enable or disable cookie mapping. By default is NO. Setting this first party cookie will enable RadiumOne to be effective in targeting the user for advertising campaigns run on behalf of the Publisher. Only enable this setting if you plan to run advertising with RadiumOne.
[R1SDK sharedInstance].cookieMapping = YES;
R1SDK.sharedInstance().cookieMapping = true;
deferredDeeplinkScheme
Enable deferred Deeplinking via Po.st.Value is the app registered URL scheme. This is optional but recommended.
[R1SDK sharedInstance].deferredDeeplinkScheme = @"your app scheme";
R1SDK.sharedInstance().deferredDeeplinkScheme = "your app scheme";
location
The current user location coordinates. Use only if your application already uses location services.
[R1SDK sharedInstance].location = [locations lastObject];
R1SDK.sharedInstance().location = ;
locationService
If your application did not use location information before this SDK installation, you can use locationService in this SDK to enable or disable it:
[R1SDK sharedInstance].locationService.enabled = YES;
R1SDK.sharedInstance().locationService.enabled = true;
N.B. - The Connect locationService uses the Location Manager in iOS. For deployment on iOS 8 and newer, it is required that the application's property list (plist) file include one of the two following keys:
NSLocationAlwaysUsageDescription
//provide location updates whether the user is actively using the application or not via infrequent background location updates
// OR
NSLocationWhenInUseUsageDescription
//provide location updates only while the user has your application as the foreground running app
These are string values that need to include a description suitable to present to a user. The description should explain the reason the application is requesting access to the user's location. Therefore, description you give should try to incorporate or reference the user benefit that may be possible through sharing location.
You must import R1LocationService.h to use this feature.
When enabled, such as in the example above, location information will be sent automatically. However, locationService doesnt fetch the location constantly. For instance, when the location is received the SDK will turn off the location in CLLocationManager and wait 10 minutes (by default) before attempting to retrieve it again. You can change this value:
[R1SDK sharedInstance].locationService.autoupdateTimeout = 1200; // 20 minutes
R1SDK.sharedInstance().locationService.autoupdateTimeout = 1200; // 20 minutes
appName
The application name associated with the emitter. By default, this property is populated with the CFBundleName string from the application bundle. If you wish to override this property, you must do so before making any tracking calls.
[R1Emitter sharedInstance].appName = @"Custom application name";
R1Emitter.sharedInstance().appName = "Custom application name";
appId
Default: nil
The application identifier associated with this emitter. If you wish to set this property, you must do so before making any tracking calls. Note: that this is not your app's bundle id, like e.g. com.example.appname.
[R1Emitter sharedInstance].appId = @"12345678";
R1Emitter.sharedInstance().appId = "12345678";
appVersion
The application version associated with this emitter. By default, this property is populated with theCFBundleShortVersionString string from the application bundle. If you wish to override this property, you must do so before making any tracking calls.
[R1Emitter sharedInstance].appVersion = @"1.0.2";
R1Emitter.sharedInstance().appVersion = "1.0.2";
sessionTimeout
If positive, indicates how long, in seconds, the application must transition to the inactive or background state for before the tracker will automatically indicate the start of a new session when the app becomes active again by setting sessionStart to true. For example, if this is set to 30 seconds, and the user receives a phone call that lasts for 45 seconds while using the app, upon returning to the app, the sessionStart parameter will be set to true. If the phone call lasted 10 seconds, sessionStart will not be modified.
To disable automatic session tracking, set this to a negative value. To indicate the start of a session anytime the app becomes inactive or backgrounded, set this to zero.
By default, this is 30 seconds.
[R1Emitter sharedInstance].sessionTimeout = 15;
R1Emitter.sharedInstance().sessionTimeout = 15;
3. Feature Activation
a. Analytics Activation
Setup your App Delegate
(Only for Objective C code)
#import "R1SDK.h"
#import "R1Emitter.h"
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
R1SDK *sdk = [R1SDK sharedInstance];
// Initialize Analytics
sdk.applicationId = @"YOUR APPLICATION ID"; //Ask your RadiumOne contact for an app id
// Start SDK
[sdk start];
return YES;
}
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
let sdk = R1SDK.sharedInstance();
// Initialize Anlaytics
sdk.applicationId = "YOUR APPLICATION ID";
// Start SDK
sdk.start();
return true
}
View ArticleWhile using the SDK toadd push messages toyour application is rather straightforward,obtaining the correct certificate from Apple to upload to the Connect portal can be confusing. Failing to upload the proper "Production" or "Development" SSL certificate can causeApple Push Notification Services to reject any push messages you create.
The key is to:
- know what type of codesigning you use on your application
- create an Apple Push Notification SSL certificate on the Apple developer portal with an environment ("production" or "development") that corresponds to your codesign selection
- download the Apple SSL certificate
- add the certificate to your keychain
- using keychain, export the certificate to a p12 format
More details can be found here.
View ArticlePush is disabled by default. You can enable it in the Application_Launching method or later.
Radiumone.Connect.Push.Instance.Enabled = true;
Once enabled, you need to add Tagging in order to target your notifications.
Push Tags
You can specify Tags for R1 Connect SDK to send Push Notifications for certain groups of users. Tags are universal attributes that describe key information about the end user and target them with relevant messaging. Tags can be anything from the end user's gender or age to how much they've spent over their lifetime in your app to just about anything else you might think of. Tags aretracked separately from event tracking and are processed in real time.
The maximum length of a Tag is 128 characters.
R1 Connect SDK saves Tags. You do not have to add Tags every time the application is launched.
Add a new Tag
Radiumone.Connect.Push.Instance.Tags.AddTag("NEW TAG");
Add multiple Tags
var tags = new List<String>() { "NEW TAG 1", "NEW TAG 2" };
Radiumone.Connect.Push.Instance.Tags.AddTags(tags);
Remove existing Tag
Radiumone.Connect.Push.Instance.Tags.DeleteTag("EXIST TAG");
Remove multiple Tags
var tags = new List<String>() { "EXIST TAG 1", "EXIST TAG 2" };
Radiumone.Connect.Push.Instance.Tags.DeleteTags(tags);
Get all Tags
var currentTags = Radiumone.Connect.Push.Instance.Tags.AllTags;
View ArticleEndpoint:
Production
https://api.r1mobileconnect.com/push
Staging
http://stage.r1mobileconnect.com:8080
Method:
POST
Authentication:
basic (app_id:master_key)
Content-type:
application/json
Accept:
application/vnd.radiumone-v1+json
Push JSON parameters:
payload
alert [String] push text
badge [Number] badge
sound [String] 'off'/'default'/<audio file name>
collapse_key [String] to consolidate similar push messages (GCM)
delay_while_idle [Boolean] (GCM)
time_to_live [Number] number of days to expire a message if not delivered
title [String] title in Android tray notifications (GCM)
data [Object] set of arbitrary key/value pairs
apns [Object] APNS specific parameters if any
sound [String] 'off'/'default'/<audio file name>
data [Object] set of arbitrary key/value pairs
gcm [Object] GCM specific parameters if any
sound [String] 'off'/'default'/<audio file name>
data [Object] set of arbitrary key/value pairs
target
platform [Array<String>] list of platforms to push to; valid platform names are "ios"/"android"/"windows" /if not specified then it means all platforms
broadcast [Boolean] true to send a broadcast push
tags [Array<String>] list of tags
schedule
run_at [Date] timestamp to schedule a push for: String (iso 8601)
Rich push parameters
payload
"payload": {"data": {"r1rich": <URL>}}
Deep link parameters
payload
"payload": {"data": {"r1deep": <URL>}}
Segment syntax
Currently supported segment criteria: "location" and "tag"
Segment operators are "and", "or" and "not"
Operators "and" and "or" operate on arrays.
Criterion "tag":
{"tag": <value>}
Criterion "location":
{"location": {"date":{<date>}, "area":{<area>}}}
"date" = "last"|"range"
"last" = {"weeks"|"days"|"hours" : <number>}
"range" = {"from": <start date>, "to": <end date>}
"area" = "center"
"center" = {"lon":<longitude>, "lat":<latitude>, "radius":<miles>}
Response
success
status: 201{"task_id": <task_id>}
Examples:
By tag:
curl -u <app_id:<master key>" -H "Accept: application/vnd.radiumone-v1+json" -H "Content-Type: application/json" -d '{"target":{"tags":[some tag"]}, "payload":{"alert:some text"}}' https://api.r1mobileconnect.com/push
for iOS:
curl -u <app_id:<master key>" -H "Accept: application/vnd.radiumone-v1+json" -H "Content-Type: application/json" -d '{"target":{"devices":{"apns":[<device token>"]}}, "payload":{"alert:some text"}}' https://api.r1mobileconnect.com/push
for Android:
curl -u <app_id:<master key>" -H "Accept: application/vnd.radiumone-v1+json" -H "Content-Type: application/json" -d '{"target":{"devices":{gcm":[<registration ID>"]}}, "payload":{"alert:some text"}}' https://api.r1mobileconnect.com/push
Broadcast for iOS Devices with Badge count 2
curl -u <app_id:<master key>" -H "Accept: application/vnd.radiumone-v1+json" -H "Content-Type: application/json" -d{"target":{"broadcast":true, "platform":["ios"]}, "payload":{"alert":"Good morning","badge":2}} https://api.r1mobileconnect.com/push
Segmented Push for "Giants" tag on both iOS and Android
curl -u <app_id:<master key>" -H "Accept: application/vnd.radiumone-v1+json" -H "Content-Type: application/json" -d{"target":{"tags":["giants"], "platform":["ios", "android"]}, "payload":{"alert":"Go Giants"}} https://api.r1mobileconnect.com/push
Broadcast Push on iOS with default sound
curl -u <app_id:<master key>" -H "Accept: application/vnd.radiumone-v1+json" -H "Content-Type: application/json" -d{"target":{"broadcast":true, "platform":["ios"]}, "payload":{"alert":"Good morning","sound":"default"}} https://api.r1mobileconnect.com/push
Broadcast Push on iOS with sound off
curl -u <app_id:<master key>" -H "Accept: application/vnd.radiumone-v1+json" -H "Content-Type: application/json" -d{"target":{"broadcast":true, "platform":["ios"]}, "payload":{"alert":"Good morning","sound":"off"}} https://api.r1mobileconnect.com/push
Segmented Rich Push for "Giants" tag on iOS opening "http://google.com"
curl -u <app_id:<master key>" -H "Accept: application/vnd.radiumone-v1+json" -H "Content-Type: application/json" -d{"target":{"tags":["giants"], "platform": ["ios"]}, "payload":{"alert":"Go Giants", "data":{"r1rich": " google.com "}}} https://api.r1mobileconnect.com/push
Segmented Push for "Giants" tag on iOS scheduled for Nov 18 2015 13:41:30
curl -u <app_id:<master key>" -H "Accept: application/vnd.radiumone-v1+json" -H "Content-Type: application/json" -d{"target":{"tags":["giants"], "platform":["ios"]}, "payload":{"alert":"Go Giants"}, "schedule":{"run_at":"2015-11-18T13:41:30-08:00"}} https://api.r1mobileconnect.com/push
Segmented Push for "Giants" and "Athletics"
curl -u <app_id:<master key>" -H "Accept: application/vnd.radiumone-v1+json" -H "Content-Type: application/json" -d{"target":{"segment": {"and": [{"tag": "giants"}, {"tag": "athletics"}]}}, "payload":{"alert":"Go Giants"}} https://api.r1mobileconnect.com/push
Segmented Push for iOS and all users seen within 50 meters of lat 37.913034 and long -122.062355 in the last 1 day
curl -u <app_id:<master key>" -H "Accept: application/vnd.radiumone-v1+json" -H "Content-Type: application/json" -d{"payload": {"alert": "TTT"}, "target": {"platform": ["ios"], "segment": {"and": [{"location": {"date": {"last": {"days": 1}}, "area": {"center": {"lat": 37.913034, "radius": 50, "lon": -122.062355}}}}]}}} https://api.r1mobileconnect.com/push
Segmented Push for iOS and "Giants" and "Athletics" tag and all users seen within 50 meters of lat 37.912 and long -122.062
curl -u <app_id:<master key>" -H "Accept: application/vnd.radiumone-v1+json" -H "Content-Type: application/json" -d{"payload": {"alert": "TTT"}, "target": {"platform": ["ios"], "segment": {"and":[{"tag":"giants"}, {"tag":"athletics"}, {"location": {"area": {"center": {"lon": -122.062, "lat": 37.912}}}}]}}} https://api.r1mobileconnect.com/push
View ArticleUse the following methods to configure push notifications.
isStarted
Callback arguments: (bool isStarted)
Indicates whether Push has started. Push starts automatically if you set up all the keys in config.xml.
R1Push.isStarted(function (isStarted) {
//...
});
setEnabled
Enable or disable R1Push.
R1Push.setEnabled(true);
isEnabled
Callback arguments: (bool isEnabled)
Indicates whether R1Push is enabled.
R1Push.isEnabled(function (isEnabled) {
//...
});
getDeviceToken
Callback arguments: (String deviceToken)
Get the push identifier for the device. Can be null if R1Push not enabled.
R1Push.getDeviceToken(function (deviceToken) {
//...
});
setBadgeNumber
Note: iOS only
Set application badge number.
R1Push.setBadgeNumber(2);
getBadgeNumber
Note: iOS only. For Android the callback will always be a 0 value.
Callback arguments: (int badgeNumber)
Get currently used badge number.
R1Push.getBadgeNumber(function (badgeNumber) {
//...
});
setTags
Set tags for the device.
R1Push.setTags(["Tag1", "Tag2"]);
addTag
Add tag for the device
R1Push.addTag("Tag1");
removeTag
Remove tag from the device
R1Push.removeTag("Tag1");
getTags
Callback arguments: (Array tags)
Get the current tags.
R1Push.getTags(function (tags) {
//...
});
Events
R1Push.deviceToken
Notify the push deviceToken has changed
document.addEventListener("R1Push.deviceToken", function(event) {
// event.deviceToken
}, false);
R1Push.foregroundNotification
For iOS and Android: Notify when a push notification is recieved when the application is running in the foreground
For Windows Phone 8: Notify when a Toast notification is recieved when the application is running in the foreground
document.addEventListener("R1Push.foregroundNotification", function(event) {
// event - object with full information about notification
alert(event);
}, false);
R1Push.backgroundNotification
Only for iOS and Android! Notify when a push notification is received when the application is running in the background and the app is opened by this notification
document.addEventListener("R1Push.backgroundNotification", function(event) {
// event - object with full information about notification
alert(event.aps.alert);
}, false);
R1Push.foregroundHttpNotification
Only for Windows Phone 8: Notify when a Raw notification is recieved when the application is running in the foreground
document.addEventListener("R1Push.foregroundHttpNotification", function(event) {
// event - object with full information about notification
alert(event);
}, false);
View Article
Push Notification Activation
i. Setup Google Cloud Messaging
ii. Initialization
iii. Rich Push Initialization
iv. Rich Push Customization
v. Inbox Initialization
vi. Deep Link Initialization
vii. Using Tagging to Segment your Audience
i. Setup Google Cloud Messaging
Prerequisites for Google Cloud Messaging Setup
This doc assumes you have already set up Google Play Services in your application project. Google Play Services is needed to use Google Cloud Messaging (GCM), the notification gateway RadiumOne Connect will use for your Android app. Also if you have not done so already, you will need to add the app you will be using to the RadiumOne Connect portal in order to add the Google API Key to it once you have generated the API Key following the steps below.
Configuring your App for GCM
Obtain an API key from Google
In order to use RadiumOne Connect with your application you will need an API key from Google. We will summarize those steps here, but for more info on this process please visit GCM Getting Started here.
1. Create a Google API project in Google APIs Console (take note of your project number which is the value after #project: it will be used later as your GCM sender ID)
2. Enable the GCM Service
3. Create a new Server key in the Google APIs Console page under API Access. when prompted, allow access to ip 0.0.0.0/0
4. Copy the key, it is used for GCM Connection Servers and for RadiumOne Connect setup
Setting up the API Key on R1 Connect
1. Please make sure you are signed into your account on RadiumOne Connect and go to the application you want to add this API key to.
2. Next, in the side menu go to Dev Tools > Push Services > Google Cloud Messaging.
3. Add your API Key to the API Key field and click Save.
If it saved correctly you will see a green badge with a white checkmark in it. Now your app is setup with GCM.
ii. Initialization
To make sure push notifications work correctly, please follow these steps:
Configure the r1connect.properties file in your project:
push.sender_id You will need to enter the project number you received when creating your Google API project.
push.client_key=<YOUR CLIENT KEY> - Obtain your Client key from the "Settings" page in your Connect dashboard.
push.enable This defaults to true and will enable or disable push notifications after you start your application
Create a class that inherits from the class Application (or you can use an existing one in the project)
To enable an action such as opening the app when a notification is clicked, create a class that inherits from BroadcastReceiver and add the necessary logic to it. If you are okay with the default, which closes the notification upon pressing it, then no further coding is required.
public class TestPushReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
try{
Context applicationContex = context.getApplicationContext();
if ( intent != null && intent.getAction() != null){
if (intent.getAction().equals(R1Push.OPENED_NOTIFICATION)){
Intent openIntent = new Intent(context, ShowNotificationActivity.class);
openIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TOP|Intent.FLAG_ACTIVITY_SINGLE_TOP);
if ( intent.getExtras() != null ){
openIntent.putExtras(intent.getExtras());
}
applicationContex.startActivity(openIntent);
}
}
} catch (Exception ex){
}
}
}
Then update the application class:
public class MyApplication extends Application{
@Override
public void onCreate() {
super.onCreate();
// drawable in notification bar
R1Emitter.getInstance().setNotificationIconResourceId(this, R.drawable.notification_icon);
// custom BroadcastReceiver
R1Emitter.getInstance().setIntentReceiver(this, TestPushReceiver.class);
R1Emitter.getInstance().connect(this);
}
}
If you don't have an application class yet, create it and don't forget to reference it inside the Manifest:
<!-- android:name of application tag must be full application name that was created in first step.-->
<application
android:name="com.example.r1connecttestapplication.MyApplication"
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
If you want to create your own notifications you have to create a class that implements R1NotificationBuilder interface and write your notification builder like in the example below:
public class CustomNotificationBuilder implements R1NotificationBuilder {
private int lastId;
@Override
public Notification createNotification(Context context, Intent intent) {
if ( context == null || intent == null){
return null;
}
String text = intent.getStringExtra(R1PushNotificationManager.NOTIFICATION_KEY);
String title = intent.getStringExtra(R1PushNotificationManager.NOTIFICATION_TITLE);
if ( text != null ){
NotificationCompat.Builder nb = new NotificationCompat.Builder(context)
.setAutoCancel(true)
.setTicker(text)
.setContentText(text)
.setWhen(System.currentTimeMillis());
if (!TextUtils.isEmpty(title)){
nb.setContentTitle(title);
} else {
nb.setContentTitle("My Application Name");
}
nb.setDefaults(Notification.DEFAULT_ALL);
nb.setSmallIcon(R.drawable.ic_launcher);
Notification notification = nb.build();
lastId++;
return notification;
}
return null;
}
@Override
public int getLastNotificationId() {
return lastId;
}
}
After that add this line just before R1Emitter.getInstance().connect(this) in your application class:
R1Emitter.getInstance().setNotificationBuilder(new CustomNotificationBuilder());
Update the manifest as shown below.
Add the following inside the application tag:
<!-- PUSH -->
<receiver android:name="com.google.android.gms.gcm.GcmReceiver"
android:exported="true"
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" />
<!-- name must be your applicationPackage -->
<category android:name="###YOUR APPLICATION PACKAGE###" />
</intent-filter>
</receiver>
<service
android:name="com.radiumone.emitter.gcm.RegistrationIntentService"
android:exported="false" />
<service
android:name="com.radiumone.emitter.gcm.R1ConnectGCMListenerService"
android:exported="false">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
</intent-filter>
</service>
<service
android:name="com.radiumone.emitter.gcm.R1ConnectInstanceIDListenerService"
android:exported="false">
<intent-filter>
<action android:name="com.google.android.gms.iid.InstanceID" />
</intent-filter>
</service>
<receiver android:name="com.radiumone.emitter.push.R1PushBroadcastReceiver"
android:exported="false">
<intent-filter>
<action android:name="com.radiumone.r1push.OPENED_INTERNAL"/>
</intent-filter>
</receiver>
<service android:name="com.radiumone.emitter.push.R1ConnectService"/>
<service android:name="com.radiumone.emitter.location.LocationService"/>
//Using the class created in Step 2 (cont):
<receiver android:name=".testpush.TestPushReceiver"
android:exported="false">
<intent-filter>
<action android:name="com.radiumone.r1push.OPENED"/>
</intent-filter>
</receiver>
<meta-data
android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version" />
<!-- END OF PUSH -->
Add the following inside the manifest tag:
<!-- PUSH -->
<!-- Permissions that are necessary for the library to work: -->
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- Permission to get location when using the network -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!-- Permission to get location when using GPS -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.WAKE_LOCK"></uses-permission>
<!-- GET Accounts permission is required to make GCM working for Android devices below 4.0.4-->
<uses-permission android:name="android.permission.GET_ACCOUNTS" android:maxSdkVersion="14"/>
<uses-permission android:name="android.permission.VIBRATE"/>
<permission android:name="###YOUR APPLICATION PACKAGE###.permission.C2D_MESSAGE" android:protectionLevel="signature"/>
<uses-permission android:name="###YOUR APPLICATION PACKAGE###.permission.C2D_MESSAGE"></uses-permission>
<!-- END OF PUSH -->
iii. Rich Push Initialization
Rich push notifications send a URL that opens upon user response to a system notification. In addition to the general push setup requirements, if you would like to enable rich push notifications that include HTML/CSS/JavaScript you have to add the following data in the AndroidManifest.xml:
<service android:name="com.radiumone.emitter.richpush.R1RichPushService" />
<activity
android:name="com.radiumone.emitter.richpush.activity.R1RichPushActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:label="@string/title_activity_rich_push"
android:launchMode="singleTask"
android:parentActivityName=".MainActivity"
android:theme="@style/AppThemeCustomNoTitle"
android:windowSoftInputMode="stateHidden">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".MainActivity" />
</activity>
The parent activity for rich activity is the view accessed when selecting the back button. Older platforms may require the meta-data attributes above.
@style/AppThemeCustomNoTitle is the window style. If you would like to present the view without a title, use the following style:
<style name="AppThemeCustomNoTitle" parent="AppTheme">
<item name="android:windowNoTitle">true</item>
</style>
Users that select rich push notifications will by default start com.radiumone.emitter.richpush.activity.R1RichPushActivity and start the HTML content.
iv. Rich Push Customization
If you want to customize Rich Push then update your custom BroadcastReceiver ( TestPushReceiver ):
Bundle extras = intent.getExtras();
if (extras != null) {
// getting rich push ID - no rich push id means that push is simple and no rich content for it
String richPushId = extras.getString(R1PushNotificationManager.RICH_PUSH);
if (TextUtils.isEmpty(richPushId)) {
openIntent = new Intent(applicationContext, ShowNotificationActivity.class);
} else {
openIntent = new Intent(applicationContext, R1RichPushActivity.class);
openIntent.putExtra(R1RichPush.R1_RICH_PUSH_ID, richPushId);
}
}
In this scenario, we check for rich push id in extras and start different activities for rich and regular push.
You can change the activity for Rich Push if you want to use fragments, toolbar, or another activity that you want to use as the Rich Push Activity. See the code below:
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.ViewGroup;
import com.radiumone.emitter.richpush.R1RichPush;
import com.radiumone.emitter.richpush.R1RichPushManager;
import com.radiumone.emitter.richpush.R1RichPushMessage;
import com.radiumone.emitter.richpush.R1RichPushWebView;
public class CustomPushActivity extends Activity implements R1RichPushManager.OnMessageReceivedListener{
private String richPushId;
private R1RichPushWebView webView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle extras = getIntent().getExtras();
if ( extras == null ){
Log.i(CustomPushActivity.class.getSimpleName(), "Wrong parameters for " + R1RichPushActivity.class.getSimpleName());
finish();
return;
}
richPushId = extras.getString(R1RichPush.R1_RICH_PUSH_ID);
}
@Override
protected void onNewIntent(Intent intent) {
setIntent(intent);
Bundle extras = getIntent().getExtras();
if ( extras == null ){
Log.i(CustomPushActivity.class.getSimpleName(), "Wrong parameters for " + R1RichPushActivity.class.getSimpleName());
finish();
return;
}
richPushId = extras.getString(R1RichPush.R1_RICH_PUSH_ID);
loadRichPush();
}
private void loadRichPush() {
if (TextUtils.isEmpty(richPushId)){
Log.i(CustomPushActivity.class.getSimpleName(), "No rich_push_id in extras");
finish();
return;
}
R1RichPushMessage message = R1RichPushManager.getR1RichPushManager().getR1RichPushMessage(this, richPushId, this);
if ( message != null ) {
webView = new R1RichPushWebView(this);
webView.setLayoutParams( new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
setContentView(webView);
if ( message.getStatus() == R1RichPushMessage.RESULT_OK ) {
webView.loadR1RichPush(message);
} else {
Log.i(CustomPushActivity.class.getSimpleName(), "Error while getting rich push message");
finish();
}
}
}
@Override
protected void onPause() {
super.onPause();
if ( webView != null ){
webView.onPause();
}
if ( !TextUtils.isEmpty(richPushId)) {
R1RichPushManager.getR1RichPushManager().removeListener(richPushId, this);
}
}
@Override
protected void onResume() {
super.onResume();
if ( webView != null ){
webView.onResume();
} else {
loadRichPush();
}
}
@Override
public void onResult(R1RichPushMessage message) {
if ( message != null && message.getStatus() == R1RichPushMessage.RESULT_OK) {
if (richPushId != null && richPushId.equals(message.getId())) {
runOnUiThread( new Runnable() {
@Override
public void run() {
loadRichPush();
}
});
}
} else {
Log.i(CustomPushActivity.class.getSimpleName(), "No Connection while getting rich push message");
finish();
}
}
@Override
public void onError(R1RichPushMessage message) {
Log.i(CustomPushActivity.class.getSimpleName(), "Error while getting rich push message");
finish();
}
}
The important line in this class is
//get R1RichPushMessage from R1RichPushManager
R1RichPushMessage message = R1RichPushManager.getR1RichPushManager().getR1RichPushMessage(this, richPushId, this);
where
R1RichPushManager.getR1RichPushManager().getR1RichPushMessage(Context context, String richPushId, R1RichPushManager.OnMessageReceivedListener receiveListener);
To make Rich Push work you have to use the following method of R1RichPushWebView:
webView.loadR1RichPush(message);
Next register your activity in AndroidManifest.xml (do not forget service android:name="com.radiumone.emitter.richpush.R1RichPushService" because it necessary for both custom and default rich push activity).
<service android:name="com.radiumone.emitter.richpush.R1RichPushService" />
<activity
android:name="###YOUR APPLICATION PACKAGE###.CustomRichPushActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:label="@string/title_activity_rich_push"
android:launchMode="singleTask"
android:parentActivityName=".MainActivity"
android:windowSoftInputMode="stateHidden">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".MainActivity" />
</activity>
Then add this line just before R1Emitter.getInstance().connect(this) in your application class:
R1Emitter.getInstance().setRichPushActivity(CustomRichPushActivity.class);
Now rich push will be opened in your custom activity.
v. Inbox Initialization
The Inbox provides an easy interface to house past rich-push messages sent to your users so they can still be visible to users that have disabled push messaging or who want to come back to them later.
If you want to enable inbox functionality you need to create a fragment or an activity that shows a list of Inbox messages and listen for messages updates in the Inbox. This reference source code shows how to implement Activity in which you can show and delete messages from Inbox (this activity must be registered in your AndroidManifest.xml). This also assumes that Rich Push functionality mentioned above is already integrated.
public class R1InboxActivity extends Activity implements R1InboxManager.OnInboxUpdateListener, AdapterView.OnItemClickListener {
// ListView for inbox messages
private ListView listView;
// Adapter for showing messages in listview
private R1InboxMessageAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// creating ListView programmatically, but it can be layout from xml
listView = new ListView(this);
listView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
listView.setId(android.R.id.list);
// creating Inbox adapter
adapter = new R1InboxMessageAdapter(this);
listView.setAdapter(adapter);
// sets click listener for this Activity
listView.setOnItemClickListener(this);
// this line is for correct working delete buttons in list
listView.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
setContentView(listView);
}
// method gets inbox messages and set to adapter for showing in list
private void loadMessages() {
final R1InboxMessage[] messages = R1InboxManager.getInboxManager().getR1InboxMessages(this);
runOnUiThread( new Runnable() {
@Override
public void run() {
if ( adapter != null ){
adapter.setInboxMessages(messages);
}
}
});
}
@Override
protected void onPause() {
super.onPause();
// remove inbox update listener when Activity goes to pause state
R1InboxManager.getInboxManager().setInboxUpdateListener(null);
}
@Override
protected void onStart() {
super.onStart();
// calls SDK onStart method
R1Emitter.getInstance().onStart(this);
}
@Override
protected void onStop() {
super.onStart();
// calls SDK onStop method
R1Emitter.getInstance().onStop(this);
}
@Override
protected void onResume() {
super.onResume();
// set inbox update listener when Activity resumes. After that all updates in inbox will invoke callback inboxUpdated() in this Activity
R1InboxManager.getInboxManager().setInboxUpdateListener(this);
// get actual messages after pause
loadMessages();
}
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if ( adapter != null ) {
// get R1InboxMessage object for pressed listview position
R1InboxMessage inboxMessage = adapter.getItem(position);
// call inboxMessageOpen() method for correct opening and showing inbox message
R1InboxManager.getInboxManager().inboxMessageOpen(this, inboxMessage);
}
}
@Override
public void inboxUpdated() {
// get actual messages after inbox updated
loadMessages();
}
@Override
public void inboxUpdateError() {
Log.i(getClass().getSimpleName(),"Inbox update error");
}
// adapter for showing Inbox messages
private class R1InboxMessageAdapter extends BaseAdapter {
private final LayoutInflater inflater;
// array of R1InboxMessage
private R1InboxMessage[] listOfMessages;
public R1InboxMessageAdapter(Context context){
listOfMessages = new R1InboxMessage[0];
inflater = (LayoutInflater)context.getSystemService(LAYOUT_INFLATER_SERVICE);
}
@Override
public int getCount() {
if ( listOfMessages == null ){
return 0;
}
return listOfMessages.length;
}
@Override
public R1InboxMessage getItem(int position) {
return listOfMessages[position];
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
ViewHolder viewHolder = null;
if (view == null) {
// Layout for inbox item. Will be shown further.
view = inflater.inflate(R.layout.r1_inbox_item, null);
viewHolder = new ViewHolder();
viewHolder.alert = (TextView)view.findViewById(R.id.alert);
viewHolder.title = (TextView)view.findViewById(R.id.title);
viewHolder.dateTime = (TextView)view.findViewById(R.id.datetime);
viewHolder.readIndicator = view.findViewById(R.id.read_indicator);
viewHolder.delete = (Button)view.findViewById(R.id.delete_button);
// set OnClickListener for delete button
viewHolder.delete.setOnClickListener( new View.OnClickListener() {
@Override
public void onClick(View v) {
// if tag for pressed button is an instance of R1InboxMessage you have to call inboxMessageDelete method in R1InboxManager for correct deletion of message
Object tag = v.getTag();
if ( tag instanceof R1InboxMessage ) {
R1InboxManager.getInboxManager().inboxMessageDelete(R1InboxActivity.this, (R1InboxMessage) tag);
}
}
});
view.setTag(viewHolder);
} else {
viewHolder = (ViewHolder)view.getTag();
}
R1InboxMessage message = getItem(position);
// set Tag for delete button. This needs for knowing what message must be deleted after button pressed.
viewHolder.delete.setTag(message);
viewHolder.alert.setText(message.getAlert());
viewHolder.title.setText(message.getTitle());
viewHolder.dateTime.setText( dateTimeLocalised( message.getDateTime() ));
// checks that message is not readed and show it
if ( message.getReadState() == R1RichPushMessage.READ ){
viewHolder.readIndicator.setVisibility(View.INVISIBLE);
} else {
viewHolder.readIndicator.setVisibility(View.VISIBLE);
}
return view;
}
public void setInboxMessages(R1InboxMessage[] inboxMessages){
this.listOfMessages = inboxMessages;
notifyDataSetChanged();
}
}
private static class ViewHolder {
TextView title;
TextView alert;
TextView dateTime;
Button delete;
View readIndicator;
}
private String dateTimeLocalised(long dateTime){
dateTime -= TimeZone.getDefault().getOffset(dateTime);
return DateFormat.getDateTimeInstance().format(dateTime);
}
}
Layout R.layout.r1_inbox_item.xml from source code above:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="?listPreferredItemHeight"
android:orientation="horizontal"
android:padding="8dp">
<View
android:id="@+id/read_indicator"
android:layout_width="10dp"
android:layout_height="10dp"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_gravity="center_vertical"
android:layout_margin="8dp"
android:background="@drawable/shape" />
<LinearLayout
android:id="@+id/notification_content"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_toEndOf="@+id/read_indicator"
android:layout_toLeftOf="@+id/delete_button"
android:layout_toRightOf="@+id/read_indicator"
android:layout_toStartOf="@+id/delete_button"
android:orientation="vertical">
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="marquee"
android:maxLines="1" />
<TextView
android:id="@+id/alert"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="marquee"
android:maxLines="2" />
</LinearLayout>
<Button
android:id="@+id/delete_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:focusable="false"
android:text="Delete" />
<TextView
android:id="@+id/datetime"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/notification_content"
android:layout_gravity="bottom"
android:layout_toLeftOf="@+id/delete_button"
android:layout_toStartOf="@+id/delete_button" />
</RelativeLayout>
R1InboxMessage is an object that has the following methods to display details of inbox messages:
datetime
inboxMessage.getDateTime()
Returns inbox message timestamp as epoch time in milliseconds
title
inboxMessage.getTitle()
Returns inbox message title text
alert
inboxMessage.getAlert()
Returns inbox message alert text
readState
inboxMessage.getReadState()
Returns the read state of an inbox message, values are R1InboxMessage.READ/ R1InboxMessage.UNREAD
To display a number of unread messages use the following code:
int unread = R1InboxManager.getInboxManager().getInboxUnreadCount(context);
To be notified for realtime updates of the number of unread messages you need to register R1InboxManager.OnInboxUpdateListener. To stop this updates you need to unregister it:
R1InboxManager.getInboxManager().setInboxUpdateListener( new R1InboxManager.OnInboxUpdateListener() {
@Override
public void inboxUpdated() {
// inbox updated
}
@Override
public void inboxUpdateError() {
// error occurred while inbox updated
}
});
vi. Deep Link Initialization
Deep linking push messages open up a designated view in an application upon user response to a system notification. To properly handle deep link push receipts, please read Androids documentation on registering a custom URL scheme here: http://developer.android.com/guide/topics/manifest/data-element.html
vii. Segment your Audience
You can specify Tags for R1 Connect SDK to send Push Notifications for certain groups of users. You can then send Push Notifications to users with specific tags.
The maximum length of a Tag is 128 characters.
R1 Connect SDK saves Tags. You do not have to add Tags every time the application is launched.
Add a new Tag
R1Push.getInstance(context).addTag("tag");
Add multiple Tags
for ( String tag: tags) {
R1Push.getInstance(this).addTag(tag);
}
Remove existing Tag
R1Push.getInstance(context).removeTag("tag");
Remove multiple Tags
for ( String tag: tags) {
R1Push.getInstance(this).removeTag(tag);
}
Replace all existing Tags
R1Push.getInstance(context).setTags(Arrays.asList("tag1","tag2"));
Get all Tags
String[] allTags = R1Push.getInstance(context).getTags(context);
Automatically created Tags
date_of_launch_dd_mm_yyyy: Replace dd_mm_yyyy with the date you want to target. Date is in your account timezone. one_time_app_users: Users who have only launched the app once
Automatically created Segments
Lapsed Users > 7 Days Lapsed Users > 14 Days Lapsed Users > 21 Days Lapsed Users > 30 Days
If you are targeting devices below Android version 4.0.4, you need to also add the following permission:
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
This is in order to enable the application to use the Google Account for communication with the Google Cloud Messaging platform (used for pushed notifications). For devices running version 4.0.4 or later, a Google account is not required anymore, therefore the permission is unnecessary.
View ArticlePush Notification Activation
i. Setup Apple Push Notification Services
ii. Initialization
iii. Rich Push Initialization
iv. Deep Link Initialization
v. Using Tagging to Segment your Audience
vi. Inbox Integration
Push Notification Activation
i. Setup Apple Push Notification Services
Prerequisites for Apple Push Notification Services Setup
The Importance of Setting your App as in Production or in Development
When creating or editing an app on RadiumOne Connect you can set the status of the app to either Production or Development. Production status for an app is considered to be a live app that is in the hands of real users and will have notifications and other data running on live servers. A Development status for an app is one that you are still performing testing on and will not be viewed by any real-life audiences because it will stay on test servers.
In the context of push notifications, it is important to know this difference because Apple will treat these two servers separately. Also device tokens for Development will not work on Production and vice versa. We recommend a Development app version and Production app version for your app on RadiumOne Connect to keep Push SSL certificates separate for each. You can also continue testing and experimenting on one app without worrying about it affecting your live app audience in any way.
iOS Developer Program Enrollment
This doc assumes that you are enrolled in the iOS Developer Program. If you are not, please enroll here. Being in the Apple Developer Program is a required component to have your iOS app communicate with the RadiumOne Connect service for push notifications and is necessary for the next step of setting up your app with the Apple Push Notification Service (APNs). It is also essential that you have Team Agent role access in the iOS Developer Program to complete this process.
Configuring your App for Apple Push Notifications
Apple Developer Members Center
Make sure you are logged into the Apple Developer Members Center. Once you are logged in you can locate your application in the Identifiers folder list.
Registered App ID
If you have not registered an App ID yet it is important that you do so now. You will need to click the + symbol, fill out the form, and check the Push Notifications checkbox. Please keep in mind it is possible to edit these choices after the App ID is registered.
You can expand the application and when doing so you will see two settings for push notifications. They will have either yellow or green status icons like here:
You will need to click Edit to continue. If the Edit button is not visible it is because you do not have Team Agent role access. This role is necessary for getting an SSL certificate.
Creating an SSL Certificate
To enable the Development or Production Push SSL Certificate please click Edit. (It is important to note that each certificate is limited to a single app, identified by its bundle ID and limited to one of two environments, either Development or Production. Read more info here.)
You will see a Create Certificate button, after clicking it you will see the Add iOS Certificate Assistant. Please follow the instructions presented in the assistant which includes launching the Keychain Access application, generating a Certificate Signing Request (CSR), generating an SSL Certificate, etc.
If you follow the assistant correctly, after downloading and opening the SSL Certificate you should have it added under My Certificates or Certificates in your Keychain Access application. Also when you are returned to the Configure App ID page the certificate should be badged with a green circle and the label Enabled.
Exporting the SSL Certificate
If not already in the Keychain Access app that contains your certificate, please open it and select the certificate that you just added. Once you select the certificate go to File > Export Items and export it as a Personal Information Exchange (.p12) file. When saving the file be sure to use the Personal Information Exchange (.p12) format.
Emailing your SSL certificate
After downloading your 2 certificates (one for production, one for development), please send them to your RadiumOne account manager (with certificate passwords if you choose to add any).
ii. Initialization
Setup your App Delegate
(Only for Objective C code)
#import "R1SDK.h"
#import "R1Emitter.h"
#import "R1Push.h"
#import "R1WebCommand.h" // required for rich push
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
R1SDK *sdk = [R1SDK sharedInstance];
// Initialize SDK
sdk.applicationId = @"Application ID"; //Ask your RadiumOne contact for an app id
// Initialize Push Notification
sdk.clientKey = @"Your Client Key"; //Ask your RadiumOne contact for a client key
[[R1Push sharedInstance] handleNotification:[launchOptions valueForKey:UIApplicationLaunchOptionsRemoteNotificationKey]
applicationState: application.applicationState];
[[R1Push sharedInstance] registerForRemoteNotificationTypes:(UIRemoteNotificationTypeBadge |
UIRemoteNotificationTypeSound |
UIRemoteNotificationTypeAlert)];
// Start SDK
[sdk start];
return YES;
}
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
let sdk = R1SDK.sharedInstance();
// Initialize Anlaytics
sdk.applicationId = "Application ID"; //Ask your RadiumOne contact for an app id
// Initialize Push Notification
sdk.clientKey = "Your Client Key"; //Ask your RadiumOne contact for a client key
R1Push.sharedInstance().delegate = self;
var remoteNotificationInfo: NSDictionary? = nil
if launchOptions != nil {
remoteNotificationInfo = (launchOptions![UIApplicationLaunchOptionsRemoteNotificationKey] as? NSDictionary)!;
}
R1Push.sharedInstance().handleNotification(remoteNotificationInfo as? [NSObject : AnyObject], applicationState: application.applicationState);
R1Push.sharedInstance().registerForRemoteNotificationTypes([.Alert,.Badge,.Sound]);
// Start SDK
sdk.start();
return true
}
Register for Remote Notifications
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
[[R1Push sharedInstance] registerDeviceToken:deviceToken];
}
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
[[R1Push sharedInstance] failToRegisterDeviceTokenWithError:error];
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
[[R1Push sharedInstance] handleNotification:userInfo applicationState:application.applicationState];
}
func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
R1Push.sharedInstance().registerDeviceToken(deviceToken);
}
func application(application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: NSError) {
R1Push.sharedInstance().failToRegisterDeviceTokenWithError(error);
}
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {
R1Push.sharedInstance().handleNotification(userInfo, applicationState: application.applicationState);
}
Push is disabled by default. You can enable it in the application:didFinishLaunchingWithOptions method or later.
[[R1Push sharedInstance] setPushEnabled:YES];
R1Push.sharedInstance().pushEnabled = true;
NOTE: If you enabled it in the application:didFinishLaunchingWithOptions method, the Push Notification AlertView will be showed at first application start.
iii. Rich Push Initialization
Rich Push Notifications send a URL that opens in a WebView upon user response to a system notification. No set up is required for this feature.
Please note that iOS 9 devices require use of HTTPS. iOS 8 and previous versions still support HTTP. Please ensure that you send HTTPS if iOS 9 devices may receive the message.
iv. Deep Link Initialization
Deep linking Push Notifications open up a designated view in an application upon user response to a system notification. To properly handle deep link push receipts, please read Apple's documentation: https://developer.apple.com/library/ios/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/Inter-AppCommunication/Inter-AppCommunication.html#//apple_ref/doc/uid/TP40007072-CH6-SW10 http://wiki.akosma.com/IPhone_URL_Schemes
v. Segment your Audience
You can specify Tags for R1 Connect SDK to send Push Notifications to certain groups of users.
The maximum length of a Tag is 128 characters.
R1 Connect SDK saves Tags. You do not have to add Tags every time the application is launched.
Add a new Tag
[[R1Push sharedInstance].tags addTag:@"NEW TAG"];
R1Push.sharedInstance().tags.addTag("NEW TAG");
Add multiple Tags
[[R1Push sharedInstance].tags addTags:@[ @"NEW TAG 1", @"NEW TAG 2" ]];
R1Push.sharedInstance().tags.addTags(["NEW TAG 1", "NEW TAG 2"]);
Remove existing Tag
[[R1Push sharedInstance].tags removeTag:@"EXIST TAG"];
R1Push.sharedInstance().tags.removeTag("EXIST TAG");
Remove multiple Tags
[[R1Push sharedInstance].tags removeTags:@[ @"EXIST TAG 1", @"EXIST TAG 2" ]];
R1Push.sharedInstance().tags.removeTags([ "EXIST TAG 1", "EXIST TAG 2" ]);
Replace all existing Tags
[R1Push sharedInstance].tags.tags = @[ @"NEW TAG 1", @"NEW TAG 2" ];
or
[[R1Push sharedInstance].tags setTags:@[ @"NEW TAG 1", @"NEW TAG 2" ]];
R1Push.sharedInstance().tags.tags = ["NEW TAG 1", "NEW TAG 2"];
Get all Tags
NSArray *currentTags = [R1Push sharedInstance].tags.tags;
let currentTags = R1Push.sharedInstance().tags.tags;
Automatically created Tags
date_of_launch_dd_mm_yyyy: Replace dd_mm_yyyy with the date you want to target. Date is in your account timezone. one_time_app_users: Users who have only launched the app once
Automatically created Segments
Lapsed Users > 7 Days Lapsed Users > 14 Days Lapsed Users > 21 Days Lapsed Users > 30 Days
vi. Inbox Integration
The Inbox provides an easy interface to house past rich-push messages sent to your users so they can still be visible to users that have disabled push messaging or who want to come back to them later.
If you want to enable inbox functionality, you need to use R1Inbox class and import R1Inbox.h header at the top of your class file (Only for Objective C code):
#import "R1Inbox.h"
If you want to add some label or button with count of unread or total Inbox messages, you should implement -(void) inboxMessageUnreadCountChanged or -(void) inboxMessagesDidChanged (func inboxMessageUnreadCountChanged() orfunc inboxMessagesDidChanged() for swift) methods from R1InboxMessagesDelegate protocol in your class. After that, add your class as delegate to [R1Inbox sharedInstance].messages (R1Inbox.sharedInstance().messages for swift).
- (void) addInboxMessagesDelegate
{
[[R1Inbox sharedInstance].messages addDelegate:self];
}
-(void) inboxMessageUnreadCountChanged
{
NSString *btnTitle = [NSString stringWithFormat:@"Inbox (%lu unread)", (unsigned long)[R1Inbox sharedInstance].messages.unreadMessagesCount];
[self.inboxButton setTitle:btnTitle forState:UIControlStateNormal];
}
func addInboxMessagesDelegate() {
R1Inbox.sharedInstance().messages.addDelegate(self);
}
func inboxMessageUnreadCountChanged() {
let btnTitle = String.init(format: "Inbox unread cound: %d", R1Inbox.sharedInstance().messages.unreadMessagesCount);
inboxButton?.setTitle(btnTitle, forState: .Normal);
}
Do not forget to remove your class from delegates when your class gets deallocated:
- (void) dealloc
{
[[R1Inbox sharedInstance].messages removeDelegate:self];
//...
}
deinit {
R1Inbox.sharedInstance().messages.removeDelegate(self);
//...
}
To display the list of Inbox messages, you should create your own ViewController to provide required customization. In this case, this screen would not look foreign to your application.
You can see the sample of Inbox implementation in DemoApplication project in files R1SampleInboxTableViewCell.h,R1SampleInboxTableViewCell.m, R1SampleInboxViewController.h, R1SampleInboxViewController.m (for Objective C) and in DemoApplicationSwift project in files R1SampleInboxTableViewCell.swift, R1SampleInboxViewController.swift (for swift)
R1SampleInboxTableViewCell.h
#import <UIKit/UIKit.h>
@class R1InboxMessage;
@interface R1SampleInboxTableViewCell : UITableViewCell
// Sets or Gets R1InboxMessage object and configures cell for it
@property (nonatomic, strong) R1InboxMessage *inboxMessage;
- (id) initWithReuseIdentifier:(NSString *)reuseIdentifier;
// Calculates the height of the cell
+ (CGFloat) heightForCellWithInboxMessage:(R1InboxMessage *) inboxMessage cellWidth:(CGFloat) cellWidth;
@end
R1SampleInboxTableViewCell.m
#import "R1SampleInboxTableViewCell.h"
#import "R1Inbox.h"
@interface R1SampleInboxTableViewCell ()
@property (nonatomic, strong) UIView *unreadMarker;
@property (nonatomic, strong) UILabel *alertLabel;
@property (nonatomic, strong) NSDateFormatter *dateFormatter;
@end
@implementation R1SampleInboxTableViewCell
- (id) initWithReuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:reuseIdentifier];
if (self)
{
self.alertLabel = [[UILabel alloc] initWithFrame:CGRectZero];
self.alertLabel.numberOfLines = 0;
self.alertLabel.lineBreakMode = NSLineBreakByWordWrapping;
[self.contentView addSubview:self.alertLabel];
self.unreadMarker = [[UIView alloc] initWithFrame:CGRectZero];
self.unreadMarker.layer.cornerRadius = 3;
self.unreadMarker.backgroundColor = [UIColor blueColor];
[self.contentView addSubview:self.unreadMarker];
self.textLabel.font = [UIFont boldSystemFontOfSize:14];
self.alertLabel.font = [UIFont systemFontOfSize:14];
self.detailTextLabel.textAlignment = NSTextAlignmentRight;
self.dateFormatter = [[NSDateFormatter alloc] init];
[self.dateFormatter setDateStyle:NSDateFormatterShortStyle];
[self.dateFormatter setTimeStyle:NSDateFormatterMediumStyle];
}
return self;
}
// Configures the cell for displaying Inbox Message
- (void) setInboxMessage:(R1InboxMessage *)inboxMessage
{
if (_inboxMessage == inboxMessage)
{
[self configureUnreadMarker];
return;
}
_inboxMessage = inboxMessage;
self.textLabel.text = inboxMessage.title;
self.alertLabel.text = inboxMessage.alert;
self.detailTextLabel.text = [self.dateFormatter stringFromDate:inboxMessage.createdDate];
[self configureUnreadMarker];
[self setNeedsLayout];
}
// Shows or hides unread marker view
- (void) configureUnreadMarker
{
if ([self.unreadMarker isHidden] != _inboxMessage.unread)
return;
[self.unreadMarker setHidden:!_inboxMessage.unread];
}
- (void) layoutSubviews
{
[super layoutSubviews];
self.unreadMarker.frame = CGRectMake(4, (self.contentView.bounds.size.height - 6)/2, 6, 6);
self.detailTextLabel.frame = CGRectMake(0, 0, self.contentView.bounds.size.width-10, 20);
if (self.textLabel.text == nil)
{
self.alertLabel.frame = CGRectMake(15, 15, self.contentView.bounds.size.width-20, self.contentView.bounds.size.height-20);
}else
{
self.textLabel.frame = CGRectMake(15, 15, self.contentView.bounds.size.width-20, 20);
self.alertLabel.frame = CGRectMake(15, 35, self.contentView.bounds.size.width-20, self.contentView.bounds.size.height-45);
}
}
// Calculates the height of the cell
+ (CGFloat) heightForCellWithInboxMessage:(R1InboxMessage *) inboxMessage cellWidth:(CGFloat) cellWidth
{
CGFloat height = 25;
if (inboxMessage.title != nil)
height += 20;
if (inboxMessage.alert != nil)
{
if ([inboxMessage.alert respondsToSelector:@selector(boundingRectWithSize:options:attributes:context:)])
{
NSMutableParagraphStyle *paragraph = [[NSMutableParagraphStyle alloc] init];
paragraph.lineBreakMode = NSLineBreakByWordWrapping;
NSDictionary *attributes = @{NSFontAttributeName : [UIFont systemFontOfSize:14],
NSParagraphStyleAttributeName: paragraph};
height += [inboxMessage.alert boundingRectWithSize:CGSizeMake(cellWidth-20, 100)
options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading)
attributes:attributes
context:nil].size.height;
}else
{
height += [inboxMessage.alert sizeWithFont:[UIFont systemFontOfSize:14]
constrainedToSize:CGSizeMake(cellWidth-20, 100)
lineBreakMode:NSLineBreakByWordWrapping].height;
}
height += 1;
}
if (height < 50)
return 50;
return height;
}
@end
R1SampleInboxViewController.h
#import <UIKit/UIKit.h>
#import "R1Inbox.h"
@protocol R1SampleInboxViewControllerDelegate;
@interface R1SampleInboxViewController : UITableViewController <R1InboxMessagesDelegate>
@property (nonatomic, assign) id<R1SampleInboxViewControllerDelegate> inboxDelegate;
- (id) initInboxViewController;
@end
@protocol R1SampleInboxViewControllerDelegate <NSObject>
- (void) sampleInboxViewControllerDidFinished:(R1SampleInboxViewController *) sampleInboxViewController;
@end
R1SampleInboxViewController.m
#import "R1SampleInboxViewController.h"
#import "R1SampleInboxTableViewCell.h"
#import "R1Inbox.h"
@interface R1SampleInboxViewController ()
@property (nonatomic, strong) R1InboxMessages *inboxMessages;
@end
@implementation R1SampleInboxViewController
// Initialize UITableViewController
- (id) initInboxViewController
{
self = [super initWithStyle:UITableViewStylePlain];
if (self)
{
self.inboxMessages = [R1Inbox sharedInstance].messages;
[self updateTitle];
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone
target:self action:@selector(closeInboxViewController)];
}
return self;
}
// Called when user presses 'Done' button
- (void) closeInboxViewController
{
[self.inboxDelegate sampleInboxViewControllerDidFinished:self];
}
// Updates the title of ViewController with number of unread messages
- (void) updateTitle
{
if (self.inboxMessages.unreadMessagesCount == 0)
self.navigationItem.title = @"Inbox";
else
self.navigationItem.title = [NSString stringWithFormat:@"Inbox (%lu unread)", (unsigned long)self.inboxMessages.unreadMessagesCount];
}
- (void) viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self updateTitle];
// Add this view controller to the list of delegates when it appears
[self.inboxMessages addDelegate:self];
}
- (void) viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
// Remove this view controller from the list of delegates when it disappears
[self.inboxMessages removeDelegate:self];
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Returns the total number of Inbox messages
return self.inboxMessages.messagesCount;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
// Returns the calculated height of the cell for R1InboxMessage object in row
return [R1SampleInboxTableViewCell heightForCellWithInboxMessage:[self.inboxMessages.messages objectAtIndex:indexPath.row]
cellWidth:self.tableView.frame.size.width];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
R1SampleInboxTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"];
if (cell == nil)
{
cell = [[R1SampleInboxTableViewCell alloc] initWithReuseIdentifier:@"Cell"];
}
// Sets up the cell for displaying R1InboxMessage object
cell.inboxMessage = [self.inboxMessages.messages objectAtIndex:indexPath.row];
return cell;
}
- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
R1InboxMessage *message = [self.inboxMessages.messages objectAtIndex:indexPath.row];
// Shows Inbox message when user interacts to the cell
[[R1Inbox sharedInstance] showMessage:message
messageDidShow:^{
[self.tableView deselectRowAtIndexPath:indexPath animated:YES];
}];
}
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
return UITableViewCellEditingStyleDelete;
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
R1InboxMessage *message = [self.inboxMessages.messages objectAtIndex:indexPath.row];
[self.inboxMessages deleteMessage:message];
}
#pragma mark - R1InboxMessagesDelegate methods
// This method called when the list of Inbox messages gets updated
- (void) inboxMessagesWillChanged
{
[self.tableView beginUpdates];
}
// This method called when any item in the list of Inbox messages gets changed (modified, inserted or removed)
- (void) inboxMessagesDidChangeMessage:(R1InboxMessage *) inboxMessage
atIndex:(NSUInteger) index
forChangeType:(R1InboxMessagesChangeType)changeType
newIndex:(NSUInteger) newIndex
{
switch (changeType)
{
case R1InboxMessagesChangeInsert:
[self.tableView insertRowsAtIndexPaths:@[ [NSIndexPath indexPathForRow:index inSection:0] ]
withRowAnimation:UITableViewRowAnimationAutomatic];
break;
case R1InboxMessagesChangeDelete:
[self.tableView deleteRowsAtIndexPaths:@[ [NSIndexPath indexPathForRow:index inSection:0] ]
withRowAnimation:UITableViewRowAnimationAutomatic];
break;
case R1InboxMessagesChangeUpdate:
((R1SampleInboxTableViewCell *)[self.tableView cellForRowAtIndexPath: [NSIndexPath indexPathForRow:index inSection:0] ]).inboxMessage = [self.inboxMessages.messages objectAtIndex:index];
break;
default:
break;
}
}
// This method called when the changes to list of Inbox messages are over
- (void) inboxMessagesDidChanged
{
[self.tableView endUpdates];
}
// This method called when the number of unread Inbox messages gets changed
- (void) inboxMessageUnreadCountChanged
{
[self updateTitle];
}
@end
R1SampleInboxViewController.swift
import UIKit
protocol R1SampleInboxViewControllerDelegate {
func sampleInboxViewControllerDidFinished(sampleInboxViewController: R1SampleInboxViewController);
}
class R1SampleInboxViewController: UITableViewController, R1InboxMessagesDelegate {
var inboxMessages: R1InboxMessages?
var inboxDelegate: R1SampleInboxViewControllerDelegate?;
override func viewDidLoad() {
super.viewDidLoad()
inboxMessages = R1Inbox.sharedInstance().messages;
updateTitle();
}
func updateTitle() {
if (inboxMessages?.unreadMessagesCount == 0) {
navigationItem.title = "Inbox";
} else {
navigationItem.title = String.init(format: "Inbox (%lu unread)", (inboxMessages?.unreadMessagesCount)!);
}
}
override func viewWillAppear(animated: Bool) {
updateTitle();
inboxMessages?.addDelegate(self);
}
override func viewDidDisappear(animated: Bool) {
inboxMessages?.removeDelegate(self);
}
@IBAction func closeButtonPressed(sender: UIBarButtonItem) {
inboxDelegate?.sampleInboxViewControllerDidFinished(self);
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return Int((inboxMessages?.messagesCount)!);
}
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
let message : R1InboxMessage = (inboxMessages?.messages[indexPath.row])! as! R1InboxMessage;
return R1SampleInboxTableViewCell.heightForCell(message, cellWidth: tableView.frame.size.width)
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! R1SampleInboxTableViewCell;
let message : R1InboxMessage = (inboxMessages?.messages[indexPath.row])! as! R1InboxMessage;
cell.setInboxMessage(message);
return cell
}
override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
return true
}
override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
if editingStyle == .Delete {
let message : R1InboxMessage = (inboxMessages?.messages[indexPath.row])! as! R1InboxMessage;
inboxMessages?.deleteMessage(message);
}
}
// MARK: - Table view delegate
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let message : R1InboxMessage = (inboxMessages?.messages[indexPath.row])! as! R1InboxMessage;
R1Inbox.sharedInstance().showMessage(message) { () -> Void in
tableView.deselectRowAtIndexPath(indexPath, animated: true)
}
}
// MARK: - R1InboxMessagesDelegate
func inboxMessagesWillChanged() {
tableView.beginUpdates()
}
func inboxMessagesDidChangeMessage(inboxMessage: R1InboxMessage!, atIndex index: UInt, forChangeType changeType: UInt, newIndex: UInt) {
if (changeType == UInt(R1InboxMessagesChangeInsert)) {
tableView.insertRowsAtIndexPaths([ NSIndexPath.init(forRow: Int(index), inSection: 0)], withRowAnimation: .Automatic);
} else if (changeType == UInt(R1InboxMessagesChangeDelete)) {
tableView.deleteRowsAtIndexPaths([ NSIndexPath.init(forRow: Int(index), inSection: 0)], withRowAnimation: .Automatic);
} else if (changeType == UInt(R1InboxMessagesChangeUpdate)) {
let cell = tableView.cellForRowAtIndexPath(NSIndexPath.init(forRow: Int(index), inSection: 0)) as! R1SampleInboxTableViewCell;
let message : R1InboxMessage = (inboxMessages?.messages[Int(index)])! as! R1InboxMessage;
cell.setInboxMessage(message);
}
}
func inboxMessagesDidChanged() {
tableView.endUpdates()
}
func inboxMessageUnreadCountChanged() {
updateTitle()
}
}
R1SampleInboxTableViewCell.swift
import UIKit
class R1SampleInboxTableViewCell: UITableViewCell {
@IBOutlet weak var unreadMarkerView: UIView?
@IBOutlet weak var alertLabel: UILabel?
@IBOutlet weak var messageLabel: UILabel?
@IBOutlet weak var dateLabel: UILabel?
var dateFormatter: NSDateFormatter?
func setInboxMessage(inboxMessage: R1InboxMessage) {
unreadMarkerView?.hidden = !inboxMessage.unread;
self.messageLabel?.text = inboxMessage.title;
self.alertLabel?.text = inboxMessage.alert;
self.dateLabel?.text = dateFormatter?.stringFromDate(inboxMessage.createdDate);
}
override func awakeFromNib() {
super.awakeFromNib()
dateFormatter = NSDateFormatter?.init();
dateFormatter?.dateStyle = .ShortStyle;
dateFormatter?.timeStyle = .MediumStyle;
}
static func heightForCell(inboxMessage: R1InboxMessage, cellWidth: CGFloat) -> CGFloat {
var height: CGFloat = 16+40;
if (inboxMessage.alert != nil) {
let paragraph : NSMutableParagraphStyle = NSMutableParagraphStyle.init();
paragraph.lineBreakMode = .ByWordWrapping;
height += inboxMessage.alert!._bridgeToObjectiveC().boundingRectWithSize(CGSize.init(width: cellWidth-16-15, height: 100), options: .UsesLineFragmentOrigin, attributes: [NSFontAttributeName : UIFont.systemFontOfSize(14), NSParagraphStyleAttributeName: paragraph], context: nil).size.height;
}
return height;
}
}
In Objective C example, initialize the R1SampleInboxViewController with the following method:
[[R1SampleInboxViewController alloc] initInboxViewController]
View ArticleIf you've scheduled push messages and your messages were sent ahead or behind the scheduled time, your account settings may be configured for a different time zone.
To edit your global time zone, go to the account settings page on the portal (after you've signed in) and update the Time Zone field. Hit Save Changes when you're done.
Your settings on this field control all components of push messaging, from scheduling to reporting.
View ArticleSystem Requirements
SDK Initialization
Import the Library
Initialize the SDK in All Activities
Configure the SDK
Update the manifest
Advanced Settings
1. System Requirements
The R1 Connect SDK supports all mobile and tablet devices running Android 2.3 and above. Google Play Services must be 4.0 or above. We have two different SDK versions that support Google Play Services <6.5 and 6.5. Please ensure that you download the version that best applies to your application.
Known Incompatibilities:
Proguard Java Optimizer breaks the Connect SDK and prevents data from being sent back to our servers.
2. SDK Initialization
a. Import the library to your project
Please start by downloading the demo project: git clone https://github.com/radiumone/r1-connect-demo-Android
Copy SdkLib/LibR1Connect.jar into the libs directory of your project. All mobile and tablet devices running Android 2.3. and above are supported.
If you have not registered your application in R1 Connect, please do so now.
In Android studio, the build.gradle should include the library, android-support-library-v4 library and Google Play Services as a dependency.
dependencies {
compile files('libs/LibR1Connect.jar')
compile 'com.android.support:support-v4:20.+'
compile com.google.android.gms:play-services:4.3.+'
}
b. Initialize the SDK in all Activities
The following steps will explain how to integrate R1 Connect to enable event tracking.
Import the emitter in all your application activities:
import com.radiumone.emitter.R1Emitter;
And override onStart and onStop methods for each activity:
@Override
protected void onStart() {
super.onStart();
R1Emitter.getInstance().onStart(this);
}
@Override
protected void onStop() {
super.onStop();
R1Emitter.getInstance().onStop(this);
}
Create a class that extends the Application class (or use an existing one), and initialize the SDK in its onCreate method:
package com.example.yourpackagename;
import com.radiumone.emitter.R1Emitter;
import android.app.Application;
public class TestApplication extends Application{
@Override
public void onCreate() {
super.onCreate();
R1Emitter.getInstance().connect(this);
}
}
c. Configure the SDK
To configure how the library will be used in your project you will need to create a file called r1connect.properties in the assets directory of your project.
app_id=<YOUR APPLICATION_ID>
#enable or disable cookie mapping. Default is false. Setting this first party cookie will enable RadiumOne to be effective in targeting the user for advertising campaigns run on behalf of the Publisher. Only enable this setting if you plan to run advertising with RadiumOne.
cookieMapping=false
4. Set Configuration Options
#enable deferred deep linking. Value is the app's registered URI scheme.deferred_deeplink_scheme=value
#default value of analytics is set to false. Set this flag to true to enable analytics.
analytics.enable=true
#allow location tracking by gps
analytics.enable_gps=false
#location update timeout for analytics sdk. Default 600 sec
analytics.location_update_time=600
#location update distance for analytics sdk. Default 100 meters
analytics.location_update_distance=100
#allow location tracking in background for analytics sdk. Default false
analytics.location_in_background=false
#prevent location tracking for analytics sdk
analytics.disable_sdk_location=false
##PUSH SETTINGS
push.client_key=<YOUR CLIENT KEY>
# default value for push when application starts -- set to false to use the SDK without push
push.enable=true
As you can see in the example above, it will contain the following:
app_id You will need to enter the App ID you received when creating your app on R1 Connect (found under Dev Tools -> Keys & Secrets)
cookieMapping enable or disable cookie mapping. Default is false. Setting this first party cookie will enable RadiumOne to be effective in targeting the user for advertising campaigns run on behalf of the Publisher. Only enable this setting if you plan to run advertising with RadiumOne.
push.client_key You will need to enter the App Key you received when creating your app on R1 Connect (found under Dev Tools -> Keys & Secrets)
analytics.enable - set to "true" enables analytics in the SDK and otherwise disables it.
analytics.disable_sdk_location - when set to true it disables the use of analytics sdk tracking location. It is useful if you want to use your own tracking location. You can pass a location object like so: R1Emitter.getInstance().trackLocation(location);
analytics.enable_gps when set to true it enables the use of device GPS to get location (only if GPS is enabled in device settings), when false only the network is used for analytics sdk
analytics.location_update_time set the timeout between location updates for analytics sdk
analytics.location_update_distance set the change in distance for location updates for analytics sdk
analytics.location_in_background set whether or not the location is allowed in analytics sdk to be sent while the app is in the background
advertising_enabled set whether or not the application is displaying advertisements. A value of true prevents the SDK from accessing the Advertising Id to comply with Google's advertising policy when advertisements are served within the application (outside of the SDK).
deferred_deeplink_scheme enable deferred deeplinking, value is the app registered scheme.
d. Update the manifest
In your manifest, add the permissions below:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
Properly declare your application class:
<application
android:name="com.example.yourpackagename.TestApplication"
android:allowBackup="true"
<service android:name="com.radiumone.emitter.location.LocationService"/>
</application>
e. Advanced Settings
The following is a list of configuration parameters for the R1 Connect SDK, most of these contain values that are sent to the tracking server to help identify your app on our platform and to provide analytics on sessions and location.
appName
The application name associated with emitter. By default, this property is populated with the package name of the application. If you wish to override this property, you must do so before making any tracking calls.
R1Emitter.getInstance().setApplicationName("customApplicationName");
appId
The application identifier associated with this emitter. By default, this property is null. If you wish to set this property, you must do so before making any tracking calls. Note that this is not your app's bundle id (e.g. com.example.appname).
R1Emitter.getInstance().setApplicationUserId("12345");
appVersion
The application version associated with this emitter. By default, this property is populated with the android:versionName= string from the application AndroidManifest.xml. If you wish to override this property, you must do so before making any tracking calls.
R1Emitter.getInstance().setAppVersion("1.0");
sessionTimeout
Indicates how long, in seconds, the application must transition to the inactive or background state before the tracker automatically indicates the start of a new session. When this happens and the app becomes active again it will set sessionStart to true. For example, if this is set to 30 seconds, and the user receives a phone call that lasts for 45 seconds while using the app, upon returning to the app the sessionStart parameter will be set to true. If, on the other hand, the phone call lasts 10 seconds, sessionStart will not be modified. By default, this is 30 seconds.
R1Emitter.getInstance().setSessionTimeout(30);
applicationUserID
Optional current user identifier.
R1Emitter.getInstance().setApplicationUserId("12345");
Next step: Event Tracking
View ArticleDebugging Tool
This tool allows you to verify that the events that you have set up are triggering correctly. You can access the debugging area of the portal to view the JSON events sent by your application.
Setup
To enable the debugging tool, you should create a flat file titled "r1DebugDevices" with a list of IDFA/AAID in "www" folder of your project. There should be one ID per line.
Once you build the app and install it on the same test devices that you added in the r1DebugDevices file, you should see any action taken in the app appear in the debug section of the portal.
Example
An example can be found in Demo. To run it, copy the files:
Demo/index.html to www/index.html
Demo/css/* to www/css
Demo/js/* to www/js
View ArticleWe've added a debugging tool that allows you to check whether the SDK is sending events to our servers.
This tool allows you to verify that the events that you have set up are triggering correctly. You can access the debugging area of the portal to view the JSON events sent by your application.
Setup
To enable the debugging tool, you should create a flat file titled "r1DebugDevices" with a list of GAID's (Google Advertising ID - the privacy compliant device identifier on each Android device)inside of the "assets" folder. There should be one ID per line in your file.
Once you build the app and install it on the same test devices that you added in the DebugDevices file you can see useage data from that device appear in real time. Go tothe "Data" tab under "SDK Tools" in the left navigation bar on the page. As you navigate the applicationyou should see JSON data display in the main window on the page.
View Article
a. Analytics Activation
i. Automatic Events
ii. Standard Events
iii. Custom Events
iv. In-App Webview Events
v. Best Practices
Analytics Activation
i. Automatic Events
The R1 Connect SDK will automatically capture some generic events in order to get the most meaningful data on how users interact with your application. These events are triggered when the state of the application is changed, and therefore do not require any additional code to work out of the box:
Launch - emitted when the app starts
First Launch - emitted when the app starts for the first time
First Launch After Update - emitted when the app starts for the first time after a version upgrade
Application Opened - emitted when your app is opened after a message is sent.
Session Start - emitted when a new session starts
Session End - emitted when a session ends; includes a Session Length attribute with the session length in seconds
ii. Standard Events
Standard Events cover all the main user flows (login, register, share, purchase...) in a standardized format for optimized reporting on the portal, providing a great foundation for your analytics strategy. They unlock great insights, particularly with respect to user lifetime value.
Note: The last argument in all of the following emitter callbacks, otherInfo, is a HashMap of key,value pairs or null, which enables you to customize these events as much as you want.
Login
Tracks a user login within the app
R1Emitter.getInstance().emitLogin("userId", "userName", parameters);
// where parameters is a HashMap. Example:
private HashMap<String, Object> parameters = new HashMap<String, Object>();
parameters.put("key","value");
Registration
Records a user registration within the app
R1Emitter.getInstance().emitRegistration("userId", "userName", "country", "city", "state", parameters);
// where parameters is a HashMap. Example:
private HashMap<String, Object> parameters = new HashMap<String, Object>();
parameters.put("key","value");
Facebook connect
Allows access to Facebook services
HashMap<String, Object> parameters = new HashMap<String, Object>();
parameters.put("custom_key","value");
R1Emitter.getInstance().emitFBConnect(socialPermissions, parameters);
where permissions is a List of R1SocialPermissions:
ArrayList<R1SocialPermission> socialPermissions = new ArrayList<R1SocialPermission>();
socialPermissions.add( new R1SocialPermission("permission", true));
Twitter connect
Allows access to Twitter services
HashMap<String, Object> parameters = new HashMap<String, Object>();
parameters.put("custom_key","value");
R1Emitter.getInstance().emitTConnect("userId", "username", socialPermissions, parameters);
where socialPermissions is a list of R1SocialPermissions:
ArrayList<R1SocialPermission> socialPermissions = new ArrayList<R1SocialPermission>();
socialPermissions.add( new R1SocialPermission("permission", true));
User Info
This event enables you to send user profiles to the backend.
UserItem userItem = new UserItem();
userItem.userId = "userId";
userItem.userName = "userName";
userItem.firstName = "firstName";
userItem.lastName = "lastName";
userItem.email = "[email protected]";
userItem.streetAddress = "address";
userItem.phone = "123456";
userItem.zip = "111111";
userItem.city = "City";
userItem.state = "State";
HashMap<String, Object> parameters = new HashMap<String, Object>();
parameters.put("custom_key","value");
R1Emitter.getInstance().emitUserInfo(userItem, parameters);
Upgrade
Tracks an application version upgrade
HashMap<String, Object> parameters = new HashMap<String, Object>();
parameters.put("custom_key","value");
R1Emitter.getInstance().emitUpgrade(parameters);
Trial Upgrade
Tracks an application upgrade from a trial version to a full version
HashMap<String, Object> parameters = new HashMap<String, Object>();
parameters.put("custom_key","value");
R1Emitter.getInstance().emitTrialUpgrade(parameters);
Screen View
Basically, a page view, it provides info about that screen
HashMap<String, Object> parameters = new HashMap<String, Object>();
parameters.put("custom_key","value");
R1Emitter.getInstance().emitAppScreen("title","description","http://www.example.com/path","example.com","path",parameters);
Transaction
EmitItem purchaseItem = new EmitItem();
purchaseItem.storeId = "storeId";
purchaseItem.storeName = "name";
purchaseItem.transactionId = "AE3237DAA";
purchaseItem.cartId = "ABBCCD";
purchaseItem.orderId = "ABCDEF";
purchaseItem.totalSale = 3.2f;
purchaseItem.currency = "EUR";
purchaseItem.shippingCosts = 1.8f;
purchaseItem.transactionTax = 2.5f;
HashMap<String, Object> parameters = new HashMap<String, Object>();
parameters.put("custom_key","value");
R1Emitter.getInstance().emitTransaction(purchaseItem, parameters);
TransactionItem
R1EmitterLineItem lineItem = new R1EmitterLineItem();
lineItem.productId = "productId";
lineItem.productName = "productName";
lineItem.quantity = 5;
lineItem.unitOfMeasure = "parts";
lineItem.msrPrice = 1.3f;
lineItem.pricePaid = 3.4f;
lineItem.currency = "EUR";
lineItem.itemCategory = "items";
HashMap<String, Object> parameters = new HashMap<String, Object>();
parameters.put("custom_key","value");
R1Emitter.getInstance().emitTransactionItem("transactionItemId", lineItem, parameters);
Create Cart
HashMap<String, Object> parameters = new HashMap<String, Object>();
parameters.put("custom_key","value");
R1Emitter.getInstance().emitCartCreate("cartId", parameters);
Delete Cart
HashMap<String, Object> parameters = new HashMap<String, Object>();
parameters.put("custom_key","value");
R1Emitter.getInstance().emitCartDelete("cartId", parameters);
Add To Cart
R1EmitterLineItem lineItem = new R1EmitterLineItem();
lineItem.productId = "productId";
lineItem.productName = "productName";
lineItem.quantity = 5;
lineItem.unitOfMeasure = "parts";
lineItem.msrPrice = 1.3f;
lineItem.pricePaid = 3.4f;
lineItem.currency = "EUR";
lineItem.itemCategory = "items";
HashMap<String, Object> parameters = new HashMap<String, Object>();
parameters.put("custom_key","value");
R1Emitter.getInstance().emitAddToCart("cartId", lineItem, parameters);
Delete From Cart
R1EmitterLineItem lineItem = new R1EmitterLineItem();
lineItem.productId = "productId";
lineItem.productName = "productName";
lineItem.quantity = 5;
lineItem.unitOfMeasure = "parts";
lineItem.msrPrice = 1.3f;
lineItem.pricePaid = 3.4f;
lineItem.currency = "EUR";
lineItem.itemCategory = "items";
HashMap<String, Object> parameters = new HashMap<String, Object>();
parameters.put("custom_key","value");
R1Emitter.getInstance().emitRemoveFromCart("cartId", lineItem, parameters);
iii. Custom Events
Custom events enable you to create and track specific events that are more closely aligned with your app. If planned and structured correctly, custom events can be strong indicators of user intent and behavior. Some examples include pressing the like button, playing a song, changing the screen mode from portrait to landscape, and zooming in or out of an image. These are all actions by the user that could be tracked with events.
To include tracking of custom events for the mobile app, the following callbacks need to be included in the application code:
// Emits a custom event without parameters
R1Emitter.getInstance().emitEvent("Your custom event name");
// Emits a custom event with parameters
private HashMap<String, Object> parameters = new HashMap<String, Object>();
parameters.put("key","value");
R1Emitter.getInstance().emitEvent("Your custom event name", parameters);
iv. In-App Webview Events
By setting up in-app webview events, you can track events that begin inside your native application but are completed in the embedded browser. To do so, you will have to embed some JavaScript in the page that you will want to fire the event, and you need to properly trigger the webview in your application.
JavaScript Setup
To properly fire the event from your webpage, please make the following call:
R1Connect.emitEvent(eventName,eventParameters);
For example, both of the following work. The use of parameters is optional.
R1Connect.emitEvent("Test Event");
R1Connect.emitEvent("Test Event",{"key":"value"});
Additionally, please attach the following r1connect.js file to your webpage:
var R1ConnectBridgePlatforms = {
UNKNOWN: 0,
IOS: 1,
ANDROID: 2
};
window.R1Connect = {
iosBridgeScheme: "r1connectbridge://",
platform: R1ConnectBridgePlatforms.UNKNOWN,
iosURLQueue: [],
iosInProgress: false,
buildIOSUrl: function(eventName, parameters) {
var url = this.iosBridgeScheme + 'emit/?event=' + eventName;
if (parameters)
url += '&params='+JSON.stringify(parameters);
return url;
},
sendURLInFrame: function(url) {
var iframe = document.createElement("IFRAME");
iframe.setAttribute("src", encodeURI(url));
document.documentElement.appendChild(iframe);
iframe.parentNode.removeChild(iframe);
iframe = null;
},
emitEvent: function(eventName, parameters) {
if (this.platform == R1ConnectBridgePlatforms.UNKNOWN) {
if (window.R1ConnectJSInterface && window.R1ConnectJSInterface.emit)
this.platform = R1ConnectBridgePlatforms.ANDROID;
else
this.platform = R1ConnectBridgePlatforms.IOS;
}
if (this.platform == R1ConnectBridgePlatforms.ANDROID) {
window.R1ConnectJSInterface.emit(eventName, parameters ? JSON.stringify(parameters) : '');
return;
}
var iosURL = this.buildIOSUrl(eventName, parameters);
if (this.iosInProgress) {
this.iosURLQueue.push(iosURL);
return;
}
this.iosInProgress = true;
this.sendURLInFrame(iosURL);
},
iosURLReceived: function() {
setTimeout(function() {
window.R1Connect._iosURLReceived();
}, 0);
},
_iosURLReceived: function() {
if (this.iosURLQueue.length == 0) {
this.iosInProgress = false;
return;
}
var iosURL = this.iosURLQueue.shift();
this.sendURLInFrame(iosURL);
},
};
Java Setup
To properly handle the events in your application, you need to first inject R1ConnectJSInterface from the R1Connect SDK:
import com.radiumone.emitter.javascript.R1ConnectJSInterface;
webView.addJavascriptInterface( new R1ConnectJSInterface(), "R1ConnectJSInterface");
You then need to enable javascript for the WebView:
WebSettings settings = webView.getSettings();
settings.setJavaScriptEnabled(true);
v. Best Practices
Event Naming Convention
One common mistake is to parametrize event names (with user data for example). Event names should be hard-coded values that you use to segement data on a specific category of event.
Example: "ProfileViewing"
Avoid: "Profile Viewing - Lady Gaga's profile"
As you may have thousands of user profiles in your database, it is preferable to keep the event name high level ("ProfileViewing") so you can run interesting anaytics on it. A high level event name will help answer a question like: How many profiles does a user visit every day on average?
Parameter Variance
Another common mistake is to add parameters to the event that have too many possible values. To follow up on the previous example, one may decide to add the number of profile followers as an event parameter:
HashMap<String, Object> parameters = new HashMap<String, Object>();
parameters.put("profileFollowers",profileFollowers);
R1Emitter.getInstance().emitEvent("ProfileViewing", parameters);
Again, the problem here is that each profile may have any number of followers. This will fragment data too much to extract any valuable information.
Instead, a good strategy would be to define relevant buckets that replace the need for high variance parameters. In this case it might be more relevant to separate traffic on the profiles with a lot of followers from traffic on profiles with a few followers. You could define 3 categories:
"VERY_INFLUENTIAL" for profiles > 100,000
"INFLUENTIAL" for profile > 10,000 and <= 100,000
"NON_INFLUENTIAL" for profile <= 10,000
In this case, a proper event could be:
HashMap<String, Object> parameters = new HashMap<String, Object>();
parameters.put("profileFollowersBucket","VERY_INFLUENTIAL");
R1Emitter.getInstance().emitEvent("ProfileViewing", parameters);
This will enable you to create more insightful reports.
vi. Debugging Tool
This tool allows you to verify that the events that you have set up are triggering correctly. You can access the debugging area of the portal to view the JSON events sent by your application.
Setup
To enable the debugging tool, you should create a flat file titled "r1DebugDevices" with a list of advertiser IDs inside of the "assets" folder. There should be one ID per line in your file.
Once you build the app and install it on the same test devices that you added in the DebugDevices file, you should see any action taken in the app appear in the debug section of the portal.
Next step: Push Notifications
View Article
As of January 2016 we no longer supportGPS versions lower than 6.5.
View ArticleAttribution Tracking Activation
We provide attribution tracking for free for all your campaigns, whether on or off the R1 DSP, through our partnership with Kochava. The integration is entirely server-side and requires no extra setup or work on your end. This service is a free add-on for our customers.
If you have another attribution tracking partner that you would prefer to use instead of Kochava, please contact your Account manager and we can work to enable these integrations based on demand from our clients.
i. Track RadiumOne Campaigns
Please contact your Account Manager to setup R1 ad campaign as well as tracking campaigns. If you don't have one, please contact us here and one of our Account Managers will assist you.
Once your Account Manager has set up tracking, you will start receiving attribution tracking report automatically!
ii. Track 3rd party Campaigns
Please contact your Account Manager to setup tracking URLs for your 3rd party campaigns. If you don't have one, please contact us here and one of our Account Managers will assist you.
Send the list of all your media suppliers (anyone you run a mobile advertising campaign with).
For each media supplier, your account manager will send you 2 tracking URLs (one impression tracking URL, 1 click tracking URL).
Send each pair of URLs to the relevant Media Supplier so they can set these tracking URLs on the creatives
You're all set and will start having access to Attribution Tracking Reports
View ArticleR1 Connect Library for WP
Overview
Downloading R1ConnectLibrary.dll allows you to begin the integration process of adding R1 Connect services to your app. It supports all mobile and tablet devices running Windows Phone 8. The file itself contains the dynamic link library (DLL) of the R1 Connect SDK for WP. The library supports the following architectures:
arm
x86
Setup
The following steps will explain how to integrate with R1 Connect to enable both push notifications and event tracking. You have the option to use the R1 Connect Demo as a sample app project to begin with or you can use your own app. Once you have downloaded the R1 Connect Library from this repo you can add it to the same directory as your project.
Required Libraries
R1 Connect SDK required protobuf-net.dll library. You can find it in folder with R1ConnectLibrary.dll
How to Add the R1 Connect files to Your Project
Open up your WP project or solution in Visual Studio.
Select PROJECT -> Add Reference...
In opened "Reference Manager" window press "Browse"
Select downloaded libraries R1ConnectLibrary.dll and protobuf-net.dll
Check Capabilities
Check your application Capabilities. For it
Open [Your project]->Properties->WMAppManifest.xml in Solution Explorer.
Select Capabilities tab
Check ID_CAP_NETWORKING, ID_CAP_IDENTITY_DEVICE, ID_CAP_LOCATION
Check ID_CAP_PUSH_NOTIFICATION if you want use R1 Connect Push
If its turned off, please turn on.
Using R1Connect SDK Namespace
You have two ways to execute SDK methods. You can write namespace directly with method, for example:
Radiumone.Connect.Emitter.Instance.EmitEvent("Your custom event name");
Or you can add to top of your current .cs file (where the method is invoked)
using Radiumone.Connect;
and then simple call SDK methods without namespace prefix:
Emitter.Instance.EmitEvent("Your custom event name");
In all examples below used first scheme.
Setting up your Application
You will need to initialize the R1 Connect Library in your App.xaml.cs. You can load R1Connect SDK configuration from xml file or configure it in source code.
Initialize from xml file
Create xml file and add it to your application project:
<?xml version="1.0" encoding="utf-8" ?>
<R1ConnectConfig>
<ApplicationId>[YOUR APPLICATION ID]</ApplicationId>
<ClientKey>[YOUR CLIENT KEY]</ClientKey>
<InProduction>false</InProduction>
<MPNSServiceName>[YOUR PUSH CHANNEL]</MPNSServiceName>
<MPNSChannelName>[YOUR SERVICE NAME]</MPNSChannelName>
<TileAllowedDomains>
<Domain>[TILES DOMAIN]</Domain>
</TileAllowedDomains>
</R1ConnectConfig>
Start R1 Connect in your application App.xaml.cs
private void Application_Launching(object sender, LaunchingEventArgs e)
{
// Start R1Connect SDK
var xmlConfig = Radiumone.Connect.Config.LoadFromFile("R1ConnectConfig.xml");
Radiumone.Connect.SDK.Instance.Start(config);
}
Initialize in source code
Start R1 Connect in your application App.xaml.cs
private void Application_Launching(object sender, LaunchingEventArgs e)
{
// Start R1Connect SDK
var config = new Radiumone.Connect.Config();
config.ApplicationId = "[YOUR APPLICATION ID]";
config.ClientKey = "[YOUR CLIENT KEY]";
config.MPNSChannelName = "[YOUR PUSH CHANNEL]";
config.MPNSServiceName = "[YOUR SERVICE NAME]";
config.TileAllowedDomains.Add(new Uri("[TILES DOMAIN]"));
#if DEBUG
config.InProduction = false;
#else
config.InProduction = true;
#endif
Radiumone.Connect.SDK.Instance.Start(config);
}
Push is disabled by default. You can enable it in the Application_Launching method or later.
Radiumone.Connect.Push.Instance.Enabled = true;
Emitter & Push Parameters
The following is a list of configuration parameters for the R1 Connect SDK, most of these contain values that are sent to the tracking server to help identify your app on our platform and to provide analytics on sessions and location.
Configuration Parameters
ApplicationUserId
Optional current user identifier.
Radiumone.Connect.SDK.Instance.ApplicationUserId = "12345";
LastCoordinate
The current user location coordinates. Use it only if your application already uses location services.
Radiumone.Connect.SDK.Instance.LastCoordinate = ;
LocationService
If your application did not use location information before this SDK installation, you can use LocationService in this SDK to enable or disable it:
Radiumone.Connect.SDK.Instance.LocationService.Enabled = true;
When enabled, such as in the example above, location information will be sent automatically. However, locationService doesnt fetch the location constantly. For instance, when the location is received the SDK will turn off the location service and wait 10 minutes (by default) before attempting to retrieve it again. You can change this value:
Radiumone.Connect.SDK.Instance.LocationService.AutoupdateTimeout = 1200; // 20 minutes
AppVersion
The application version associated with this emitter. By default, this property is populated with the App Version string from the WMAppManifest.xml. If you wish to override this property, you must do so before making any tracking calls.
Radiumone.Connect.Emitter.Instance.AppVersion = "1.0.2";
SessionStart
If true, indicates the start of a new session. Note that when a emitter is first instantiated, this is initialized to true. To prevent this default behavior, set this to false when the tracker is first obtained.
By itself, setting this does not send any data. If this is true, when the next emitter call is made, a parameter will be added to the resulting emitter information indicating that it is the start of a session, and this flag will be cleared.
Radiumone.Connect.Emitter.Instance.SessionStart = true;
// Your code here
Radiumone.Connect.Emitter.Instance.SessionStart = false;
SessionTimeout
If non-negative, indicates how long, in seconds, the application must transition to the inactive or background state for before the tracker will automatically indicate the start of a new session when the app becomes active again by setting sessionStart to true. For example, if this is set to 30 seconds, and the user receives a phone call that lasts for 45 seconds while using the app, upon returning to the app, the sessionStart parameter will be set to true. If the phone call instead lasted 10 seconds, sessionStart will not be modified.
To disable automatic session tracking, set this to a negative value. To indicate the start of a session anytime the app becomes inactive or backgrounded, set this to zero.
By default, this is 30 seconds.
Radiumone.Connect.Emitter.Instance.SessionTimeout = 15;
View Article
The R1 Connect SDK will automatically capture some generic events, but in order to get the most meaningful data on how users interact with your app the SDK also offers pre-built user-defined events for popular user actions as well as the ability to create your own custom events.
State Events
Some events are emitted automatically when the state of the application is changed by the OS and, therefore, they do not require any additional code to be written in the app in order to work out of the box:
Launch - emitted when the app starts
First Launch - emitted when the app starts for the first time
First Launch After Update - emitted when the app starts for the first time after a version upgrade
Suspend - emitted when the app is put into the background state
Resume - emitted when the app returns from the background state
Pre-Defined Events
Pre-Defined Events are also helpful in measuring certain metrics within the apps and do not require further developer input to function. These particular events below are used to help measure app open events and track Sessions.
Application Opened - This event is very useful for push notifications and can measure when your app is opened after a message is sent.
Session Start - As the name implies the Session Start event is used to start a session.
Session End - The Session End event is used to end a session and passes with it a Session Length attribute that calculates the session length in seconds.
User-Defined Events
User-Defined Events are not sent automatically so it is up to you if you want to use them or not. They can provide some great insights on popular user actions if you decide to track them. In order to set this up the application code needs to include the emitter callbacks in order to emit these events.
Note: The last argument in all of the following emitter methods, otherInfo, is an optional dictionary of key,value pairs or null
Login
Tracks a user login within the app
var otherInfo = new Dictionary<string, object>();
otherInfo.Add("custom_key", "value");
Radiumone.Connect.Emitter.Instance.EmitLogin("userId", "user_name", otherInfo);
User Info
Records an user information
var userInfo = new Radiumone.Connect.EmitterInfo.UserInfo();
userInfo.UserID = "userID";
userInfo.UserName = "userName";
userInfo.Email = "email";
userInfo.FirstName = "firstName";
userInfo.LastName = "lastName";
userInfo.City = "city";
userInfo.Phone = "phone";
userInfo.State = "state";
userInfo.StreetAddress = "streetAddress";
userInfo.Zip = "zip";
var otherInfo = new Dictionary<string, object>();
otherInfo.Add("custom_key", "value");
Radiumone.Connect.Emitter.Instance.EmitUserInfo(userInfo, otherInfo);
Registration
Records a user registration within the app
var otherInfo = new Dictionary<string, object>();
otherInfo.Add("custom_key", "value");
Radiumone.Connect.Emitter.Instance.EmitRegistration("userId", "userName", "country", "state", "city", otherInfo);
Facebook connect
Allows access to Facebook services
var socialPermissions = new List<Radiumone.Connect.EmitterInfo.SocialPermission>();
socialPermissions.Add(new Radiumone.Connect.EmitterInfo.SocialPermission("photos", YES));
var otherInfo = new Dictionary<string, object>();
otherInfo.Add("custom_key", "value");
Radiumone.Connect.Emitter.Instance.EmitFBConnect(socialPermissions, otherInfo);
Twitter connect
Allows access to Twitter services
var socialPermissions = new List<Radiumone.Connect.EmitterInfo.SocialPermission>();
socialPermissions.Add(new Radiumone.Connect.EmitterInfo.SocialPermission("photos", YES));
var otherInfo = new Dictionary<string, object>();
otherInfo.Add("custom_key", "value");
Radiumone.Connect.Emitter.Instance.EmitTConnect("12345", "user_name", socialPermissions, otherInfo);
Upgrade
Tracks an application version upgrade
var otherInfo = new Dictionary<string, object>();
otherInfo.Add("custom_key", "value");
Radiumone.Connect.Emitter.Instance.EmitUpgrade(otherInfo);
Trial Upgrade
Tracks an application upgrade from a trial version to a full version
var otherInfo = new Dictionary<string, object>();
otherInfo.Add("custom_key", "value");
Radiumone.Connect.Emitter.Instance.EmitTrialUpgrade(otherInfo);
Screen View
Basically, a page view, it provides info about that screen
var otherInfo = new Dictionary<string, object>();
otherInfo.Add("custom_key", "value");
Radiumone.Connect.Emitter.Instance.EmitScreenView("title",
"description",
"http://www.example.com/path",
"example.com",
"path",
otherInfo);
E-Commerce Events
Transaction
var otherInfo = new Dictionary<string, object>();
otherInfo.Add("custom_key", "value");
Radiumone.Connect.Emitter.Instance.EmitTransaction("transaction_id", "store_id", "store_name", "cart_id", "order_id", 1.5, "USD", 10.5, 12.0, otherInfo);
TransactionItem
var lineItem = new Radiumone.Connect.EmitterInfo.LineItem();
lineItem.ProductID = "product_id";
lineItem.ProductName = "product_name";
lineItem.Quantity = 5;
lineItem.UnitOfMeasure = "unit";
lineItem.MsrPrice = 10;
lineItem.PricePaid = 10;
lineItem.Currency = "USD";
lineItem.ItemCategory = "category";
var otherInfo = new Dictionary<string, object>();
otherInfo.Add("custom_key", "value");
Radiumone.Connect.Emitter.Instance.EmitTransactionItem("transaction_id", lineItem, otherInfo);
Create Cart
var otherInfo = new Dictionary<string, object>();
otherInfo.Add("custom_key", "value");
Radiumone.Connect.Emitter.Instance.EmitCartCreate("cart_id", otherInfo);
Delete Cart
var otherInfo = new Dictionary<string, object>();
otherInfo.Add("custom_key", "value");
Radiumone.Connect.Emitter.Instance.EmitCartDelete("cart_id", otherInfo);
Add To Cart
var lineItem = new Radiumone.Connect.EmitterInfo.LineItem();
lineItem.ProductID = "product_id";
lineItem.ProductName = "product_name";
lineItem.Quantity = 5;
lineItem.UnitOfMeasure = "unit";
lineItem.MsrPrice = 10;
lineItem.PricePaid = 10;
lineItem.Currency = "USD";
lineItem.ItemCategory = "category";
var otherInfo = new Dictionary<string, object>();
otherInfo.Add("custom_key", "value");
Radiumone.Connect.Emitter.Instance.EmitAddToCart("cart_id", lineItem, otherInfo);
Delete From Cart
var lineItem = new Radiumone.Connect.EmitterInfo.LineItem();
lineItem.ProductID = "product_id";
lineItem.ProductName = "product_name";
lineItem.Quantity = 5;
lineItem.UnitOfMeasure = "unit";
lineItem.MsrPrice = 10;
lineItem.PricePaid = 10;
lineItem.Currency = "USD";
lineItem.ItemCategory = "category";
var otherInfo = new Dictionary<string, object>();
otherInfo.Add("custom_key", "value");
Radiumone.Connect.Emitter.Instance.EmitDeleteFromCart("cart_id", lineItem, otherInfo);
Custom Events
With custom events you have the ability to create and track specific events that are more closely aligned with your app. If planned and structured correctly, custom events can be strong indicators of user intent and behavior. Some examples include pressing the like button, playing a song, changing the screen mode from portrait to landscape, and zooming in or out of an image. These are all actions by the user that could be tracked with events.
To include tracking of custom events for the mobile app, the following callbacks need to be included in the application code:
// Emits a custom event without parameters
Radiumone.Connect.Emitter.Instance.EmitEvent("Your custom event name");
Or
// Emits a custom event with parameters
var otherInfo = new Dictionary<string, object>();
otherInfo.Add("custom_key", "value");
Radiumone.Connect.Emitter.Instance.EmitEvent("Your custom event name", otherInfo);
View Article
Analytics Activation
i. Automatic Events
ii. Standard Events
iii. Custom Events
iv. In-App Webview Events
v. Best Practices
a. Analytics Activation Setup your App Delegate
(Only for Objective C code)
#import "R1SDK.h"
#import "R1Emitter.h"
#import "R1Push.h"
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
R1SDK *sdk = [R1SDK sharedInstance];
// Initialize Analytics
sdk.applicationId = @"YOUR APPLICATION ID"; //Ask your RadiumOne contact for an app id
// Start SDK
[sdk start];
return YES;
}
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
let sdk = R1SDK.sharedInstance();
// Initialize Anlaytics
sdk.applicationId = "YOUR APPLICATION ID";
// Start SDK
sdk.start();
return true
}
i. Automatic Events
The R1 Connect SDK will automatically capture some generic events in order to get the most meaningful data on how users interact with your app. These events are triggered when the state of the application is changed, and therefore do not require any additional code to work out of the box:
Launch - emitted when the app starts
First Launch - emitted when the app starts for the first time
First Launch After Update - emitted when the app starts for the first time after a version upgrade
Suspend - emitted when the app is put into the background state
Resume - emitted when the app returns from the background state
Application Opened - emitted when the app is opened and can measure when your app is opened after a message is sent
Session Start - emitted when a new session begins
Session End - emitted when a session ends; includes a Session Length attribute with the session length in seconds.
ii. Standard Events
Standard events cover all the main user flows (login, register, share, purchase...) in a standardized format for optimized reporting on the portal, providing a great foundation to your analytics strategy. Once you set them up in your code, they unlock great insights, particularly on user lifetime value.
Note: The last argument in all of the following emitter callbacks, otherInfo, is a dictionary of key,value pairs or nil, which enables you to customize these events as much as you want.
Login
Tracks a user login within the app
[[R1Emitter sharedInstance] emitLoginWithUserID:@"userId"
userName:@"user_name"
otherInfo:@{@"custom_key":@"value"}];
R1Emitter.sharedInstance()
.emitLoginWithUserID("userId", userName: "user_name", otherInfo: ["custom_key": "value"]);
Registration
Records a user registration within the app
[[R1Emitter sharedInstance] emitRegistrationWithUserID:@"userId"
userName:@"userName"
country:@"country"
state:@"state"
city:@"city"
otherInfo:@{@"custom_key":@"value"}];
R1Emitter.sharedInstance()
.emitRegistrationWithUserID("userId", userName: "userName", country: "country", state: "state", city: "city", otherInfo: ["custom_key": "value"]);
Facebook connect
Allows access to Facebook services
NSArray *permissions = @[[R1EmitterSocialPermission socialPermissionWithName:@"photos" granted:YES]];
[[R1Emitter sharedInstance] emitFBConnectWithPermissions:permissions
otherInfo:@{@"custom_key":@"value"}];
let permissions = [R1EmitterSocialPermission.init(name: "photos", granted: true)];
R1Emitter.sharedInstance()
.emitFBConnectWithPermissions(permissions, otherInfo: ["custom_key": "value"]);
Twitter connect
Allows access to Twitter services
NSArray *permissions = @[[R1EmitterSocialPermission socialPermissionWithName:@"photos" granted:YES]];
[[R1Emitter sharedInstance] emitTConnectWithUserID:@"12345"
userName:@"user_name"
permissions:permissions
otherInfo:@{@"custom_key":@"value"}];
let permissions = [R1EmitterSocialPermission.init(name: "photos", granted: true)];
R1Emitter.sharedInstance()
.emitTConnectWithUserID("12345", userName: "user_name", permissions: permissions, otherInfo: ["custom_key": "value"]);
User Info
Enables you to send user profiles to the backend.
R1EmitterUserInfo *userInfo = [R1EmitterUserInfo userInfoWithUserID:@"userId"
userName:@"userName"
email:@"[email protected]"
firstName:@"first name"
lastName:@"last name"
streetAddress:@"streetAddress"
phone:@"phone"
city:@"city"
state:@"state"
zip:@"zip"];
[[R1Emitter sharedInstance] emitUserInfo:userInfo
otherInfo:@{@"custom_key":@"value"}];
let userInfo = R1EmitterUserInfo.init(userID: "userID", userName: "userName", email: "email", firstName: "firstName", lastName: "lastName", streetAddress: "streetAddress", phone: "phone", city: "city", state: "state", zip: "zip");
R1Emitter.sharedInstance().emitUserInfo(userInfo, otherInfo: ["custom_key": "value"]);
Upgrade
Tracks an application version upgrade
[[R1Emitter sharedInstance] emitUpgradeWithOtherInfo:@{@"custom_key":@"value"}];
R1Emitter.sharedInstance()
.emitUpgradeWithOtherInfo(["custom_key": "value"]);
Trial Upgrade
Tracks an application upgrade from a trial version to a full version
[[R1Emitter sharedInstance] emitTrialUpgradeWithOtherInfo:@{@"custom_key":@"value"}];
R1Emitter.sharedInstance()
.emitTrialUpgradeWithOtherInfo(["custom_key": "value"]);
Screen View
A page view that provides info about that screen
[[R1Emitter sharedInstance] emitScreenViewWithDocumentTitle:@"title"
contentDescription:@"description"
documentLocationUrl:@"http://www.example.com/path"
documentHostName:@"example.com"
documentPath:@"path"
otherInfo:@{@"custom_key":@"value"}];
R1Emitter.sharedInstance()
.emitScreenViewWithDocumentTitle("title", contentDescription: "description", documentLocationUrl: "http://www.example.com/path", documentHostName: "example.com", documentPath: "path", otherInfo:["custom_key": "value"]);
Transaction
[[R1Emitter sharedInstance] emitTransactionWithID:@"transaction_id"
storeID:@"store_id"
storeName:@"store_name"
cartID:@"cart_id"
orderID:@"order_id"
totalSale:1.5
currency:@"USD"
shippingCosts:10.5
transactionTax:12.0
otherInfo:@{@"custom_key":@"value"}];
R1Emitter.sharedInstance()
.emitTransactionWithID("transaction_id", storeID: "store_id", storeName: "store_name", cartID: "cart_id", orderID: "order_id", totalSale: 1.5, currency: "USD", shippingCosts: 10.5, transactionTax: 12.0, otherInfo:["custom_key": "value"]);
TransactionItem
R1EmitterLineItem *lineItem = [R1EmitterLineItem itemWithID:@"product_id"
name:@"product_name"
quantity:5
unitOfMeasure:@"unit"
msrPrice:10
pricePaid:10
currency:@"USD"
itemCategory:@"category"];
[[R1Emitter sharedInstance] emitTransactionItemWithTransactionID:@"transaction_id"
lineItem:lineItem
otherInfo:@{@"custom_key":@"value"}];
let lineItem = R1EmitterLineItem.init(
ID: "product_id",
name: "product_name",
quantity: 5,
unitOfMeasure: "unit",
msrPrice: 10,
pricePaid: 10,
currency: "USD",
itemCategory: "category");
R1Emitter.sharedInstance()
.emitTransactionItemWithTransactionID("transaction_id", lineItem: lineItem, otherInfo: ["custom_key": "value"]);
Create Cart
[[R1Emitter sharedInstance] emitCartCreateWithCartID:@"cart_id"
otherInfo:@{@"custom_key":@"value"}];
R1Emitter.sharedInstance()
.emitCartCreateWithCartID("cart_id", otherInfo: ["custom_key": "value"]);
Delete Cart
[[R1Emitter sharedInstance] emitCartDeleteWithCartID:@"cart_id"
otherInfo:@{@"custom_key":@"value"}];
R1Emitter.sharedInstance()
.emitCartDeleteWithCartID("cart_id", otherInfo: ["custom_key": "value"]);
Add To Cart
R1EmitterLineItem *lineItem = [R1EmitterLineItem itemWithID:@"product_id"
name:@"product_name"
quantity:5
unitOfMeasure:@"unit"
msrPrice:10
pricePaid:10
currency:@"USD"
itemCategory:@"category"];
[[R1Emitter sharedInstance] emitAddToCartWithCartID:@"cart_id"
lineItem:lineItem
otherInfo:@{@"custom_key":@"value"}];
let lineItem = R1EmitterLineItem.init(
ID: "product_id",
name: "product_name",
quantity: 5,
unitOfMeasure: "unit",
msrPrice: 10,
pricePaid: 10,
currency: "USD",
itemCategory: "category");
R1Emitter.sharedInstance()
.emitAddToCartWithCartID("cart_id", lineItem: lineItem, otherInfo: ["custom_key": "value"]);
Delete From Cart
R1EmitterLineItem *lineItem = [R1EmitterLineItem itemWithID:@"product_id"
name:@"product_name"
quantity:5
unitOfMeasure:@"unit"
msrPrice:10
pricePaid:10
currency:@"USD"
itemCategory:@"category"];
[[R1Emitter sharedInstance] emitDeleteFromCartWithCartID:@"cart_id"
lineItem:lineItem
otherInfo:@{@"custom_key":@"value"}];
let lineItem = R1EmitterLineItem.init(
ID: "product_id",
name: "product_name",
quantity: 5,
unitOfMeasure: "unit",
msrPrice: 10,
pricePaid: 10,
currency: "USD",
itemCategory: "category");
R1Emitter.sharedInstance()
.emitDeleteFromCartWithCartID("cart_id", lineItem: lineItem, otherInfo: ["custom_key": "value"]);
iii. Custom Events
Custom events allow you to create and track specific events that are more closely aligned with your app. If planned and structured correctly, custom events can be strong indicators of user intent and behavior. Some examples include pressing the like button, playing a song, changing the screen mode from portrait to landscape, and zooming in or out of an image. These are all actions by the user that could be tracked with events.
To include tracking of custom events for the mobile app, the following callbacks need to be included in the application code:
// Emits a custom event without parameters
[[R1Emitter sharedInstance] emitEvent:@"Your custom event name"];
// Emits a custom event with parameters
[[R1Emitter sharedInstance] emitEvent:@"Your custom event name"
withParameters:@{@"key":@"value"}];
// Emits a custom event without parameters
R1Emitter.sharedInstance().emitEvent("Your custom event name");
// Emits a custom event with parameters
R1Emitter.sharedInstance().emitEvent("Your custom event name", withParameters: ["key": "value"]);
iv. In-App Webview Events
By setting up in-app webview events, you can track events that begin inside your native application but are completed in the embedded browser. To do so, you will have to embed some JavaScript in the page that you will want to fire the event, and you need to properly trigger the webview in your application.
JavaScript Setup
To properly fire the event from your webpage, please make the following call:
R1Connect.emitEvent(eventName,eventParameters);
For example, both of the following work. The use of parameters is optional.
R1Connect.emitEvent("Test Event");
R1Connect.emitEvent("Test Event",{"key":"value"});
Additionally, please attach the following r1connect.js file to your webpage:
var R1ConnectBridgePlatforms = {
UNKNOWN: 0,
IOS: 1,
ANDROID: 2
};
window.R1Connect = {
iosBridgeScheme: "r1connectbridge://",
platform: R1ConnectBridgePlatforms.UNKNOWN,
iosURLQueue: [],
iosInProgress: false,
buildIOSUrl: function(eventName, parameters) {
var url = this.iosBridgeScheme + 'emit/?event=' + eventName;
if (parameters)
url += '&params='+JSON.stringify(parameters);
return url;
},
sendURLInFrame: function(url) {
var iframe = document.createElement("IFRAME");
iframe.setAttribute("src", encodeURI(url));
document.documentElement.appendChild(iframe);
iframe.parentNode.removeChild(iframe);
iframe = null;
},
emitEvent: function(eventName, parameters) {
if (this.platform == R1ConnectBridgePlatforms.UNKNOWN) {
if (window.R1ConnectJSInterface && window.R1ConnectJSInterface.emit)
this.platform = R1ConnectBridgePlatforms.ANDROID;
else
this.platform = R1ConnectBridgePlatforms.IOS;
}
if (this.platform == R1ConnectBridgePlatforms.ANDROID) {
window.R1ConnectJSInterface.emit(eventName, parameters ? JSON.stringify(parameters) : '');
return;
}
var iosURL = this.buildIOSUrl(eventName, parameters);
if (this.iosInProgress) {
this.iosURLQueue.push(iosURL);
return;
}
this.iosInProgress = true;
this.sendURLInFrame(iosURL);
},
iosURLReceived: function() {
setTimeout(function() {
window.R1Connect._iosURLReceived();
}, 0);
},
_iosURLReceived: function() {
if (this.iosURLQueue.length == 0) {
this.iosInProgress = false;
return;
}
var iosURL = this.iosURLQueue.shift();
this.sendURLInFrame(iosURL);
},
};
To properly handle the events in your application, you first need to import the R1WebViewHelper header file in your ViewController .m implementation file:
(Only for Objective C code)
#import "R1WebViewHelper.h"
You then should setup the UIWebView delegate from the Interface Builder or from code:
- (void) viewDidLoad {
[super viewDidLoad];
self.webView.delegate = self;
// Your code here
}
override func viewDidLoad() {
super.viewDidLoad();
webView?.delegate = self;
// Your code here
}
Finally, add the delegate method implementation:
-(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { if (![R1WebViewHelper webView:webView shouldStartLoadWithRequest:request navigationType:navigationType]) return NO; // Your code here return YES; }
func webView(webView: UIWebView, shouldStartLoadWithRequest request: NSURLRequest, navigationType: UIWebViewNavigationType) -> Bool {
if R1WebViewHelper.webView(webView, shouldStartLoadWithRequest: request, navigationType: navigationType) {
return false;
}
// Your code here
return true;
}
v. Best Practices
Event Naming Convention
One common mistake is to parametrize event names (with user data for example). Event names should be hard-coded values that you use to segement data on a specific category of event.
Example: "ProfileViewing"
Avoid: "Profile Viewing - Lady Gaga's profile"
As you may have thousands of user profiles in your database, it is preferable to keep the event name high level ("ProfileViewing") so you can run interesting anaytics on it. High level events help answer questions like "how many profiles does a user visit every day on average?"
Parameter Variance
Another common mistake is to add parameters to the event that have too many possible values. To follow up on the previous example, one may decide to add the number of profile followers as an event parameter:
[[R1Emitter sharedInstance] emitEvent:@"ProfileViewing"
withParameters:@{@"profileFollowers":profileFollowers}];
R1Emitter.sharedInstance()
.emitEvent("ProfileViewing", withParameters: ["profileFollowers": profileFollowers]);
Again, the problem here is that each profile may have any number of followers. This will fragment your data too much to extract any valuable information.
A good strategy would be to define relevant buckets for high variance parameters. In this case, it might be more relevant to separate traffic on the profiles with a lot of followers from traffic on profiles with very few followers. You could define 3 categories:
"VERY_INFLUENTIAL" for profiles > 100,000
"INFLUENTIAL" for profile > 10,000 and <= 100,000
"NON_INFLUENTIAL" for profile <= 10,000
A proper event could be
[[R1Emitter sharedInstance] emitEvent:@"ProfileViewing"
withParameters:@{@"profileFollowersBucket":@"VERY_INFLUENTIAL"}];
R1Emitter.sharedInstance()
.emitEvent("ProfileViewing", withParameters: ["profileFollowersBucket": "VERY_INFLUENTIAL"]);
This will enable you to create more insightful reports.
View ArticleThe R1 Connect SDK will automatically capture some generic events, but in order to get the most meaningful data on how users interact with your app the SDK also offers pre-built user-defined events for popular user actions as well as the ability to create your own custom events.
Automatically tracked events:
Some events are emitted automatically when the state of the application is changed by the OS and, therefore, they do not require any additional code to be written in the app in order to work out of the box:
Launch - emitted when the app starts
First Launch - emitted when the app starts for the first time
First Launch After Update - emitted when the app starts for the first time after a version upgrade
Suspend - emitted when the app is put into the background state
Resume - emitted when the app returns from the background state
Pre-Defined Events
Pre-Defined Events are also helpful in measuring certain metrics within the apps and do not require further developer input to function. These particular events below are used to help measure app open events and track Sessions.
Application Opened - This event is very useful for push notifications and can measure when your app is opened after a message is sent.
Session Start - As the name implies the Session Start event is used to start a new session.
Session End - The Session End event is used to end a session and passes with it a Session Length attribute that calculates the session length in seconds.
User-Defined Events
User-Defined Events are not sent automatically so it is up to you if you want to use them or not. They can provide some great insights on popular user actions if you decide to track them. In order to set this up the application code needs to include the emitter callbacks in order to emit these events.
Note: The last argument in all of the following emitter callbacks, otherInfo, is a dictionary of key,value pairs or nil
User Info
This event enables you to send user profiles to the backend.
var userInfo = {"userID":"userId", "userName":"userName", "email":"email",
"firstName":"firstName", "lastName":"lastName",
"streetAddress":"streetAddress", "phone":"phone",
"city":"city", "state":"state", "zip":"zip"};
R1Emitter.emitUserInfo(userInfo, {"custom_key":"value"});
Login
Tracks a user login within the app
R1Emitter.emitLogin("userId", "user_name", {"custom_key":"value"});
Registration
Records a user registration within the app
R1Emitter.emitRegistration("userId", "userName", "country", "state", "city", {"custom_key":"value"});
Facebook connect
Allows access to Facebook services
R1Emitter.emitFBConnect([{name:"photos", granted:true}], {"custom_key":"value"});
Twitter connect
Allows access to Twitter services
R1Emitter.emitTConnect("12345", "user_name", [{name:"photos", granted:true}], {"custom_key":"value"});
Upgrade
Tracks an application version upgrade
R1Emitter.emitUpgrade({"custom_key":"value"});
Trial Upgrade
Tracks an application upgrade from a trial version to a full version
R1Emitter.emitTrialUpgrade({"custom_key":"value"});
Screen View
Basically, a page view, it provides info about that screen
R1Emitter.emitScreenView("title", "description", "http://www.example.com/path", "example.com", "path", {"custom_key":"value"});
E-Commerce Events
Transaction
R1Emitter.emitTransaction("transaction_id", "store_id", "store_name", "cart_id", "order_id", 1.5, "USD", 10.5, 12.0, {"custom_key":"value"});
TransactionItem
var lineItem = {productID:"product_id", productName:"product_name", quantity:5, unitOfMeasure:"unit", msrPrice:10, pricePaid:10, currency:"USD", itemCategory:"category"};
R1Emitter.emitTransactionItem("transaction_id", lineItem, {"custom_key":"value"});
Create Cart
R1Emitter.emitCartCreate("cart_id", {"custom_key":"value"});
Delete Cart
R1Emitter.emitCartDelete("cart_id", {"custom_key":"value"});
Add To Cart
var lineItem = {productID:"product_id", productName:"product_name", quantity:5, unitOfMeasure:"unit", msrPrice:10, pricePaid:10, currency:"USD", itemCategory:"category"};
R1Emitter.emitAddToCart("cart_id", lineItem, {"custom_key":"value"});
Delete From Cart
var lineItem = {productID:"product_id", productName:"product_name", quantity:5, unitOfMeasure:"unit", msrPrice:10, pricePaid:10, currency:"USD", itemCategory:"category"};
R1Emitter.emitDeleteFromCart("cart_id", lineItem, {"custom_key":"value"});
Custom Events
With custom events you have the ability to create and track specific events that are more closely aligned with your app. If planned and structured correctly, custom events can be strong indicators of user intent and behavior. Some examples include pressing the like button, playing a song, changing the screen mode from portrait to landscape, and zooming in or out of an image. These are all actions by the user that could be tracked with events.
To include tracking of custom events for the mobile app, the following callbacks need to be included in the application code:
// Emits a custom event without parameters
R1Emitter.emitEvent("Your custom event name");
// Emits a custom event with parameters
R1Emitter.emitEvent("Your custom event name", {"key":"value"});
View ArticleisStarted
Callback arguments: (bool isStarted)
Indicates whether the SDK is started. The SDK started automatically if you setted up config.xml.
R1SDK.isStarted(function (isStarted) {
//...
});
setApplicationUserId
Set optional current user identifier.
R1SDK.setApplicationUserId("Your application user id");
getApplicationUserId
Callback arguments: (string applicationUserId)
Get last setted application user identifier.
R1SDK.getApplicationUserId(function (applicationUserId) {
//...
});
setGeofencingEnabled
Enable or disable the Geofencing service in the SDK.
R1SDK.setGeofencingEnabled(true);
isGeofencingEnabled
Callback arguments: (bool isGeofencingEnabled)
Indicates whether Geofencing service is enabled.
R1SDK.isGeofencingEnabled(function (isGeofencingEnabled) {
//...
});
setEngageEnabled
Enable or disable the Engage in the SDK.
R1SDK.setEngageEnabled(true);
isEngageEnabled
Callback arguments: (bool isEngageEnabled)
Indicates whether Engage is enabled.
R1SDK.isEngageEnabled(function (isEngageEnabled) {
//...
});
R1LocationService
setEnabled
Enable or disable the location service for giving location in the SDK.
R1LocationService.setEnabled(true);
isEnabled
Callback arguments: (bool isEnabled)
Indicates whether R1LocationService is enabled.
R1LocationService.isEnabled(function (isEnabled) {
//...
});
setAutoupdateTimeout
When location service is enabled location information will be sent automatically. However, locationService doesnt fetch the location constantly. For instance, when the location is received the SDK will turn off the location in CLLocationManager and wait 10 minutes (by default) before attempting to retrieve it again. You can change this value.
R1LocationService.setAutoupdateTimeout(1200); // 20 minutes
getAutoupdateTimeout
Callback arguments: (float autoupdateTimeout)
Get currently used autoupdate timeout.
R1LocationService.getAutoupdateTimeout(function (autoupdateTimeout) {
//...
});
getState
Callback arguments: (string state)
Get current state of R1LocationService.
R1LocationService.getState(function (state) {
//...
});
Possible state values:
"Disabled"
"Off"
"Searching"
"Has Location"
"Wait Next Update"
getCoordinate
Callback arguments: (object coordinate)
Get currently used user coordinate.
R1LocationService.getCoordinate(function (coordinate) {
if (coordinate == null)
{
// Location not received yet
}else
{
// coordinate.latitude
// coordinate.longitude
}
//...
});
updateNow
If R1LocationService is in "Wait Next Update" state, you can update the location manually.
R1LocationService.updateNow();
Events
R1LocationService.state
Notify the location service state has changed
document.addEventListener("R1LocationService.state", function(event) {
// event.state
}, false);
R1LocationService.coordinate
Notify the location service coordinate has changed
document.addEventListener("R1LocationService.coordinate", function(event) {
// event.latitude, event.longitude
}, false);
R1Emitter
isStarted
Callback arguments: (bool isStarted)
Indicates whether the Emitter has started. The Emitter starts automatically if you set the upcom.radiumone.r1connect.applicationId key in config.xml.
R1Emitter.isStarted(function (isStarted) {
//...
});
setAppName
The application name associated with this emitter. By default, this property is populated with the CFBundleName string from the application bundle. If you wish to override this property, you must do so before making any tracking calls.
R1Emitter.setAppName("Custom application name");
getAppName
Callback arguments: (string appName)
Get last setted application name or CFBundleName by default.
R1Emitter.getAppName(function (appName) {
//...
});
setAppId
The application identifier associated with this emitter. If you wish to set this property, you must do so before making any tracking calls. Note: that this is not your app's bundle id, like e.g. com.example.appname.
R1Emitter.setAppId("12345678");
getAppId
Callback arguments: (string appId)
Get last setted app id.
R1Emitter.getAppId(function (appId) {
//...
});
setAppVersion
The application version associated with this emitter. By default, this property is populated with theCFBundleShortVersionString string from the application bundle. If you wish to override this property, you must do so before making any tracking calls.
R1Emitter.setAppId("12345678");
getAppVersion
Callback arguments: (string appVersion)
Get last setted app version or CFBundleShortVersionString string from the application bundle.
R1Emitter.getAppVersion(function (appVersion) {
//...
});
setSessionTimeout
Indicates how long, in seconds, the application must transition to the inactive or background state for before the tracker will automatically indicate the start of a new session when the app becomes active again by setting sessionStart to true. For example, if this is set to 30 seconds, and the user receives a phone call that lasts for 45 seconds while using the app, upon returning to the app, the sessionStart parameter will be set to true. If the phone call instead lasted 10 seconds, sessionStart will not be modified.
By default, this is 30 seconds.
R1Emitter.setSessionTimeout(15); // 15 seconds
getSessionTimeout
Callback arguments: (float sessionTimeout)
Get last setted session timeout or default value
R1Emitter.getSessionTimeout(function (sessionTimeout) {
//...
});
View ArticleR1Connect PhoneGap/Cordova Plugin
Platform Support
This plugin supports PhoneGap/Cordova apps running on iOS, Android and Windows Phone 8.
Version Requirements
This plugin is meant to work with PhoneGap 3.x - 4.x. For PhoneGap 5.x+ use branch cordova5
Installation
Overview
This integration doc assumes you have already set up Google Play Services in your application project for android, which is needed to use Google Cloud Messaging (GCM), the notification gateway R1 Connect utilizes. Also you will need to have created the app you will be using in R1 Connect.
In order to use R1 Connect with your application you will need a project number (sender ID) and API key from Google. Please visit GCM Getting Started here and create a google project and an API key.
If you do not want to use Push on android you can skip Google Play Services setup (but we recommend not skip this setup);
Automatic Installation using PhoneGap/Cordova CLI (iOS, Android and WP8)
Install this plugin using PhoneGap/Cordova cli:
cordova plugin add https://github.com/radiumone/r1-connect-demo-phonegap
Modify the www/config.xml ( res/xml/config.xml for android ) directory to contain (replacing with your configuration settings) : Required (for Emitter only):
If you want to use Push on all platforms:
<preference name="com.radiumone.r1connect.clientKey" value="Your client Key" />
If you want to use Push on Android:
<preference name="com.radiumone.r1connect.senderId" value="Your GCM sender id" />
If you want to use Push on WP8:
<preference name="com.radiumone.r1connect.MPNSServiceName" value="[YOUR SERVICE NAME]" />
<preference name="com.radiumone.r1connect.MPNSChannelName" value="[YOUR PUSH CHANNEL]" />
<preference name="com.radiumone.r1connect.TileAllowedDomains" value="[TILE DOMAIN 1], [TILE DOMAIN 2]" />
If you have set up Google Play Services add this line
<meta-data
android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version" />
If you want to disable sending all advertising ids to the server add this line
<preference name="com.radiumone.r1connect.disableAllAdvertisingIds" value="true" />
iOS manual installation (unnecessary if installed automatically)
Copy all files from src/ios with subfolders to your project
Add LibR1Connect.a as a library (Target -> Build Phases -> Link Binary With Libraries)
Make sure the following frameworks are linked (Target -> Build Phases -> Link Binary With Libraries):
libsqlite3.dylib
UIKit.framework
Foundation.framework
CoreGraphics.framework
AdSupport.framework
CoreTelephony.framework
CoreLocation.framework
SystemConfiguration.framework
Security.framework
CoreBluetooth.framework
Modify the cordova config.xml file to include the R1ConnectPlugin and preferences:
<feature name="R1ConnectPlugin">
<param name="ios-package" value="R1ConnectPlugin" />
<param name="onload" value="true" />
</feature>
<preference name="com.radiumone.r1connect.applicationId" value="Your application Id" />
<preference name="com.radiumone.r1connect.clientKey" value="Your client Key (For Push only)" />
Copy www/R1Connect.js into the project's www directory
Require the R1Connect module var R1Connect = require('<Path to R1Connect.js>')
Android manual installation (unnecessary if installed automatically)
Copy src/Android/R1ConnectPlugin.java and src/Android/CordovaPushReceiver.java files to your projects src/com/radiumone/cordova/plugin/ directory
Copy src/Android/*.jar files to your projects libs directory
Copy src/Android/r1connect.properties to your assets directory
Modify the AndroidManifest.xml to include these permissions:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!-- Please, replace $PACKAGE_NAME with your apps package name-->
<uses-permission android:name="$PACKAGE_NAME.permission.C2D_MESSAGE" />
<!-- Please, replace $PACKAGE_NAME with your apps package name-->
<permission android:name="$PACKAGE_NAME.permission.C2D_MESSAGE" android:protectionLevel="signature" />
Modify the AndroidManifest.xml Application section to include:
<receiver android:exported="true" android:name="com.radiumone.emitter.gcm.R1GCMPushReceiver" android:permission="com.google.android.c2dm.permission.SEND">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<!-- Please, replace $PACKAGE_NAME with your apps package name-->
<category android:name="$PACKAGE_NAME" />
</intent-filter>
</receiver>
<receiver android:exported="false" android:name="com.radiumone.emitter.push.R1PushBroadcastReceiver">
<intent-filter>
<action android:name="com.radiumone.r1push.OPENED_INTERNAL" />
</intent-filter>
</receiver>
<receiver android:exported="false" android:name="com.radiumone.cordova.plugin.CordovaPushReceiver">
<intent-filter>
<action android:name="com.radiumone.r1push.OPENED" />
</intent-filter>
</receiver>
<service android:name="com.radiumone.emitter.push.R1ConnectService" />
<service android:name="com.radiumone.emitter.location.LocationService" />
If you have set up Google Play Services add this line
<meta-data
android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version" />
Modify the cordova config.xml file to include the PushNotificationPlugin:
<feature name="R1ConnectPlugin">
<param name="android-package" value="com.radiumone.cordova.plugin.R1ConnectPlugin" />
<param name="onload" value="true" />
</feature>
<preference name="com.radiumone.r1connect.applicationId" value="Your application Id" />
<preference name="com.radiumone.r1connect.clientKey" value="Your client Key (For Push only)" />
<preference name="com.radiumone.r1connect.senderId" value="Your google sender id (For Push only)" />
Copy www/R1Connect.js into the project's www directory
Require the R1Connect module var R1Connect = require('<Path to R1Connect.js>')
Windows Phone 8 manual installation (unnecessary if installed automatically)
Copy all files from src/wp8 with subfolders to your project
Select PROJECT -> Add Reference...
In opened "Reference Manager" window press "Browse"
Select copied libraries R1ConnectLibrary.dll, Newtonsoft.Json.dll and protobuf-net.dll
Check your application Capabilities. For it
Open [Your project]->Properties->WMAppManifest.xml in Solution Explorer.
Select Capabilities tab
Check ID_CAP_NETWORKING, ID_CAP_IDENTITY_DEVICE, ID_CAP_LOCATION
Check ID_CAP_PUSH_NOTIFICATION if you want use R1 Connect Push
Modify the cordova config.xml file to include the R1ConnectPlugin and preferences:
Copy www/R1Connect.js into the project's www directory
Require the R1Connect module var R1Connect = require('<Path to R1Connect.js>')
View Article
Attribution Tracking Activation
We provide attribution tracking for free for all your Android campaigns, whether on or off the R1 DSP, through our partnership with Kochava. The integration is entirely server-side and requires no extra setup or work on your end. This service is a free add-on for our customers.
If you have another attribution tracking partner that you would prefer to use instead of Kochava, please contact your Account manager and we can work to enable these integrations based on demand from our clients.
i. Track RadiumOne Campaigns
Please contact your Account Manager to setup R1 ad campaign as well as tracking campaigns. If you don't have one, please contact us here and one of our Account Managers will assist you.
Once your Account Manager has set up tracking, you will start receiving attribution tracking report automatically!
ii. Track 3rd party Campaigns
Please contact your Account Manager to setup tracking URLs for your 3rd party campaigns. If you don't have one, please contact us here and one of our Account Managers will assist you.
Send the list of all your media suppliers (anyone you run a mobile advertising campaign with).
For each media supplier, your account manager will send you 2 tracking URLs (one impression tracking URL, 1 click tracking URL).
Send each pair of URLs to the relevant Media Supplier so they can set these tracking URLs on the creatives
You're all set and will start having access to Attribution Tracking Reports
View ArticleWhen preparing to send your binary to Apple, you will set up an application target in the iTunes Connect portal ( http://itunesconnect.apple.com for details). During this process, you will be presented with the question, "Does this app use the Advertising Identifier (IDFA)?"
Your application may or may not be using this value for your own purposes, but the Connect SDK does access it (described below). So, it is required that you answer, "Yes" to the aforementioned question.
If your application is utilizing Connect's analytics, geofencing or push notification features, be sure to check the last use case option - that the application uses the IDFA to "Attribute an action taken within this app to a previously served advertisement" as advertisments that you might have served can be related to users actions within your app.
If your application is also using Connect's Engage (display advertisements) feature, be sure to select the option: "Serve advertisements within the app". Naturally, if your application is only using the Engage functionality, leave all other options unchecked (as related to Connect's use of the IDFA)
You will also need to confirm that your app honors a user's "Limit Ad Tracking" setting in iOS. The Connect SDK does honor this flag and will not access or otherwise utilize the IDFA value if the user has selected the "Limit Ad Tracking" feature. Ensure that this confirmation and the previously mentioned IDFA use options are checked to facilitate a smooth application review process.
View ArticleAttribution Tracking Activation
We provide attribution tracking for free for all your campaigns, whether on or off the R1 DSP, through our partnership with Kochava. The integration is entirely server-side and requires no extra setup or work on your end. This service is a free add-on for our customers.
If you have another attribution tracking partner that you would prefer to use instead of Kochava, please contact your Account manager and we can work to enable these integrations based on demand from our clients.
i. Track RadiumOne Campaigns
Please contact your Account Manager to setup R1 ad campaign as well as tracking campaigns. If you don't have one, please contact us here and one of our Account Managers will assist you.
Once your Account Manager has set up tracking, you will start receiving attribution tracking report automatically!
ii. Track 3rd party Campaigns
Please contact your Account Manager to setup tracking URLs for your 3rd party campaigns. If you don't have one, please contact us here and one of our Account Managers will assist you.
Send the list of all your media suppliers (anyone you run a mobile advertising campaign with).
For each media supplier, your account manager will send you 2 tracking URLs (one impression tracking URL, 1 click tracking URL).
Send each pair of URLs to the relevant Media Supplier so they can set these tracking URLs on the creatives
You're all set and will start having access to Attribution Tracking Reports
View ArticleWe've provided you with the ability to create "Production" and "Development" applications as an easy way to discern between test and production data.
Nevertheless, these two application types are identical and offer no advantages or disadvantages. While we suggest using "Production" for live data and "Development" for test data, how you use each type of application is entirely up to you.
View ArticleIf you've just setup Connect for the first time and don't see data on the dashboard after triggering events, don't be alarmed!
Every night at midnight Eastern time we run a process that aggregates all data for the last 24 hours. This process could take several hours to complete.
If you don't see any data 24 hours after triggering events, please reach out to us at [email protected].
View Article