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 accessible over the public network and install the IP Geolocation database.
Application Integration¶
- Go to User Access Monitoring > New 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 remote repository address for the Plugin
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 remote repository address for the Plugin
maven {
url('https://mvnrepo.jiagouyun.com/repository/maven-releases')
}
}
}
//build.gradle
plugins{
//Add the Plugin dependency, 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.
//
// 1.RUM: App startup, OkHttp requests, WebView activity, Activity/Fragment navigation, click events
// 2.Log: Console Logcat
apply plugin: 'ft-plugin' //If using ft-plugin-legacy, use the same configuration
//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 the path
//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.+'
}
For the latest versions, see the version names for
ft-sdk,ft-plugin, andft-nativeabove.
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 yet, you need to create one and declare it in AndroidManifest.xml. For an example, refer 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 class names from being obfuscated when getting action_name in Action ###
-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, port defaults to 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 [User Access Monitoring] 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, SDK runtime logs are printed when enabled. |
| setEnv | EnvType | No | Set the collection environment, defaults to EnvType.PROD. |
| setEnv | String | No | Set the collection environment, defaults to prod. Note: Only configure one of String or EnvType type |
| setOnlySupportMainProcess | Boolean | No | Whether to only support running in the main process, defaults to true. Set this field to false if needed in other processes. |
| setEnableAccessAndroidID | Boolean | No | Enable getting Android ID, defaults to true. Set to false, then the device_uuid field data will not be collected. For market privacy audits, see here |
| addGlobalContext | Dictionary | No | Add SDK global attributes. For addition rules, please check 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 synchronization manually. |
| setSyncPageSize | Int | No | Set the sync request item count, SyncPageSize.MINI 5 items, SyncPageSize.MEDIUM 10 items, SyncPageSize.LARGE 50 items, default SyncPageSize.MEDIUM |
| setCustomSyncPageSize | Enum | No | Set the sync request item count, range [5,). Note: a larger item count means data synchronization uses more computing resources, defaults to 10 Note: Only configure one of setSyncPageSize and setCustomSyncPageSize |
| setSyncSleepTime | Int | No | Set the sync interval time, range [0,5000], unit ms, defaults to 0 |
| enableDataIntegerCompatible | Void | No | Recommended to enable 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 | Compress upload sync data with deflate, disabled by default, supported in ft-sdk version 1.6.3+ |
| enableLimitWithDbSize | Void | No | Enable using db to limit data size, default 100MB, unit Byte. Larger database means more disk pressure, disabled by default. Note: After enabling, FTLoggerConfig.setLogCacheLimitCount and FTRUMConfig.setRumCacheLimitCount will become invalid. Supported in ft-sdk version 1.6.6+ |
| setEnableOkhttpRequestTag | Boolean | No | Automatically add unique ResourceID to Okhttp Request, for high concurrency scenarios with the same request. Supported in ft-sdk 1.6.10+, ft-plugin 1.3.5+ |
| setProxy | java.net.Proxy | No | Set Proxy proxy for data network sync requests, only supports okhttp3, supported in ft-sdk 1.6.10+ |
| setProxyAuthenticator | okhttp3.Authenticator | No | Set Proxy proxy for data sync network requests, only supports okhttp3, supported in ft-sdk 1.6.10+ |
| setDns | okhttp3.Dns | No | Data sync network requests support custom Dns for custom domain name resolution, only supports okhttp3, supported in ft-sdk 1.6.10+ |
| setDataModifier | DataModifier | No | Modify individual fields. Supported in ft-sdk 1.6.11+, usage example here |
| setLineDataModifier | LineDataModifier | No | Modify single data item. Supported in ft-sdk 1.6.11+, usage example here |
| setRemoteConfiguration | Boolean | No | Whether to enable remote configuration for data collection, defaults to false. When enabled, SDK initialization or application hot start will trigger data update. Supported in ft-sdk 1.6.12+. Datakit version requirement >=1.60 or use public dataway. |
| setRemoteConfigMiniUpdateInterval | Int | No | Set the minimum update interval for data, unit seconds, default 12 hours. Supported in ft-sdk 1.6.12+ |
| setRemoteConfigurationCallBack | FTRemoteConfigManager.FetchResult | No | Remote configuration result callback, code example. Supported in ft-sdk 1.6.16+ |
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 the RUM appid, which enables the RUM collection function. Get appid method |
| setSamplingRate | Float | No | Set collection rate, value range [0,1], 0 means no collection, 1 means full collection, default value is 1. Scope is 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. Value range [0,1], 0 means no collection, 1 means full collection, default value is 0. Scope is 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. When enabled, error stack data will be shown in error analysis.About converting obfuscated content in crash logs. In ft-sdk version 1.5.1+, you can use extraLogCatWithJavaCrash, extraLogCatWithNativeCrash to set whether to show logcat 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 rate, not set by default. |
| setDeviceMetricsMonitorType | Array | No | Set View monitoring information. During the View cycle, add monitoring data. DeviceMetricsMonitorType.BATTERY monitors the highest output current of the current page, DeviceMetricsMonitorType.MEMORY monitors the current application memory usage, DeviceMetricsMonitorType.CPU monitors CPU ticks, DeviceMetricsMonitorType.FPS monitors screen frame rate. Monitoring frequency: DetectFrequency.DEFAULT 500 ms, DetectFrequency.FREQUENT 100ms, DetectFrequency.RARE 1 second, not set by default. |
| setEnableTrackAppANR | Boolean | No | Whether to enable ANR detection, defaults to false.In ft-sdk version 1.5.1+, you can use extraLogCatWithANR to set whether to show logcat in ANR. |
| setEnableTrackAppUIBlock | Boolean, long | No | Whether to enable UI blocking detection, defaults to false. ft-sdk version 1.6.4+ can use blockDurationMs to control detection time range [100,), unit ms, default is 1 second. |
| setEnableTraceUserAction | Boolean | No | Whether to automatically track user operations, currently only supports user startup and click operations. This configuration depends on ft-plugin, defaults to false. |
| setEnableTraceUserView | Boolean | No | Whether to automatically track user page operations. This configuration depends on ft-plugin, defaults to false. |
| setEnableTraceUserViewInFragment | Boolean | No | Whether to automatically track Fragment type page data. This configuration depends on ft-plugin, defaults to false. Supported in ft-sdk 1.6.11+. |
| setEnableTraceUserResource | Boolean | No | Whether to automatically track user network requests. This configuration depends on ft-plugin, only supports Okhttp, defaults to false. |
| setEnableResourceHostIP | Boolean | No | Whether to collect the IP address of the requested target domain. Scope: Only affects the default collection when EnableTraceUserResource is true. For custom Resource collection, you need to use FTResourceEventListener.FTFactory(true) to enable this function. Also, a single Okhttp has an IP caching mechanism for the same domain name. For the same OkhttpClient, if the server IP does not change, it will only be generated once. |
| 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 user monitoring data source differentiation. If you need to use the tracing function, then the parameter key is track_id, value is any value. For addition rule precautions, please check here. |
| setRumCacheLimitCount | int | No | Local cache RUM limit count [10_000,), default is 100_000. Supported in ft-sdk 1.6.6+. |
| setEnableTraceWebView | Boolean | No | Configure whether to collect WebView data through the Android SDK, defaults to true. Supported in ft-sdk 1.6.12+. |
| setAllowWebViewHost | Array | No | Set the WebView host addresses allowed for data tracking, null means collect all, defaults to null. Supported in ft-sdk 1.6.12+. |
| setViewActivityTrackingHandler | FTViewActivityTrackingHandler | No | Used to customize how Activity views are tracked. When an Activity lifecycle event occurs, this handler is called 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. When a Fragment lifecycle event occurs, this handler is called to decide how to track the Fragment. Supported in ft-sdk 1.6.13+. |
| setActionTrackingHandler | FTActionTrackingHandler | No | Used to customize how user operations (app startup, clicks) are tracked. When a user performs an operation, this handler is called to decide how to track the operation. No processing by default. Supported in ft-sdk 1.6.13+. |
Log Configuration¶
| Method Name | Type | Required | Meaning |
|---|---|---|---|
| setSamplingRate | Float | No | Set collection rate, value range [0,1], 0 means no collection, 1 means full collection, default value is 1. |
| setEnableConsoleLog | Boolean | No | Whether to report console logs. This configuration depends on ft-plugin, default false. Log level correspondence:Log.v -> ok; Log.i -> info; Log.d -> debug; Log.e -> error; Log.w -> warning. prefix is the control prefix filter parameter, no filtering by default. Note: The Android console volume is very large. To avoid affecting application performance and reduce unnecessary resource waste, it is recommended to use prefix to filter out valuable logs. ft-plugin version 1.3.5+ supports capturing logs printed by Log.println. |
| setEnableLinkRUMData | Boolean | No | Whether to associate with RUM data, defaults to false. |
| setEnableCustomLog | Boolean | No | Whether to upload custom logs, defaults to false. |
| setLogLevelFilters | Array | No | Set level log filtering, not set by default. |
| addGlobalContext | Dictionary | No | Add log global attributes. For addition rules, please check here. |
| setLogCacheLimitCount | Int | No | Local cache maximum log entry count limit [1000,). Larger log means greater disk cache pressure, defaults to 5000. |
| setLogCacheDiscardStrategy | LogCacheDiscard | No | Set the log discard rule when the log reaches the upper limit. Defaults to LogCacheDiscard.DISCARD. DISCARD discards appended data, DISCARD_OLDEST discards oldest data. |
Trace Configuration¶
| Method Name | Type | Required | Meaning |
|---|---|---|---|
| setSamplingRate | Float | No | Set collection rate, value range [0,1], 0 means no collection, 1 means full collection, default value is 1. |
| setTraceType | TraceType | No | Set the type of trace linking, defaults to DDTrace. Currently supports Zipkin, Jaeger, DDTrace, Skywalking (8.0+), TraceParent (W3C). If integrating OpenTelemetry, please check the supported types and agent related configurations when selecting the corresponding trace type. |
| setEnableLinkRUMData | Boolean | No | Whether to associate with RUM data, defaults to false. |
| setEnableAutoTrace | Boolean | No | Set whether to enable automatic http trace. This configuration depends on ft-plugin, 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¶
Configure enableTraceUserAction, enableTraceUserView, enableTraceUserResource,setEnableTrackAppUIBlock,setEnableTrackAppCrash and setEnableTrackAppANR in FTRUMConfig to achieve automatic collection of Action, View, Resource, LongTask, Error data. If you want custom collection, you can use FTRUMGlobalManager to report data, examples are as follows:
Action¶
Usage¶
/**
* Add Action
*
* @param actionName action name
* @param actionType action type
* @param property additional attribute parameters (optional)
*/
public void startAction(String actionName, String actionType, HashMap<String, Object> property)
/**
* Add Action. This type of data cannot associate Error, Resource, LongTask data.
*
* @param actionName action name
* @param actionType action type
* @param duration nanoseconds, duration (optional)
* @param property extension 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 attribute parameters (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 extension attributes (optional)
*/
fun addAction(actionName: String, actionType: String, duration: Long, property: HashMap<String, Any>)
startAction has an internal algorithm to calculate time consumption. During the calculation period, it will try to associate data with nearby Resource, LongTask, Error data, and has a 100 ms frequent trigger protection. It is recommended for user operation type data. If you need frequent calls, please use addAction. This data will not conflict with startAction and will not associate 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 attribute parameters (optional)
*/
public void startView(String viewName, HashMap<String, Object> property)
/**
* view end
*
* @param property additional attribute parameters (optional)
*/
public void stopView(HashMap<String, Object> property)
/**
* Update the current view loading_time metric, unit nanoseconds.
* @param duration
*/
public void updateLoadTime(long duration)
/**
* view start
*
* @param viewName current page name
* @param property additional attribute parameters (optional)
*/
fun startView(viewName: String, property: HashMap<String, Any>)
/**
* view end
*
* @param property additional attribute parameters (optional)
*/
fun stopView(property: HashMap<String, Any>)
/**
* Update the 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"); //The value for ft_key_will_change will be changed to ft_value_change at stopView time.
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" //The value for ft_key_will_change will be changed to ft_value_change at stopView time.
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: Delay recording the occurred error, the time here is usually the time the error occurred.
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: Delay recording the occurred error, the time here is usually the time the error occurred.
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 attribute parameters (optional)
*/
public void startResource(String resourceId, HashMap<String, Object> property)
/**
* resource stop
*
* @param resourceId resource Id
* @param property additional attribute parameters (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 attribute parameters (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 the request-related data metrics.
ResourceParams params = new ResourceParams();
params.setUrl("https://truewatch.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"); //The value for ft_key_will_change will be changed to ft_value_change at stopResource time.
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 the request-related data metrics.
val params = ResourceParams()
params.url = "https://truewatch.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"
)
// The value for ft_key_will_change will be changed to ft_value_change at stopResource time.
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).
The log content is currently limited to 30 KB. Characters beyond this limit 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 enableAutoTrace in FTTraceConfig to automatically add trace data, or manually use FTTraceManager to add Propagation Header in Http requests, examples are as follows:
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()
Customizing Resource and TraceHeader via OKHttp Interceptor¶
Resource¶
When FTRUMConfig.setEnableTraceUserResource(true) or FTRUMConfig.setOkHttpResourceContentHandler(FTResourceInterceptor.ContentHandlerHelperEx) is enabled, custom Interceptor in Okhttp will be loaded first.
new OkHttpClient.Builder()
.addInterceptor(new FTTraceInterceptor())
.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 read part of the body to avoid consuming large data
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())
.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 situations
}
}))
.eventListenerFactory(FTResourceEventListener.FTFactory())
.build()
TraceHeader¶
When FTTraceConfig.setEnableAutoTrace(true) or FTTraceConfig.setOkHttpTraceHeaderHandler(FTTraceInterceptor.HeaderHandler) is enabled, custom Interceptor in Okhttp will be loaded first. The following is an example for w3c-traceContext.
ft-sdk < 1.4.1, need to disable
FTTraceConfig.setEnableAutoTrace(false). ft-sdk > 1.6.7 supports custom Trace Header association with RUM data.
new OkHttpClient.Builder()
.addInterceptor(new FTTraceInterceptor(new FTTraceInterceptor.HeaderHandler() {
private String[] splits;
@Override
public HashMap<String, String> getTraceHeader(Request request) {
HashMap<String, String> map = new HashMap<>();
String headerString = FTTraceManager.get().
getTraceHeader(request.url().toString())
// Get propagation header from header
.get(FTTraceHandler.W3C_TRACEPARENT_KEY);
splits = headerString.split("-");
map.put(W3C_TRACEPARENT_KEY, headerString);
return map;
}
@Override
public String getSpanID() {
if (splits != null) {
return splits[2];
}
return null;
}
@Override
public String getTraceID() {
if (splits != null) {
return splits[1];
}
return null;
}
}))
.addInterceptor(new FTResourceInterceptor())
.eventListenerFactory(new FTResourceEventListener.FTFactory())
.build();
OkHttpClient.Builder()
.addInterceptor(
FTTraceInterceptor(object : FTTraceInterceptor.HeaderHandler {
private var splits: Array<String>? = null
override fun getTraceHeader(request: Request): HashMap<String, String> {
val map = HashMap<String, String>()
val headerString = FTTraceManager.get()
.getTraceHeader(request.url.toString())
// Get propagation header from header
.get(FTTraceHandler.W3C_TRACEPARENT_KEY)
splits = headerString?.split("-")?.toTypedArray()
headerString?.let {
map[W3C_TRACEPARENT_KEY] = it
}
return map
}
override fun getSpanID(): String? {
return splits?.getOrNull(2)
}
override fun getTraceID(): String? {
return splits?.getOrNull(1)
}
})
)
.addInterceptor(FTResourceInterceptor())
.eventListenerFactory(FTResourceEventListener.FTFactory())
.build()
OKhttp Adding ResourceID¶
Add uuid to Okhttp Request. It is recommended to enable this for high-frequency concurrent scenarios with the same request. ft-plugin version 1.3.5+, ft-sdk version 1.6.10+ enable FTSDKConfig.setEnableOkhttpRequestTag(true) can 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 | For addition rules, please check here |
Code Example¶
// You can call this method after the user successfully logs in to bind user information.
FTSdk.bindRumUserData("001");
UserData userData = new UserData();
userData.setName("test.user");
userData.setId("test.id");
userData.setEmail("[email protected]");
Map<String, String> extMap = new HashMap<>();
extMap.put("ft_key", "ft_value");
userData.setExts(extMap);
FTSdk.bindRumUserData(userData);
// You can call this method after the user logs out to unbind user information.
FTSdk.unbindRumUserData();
//You can call this method after the user successfully logs in to bind user information.
FTSdk.bindRumUserData("001")
//Bind more user data
val userData = UserData()
userData.name = "test.user"
userData.id = "test.id"
userData("[email protected]")
val extMap = HashMap<String, String>()
extMap["ft_key"] = "ft_value"
userData.setExts(extMap)
FTSdk.bindRumUserData(userData)
//You can call this method after the user logs out to unbind user information.
FTSdk.unbindRumUserData()
Shut Down SDK¶
Use FTSdk to shut down the SDK. If dynamically changing SDK configuration, you need to shut down first to avoid generating wrong data.
Clear SDK Cache Data¶
Use FTSdk to clear unreported cache data.
Actively Sync Data¶
Use FTSdk to actively sync data.
Only needed when FTSdk.setAutoSync(false) is set.
Actively Sync Dynamic Configuration¶
Use FTSdk to actively sync dynamic configuration. When automatic updates do not meet the requirements, adjust the update timing by actively calling this method.
ft-sdk:>1.6.16 support. Use
FetchResult.onConfigSuccessFetched(RemoteConfigBean configBean, String jsonConfig)to parse environment variables yourself.
/**
* Actively update remote configuration, call frequency is affected by FTSDKConfig.setRemoteConfigMiniUpdateInterval
*/
FTSdk.updateRemoteConfig();
/**
* Actively update remote configuration, this method ignores the FTSDKConfig.setRemoteConfigMiniUpdateInterval configuration
*
* @param remoteConfigMiniUpdateInterval remote configuration time interval, unit seconds [0,)
* @param result returns update result
*/
FTSdk.updateRemoteConfig(int remoteConfigMiniUpdateInterval, FTRemoteConfigManager.FetchResult result);
/**
* Actively update remote configuration, call frequency is affected by FTSDKConfig.setRemoteConfigMiniUpdateInterval
*/
FTSdk.updateRemoteConfig()
/**
* Actively update remote configuration, this method ignores the FTSDKConfig.setRemoteConfigMiniUpdateInterval configuration
*
* @param remoteConfigMiniUpdateInterval remote configuration time interval, unit seconds [0,)
* @param result returns update result
*/
FTSdk.updateRemoteConfig(remoteConfigMiniUpdateInterval:Int,result:FTRemoteConfigManager.FetchResult)
Code Example¶
FTSdk.updateRemoteConfig(0, new FTRemoteConfigManager.FetchResult() {
@Override
public void onResult(boolean success) {
//
}
// Optional extension, custom parsing to change local configuration
@Override
public RemoteConfigBean onConfigSuccessFetched(RemoteConfigBean configBean, String jsonConfig) {
boolean isVip = false;
try {
JSONObject jsonObject = new JSONObject(jsonConfig);
String userid = jsonObject.optString("custom_userid");
isVip = (userid.equals("custom_user_test6"));
} catch (JSONException e) {
}
if (isVip) {
configBean.setRumSampleRate(1f);
configBean.setLogSampleRate(1f);
configBean.setTraceSampleRate(1f);
}
return configBean;
}
});
FTSdk.updateRemoteConfig(0, object : FTRemoteConfigManager.FetchResult {
override fun onResult(success: Boolean) {
//
}
// Optional extension, custom parsing to change local configuration
override fun onConfigSuccessFetched(
configBean: RemoteConfigBean,
jsonConfig: String
): RemoteConfigBean {
var isVip = false
try {
val jsonObject = JSONObject(jsonConfig)
val userId = jsonObject.optString("custom_userid")
isVip = userId == "custom_user_test6"
} catch (e: JSONException) {
// ignore
}
if (isVip) {
configBean.setRumSampleRate(1f)
}
return configBean
}
})
Dynamically Enable and Disable Getting AndroidID¶
Use FTSdk to set whether to get 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 needs 1.3.0+ to support the latest symbol file upload rules. Supports productFlavor multi-version differentiated management. The plugin will execute the symbol file upload 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 file
// |-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 will override 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 to enable generateSourceMapOnly = true, execute gradle task assembleRelease to generate, or package it into a zip file yourself, then upload it to datakit or upload it from TrueWatch Studio. It is recommended to use the zip command line for packaging to avoid including some system hidden files in the zip package. For symbol upload, please refer to sourcemap upload
For Unity Native Symbol files, please refer to the official documentation
Permission Configuration Description¶
| Name | Required | Reason for Use |
|---|---|---|
READ_PHONE_STATE |
No | Used to get the phone's cellular network device information. |
For how to apply for dynamic permissions, refer to Android Developer
Plugin AOP Ignore¶
Add @IngoreAOP to the overridden method in Plugin AOP to ignore ASM insertion. If batch ignoring is needed, use ignorePackages in ft-plugin FTExt for ignoring.
WebView Data Monitoring¶
WebView data monitoring requires integrating the Web Monitoring SDK in the WebView access page.
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 and adapts according 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, you need to use tools:replace to override the provider settings and set meta-data.
Note that
android:authoritiesin theproviderneeds to be consistent withandroid:valuein themeta-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" />
Frequently Asked Questions¶
Add Global Variables to Avoid Conflicting Fields¶
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 from the source code. When the same variable appears in the SDK global globalvariables and RUM/Log, the RUM/Log variables will override those in the SDK global variables.
SDK Compatibility¶
Adapting to 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 initialization
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 initialization
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 in the following way.
// Application
public class DemoApplication extends Application {
@Override
public void onCreate() {
//If already agreed to the policy, 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 ) {
//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 policy, 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) {
// 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 a delayed initialization method similar to native Android to cope with app market privacy audits.
Jetpack Compose Support¶
Automatic collection of pages generated by compose components is currently not supported. However, you can use the manual Action and View custom interfaces to track click events and page navigation events. You can refer to here
How to Integrate SDK Without Using ft-plugin¶
TrueWatch uses Androig Grale Plugin Transformation to implement code injection, thereby achieving automatic data collection. However, due to compatibility issues, there may be problems that prevent the use of ft-plugin or ft-plugin-legacy. Affected functions include RUM Action, Resource, and automatic capture of console logs from android.util.Log, Java and Kotlin println, as well as automatic upload of symbol files.
Currently, we have another integration solution 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 example reference ManualActivity.kt:
OKhttpintegratesResourceandTracethroughaddInterceptor,eventListener. Examples are as follows. Source code example 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 the use of
startResource,stopResource,addResourceinFTRUMGlobalManager, andFTTraceManager.getTraceHeaderby themselves. For specific implementation, please refer to the source code example ManualActivity.kt -
WebView data collection configuration