Android Application Integration¶
Collect metrics data from Android applications to analyze application performance visually.
Prerequisites¶
Note
If you have already activated the RUM Headless service, the prerequisites are automatically configured, and you can directly integrate the application.
- Install DataKit;
- Configure the RUM collector;
- Configure DataKit to be publicly accessible and install the IP Geolocation database.
Application Integration¶
- Go to RUM > Create Application > Android;
- Enter the application name;
- Enter the application ID;
-
Choose the application integration method:
- Public DataWay: Directly receives RUM data without installing the DataKit collector.
- Local Environment Deployment: Receives RUM data after meeting the prerequisites.
Installation¶
Source Code Repository: https://github.com/GuanceCloud/datakit-android
Demo: https://github.com/GuanceDemo/guance-app-demo
Gradle Configuration¶
Apply Plugin¶
- Add the remote repository address of the
SDKin the root directory'sbuild.gradlefile.
//build.gradle
buildscript {
//...
repositories {
//...
//Add the Plugin's remote repository address
maven {
url 'https://mvnrepo.jiagouyun.com/repository/maven-releases'
}
}
dependencies {
//...
//Add the Plugin dependency, requires AGP 7.4.2+ and Gradle 7.2.0+
classpath 'com.cloudcare.ft.mobile.sdk.tracker.plugin:ft-plugin:[latest_version]'
// For AGP versions below 7.4.2, use ft-plugin-legacy
//classpath 'com.cloudcare.ft.mobile.sdk.tracker.plugin:ft-plugin-legacy:[latest_version]'
}
}
//setting.gradle
pluginManagement {
repositories {
google()
mavenCentral()
gradlePluginPortal()
//Add the Plugin's remote repository address
maven {
url('https://mvnrepo.jiagouyun.com/repository/maven-releases')
}
}
}
//build.gradle
plugins{
//Add the Plugin, requires AGP 7.4.2+ and Gradle 7.2.0+
id 'com.cloudcare.ft.mobile.sdk.tracker.plugin' version '[lastest_version]' apply false
// For AGP versions below 7.4.2, use ft-plugin-legacy
//id 'com.cloudcare.ft.mobile.sdk.tracker.plugin.legacy' version '[lastest_version]' apply false
}
- Apply the
Pluginin the main module'sapp/build.gradlefile.
//Apply the plugin in app/build.gradle. Missing configuration will affect the following automatic collection functions.
//
// Plugin configuration purpose:
// * Automatic collection: App startup, OkHttp requests, WebView activities, Activity navigation
// * Automatic collection of View click events, Console Logcat
// * Automatic collection of Console Logcat
apply plugin: 'ft-plugin' //If using ft-plugin-legacy, use this configuration as well.
//Configure plugin usage parameters (optional)
FTExt {
//Whether to show Plugin logs, defaults to false
//showLog = true
//Set ASM version, supports asm7 - asm9, defaults to asm9
//asmVersion='asm7'
//ASM ignore path configuration, '.' and '/' are equivalent in paths
//ignorePackages=['com.ft','com/ft']
}
Apply SDK¶
- Add the remote repository address of the
SDKin the root directory'sbuild.gradlefile.
- Add the
SDKdependency in the main module'sapp/build.gradlefile.
//app/build.gradle
dependencies {
//Add SDK dependency
implementation 'com.cloudcare.ft.mobile.sdk.tracker.agent:ft-sdk:[latest_version]'
//Dependency for capturing native layer crash information, must be used with ft-sdk, cannot be used alone.
implementation 'com.cloudcare.ft.mobile.sdk.tracker.agent:ft-native:[latest_version]'
// json serialization
implementation 'com.google.code.gson:gson:2.8.+'
//Optional, required if automatic network request collection and automatic trace linking are needed, minimum compatible version 3.12.+
implementation 'com.squareup.okhttp3:okhttp:4.+'
}
Check the latest version above for
ft-sdk,ft-plugin,ft-native.
Application Configuration¶
The best place to initialize the SDK is in the onCreate method of the Application. If your application hasn't created an Application, you need to create one and declare it in AndroidManifest.xml. For an example, refer to here.
R8 / Proguard Obfuscation Configuration¶
If you need to set minifyEnabled = true in android.buildTypes, enable the following configuration:
-dontwarn com.ft.sdk.**
### ft-sdk library
-keep class com.ft.sdk.**{*;}
### ft-native library
-keep class ftnative.*{*;}
### Prevent Action class names from being obfuscated in action_name ###
-keepnames class * extends android.view.View
-keepnames class * extends android.view.MenuItem
SDK Initialization¶
Basic Configuration¶
public class DemoApplication extends Application {
@Override
public void onCreate() {
//Local environment deployment, Datakit deployment
FTSDKConfig config = FTSDKConfig.builder(datakitUrl);
//Use public DataWay
FTSDKConfig config = FTSDKConfig.builder(datawayUrl, clientToken);
//...
//config.setDebug(true); //debug mode
config.setCompressIntakeRequests(true); //Compress intake requests
FTSdk.install(config);
}
}
class DemoApplication : Application() {
override fun onCreate() {
//Local environment deployment, Datakit deployment
val config = FTSDKConfig.builder(datakitUrl)
//Use public DataWay
val config = FTSDKConfig.builder(datawayUrl, clientToken)
//...
//config.setDebug(true); //debug mode
config.setCompressIntakeRequests(true) //Compress intake requests
FTSdk.install(config)
}
}
| Method Name | Type | Required | Meaning |
|---|---|---|---|
| datakitUrl | String | Yes | Local environment deployment (Datakit) reporting URL address, e.g., http://10.0.0.1:9529, default port 9529. The device installing the SDK must be able to access this address. Note: Choose one between datakitUrl and datawayUrl configuration |
| datawayUrl | String | Yes | Public DataWay reporting URL address, obtained from the [RUM] application, e.g., https://open.dataway.url. The device installing the SDK must be able to access this address. Note: Choose one between datakitUrl and datawayUrl configuration |
| clientToken | String | Yes | Authentication token, must be configured together with datawayUrl |
| setDebug | Boolean | No | Whether to enable debug mode. Defaults to false. Enabling it prints SDK runtime logs. |
| setEnv | EnvType | No | Set the collection environment, defaults to EnvType.PROD. |
| setEnv | String | No | Set the collection environment, defaults to prod. Note: Configure only one, either String or EnvType |
| setOnlySupportMainProcess | Boolean | No | Whether to support running only in the main process. Defaults to true. Set to false if needed in other processes. |
| setEnableAccessAndroidID | Boolean | No | Enable obtaining Android ID. Defaults to true. Set to false to stop collecting device_uuid field data. Related to market privacy audits see here. |
| addGlobalContext | Dictionary | No | Add SDK global attributes. See rules for adding here. |
| setServiceName | String | No | Set the service name, affects the service field data in Log and RUM. Defaults to df_rum_android. |
| setAutoSync | Boolean | No | Whether to automatically sync data to the server after collection. Defaults to true. When false, use FTSdk.flushSyncData() to manage data sync manually. |
| setSyncPageSize | Int | No | Set the number of entries per sync request. SyncPageSize.MINI 5 entries, SyncPageSize.MEDIUM 10 entries, SyncPageSize.LARGE 50 entries. Default SyncPageSize.MEDIUM. |
| setCustomSyncPageSize | Enum | No | Set the number of entries per sync request, range [5,). Note: Larger numbers consume more computational resources. Defaults to 10. Note: Configure only one between setSyncPageSize and setCustomSyncPageSize. |
| setSyncSleepTime | Int | No | Set the sync interval time, range [0,5000], unit ms, defaults to 0. |
| enableDataIntegerCompatible | Void | No | Recommended when coexisting with web data. This configuration handles web data type storage compatibility issues. Enabled by default in version 1.6.9. |
| setNeedTransformOldCache | Boolean | No | Whether to be compatible with syncing old cache data from ft-sdk versions below 1.6.0. Defaults to false. |
| setCompressIntakeRequests | Boolean | No | Deflate compression for upload sync data. Disabled by default. Supported in ft-sdk 1.6.3+. |
| enableLimitWithDbSize | Void | No | Enable using db to limit data size, default 100MB, unit Byte. Larger database increases disk pressure. Disabled by default. Note: After enabling, FTLoggerConfig.setLogCacheLimitCount and FTRUMConfig.setRumCacheLimitCount become invalid. Supported in ft-sdk 1.6.6+. |
| setEnableOkhttpRequestTag | Boolean | No | Automatically add unique ResourceID to Okhttp Request for high concurrency scenarios with identical requests. Supported in ft-sdk 1.6.10+, ft-plugin 1.3.5+. |
| setProxy | java.net.Proxy | No | Set Proxy for data network sync requests, only supports okhttp3. Supported in ft-sdk 1.6.10+. |
| setProxyAuthenticator | okhttp3.Authenticator | No | Set Proxy Authenticator for data sync network requests, only supports okhttp3. Supported in ft-sdk 1.6.10+. |
| setDns | okhttp3.Dns | No | Custom Dns for domain name resolution in data sync network requests, only supports okhttp3. Supported in ft-sdk 1.6.10+. |
| setDataModifier | DataModifier | No | Modify individual fields. Supported in ft-sdk 1.6.11+. See example here. |
| setLineDataModifier | LineDataModifier | No | Modify single data lines. Supported in ft-sdk 1.6.11+. See example here. |
| setRemoteConfiguration | Boolean | No | Whether to enable remote configuration for data collection. Defaults to false. When enabled, SDK initialization or app hot start triggers data updates. Supported in ft-sdk 1.6.12+. Requires datakit version >=1.60 or using public dataway. |
| setRemoteConfigMiniUpdateInterval | Int | No | Set the minimum update interval for data, unit seconds, default 12 hours. Supported in ft-sdk 1.6.12+. |
RUM Configuration¶
FTSdk.initRUMWithConfig(
new FTRUMConfig()
.setRumAppId(RUM_APP_ID)
.setEnableTraceUserView(true)
.setDeviceMetricsMonitorType(DeviceMetricsMonitorType.ALL.getValue())
.setEnableTraceUserAction(true)
.setEnableTraceUserResource(true)
.setEnableTrackAppUIBlock(true)
.setEnableTrackAppCrash(true)
.setEnableTrackAppANR(true)
.setExtraMonitorTypeWithError(ErrorMonitorType.ALL.getValue())
);
FTSdk.initRUMWithConfig(
FTRUMConfig()
.setRumAppId(RUM_APP_ID)
.setEnableTraceUserView(true)
.setDeviceMetricsMonitorType(DeviceMetricsMonitorType.ALL.getValue())
.setEnableTraceUserAction(true)
.setEnableTraceUserResource(true)
.setEnableTrackAppUIBlock(true)
.setEnableTrackAppCrash(true)
.setEnableTrackAppANR(true)
.setExtraMonitorTypeWithError(ErrorMonitorType.ALL.getValue())
)
| Method Name | Type | Required | Meaning |
|---|---|---|---|
| setRumAppId | String | Yes | Set Rum AppId. Corresponds to setting RUM appid to enable RUM collection. Get appid method |
| setSamplingRate | Float | No | Set collection rate, range [0,1], 0 means no collection, 1 means full collection, default 1. Scope: all View, Action, LongTask, Error data under the same session_id. |
| setSessionErrorSampleRate | Float | No | Set error collection rate. When a session is not sampled by setSamplingRate, if an error occurs during the session, data from 1 minute before the error can be collected. Range [0,1], 0 means no collection, 1 means full collection, default 0. Scope: all View, Action, LongTask, Error data under the same session_id. Supported in ft-sdk 1.6.11+. |
| setEnableTrackAppCrash | Boolean | No | Whether to report App crash logs. Defaults to false. Enabling it shows error stack data in error analysis.About converting obfuscated content in crash logs. ft-sdk 1.5.1+ allows setting extraLogCatWithJavaCrash, extraLogCatWithNativeCrash to control logcat display for Java Crash and Native Crash. |
| setExtraMonitorTypeWithError | Array | No | Set auxiliary monitoring information, add additional monitoring data to Rum crash data. ErrorMonitorType.BATTERY for battery level, ErrorMonitorType.MEMORY for memory usage, ErrorMonitorType.CPU for CPU usage. Not set by default. |
| setDeviceMetricsMonitorType | Array | No | Set View monitoring information. Adds monitoring data during the View lifecycle. DeviceMetricsMonitorType.BATTERY monitors max current output on the current page, DeviceMetricsMonitorType.MEMORY monitors current app memory usage, DeviceMetricsMonitorType.CPU monitors CPU tick count, DeviceMetricsMonitorType.FPS monitors screen frame rate. Monitoring frequency: DetectFrequency.DEFAULT 500 ms, DetectFrequency.FREQUENT 100 ms, DetectFrequency.RARE 1 sec. Not set by default. |
| setEnableTrackAppANR | Boolean | No | Whether to enable ANR detection. Defaults to false.ft-sdk 1.5.1+ allows setting extraLogCatWithANR to control logcat display for ANR. |
| setEnableTrackAppUIBlock | Boolean, long | No | Whether to enable UI freeze detection. Defaults to false. ft-sdk 1.6.4+ allows controlling detection time range [100,) with blockDurationMs, unit ms, default 1 sec. |
| setEnableTraceUserAction | Boolean | No | Whether to automatically track user actions. Currently supports user startup and click actions. Defaults to false. |
| setEnableTraceUserView | Boolean | No | Whether to automatically track user page actions. Defaults to false. |
| setEnableTraceUserViewInFragment | Boolean | No | Whether to automatically track Fragment type page data. Defaults to false. Supported in ft-sdk 1.6.11+. |
| setEnableTraceUserResource | Boolean | No | Whether to automatically track user network requests, only supports Okhttp. Defaults to false. |
| setEnableResourceHostIP | Boolean | No | Whether to collect the IP address of the requested target domain. Scope: Only affects default collection when EnableTraceUserResource is true. For custom Resource collection, use FTResourceEventListener.FTFactory(true) to enable this function. Also, a single Okhttp has an IP caching mechanism for the same domain; the same OkhttpClient will only generate it once if the server IP doesn't change. |
| setResourceUrlHandler | Callback | No | Set conditions for filtering Resources. No filtering by default. |
| setOkHttpEventListenerHandler | Callback | No | ASM sets global Okhttp EventListener. Not set by default. |
| setOkHttpResourceContentHandler | Callback | No | ASM sets global FTResourceInterceptor.ContentHandlerHelper. Not set by default. Supported in ft-sdk 1.6.7+. Custom Resource. |
| addGlobalContext | Dictionary | No | Add custom tags for distinguishing user monitoring data sources. If tracing is needed, use key as track_id and value as any value. See notes on adding rules here. |
| setRumCacheLimitCount | int | No | Local RUM cache limit count [10_000,), default is 100_000. Supported in ft-sdk 1.6.6+. |
| setEnableTraceWebView | Boolean | No | Configure whether to collect WebView data via Android SDK. Defaults to true. Supported in ft-sdk 1.6.12+. |
| setAllowWebViewHost | Array | No | Set allowed WebView host addresses for data tracking. null means collect all, default null. Supported in ft-sdk 1.6.12+. |
| setViewActivityTrackingHandler | FTViewActivityTrackingHandler | No | Used to customize how Activity views are tracked. This handler is called when Activity lifecycle events occur to decide how to track the Activity. No processing by default. Supported in ft-sdk 1.6.13+. |
| setViewFragmentTrackingHandler | FTViewFragmentTrackingHandler | No | Used to customize how Fragment views are tracked. This handler is called when Fragment lifecycle events occur to decide how to track the Fragment. Supported in ft-sdk 1.6.13+. |
| setActionTrackingHandler | FTActionTrackingHandler | No | Used to customize how user actions (app startup, clicks) are tracked. This handler is called when a user performs an action to decide how to track it. No processing by default. Supported in ft-sdk 1.6.13+. |
Log Configuration¶
| Method Name | Type | Required | Meaning |
|---|---|---|---|
| setSamplingRate | Float | No | Set collection rate, range [0,1], 0 means no collection, 1 means full collection, default 1. |
| setEnableConsoleLog | Boolean | No | Whether to report console logs. Default false. Log level mapping:Log.v -> ok; Log.i -> info; Log.d -> debug; Log.e -> error; Log.w -> warning. prefix is the control prefix filter parameter, not set by default. Note: Android console logs can be voluminous. To avoid impacting app performance and wasting resources, use prefix to filter valuable logs. ft-plugin 1.3.5+ supports capturing logs printed by Log.println. |
| setEnableLinkRUMData | Boolean | No | Whether to correlate with RUM data. Defaults to false. |
| setEnableCustomLog | Boolean | No | Whether to upload custom logs. Defaults to false. |
| setLogLevelFilters | Array | No | Set log level filtering. Not set by default. |
| addGlobalContext | Dictionary | No | Add log global attributes. See rules for adding here. |
| setLogCacheLimitCount | Int | No | Local cache maximum log entry limit [1000,). Larger logs mean greater disk cache pressure. Defaults to 5000. |
| setLogCacheDiscardStrategy | LogCacheDiscard | No | Set log discard rule when the limit is reached. Defaults to LogCacheDiscard.DISCARD. DISCARD discards new data, DISCARD_OLDEST discards old data. |
Trace Configuration¶
| Method Name | Type | Required | Meaning |
|---|---|---|---|
| setSamplingRate | Float | No | Set collection rate, range [0,1], 0 means no collection, 1 means full collection, default 1. |
| setTraceType | TraceType | No | Set the trace type. Defaults to DDTrace. Currently supports Zipkin, Jaeger, DDTrace, Skywalking (8.0+), TraceParent (W3C). If integrating OpenTelemetry, choose the corresponding trace type and check supported types and agent configuration. |
| setEnableLinkRUMData | Boolean | No | Whether to correlate with RUM data. Defaults to false. |
| setEnableAutoTrace | Boolean | No | Whether to enable automatic http trace. Currently only supports automatic tracing for OKhttp. Defaults to false. |
| setOkHttpTraceHeaderHandler | Callback | No | ASM sets global FTTraceInterceptor.HeaderHandler. Not set by default. Supported in ft-sdk 1.6.8+. Example reference Custom Trace. |
RUM User Data Tracking¶
Use FTRUMConfig to configure enableTraceUserAction, enableTraceUserView, enableTraceUserResource,setEnableTrackAppUIBlock,setEnableTrackAppCrash and setEnableTrackAppANR to achieve automatic collection of Action, View, Resource, LongTask, Error data. For custom collection, use FTRUMGlobalManager to report data, as shown below:
Action¶
Usage¶
/**
* Add Action
*
* @param actionName action name
* @param actionType action type
* @param property additional attributes (optional)
*/
public void startAction(String actionName, String actionType, HashMap<String, Object> property)
/**
* Add Action. This type of data cannot be associated with Error, Resource, LongTask data.
*
* @param actionName action name
* @param actionType action type
* @param duration nanoseconds, duration (optional)
* @param property extended attributes (optional)
*/
public void addAction(String actionName, String actionType, long duration, HashMap<String, Object> property)
/**
* Add action
*
* @param actionName action name
* @param actionType action type
* @param property additional attributes (optional)
*/
fun startAction(actionName: String, actionType: String, property: HashMap<String, Any>)
/**
* Add Action
*
* @param actionName action name
* @param actionType action type
* @param duration nanoseconds, duration (optional)
* @param property extended attributes (optional)
*/
fun addAction(actionName: String, actionType: String, duration: Long, property: HashMap<String, Any>)
startAction internally calculates duration and tries to associate with nearby Resource, LongTask, Error data. Has a 100 ms frequent trigger protection. Recommended for user action type data. For frequent calls, use addAction. This data does not conflict with startAction and is not associated with current Resource, LongTask, Error data.
Code Example¶
// Scenario 1
FTRUMGlobalManager.get().startAction("login", "action_type");
// Scenario 2: Dynamic parameters
HashMap<String, Object> map = new HashMap<>();
map.put("ft_key", "ft_value");
FTRUMGlobalManager.get().startAction("login", "action_type", map);
// Scenario 1
FTRUMGlobalManager.get().addAction("login", "action_type");
// Scenario 2: Dynamic parameters
HashMap<String, Object> map = new HashMap<>();
map.put("ft_key", "ft_value");
FTRUMGlobalManager.get().addAction("login", "action_type", map);
// Scenario 1
FTRUMGlobalManager.get().startAction("login", "action_type")
// Scenario 2: Dynamic parameters
val map = HashMap<String,Any>()
map["ft_key"]="ft_value"
FTRUMGlobalManager.get().startAction("login","action_type",map)
// Scenario 1
FTRUMGlobalManager.get().startAction("login", "action_type")
// Scenario 2: Dynamic parameters
val map = HashMap<String,Any>()
map["ft_key"]="ft_value"
FTRUMGlobalManager.get().startAction("login","action_type",map)
View¶
Usage¶
/**
* view start
*
* @param viewName current page name
* @param property additional attributes (optional)
*/
public void startView(String viewName, HashMap<String, Object> property)
/**
* view end
*
* @param property additional attributes (optional)
*/
public void stopView(HashMap<String, Object> property)
/**
* Update current view loading_time metric, unit nanoseconds.
* @param duration
*/
public void updateLoadTime(long duration)
/**
* view start
*
* @param viewName current page name
* @param property additional attributes (optional)
*/
fun startView(viewName: String, property: HashMap<String, Any>)
/**
* view end
*
* @param property additional attributes (optional)
*/
fun stopView(property: HashMap<String, Any>)
/**
* Update current view loading_time metric, unit nanoseconds
* @param duration
*/
fun updateLoadTime(duration: Long)
Code Example¶
@Override
protected void onResume() {
super.onResume();
// Scenario 1
FTRUMGlobalManager.get().startView("Current Page Name");
// Scenario 2: Dynamic parameters
HashMap<String, Object> map = new HashMap<>();
map.put("ft_key", "ft_value");
map.put("ft_key_will_change", "ft_value");
FTRUMGlobalManager.get().startView("Current Page Name", map);
}
@Override
protected void onPause() {
super.onPause();
// Scenario 1
FTRUMGlobalManager.get().stopView();
// Scenario 2 : Dynamic parameters
HashMap<String, Object> map = new HashMap<>();
map.put("ft_key_will_change", "ft_value_change"); //ft_key_will_change value will be changed to ft_value_change at stopView
FTRUMGlobalManager.get().startView("Current Page Name", map);
}
override fun onResume() {
super.onResume()
// Scenario 1
FTRUMGlobalManager.get().startView("Current Page Name")
// Scenario 2: Dynamic parameters
val map = HashMap<String, Any>()
map["ft_key"] = "ft_value"
map["ft_key_will_change"] = "ft_value"
FTRUMGlobalManager.get().startView("Current Page Name", map)
}
override fun onPause() {
super.onPause()
// Scenario 1
FTRUMGlobalManager.get().stopView()
// Scenario 2 : Dynamic parameters
val map = HashMap<String, Any>()
map["ft_key_will_change"] = "ft_value_change" //ft_key_will_change value will be changed to ft_value_change at stopView
FTRUMGlobalManager.get().startView("Current Page Name", map)
}
Error¶
Usage¶
/**
* Add error information
*
* @param log log
* @param message message
* @param errorType error type, ErrorType
* @param state program running state
* @param dateline occurrence time, nanoseconds (optional)
* @param property additional attributes (optional)
*/
public void addError(String log, String message, long dateline, ErrorType errorType,
AppState state, HashMap<String, Object> property)
/**
* Add error information
*
* @param log log
* @param message message
* @param errorType error type, String
* @param state program running state
* @param dateline occurrence time, nanoseconds (optional)
* @param property additional attributes (optional)
*/
public void addError(String log, String message, long dateline, String errorType,
AppState state, HashMap<String, Object> property)
/**
* Add error information
*
* @param log log
* @param message message
* @param errorType error type, ErrorType
* @param state program running state
* @param dateline occurrence time, nanoseconds (optional)
* @param property additional attributes (optional)
*/
fun addError(log: String, message: String, dateline: Long, errorType: ErrorType,state: AppState, property: HashMap<String, Any>)
/**
* Add error information
*
* @param log log
* @param message message
* @param errorType error type, String
* @param state program running state
* @param dateline occurrence time, nanoseconds (optional)
* @param property additional attributes (optional)
*/
fun addError(log: String, message: String, dateline: Long, errorType: String,state: AppState, property: HashMap<String, Any>)
Code Example¶
// Scenario 1:
FTRUMGlobalManager.get().addError("error log", "error msg", ErrorType.JAVA, AppState.RUN);
// Scenario 2: Record error that occurred later, time here is usually the error occurrence time.
FTRUMGlobalManager.get().addError("error log", "error msg", 16789000000000000000L, ErrorType.JAVA, AppState.RUN);
// Scenario 3:Dynamic parameters
HashMap<String, Object> map = new HashMap<>();
map.put("ft_key", "ft_value");
FTRUMGlobalManager.get().addError("error log", "error msg", ErrorType.JAVA, AppState.RUN, map);
// Scenario 1:
FTRUMGlobalManager.get().addError("error log", "error msg", ErrorType.JAVA, AppState.RUN)
// Scenario 2: Record error that occurred later, time here is usually the error occurrence time.
FTRUMGlobalManager.get().addError("error log", "error msg", 16789000000000000000, ErrorType.JAVA, AppState.RUN)
// Scenario 3:Dynamic parameters
val map = HashMap<String, Any>()
map["ft_key"] = "ft_value"
FTRUMGlobalManager.get().addError("error log", "error msg",ErrorType.JAVA,AppState.RUN,map)
LongTask¶
Usage¶
Code Example¶
Resource¶
Usage¶
/**
* resource start
*
* @param resourceId resource Id
* @param property additional attributes (optional)
*/
public void startResource(String resourceId, HashMap<String, Object> property)
/**
* resource stop
*
* @param resourceId resource Id
* @param property additional attributes (optional)
*/
public void stopResource(final String resourceId, HashMap<String, Object> property)
/**
* Set network transmission content
*
* @param resourceId
* @param params
* @param netStatusBean
*/
public void addResource(String resourceId, ResourceParams params, NetStatusBean netStatusBean)
/**
* resource start
*
* @param resourceId resource Id(optional)
*/
fun startResource(resourceId: String, property: HashMap<String, Any>)
/**
* resource stop
*
* @param resourceId resource Id
* @param property additional attributes (optional)
*/
fun stopResource(resourceId: String, property: HashMap<String, Any>)
/**
* Set network transmission content
*
* @param resourceId
* @param params
* @param netStatusBean
*/
fun addResource(resourceId: String, params: ResourceParams, netStatusBean: NetStatusBean)
Code Example¶
// Scenario 1
// Request start
FTRUMGlobalManager.get().startResource("resourceId");
//...
// Request end
FTRUMGlobalManager.get().stopResource("resourceId");
// Finally, after the request ends, send request-related data metrics.
ResourceParams params = new ResourceParams();
params.setUrl("https://guance.com");
params.setResponseContentType(response.header("Content-Type"));
params.setResponseConnection(response.header("Connection"));
params.setResponseContentEncoding(response.header("Content-Encoding"));
params.setResponseHeader(response.headers().toString());
params.setRequestHeader(request.headers().toString());
params.setResourceStatus(response.code());
params.setResourceMethod(request.method());
NetStatusBean bean = new NetStatusBean();
bean.setTcpStartTime(60000000);
//...
FTRUMGlobalManager.get().addResource("resourceId", params, bean);
// Scenario 2 :Dynamic parameter usage
HashMap<String, Object> map = new HashMap<>();
map.put("ft_key", "ft_value");
map.put("ft_key_will_change", "ft_value");
FTRUMGlobalManager.get().startResource("resourceId",map);
//...
HashMap<String, Object> map = new HashMap<>();
map.put("ft_key_will_change", "ft_value_change"); //ft_key_will_change value will be changed to ft_value_change at stopResource
FTRUMGlobalManager.get().stopResource(uuid,map);
// Scenario 1
//Request start
FTRUMGlobalManager.get().startResource("resourceId")
//Request end
FTRUMGlobalManager.get().stopResource("resourceId")
//Finally, after the request ends, send request-related data metrics.
val params = ResourceParams()
params.url = "https://guance.com"
params.responseContentType = response.header("Content-Type")
arams.responseConnection = response.header("Connection")
params.responseContentEncoding = response.header("Content-Encoding")
params.responseHeader = response.headers.toString()
params.requestHeader = request.headers.toString()
params.resourceStatus = response.code
params.resourceMethod = request.method
val bean = NetStatusBean()
bean.tcpStartTime = 60000000
//...
FTRUMGlobalManager.get().addResource("resourceId",params,bean)
// Scenario 2 :Dynamic parameter usage
val map = hashMapOf<String, Any>(
"ft_key" to "ft_value",
"ft_key_will_change" to "ft_value"
)
FTRUMGlobalManager.get().startResource("resourceId", map)
//...
val map = hashMapOf<String, Any>(
"ft_key_will_change" to "ft_value_change"
)
// ft_key_will_change value will be changed to ft_value_change at stopResource
FTRUMGlobalManager.get().stopResource(uuid, map)
| Method Name | Required | Meaning | Description |
|---|---|---|---|
| NetStatusBean.fetchStartTime | No | Request start time | |
| NetStatusBean.tcpStartTime | No | tcp connection time | |
| NetStatusBean.tcpEndTime | No | tcp end time | |
| NetStatusBean.dnsStartTime | No | dns start time | |
| NetStatusBean.dnsEndTime | No | dns end time | |
| NetStatusBean.responseStartTime | No | Response start time | |
| NetStatusBean.responseEndTime | No | Response end time | |
| NetStatusBean.sslStartTime | No | ssl start time | |
| NetStatusBean.sslEndTime | No | ssl end time | |
| NetStatusBean.property | No | Additional attributes | |
| ResourceParams.url | Yes | url address | |
| ResourceParams.requestHeader | No | Request header parameters | |
| ResourceParams.responseHeader | No | Response header parameters | |
| ResourceParams.responseConnection | No | Response connection | |
| ResourceParams.responseContentType | No | Response ContentType | |
| ResourceParams.responseContentEncoding | No | Response ContentEncoding | |
| ResourceParams.resourceMethod | No | Request method | GET,POST etc. |
| ResourceParams.responseBody | No | Return body content | |
| ResourceParams.property | No | Additional attributes |
Logger Log Printing¶
Use FTLogger for custom log output. Requires enabling FTLoggerConfig.setEnableCustomLog(true).
Current log content limit is 30 KB. Excess characters will be truncated.
Usage¶
/**
* Store a single log data locally and sync
*
* @param content log content
* @param status log level, enum Status
* @param property additional attributes (optional)
*/
public void logBackground(String content, Status status, HashMap<String, Object> property)
/**
* Store a single log data locally and sync
*
* @param content log content
* @param status log level, String
* @param property additional attributes (optional)
*/
public void logBackground(String content, String status, HashMap<String, Object> property)
/**
* Store multiple log data locally and sync
*
* @param logDataList {@link LogData} list
*/
public void logBackground(List<LogData> logDataList)
/**
* Store a single log data locally and sync
*
* @param content log content
* @param status log level
* @param property log attributes (optional)
*/
fun logBackground(content: String, status: Status, property: HashMap<String, Any>)
/**
* Store a single log data locally and sync
*
* @param content log content
* @param status log level
* @param property log attributes (optional)
*/
fun logBackground(content: String, status: String, property: HashMap<String, Any>)
/**
* Store multiple log data locally and sync
*
* @param logDataList log data list
*/
fun logBackground(logDataList: List<LogData>)
Log Levels¶
| Method Name | Meaning |
|---|---|
| Status.DEBUG | Debug |
| Status.INFO | Info |
| Status.WARNING | Warning |
| Status.ERROR | Error |
| Status.CRITICAL | Critical |
| Status.OK | OK |
Code Example¶
// Upload single log
FTLogger.getInstance().logBackground("test", Status.INFO);
// Pass parameters to HashMap
HashMap<String, Object> map = new HashMap<>();
map.put("ft_key", "ft_value");
FTLogger.getInstance().logBackground("test", Status.INFO, map);
// Batch upload logs
List<LogData> logList = new ArrayList<>();
logList.add(new LogData("test", Status.INFO));
FTLogger.getInstance().logBackground(logList);
//Upload single log
FTLogger.getInstance().logBackground("test", Status.INFO)
//Pass parameters to HashMap
val map = HashMap<String,Any>()
map["ft_key"]="ft_value"
FTLogger.getInstance().logBackground("test", Status.INFO,map)
//Batch upload logs
FTLogger.getInstance().logBackground(mutableListOf(LogData("test",Status.INFO)))
Tracer Network Trace Linking¶
Configure FTTraceConfig to enable enableAutoTrace for automatic trace data addition, or manually use FTTraceManager to add Propagation Header in Http requests, as shown below:
String url = "https://request.url";
String uuid = "uuid";
// Get trace header parameters
Map<String, String> headers = FTTraceManager.get().getTraceHeader(uuid, url);
OkHttpClient client = new OkHttpClient.Builder().addInterceptor(chain -> {
Request original = chain.request();
Request.Builder requestBuilder = original.newBuilder();
// Add trace header parameters to the request
for (String key : headers.keySet()) {
requestBuilder.header(key, headers.get(key));
}
Request request = requestBuilder.build();
Response response = chain.proceed(request);
if (response != null) {
Map<String, String> requestHeaderMap = new HashMap<>();
Map<String, String> responseHeaderMap = new HashMap<>();
for (Pair<String, String> header : response.request().headers()) {
requestHeaderMap.put(header.first, header.second);
}
for (Pair<String, String> header : response.headers()) {
responseHeaderMap.put(header.first, header.second);
}
}
return response;
}).build();
Request.Builder builder = new Request.Builder().url(url).method(RequestMethod.GET.name(), null);
client.newCall(builder.build()).execute();
val url = "https://request.url"
val uuid ="uuid"
//Get trace header parameters
val headers = FTTraceManager.get().getTraceHeader(uuid, url)
val client: OkHttpClient = OkHttpClient.Builder().addInterceptor { chain ->
val original = chain.request()
val requestBuilder = original.newBuilder()
//Add trace header parameters to the request
for (key in headers.keys) {
requestBuilder.header(key!!, headers[key]!!)
}
val request = requestBuilder.build()
response = chain.proceed(request)
if (response != null) {
val requestHeaderMap = HashMap<String, String>()
val responseHeaderMap = HashMap<String, String>()
request.headers.forEach {
requestHeaderMap[it.first] = it.second
}
response!!.headers.forEach {
responseHeaderMap[it.first] = it.second
}
}
response!!
}.build()
val builder: Request.Builder = Request.Builder().url(url).method(RequestMethod.GET.name, null)
client.newCall(builder.build()).execute()
Custom Resource and TraceHeader via OKHttp Interceptor¶
When both FTRUMConfig's enableTraceUserResource and FTTraceConfig's enableAutoTrace are configured and enabled, custom Interceptor configuration takes priority.
ft-sdk < 1.4.1, need to disable
FTRUMConfig'senableTraceUserResourceandFTTraceConfig'senableAutoTrace. ft-sdk > 1.6.7 supports custom Trace Header association with RUM data.
new OkHttpClient.Builder()
.addInterceptor(new FTTraceInterceptor(new FTTraceInterceptor.HeaderHandler() {
@Override
public HashMap<String, String> getTraceHeader(Request request) {
HashMap<String, String> map = new HashMap<>();
map.put("custom_header","custom_value");
return map;
}
// Supported in 1.6.7+
@Override
public String getSpanID() {
return "span_id";
}
// Supported in 1.6.7+
@Override
public String getTraceID() {
return "trace_id";
}
}))
.addInterceptor(new FTResourceInterceptor(new FTResourceInterceptor.ContentHandlerHelper() {
@Override
public void onRequest(Request request, HashMap<String, Object> extraData) {
String contentType = request.header("Content-Type");
extraData.put("df_request_header", request.headers().toString());
if ("application/json".equals(contentType) ||
"application/x-www-form-urlencoded".equals(contentType) ||
"application/xml".equals(contentType)) {
extraData.put("df_request_body", request.body());
@Override
public void onResponse(Response response, HashMap<String, Object> extraData) throws IOException {
String contentType = response.header("Content-Type");
extraData.put("df_response_header", response.headers().toString());
if ("application/json".equals(contentType) ||
"application/xml".equals(contentType)) {
//copy part of the body to avoid large data consumption
ResponseBody body = response.peekBody(33554432);
extraData.put("df_response_body", body.string());
}
@Override
public void onException(Exception e, HashMap<String, Object> extraData)
}
}))
.eventListenerFactory(new FTResourceEventListener.FTFactory())
.build();
OkHttpClient.Builder()
.addInterceptor(FTTraceInterceptor(object : FTTraceInterceptor.HeaderHandler {
override fun getTraceHeader(request: Request): HashMap<String, String> {
val map = HashMap<String, String>()
map["custom_header"] = "custom_value"
return map
}
}))
.addInterceptor(FTResourceInterceptor(object : FTResourceInterceptor.ContentHandlerHelper {
override fun onRequest(request: Request, extraData: HashMap<String, Any>) {
val contentType = request.header("Content-Type")
extraData["df_request_header"] = request.headers().toString()
if ("application/json" == contentType ||
"application/x-www-form-urlencoded" == contentType ||
"application/xml" == contentType) {
extraData["df_request_body"] = request.body()
}
}
override fun onResponse(response: Response, extraData: HashMap<String, Any>) {
val contentType = response.header("Content-Type")
extraData["df_response_header"] = response.headers().toString()
if ("application/json" == contentType ||
"application/xml" == contentType) {
// Copy part of the response body to avoid large data consumption
val body = response.peekBody(33554432)
extraData["df_response_body"] = body.string()
}
}
override fun onException(e: Exception, extraData: HashMap<String, Any>) {
// Handle exception
}
}))
.eventListenerFactory(FTResourceEventListener.FTFactory())
.build()
ContentHandlerHelperEx Local Network Error Filtering¶
ContentHandlerHelperEx is an enhancement on ContentHandlerHelper, allowing filtering of local network IOException errors.
new FTResourceInterceptor.ContentHandlerHelperEx() {
//...
/**
* Returns exceptions during network connection
*
* @param e IOException data from the request
* @param extraData additional data
* @return Whether to filter local network `network_error` type errors. true means override.
*/
@Override
public boolean onExceptionWithFilter(Exception e, HashMap<String, Object> extraData) {
if (e instanceof SocketTimeoutException) { //Network timeout
return true;
}
return super.onExceptionWithFilter(e, extraData);
}
}
object : FTResourceInterceptor.ContentHandlerHelperEx() {
//...
/**
* Returns exceptions during network connection
*
* @param e IOException data from the request
* @param extraData additional data
* @return Whether to filter local network `network_error` type errors. true means override.
*/
override fun onExceptionWithFilter(e: Exception, extraData: HashMap<String, Any>): Boolean {
return if (e is SocketTimeoutException) {
true
} else {
super.onExceptionWithFilter(e, extraData)
}
}
}
OKhttp Add ResourceID¶
Add uuid to Okhttp Request. Recommended for high concurrency scenarios with identical requests. ft-plugin 1.3.5+, ft-sdk 1.6.10+ enable FTSDKConfig.setEnableOkhttpRequestTag(true) to automatically add ResourceID to Request.
User Information Binding and Unbinding¶
Use FTSdk for user binding and unbinding.
Usage¶
UserData¶
| Method Name | Meaning | Required | Note |
|---|---|---|---|
| setId | Set user ID | No | |
| setName | Set username | No | |
| setEmail | Set email | No | |
| setExts | Set user extensions | No | See rules for adding here |
Code Example¶
// Call this method after successful user login to bind user information.
FTSdk.bindRumUserData("001");
UserData userData = new UserData();
userData.setName("test.user");
userData.setId("test.id");
userData.setEmail("test@mail.com");
Map<String, String> extMap = new HashMap<>();
extMap.put("ft_key", "ft_value");
userData.setExts(extMap);
FTSdk.bindRumUserData(userData);
// Call this method after user logout to unbind user information.
FTSdk.unbindRumUserData();
//Call this method after successful user login to bind user information.
FTSdk.bindRumUserData("001")
//Bind more user data
val userData = UserData()
userData.name = "test.user"
userData.id = "test.id"
userData("test@mail.com")
val extMap = HashMap<String, String>()
extMap["ft_key"] = "ft_value"
userData.setExts(extMap)
FTSdk.bindRumUserData(userData)
//Call this method after user logout to unbind user information.
FTSdk.unbindRumUserData()
Shut Down SDK¶
Use FTSdk to shut down the SDK. If dynamically changing SDK configuration, shut down first to avoid generating erroneous data.
Clear SDK Cache Data¶
Use FTSdk to clear unsynced cache data.
Manually Sync Data¶
Use FTSdk to manually sync data.
Only needed when FTSdk.setAutoSync(false) is set.
Manually Sync Dynamic Configuration¶
Use FTSdk to manually sync dynamic configuration. When automatic updates don't meet requirements, use this to adjust update timing.
/**
* Manually update remote configuration, frequency controlled by FTSDKConfig.setRemoteConfigMiniUpdateInterval
*/
FTSdk.updateRemoteConfig();
/**
* Manually update remote configuration, ignores FTSDKConfig.setRemoteConfigMiniUpdateInterva configuration
*
* @param remoteConfigMiniUpdateInterval remote configuration time interval, unit seconds [0,)
* @param result returns update result
*/
FTSdk.updateRemoteConfig(int remoteConfigMiniUpdateInterval, FTRemoteConfigManager.FetchResult result);
/**
* Manually update remote configuration, frequency controlled by FTSDKConfig.setRemoteConfigMiniUpdateInterval
*/
FTSdk.updateRemoteConfig()
/**
* Manually update remote configuration, ignores FTSDKConfig.setRemoteConfigMiniUpdateInterva configuration
*
* @param remoteConfigMiniUpdateInterval remote configuration time interval, unit seconds [0,)
* @param result returns update result
*/
FTSdk.updateRemoteConfig(remoteConfigMiniUpdateInterval:Int,result:FTRemoteConfigManager.FetchResult)
Dynamically Enable and Disable AndroidID Access¶
Use FTSdk to set whether to obtain Android ID in the SDK.
Add Custom Tags¶
Use FTSdk to dynamically add tags during SDK runtime.
Usage¶
/**
* Dynamically set global tag
* @param globalContext
*/
public static void appendGlobalContext(HashMap<String,Object> globalContext)
/**
* Dynamically set RUM global tag
* @param globalContext
*/
public static void appendRUMGlobalContext(HashMap<String,Object> globalContext)
/**
* Dynamically set log global tag
* @param globalContext
*/
public static void appendLogGlobalContext(HashMap<String,Object> globalContext)
/**
* Dynamically set global tag
* @param globalContext
*/
fun appendGlobalContext(globalContext: HashMap<String, Any>)
/**
* Dynamically set RUM global tag
* @param globalContext
*/
fun appendRUMGlobalContext(globalContext: HashMap<String, Any>)
/**
* Dynamically set log global tag
* @param globalContext
*/
fun appendLogGlobalContext(globalContext: HashMap<String, Any>)
Code Example¶
HashMap<String, Object> globalContext = new HashMap<>();
globalContext.put("global_key", "global_value");
FTSdk.appendGlobalContext(globalContext);
HashMap<String, Object> rumGlobalContext = new HashMap<>();
rumGlobalContext.put("rum_key", "rum_value");
FTSdk.appendRUMGlobalContext(rumGlobalContext);
HashMap<String, Object> logGlobalContext = new HashMap<>();
logGlobalContext.put("log_key", "log_value");
FTSdk.appendLogGlobalContext(logGlobalContext);
val globalContext = hashMapOf<String, Any>(
"global_key" to "global_value"
)
FTSdk.appendGlobalContext(globalContext)
val rumGlobalContext = hashMapOf<String, Any>(
"rum_key" to "rum_value"
)
FTSdk.appendRUMGlobalContext(rumGlobalContext)
val logGlobalContext = hashMapOf<String, Any>(
"log_key" to "log_value"
)
FTSdk.appendLogGlobalContext(logGlobalContext)
Symbol File Upload¶
plugin upload (Only supports datakit [Local Deployment])¶
ft-plugin version 1.3.0+ supports the latest symbol file upload rules, supports productFlavor multi-version management. The plugin will upload symbol files after gradle task assembleRelease. For detailed configuration, refer to SDK Demo
FTExt {
//...
autoUploadMap = true // Upload mapping.txt file, defaults to false
autoUploadNativeDebugSymbol = true // Upload c/c++ symbol so files, defaults to false
datakitUrl = 'https://datakit.url' // datakit upload address, not needed when generateSourceMapOnly=true
datawayToken = 'dataway_token' // Workspace token, not needed when generateSourceMapOnly=true
appId = "appid_xxxxx" // appid, not needed when generateSourceMapOnly=true
env = 'common' // environment, not needed when generateSourceMapOnly=true
// native so specified path, just specify the upper directory of the abi files
// |-stripped_native_libs
// |-release
// |-out
// |-lib
// |-arm64-v8a
// |-armeabi-v7a
// |-...
//nativeLibPath='/build/intermediates/merged_native_libs/release/out/lib'
generateSourceMapOnly = false //Only generate sourcemap, defaults to false, path example: /app/build/tmp/ft{flavor}SourceMapMerge-release.zip, supported in ft-plugin:1.3.4+
prodFlavors { //prodFlavors configuration overrides outer settings
prodTest {
autoUploadMap = false
autoUploadNativeDebugSymbol = false
datakitUrl = 'https://datakit.url'
datawayToken = 'dataway_token'
appId = "appid_prodTest"
env = "gray"
}
prodPublish {
autoUploadMap = true
autoUploadNativeDebugSymbol = true
datakitUrl = 'https://datakit.url'
datawayToken = 'dataway_token'
appId = "appid_prodPublish"
env = "prod"
}
}
}
Manual Upload¶
Use plugin with generateSourceMapOnly = true, execute gradle task assembleRelease to generate, or package into a zip file yourself, then upload to datakit or upload from Guance Studio. Recommended to use zip command line to package, avoiding including system hidden files in the zip. For symbol upload, refer to sourcemap upload
For Unity Native Symbol files, refer to official documentation
Permission Configuration Description¶
| Name | Required | Usage Reason |
|---|---|---|
READ_PHONE_STATE |
No | Used to obtain phone cellular network device information |
For how to request dynamic permissions, refer to Android Developer
Plugin AOP Ignore¶
Add @IngoreAOP to methods overridden by Plugin AOP to ignore ASM insertion. For batch ignore, use ft-plugin FTExt's ignorePackages.
WebView Data Monitoring¶
WebView data monitoring requires integrating the Web Monitoring SDK on the WebView access page.
Data Masking¶
If you want full masking of fields, setDataModifier is recommended for better performance. For detailed rule replacement, setLineDataModifier is recommended.
Do not use complex or high-latency methods in the callback, as this will severely impact SDK data writing performance.
FTSdk.install(
FTSDKConfig.builder("xxx")
.setDataModifier(new DataModifier() {
/**
* Modify a specific field
*
* @param key field name
* @param value field value (original value)
* @return new value, return null for no change
*/
@Override
public Object modify(String key, Object value) {
if (key.equals("device_uuid")) {
return "xxx";
}
return null;
}
}).setLineDataModifier(new LineDataModifier() {
/***
* Modify a single line of data
*
* @param measurement data measurement type view, action, resource,
* longtask, error, df_rum_android_log
* @param data original data key-value pairs
* @return key-value pairs to modify (returning null or empty map means no change)
*/
@Override
public Map<String, Object> modify(String measurement, HashMap<String, Object> data) {
if(measurement.equals("view")){
HashMap<String,Object> changeMap = new HashMap<String,Object>();
changeMap.put("view_url", "xxx");
}
return null;
}
}))
FTSdk.install(
FTSDKConfig.builder("xxx")
.setDataModifier(object : DataModifier {
/**
* Modify a specific field
*
* @param key field name
* @param value field value (original value)
* @return new value, return null for no change
*/
override fun modify(key: String, value: Any?): Any? {
return if (key == "device_uuid") {
"xxx" // Replace with custom device_uuid
} else {
null
}
}
})
// Batch modify specific fields in a single data line
.setLineDataModifier(object : LineDataModifier {
/**
* Modify a single line of data
*
* @param measurement data measurement type view, action, resource,
* longtask, error, df_rum_android_log
* @param data original data key-value pairs
* @return key-value pairs to modify (returning null or empty map means no change)
*/
override fun modify(
measurement: String,
data: HashMap<String, Any>
): Map<String, Any>? {
return if (measurement == "view") {
hashMapOf("view_url" to "xxx")
} else {
null
}
}
}))
RUM Custom Collection Rules¶
View¶
Activity¶
- Requires
FTRUMConfig.setEnableTraceUserView(true)enabled.
FTSdk.initRUMWithConfig(new FTRUMConfig()
.setViewActivityTrackingHandler(new FTViewActivityTrackingHandler() {
@Override
public HandlerView resolveHandlerView(Activity activity) {
String activityName = activity.getClass().getSimpleName();
// Customize view name based on Activity name
if (activityName.startsWith("Main")) {
return new HandlerView("Custom Main Page");
} else if (activityName.startsWith("Detail")) {
HashMap<String, Object> properties = new HashMap<>();
properties.put("extra_key", "extra_value");
return new HandlerView("Custom Detail Page", properties);
}
// Return null to skip tracking
return null;
}
})
);
FTSdk.initRUMWithConfig(
FTRUMConfig()
.setViewActivityTrackingHandler(object : FTViewActivityTrackingHandler {
override fun resolveHandlerView(activity: Activity): HandlerView? {
val activityName = activity.javaClass.simpleName
return when {
activityName.startsWith("Main") ->
HandlerView("Custom Main Page")
activityName.startsWith("Detail") -> {
val properties = hashMapOf<String, Any>("extra_key" to "extra_value")
HandlerView("Custom Detail Page", properties)
}
else -> null // Skip tracking
}
}
})
)
Fragment¶
- Requires both
FTRUMConfig.setEnableTraceUserView(true)andFTRUMConfig.setEnableTraceUserViewInFragment(true)enabled.
FTSdk.initRUMWithConfig(new FTRUMConfig()
.setViewFragmentTrackingHandler(new FTViewFragmentTrackingHandler() {
@Override
public HandlerView resolveHandlerView(FragmentWrapper fragment) {
String fragmentName = fragment.getSimpleClassName();
// Customize view name based on Fragment name
if (fragmentName.equals("HomeFragment")) {
return new HandlerView("Custom Home Fragment");
} else if (fragmentName.startsWith("Detail")) {
HashMap<String, Object> properties = new HashMap<>();
properties.put("extra_key", "extra_value");
return new Handler HandlerView("Custom Detail Fragment", properties);
}
// Return null to skip tracking
return null;
}
})
);
FTSdk.initRUMWithConfig(
FTRUMConfig()
.setViewFragmentTrackingHandler(object : FTViewFragmentTrackingHandler {
override fun resolveHandlerView(fragment: FragmentWrapper): HandlerView? {
val fragmentName = fragment.simpleClassName
return when {
fragmentName == "HomeFragment" ->
HandlerView("Custom Home Fragment")
fragmentName.startsWith("Detail") -> {
val properties = hashMapOf<String, Any>("extra_key" to "extra_value")
HandlerView("Custom Detail Fragment", properties)
}
else -> null // Skip tracking
}
}
})
)
Action¶
- Requires
FTRUMConfig.setEnableTraceUserAction(true)enabled.
FTSdk.initRUMWithConfig(new FTRUMConfig()
.setActionTrackingHandler(new FTActionTrackingHandler() {
@Override
public HandlerAction resolveHandlerAction(ActionEventWrapper actionEventWrapper) {
// Get operation type
ActionSourceType actionType = actionEventWrapper.getSourceType();
// Custom tracking based on operation type
if (actionType == ActionSourceType.CLICK_VIEW) {
HashMap<String, Object> properties = new HashMap<>();
properties.put("extra_key", "extra_value");
return new HandlerAction("Custom Button Click", properties);
} else if (actionType == ActionSourceType.CLICK_LIST_ITEM) {
return new HandlerAction("Custom List Item Click");
}
// Return null to skip tracking
return null;
}
})
);
FTSdk.initRUMWithConfig(
FTRUMConfig()
.setActionTrackingHandler(object : FTActionTrackingHandler {
override fun resolveHandlerAction(actionEventWrapper: ActionEventWrapper): HandlerAction? {
return when (actionEventWrapper.sourceType) {
ActionSourceType.CLICK_VIEW -> {
val properties = hashMapOf<String, Any>("extra_key" to "extra_value")
HandlerAction("Custom Button Click", properties)
}
ActionSourceType.CLICK_LIST_ITEM ->
HandlerAction("Custom List Item Click")
else -> null // Skip tracking
}
}
})
)
Resource¶
- Requires
FTRUMConfig.setEnableTraceUserResource(true)enabled.
Custom Tag Usage Example¶
Compile Configuration Method¶
- Create multiple
productFlavorsinbuild.gradleto differentiate tags.
android{
//...
productFlavors {
prodTest {
buildConfigField "String", "CUSTOM_VALUE", "\"Custom Test Value\""
//...
}
prodPublish {
buildConfigField "String", "CUSTOM_VALUE", "\"Custom Publish Value\""
//...
}
}
}
- Add corresponding
BuildConfigconstants inRUMconfiguration.
Runtime Read/Write File Method¶
- Store data in files, such as
SharedPreferences, configure theSDK, and add code to get tag data at the configuration point.
SharedPreferences sp = context.getSharedPreferences(SP_STORE_DATA, MODE_PRIVATE);
String customDynamicValue = sp.getString(CUSTOM_DYNAMIC_TAG, "not set");
// Configure RUM
FTSdk.initRUMWithConfig(
new FTRUMConfig().addGlobalContext(CUSTOM_DYNAMIC_TAG, customDynamicValue)
//... Add other configurations
);
- Add methods to change file data anywhere.
- Finally, restart the application. For details, see SDK Demo
Add at SDK Runtime¶
After SDK initialization, use FTSdk.appendGlobalContext(globalContext), FTSdk.appendRUMGlobalContext(globalContext), FTSdk.appendLogGlobalContext(globalContext) to dynamically add tags. After setting, it takes effect immediately. Subsequently, RUM or Log data reported later will automatically include tag data. This method is suitable for scenarios where data acquisition is delayed, such as tag data requiring network requests.
//SDK initialization pseudo code, get parameters from the network before setting tags.
FTSdk.init()
getInfoFromNet(info){
HashMap<String, Object> globalContext = new HashMap<>();
globalContext.put("delay_key", info.value);
FTSdk.appendGlobalContext(globalContext)
}
Content Provider Setup Guide¶
To optimize multi-process data collection. ft-sdk: >= 1.6.14 version uses ContentProvider. The SDK uses the following configuration by default, adapting to different applicationIds.
<provider
android:name="com.ft.garble.db.FTContentProvider"
android:authorities="${applicationId}.com.ft.sdk.provider"
android:exported="false"
android:multiprocess="true" >
</provider>
Custom provider¶
If customization is needed, use tools:replace to override the provider settings, set meta-data.
Note:
android:authoritiesinprovidermust matchandroid:valueinmeta-data.
<provider
tools:replace="android:authorities"
android:name="com.ft.sdk.garble.db.FTContentProvider"
android:authorities="com.custom.app.provider"
android:exported="false"
android:multiprocess="true" >
</provider>
<meta-data
android:name="com.ft.sdk.PROVIDER_AUTHORITY"
android:value="com.custom.app.provider" />
Common Questions¶
Avoid Conflict Fields by Adding Project Prefix¶
To avoid conflicts between custom fields and SDK data, it is recommended to add a project abbreviation prefix to tag names, such as df_tag_name. The key values used in the project can be queried in the source code. When the same variable appears in the SDK global variables and RUM/Log, RUM/Log will override the global variables in the SDK.
SDK Compatibility¶
Coping with Market Privacy Audits¶
Privacy Statement¶
Method 1: SDK AndroidID Configuration¶
The SDK uses Android ID to better associate data from the same user. If you need to publish on app markets, use the following method to comply with market privacy audits.
public class DemoApplication extends Application {
@Override
public void onCreate() {
// Set setEnableAccessAndroidID to false during initial setup
FTSDKConfig config = new FTSDKConfig.Builder(DATAKIT_URL)
.setEnableAccessAndroidID(false)
.build();
FTSdk.install(config);
// ...
}
}
// Enable after user agrees to privacy policy
FTSdk.setEnableAccessAndroidID(true);
class DemoApplication : Application() {
override fun onCreate() {
//Set setEnableAccessAndroidID to false during initial setup
val config = FTSDKConfig
.builder(DATAKIT_URL)
. setEnableAccessAndroidID(false)
FTSdk.install(config)
//...
}
}
//Enable after user agrees to privacy policy
FTSdk.setEnableAccessAndroidID(true);
Method 2: Delay SDK Initialization¶
If you need to delay loading the SDK in the application, it is recommended to initialize it as follows.
// Application
public class DemoApplication extends Application {
@Override
public void onCreate() {
//If already agreed to the protocol, initialize in Application
if(agreeProtocol){
FTSdk.init(); //SDK initialization pseudo code
}
}
}
// Privacy Statement Activity page
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
//Not read privacy statement
if ( notReadProtocol ) {
//Show privacy statement popup
showProtocolView();
//If agree to privacy statement
if( agreeProtocol ){
FTSdk.init(); //SDK initialization pseudo code
}
}
}
}
// Application
class DemoApplication : Application() {
override fun onCreate() {
// If already agreed to the protocol, initialize in Application
if (agreeProtocol) {
FTSdk.init() //SDK initialization pseudo code
}
}
}
// Privacy Statement Activity page
class MainActivity : Activity() {
override fun onCreate(savedInstanceState: Bundle?) {
// Not read privacy statement
if (notReadProtocol) {
// Show privacy statement popup
showProtocolView()
// If agree to privacy statement
if (agreeProtocol) {
FTSdk.init() //SDK initialization pseudo code
}
}
}
}
Third-party Frameworks¶
flutter, react-native, uni-app, unity can adopt similar delayed initialization methods as native Android to cope with app market privacy audits.
Jetpack Compose Support¶
Currently does not support automatic collection of pages generated by compose components, but you can use manual Action and View custom interfaces to track click events and page navigation events. Refer to here
How to Integrate SDK Without Using ft-plugin¶
Guance uses Android Gradle Plugin Transformation for code injection to achieve automatic data collection. However, due to compatibility issues, there may be problems using ft-plugin or ft-plugin-legacy. Affected functions include RUM Action, Resource, and android.util.Log, Java and Kotlin println console log automatic capture, and automatic upload of symbol files.
Currently, we have another integration scheme for this situation. The coping plan is as follows:
- Application startup event, source code example reference DemoForManualSet.kt
- Button and other events need to be added manually at the trigger point. For example, take Button onClick event as an example, source code reference ManualActivity.kt:
OKhttpintegratesResource,TracethroughaddInterceptor,eventListenermethods, as shown below. Source code reference ManualActivity.kt:
OkHttpClient.Builder builder = new OkHttpClient.Builder()
.addInterceptor(new FTTraceInterceptor())
.addInterceptor(new FTResourceInterceptor())
.eventListenerFactory(new FTResourceEventListener.FTFactory());
//.eventListenerFactory(new FTResourceEventListener.FTFactory(true));
OkHttpClient client = builder.build();
-
Other network frameworks need to implement
startResource,stopResource,addResourceinFTRUMGlobalManager, andFTTraceManager.getTraceHeaderthemselves. For specific implementation, refer to the source code example ManualActivity.kt -
WebView data collection configuration