NOTE
While we do continue to support version 1, we encourage the reader to upgrade devices to version 2 for security and usability going forward.
Introduction
The embedded agent is a bridge between your application and the App47 service. It provides an easy to use API for recording session times and durations, log messages and performance events. Once you've added your Android App to the App47 Dashboard, be sure to record the App ID as it will be used to configure the agent after installation.
Android Agent
Required steps:
- Download the embedded agent
- Add build dependency on EmbeddedAgent.jar
- Add embedded agent services to AndroidManifest.xml
- Set up your App to capture events
- Configure embedded agent
Optional steps:
- Add EmbeddedAgentSettings.xml file to set additional configuration parameter XJX
- Add logging statements to your App
- Add timed events to your App
- Add generic events to your App
- Use Configuration groups in your App
- Automatically require App upgrades
- Listening for Agent configured event
The Required Steps -- Explained
1. Download the embedded agent
- Download the embedded agent zip file from from: Resource Center
- Once you have downloaded the file, open the zip file and you should see the following files:
File | Description | Required? |
---|---|---|
EmbeddedAgent.jar | jar file that contains the EmbeddedAgent | Yes |
EmbeddedAgentConfig.xml | Additional settings for configuring the embedded agent. | No |
ManifestExample.xml | Shows you how to configure your AndroidManifest.xml to use the Embedded Agent | No |
android-support-v4.jar | Used for LocalBroadcastManager events | Yes |
- Include the Embedded Agent library into your project by copying the EmbeddedAgent.jar file to the directory in your project that contains libraries.
- Note: {PROJECT}/libs in our example
2. Add build dependency on EmbeddedAgent.jar
When using IntelliJ:
- Right click your App’s module, choose Open Module Settings.
- Go to the Dependencies tab, then click on Add….
- Choose Single-Entry Module Library.
- Choose the EmbeddedAgent.jar from the file tree that appears.
- Click on the OK button once done.

When using Eclipse:
- Right click your app project’s folder, then choose Build Path->Add External Archives.
- Choose the EmbeddedAgent.jar from the file tree that appears.
- Click on the Open button once done.

3. Add embedded agent services to AndroidManifest.xml
The embedded agent library requires services that run in the background to process network calls and file caching. In order for a service to be called in an Android Application, it must be declared in the project’s AndroidManifest.xml, within the file’s application tag.
The required Service Declarations are:
<service android:enabled="true" android:name="com.app47.embeddedagent.AgentConfigService"/> <service android:enabled="true" android:name="com.app47.embeddedagent.AgentSessionService”/> <service android:enabled="true" android:name="com.app47.embeddedagent.AgentEventService"/>
The agent also requires two permissions to be declared in your manifest, INTERNET and ACCESS_FINE_LOCATION.
-
INTERNET is required, as the agent can’t make any server calls without it.
-
ACCESS_FINE_LOCATION is only required if you wish to include location information to your agent data.
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
The AndroidManifest.xml used by MyApp:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example" android:versionCode="1" android:versionName="1.0"> <uses-sdk android:minSdkVersion="8" /> <application android:icon="@drawable/icon" android:label="@string/app_name"> <activity android:name=".MyActivity" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <service android:enabled="true" android:name="com.app47.embeddedagent.AgentConfigService"/> <service android:enabled="true" android:name="com.app47.embeddedagent.AgentSessionService"/> <service android:enabled="true" android:name="com.app47.embeddedagent.AgentEventService"/> </application> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> </manifest>
4. Set up your App to capture events
In order to function, the embedded agent has to know when particular events are triggered in your Activity’s Lifecycle.
There are two ways to configure this:
-
Extend EmbeddedAgentActivity
-
Use EmbeddedAgent.onResume() and EmbeddedAgent.onPause()
Extend embedded agent activity
When you create an Activity of your own, it extends the Activity class. The easiest way to set up the embedded agent required events is to extend EmbeddedAgentActivity class from your Activity classes, instead of SDK-based Activity class.
For example, this class:
public class MyActivity extends Activity{ //fields... public void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); //do setup.... } //more implementation.... }
will become:
import com.app47.embeddedagent.EmbeddedAgentActivity; public class MyActivity extends EmbeddedAgentActivity{ //fields... public void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); //do setup.... } //more implementation.... }
Use EmbeddedAgent.onResume() and EmbeddedAgent.onPause()
If you use a specialized Activity type, such as ListActivity, PreferencesActivity, or even your own custom Activity, you can still set up your Activity using the onResume and onPause functions provided by EmbeddedAgent.
In your Activity’s protected void onResume method, add the line “EmbeddedAgent.onResume(getApplicationContext());” directly after the call to super.onResume.
In your Activity’s protected void onPause method, add the line “EmbeddedAgent.onPause(getApplicationContext());” directly after the call to super.onPause. This will set up your activity to use the Agent correctly.
For example, this class:
public class MyActivity extends ListActivity{ //fields... protected void onResume(){ super.onResume(); //Setup your app for Resume } protected void onPause(){ super.onPause(); //Setup your app for Pause } //more implementation.... }
will become:
import com.app47.embeddedagent.EmbeddedAgent; public class MyActivity extends ListActivity{ protected void onResume(){ super.onResume(); EmbeddedAgent.onResume(getApplicationContext()); //Setup your app for Resume } protected void onPause(){ super.onPause(); EmbeddedAgent.onPause(getApplicationContext()); //Setup your app for Pause } //more implementation... }
5. Configure Embedded Agent
The simplest way to configure the agent is to include the com.app47.embeddedagent package and use the configureAgentWithAppID method using the App ID obtained from the App47 Web application.
Note: This method will assume intelligent default configuration values for various aspects of the agent framework. Regardless, if you use the method configureAgentWithAppID, this will record session start, duration, location and capture relevant device and app information.
import com.app47.embeddedagent.*; public class MyActivity extends EmbeddedAgentActivity{ //fields... public void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); EmbeddedAgent.configureAgentWithAppID (getApplicationContext(),“4d556ab4530a69fb4b000002”); //do setup.... } //more implementation.... }
If you'd like to provide/override the default values assumed in the configureAgentWithAppID call, use this initializer instead:
public static void configureAgentWithAppID(final Context c, final String appID, final Map<String, String> options)
Where that Map named options can have any of the following keys:
Name | Description | Default | Required? | Valid Values |
---|---|---|---|---|
ConfigurationUpdateFrequency | The amount of time in days the agent should update it’s configuration with the service. A value of 0.5 will cause the agent to update its configuration once every 12 hours. | 0.1 | No | Decimal number greater than zero, 1 = check once a day, 2= check every other day, 0.5 = check twice a day, 0.000001 =check every time. |
DelayDataUploadInterval | The number of seconds to wait after startup before sending data to the service. This allows your App to startup and be responsive without competing for valuable cpu and network resources. | 10 | No | Integer value greater than zero. |
SendActualDeviceIdentifier | If the agent should send the actual UDID value from the device, or a hashed value. If this value is set to False, the value is hashed before being sent to the service, otherwise the actual value is sent. | FALSE | No | True or false |
ConfigurationEndpoint | Configure where the agent will initially connect to retrieve configuration information and upload analytics. | https://api.app47.mobi/ | No | A fully qualified URL, if you are using an agent version prior to 1.8.1, please ensure that you have a trailing slash as part of the url, https://api.app47.mobiwill not work. |
The Optional Steps -- Explained
Add EmbeddedAgentSettings.xml file to set additional configuration parameter XJX
The Agent can load configuration options from an XML value in one of your Resource files included in your project. You can either include the provided EmbeddedAgentConfig.xml file in your res/values/ directory, or add string elements listed below to any existing XML value file.
Configuration string elements:
Name | Description | Default | Required? | Valid Values |
---|---|---|---|---|
EmbeddedAgent_applicationID | The App ID provided in your dashboard. | None | Yes | Valid App ID from your account |
EmbeddedAgent_configurationUpdateFrequency | The amount of time in days the agent should update it’s configuration with the service. A value of 0.5 will cause the agent to update its configuration once every 12 hours. | 0.1 | No | Decimal number greater than zero, 1 = check once a day, 2= check every other day, 0.5 = check twice a day, 0.000001 =check every time. |
EmbeddedAgent_delayDataUploadInterval | The number of seconds to wait after startup before sending data to the service. This allows your App to startup and be responsive without competing for valuable cpu and network resources. | 10 | No | Integer value greater than zero. |
EmbeddedAgent_ sendActualDeviceIdentifier | If the agent should send the actual UDID value from the device, or a hashed value. If this value is set to False, the value is hashed before being sent to the service, otherwise the actual value is sent. | FALSE | No | true or false |
EmbeddedAgent_configurationEndpoint | Configure where the agent will initially connect to retrieve configuration information and upload analytics. | https://api.app47.mobi/ | No | A fully qualified URL, if you are using an agent version prior to 1.8.1, please ensure that you have a trailing slash as part of the url, https://api.app47.mobiwill not work. |
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="EmbeddedAgent_applicationID">4d556ab4530a69fb4b000002</string> <string name="EmbeddedAgent_configurationUpdateFrequency">0.25</string> <string name="EmbeddedAgent_delayDataUploadInterval">10</string> <string name="EmbeddedAgent_sendActualDeviceIdentifier" >false</string> </resources>
When using the EmbeddedAgentSettings.xml, the following configuration selector must be used.
import com.app47.embeddedagent.*; public class MyActivity extends EmbeddedAgentActivity{ //fields... public void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); EmbeddedAgent.configureAgent(getApplicationContext()); //do setup.... } //more implementation.... }
Add logging statements to your App
Additional level logging can be added to your App to capture debug, info, warn, error, and crash log information. Log information is recorded locally and then uploaded to the service the next time the application resumes the active state or is started.
Examples of logging statements:
import com.app47.embeddedagent.*; public class MyActivity extends EmbeddedAgentActivity{ //fields... public void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); EmbeddedAgent.configureAgent(getApplicationContext()); //Info level log statement EmbeddedAgentLogger.i(“Agent told to configure”); //do setup.... //Debug level log statement EmbeddedAgentLogger.d(“Finished creating activity”); } public void doSomeThing(String param, String anotherParam) { //can overload methods with tags for additional search criteria in //the web app EmbeddedAgentLogger.i(“doing something”, “doing”, param,anotherParam); try{ openFileInput(param); }catch(IOException e){ //can pass a Throwable to add to log EmbeddedAgentLogger.e(“doSomeThing no file found”,e); } }
The Logger methods follow the Android Log class:
-
d Debug
-
i Info
-
w Warn
-
e Error
-
wtf What a Terrible Failure (Crash)
Add timed events to your App
Timed events allow you to measure and record events in your application along with the duration of the event. Timed events are sent to the service immediately upon completion. If the agent is unable to send the event immediately, it is cached locally and then sent at the next App startup or activation. A simple example of using timed events in your application would look like the following code:
public void performMyTransaction() { String eventID = EmbeddedAgent.startTimedEvent(“Transaction"); // Perform some business logic to complete the transaction // … // EmbeddedAgent.endTimedEvent(eventID); }
Add generic events to your App
Generic events are like timed events, but with no duration. Generic events are sent to the service immediately upon request. If the agent is unable to send the event immediately, it is cached locally and then sent at the next App startup or activation.
A simple example of using generic events in your application would look like the following code:
public void performMyTransaction() { EmbeddedAgent.sendGenericEvent(“Transaction"); // Perform some business logic to complete the transaction // … // }
Use Configuration Groups in your App
Configuration groups allow you to set a collection of key value pairs through the main web interface that are then downloaded by the agent at initial startup, and then subsequently at a frequency set by the “EmbeddedAgent_configurationUpdateFrequency” parameter in the EmbeddedAgentConfig.xml file. Configuration items must be requested by a group name and key name. A default value may be given to be used in the event that the configuration group does not contain an item with the requested key name. If a default value is not given, and the key does not exist in the group, the value null is returned. Configuration groups can be assigned to agents based on App version, OS version and platform.
A simple example of using configuration groups in your application would look like the following code:
public void myMethod() { String prodURL = EmbeddedAgent. configurationStringForKey(“server_url", “prod_urls”, “http://default.url”); // Do something with the prodURL value // … }
Automatically require App upgrades
You can force users of an App that contains the App47 Agent to upgrade to a minimum App version.
In order to enforce this feature on Apps, you must got to the security screen from within the App47 dashboard. You will see a screen that looks like this:
From here, you can select a particular platform and environment to enforce – for example, you can select Android Test instances be on version 1.5. Additionally, you can set a custom message that a user will see upon an App upgrade notice.
Android Agent requirements for app upgrade requirement
In order for the App upgrade process to work smoothly, you must do a few things. Namely, you'll have to add one new permissions to your App's manifest file.
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
There is a dialog that pops up to inform the user of this feature; therefore, you'll need to add the following Activity to your App's manifest as well:
<activity android:label="@string/app_name" android:name="com.app47.sdk.util.UpgradeDialogActivity" android:theme="@android:style/Theme.Translucent.NoTitleBar"/>
Test Environment settings
If you include an array of allowed UDIDs for a particular app in its manifest file, the App47 system will treat the app as a test version (i.e. this is a mirroring feature of standard iOS behavior w/r to ad hoc builds and provisioning certificates). For instance, if you include the following XML array of values in any values XML file in your app, the agent, at runtime, will determine this instance of the app to be a test version:
<string-array name="allowed_udids"> <item>some device UDID</item> <item>some other device UDID</item> </string-array>
Note: The attribute value of allowed_udids
is required.
Listening for Agent configured event
When the configuration for an Agent is updated, a new Intent is created dubbed “agent-config” – you can listen for it and act accordingly when you receive the event. For example, if you use configuration values, you can listen for this event and then grab values you may require.
Note: This event becomes important in frameworks like PhoneGap and Appcelerator where Agent configuration can take a few moments.
You'll need to register a BroadcastReceiver. You can do this like so:
// handler for received Intents for the "agent-config" event private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { //things are broadcasted only on update so this code will execute then... } }; //somewhere else in your code: // Register mMessageReceiver to receive messages. LocalBroadcastManager.getInstance(this).registerReceiver(mMessageReceiver, new IntentFilter(EmbeddedAgent.AGENT_CONFIGURATION_COMPLETE_BROADCAST));
Note that you can statically import EmbeddedAgent.AGENT_CONFIGURATION_COMPLETE_BROADCAST like so:
import static com.app47.embeddedagent.EmbeddedAgent.AGENT_CONFIGURATION_COMPLETE_BROADCAST;
And then your code is less verbose:
LocalBroadcastManager.getInstance(this).registerReceiver(mMessageReceiver, new IntentFilter(AGENT_CONFIGURATION_COMPLETE_BROADCAST));
You can also listen for configuration group changes via CONFIG_GROUPS_COMPLETE_BROADCAST. This is the same as the code above, just a different broadcast name. This broadcast is sent when any configuration group changes.
Releases
1.9.1
-
Recompiled agent with Java version 6 to allow for wider range of applications.
Comments
2 comments
1) AgentConfigService.handleNotification(String, NotificationManager, Notification) uses Notification.setLatestEventInfo(Context, CharSequence, CharSequence, PendingIntent) that was removed from 23 API:
https://developer.android.com/sdk/api_diff/23/changes/android.app.Notification.html
so you can't use compileSdkVersion >23
2) to avoid NullPointerException that library throws inside of
EmbeddedAgent.onResume(context);
you need to add try-catch:
3) this library uses Apache client for internet communication and doesn't provide the way to replace it
Sergey,
If you take a look at our latest version https://app47.zendesk.com/hc/en-us/articles/360000626913-Android-Agent-Version-2-X, you should find these issues have been resolved. Please let us know if you have any trouble upgrading.
Please sign in to leave a comment.