Skip to content

Android Application Integration


Visualize and analyze application performance by collecting metric data from Android applications.

Prerequisites

Note

If the RUM Headless service has been activated, the prerequisites have already been automatically configured. You can proceed directly with integrating the application.

  • Install DataKit;
  • Configure the RUM Collector;
  • Ensure DataKit is accessible over the public network and install the IP geolocation database](../../datakit/datakit-tools-how-to.md#install-ipdb).

Application Integration

  1. Navigate to User Experience Monitoring > Create Application > Android;
  2. Enter an application name;
  3. Input an application ID;
  4. Select an integration method for your application:

    • Public DataWay: Directly receives RUM data without requiring the installation of a DataKit collector.
    • Local Environment Deployment: Receive RUM data after fulfilling prerequisites.

Installation

Source Code: https://github.com/GuanceCloud/datakit-android

Demo: https://github.com/GuanceDemo/guance-app-demo

Gradle Configuration

  • Add the remote repository address of the SDK in the build.gradle file located at the root directory of your project.
buildscript {
    //...
    repositories {
        //...
        //Add the remote repository address of the SDK
        maven {
            url 'https://mvnrepo.jiagouyun.com/repository/maven-releases'
        }
    }
    dependencies {
        //...
        //Add the plugin for Plugin, which depends on AGP 7.4.2 or higher, Gradle 7.2.0 or higher
        classpath 'com.cloudcare.ft.mobile.sdk.tracker.plugin:ft-plugin:[latest_version]'
        // For versions below AGP 7.4.2, please use ft-plugin-legacy 
        //classpath 'com.cloudcare.ft.mobile.sdk.tracker.plugin:ft-plugin-legacy:[latest_version]'

    }
}
allprojects {
    repositories {
        //...
        //Add the remote repository address of the SDK
        maven {
            url 'https://mvnrepo.jiagouyun.com/repository/maven-releases'
        }
    }
}
//setting.gradle
pluginManagement {
    repositories {
        google()
        mavenCentral()
        gradlePluginPortal()
        //Add the remote repository address of the SDK
        maven {
            url('https://mvnrepo.jiagouyun.com/repository/maven-releases')
        }
    }
}
dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
        //Add the remote repository address of the SDK
        maven {
            url('https://mvnrepo.jiagouyun.com/repository/maven-releases')
        }
    }
}

//build.gradle
plugins{
    //Add the plugin for Plugin, which depends on AGP 7.4.2 or higher, Gradle 7.2.0 or higher
    id 'com.cloudcare.ft.mobile.sdk.tracker.plugin' version '[lastest_version]' apply false
    //For versions below AGP 7.4.2, please use ft-plugin-legacy 
    //id 'com.cloudcare.ft.mobile.sdk.tracker.plugin.legacy' version '[lastest_version]' apply false

    //The function of the plugin configuration:
    // 1. Automatically configure collection: App startup, OkHttp requests, WebView activities, Activity transitions
    // 2. Automatically collect View click events, Console Logcat
    // 3. Automatically collect Console Logcat
}
  • In the build.gradle file of the main module app of your project, add the dependency for the SDK and the usage of Plugin.
dependencies {
    //Add the dependency for the SDK
    implementation 'com.cloudcare.ft.mobile.sdk.tracker.agent:ft-sdk:[latest_version]'
    //Dependency for capturing crash information at the native layer, needs to be used together with ft-sdk but 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, if you need to automatically capture network requests and enable tracing, this must be added
    implementation 'com.squareup.okhttp3:okhttp:4.+'
}
//Apply the plugin
apply plugin: 'ft-plugin'   //If using the legacy version compatible with ft-plugin-legacy, no changes are needed

//Configure plugin usage parameters (optional)
FTExt {
    //Whether to display Plugin logs, default is false
    //showLog = true

    //Set ASM version, supports asm7 - asm9, default is asm9
    //asmVersion='asm7'

    //ASM ignore path configuration, paths where . and / are equivalent
    //ignorePackages=['com.ft','com/ft']
}
android{
    //... partial code omitted
    defaultConfig {
        //... partial code omitted
        ndk {
            //When using ft-native to capture crash information at the native layer, choose the supported abi architecture according to the different platforms your app adapts to.
            //Currently, ft-native includes the following abi architectures: 'arm64-v8a',
            // 'armeabi-v7a', 'x86', 'x86_64'
            abiFilters 'armeabi-v7a'
        }
    }
    compileOptions {
        sourceCompatibility = 1.8
        targetCompatibility = 1.8
    }
}

Please check the latest version above for the names of the ft-sdk, ft-plugin, and ft-native versions.

Application Configuration

The best place to initialize the SDK is in the onCreate method of Application. If your application hasn't created an Application, you need to create one and declare it in AndroidManifest.xml. An example can be found here.

<application 
       android:name="YourApplication"> 
</application> 

R8 / Proguard Obfuscation Configuration

If you need to set android.buildTypes minifyEnabled = true, you need to enable the following configuration:

-dontwarn com.ft.sdk.**

### ft-sdk library
-keep class com.ft.sdk.**{*;}

### ft-native library
-keep class ftnative.*{*;}

### Prevent Action Name Class Name from Being Obfuscated During Action Retrieval ###
-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);
        //Using public DataWay
        FTSDKConfig config = FTSDKConfig.builder(datawayUrl, clientToken);
        //...
        //config.setDebug(true);                //debug mode
        config.setCompressIntakeRequests(true); //report data compression
        FTSdk.install(config);
    }
}
class DemoApplication : Application() {
    override fun onCreate() {
        //Local environment deployment, Datakit deployment
        val config = FTSDKConfig.builder(datakitUrl)
        //Using public DataWay
        val config = FTSDKConfig.builder(datawayUrl, clientToken)
        //...
        //config.setDebug(true);                //debug mode
        config.setCompressIntakeRequests(true)  //report data compression
        FTSdk.install(config)
    }
}
Method Name Type Required Meaning
datakitUrl String Yes URL address for reporting in local environment deployment (Datakit), e.g., http://10.0.0.1:9529. The default port is 9529, and the device installing the SDK must be able to access this address. Note: Only one of datakitUrl and datawayUrl should be configured.
datawayUrl String Yes URL address for reporting via public Dataway, 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: Only one of datakitUrl and datawayUrl should be configured.
clientToken String Yes Authentication token, must be configured along with datawayUrl
setDebug Boolean No Whether to enable debug mode. Default is false. Enabling it allows printing SDK runtime logs
setEnv EnvType No Set the collection environment. Default is EnvType.PROD
setEnv String No Set the collection environment. Default is prod. Note: Either String or EnvType type should be configured
setOnlySupportMainProcess Boolean No Whether to support running only in the main process. Default is true. If execution in other processes is required, set this field to false
setEnableAccessAndroidID Boolean No Enable getting Android ID. Default is true. Setting to false will not collect the device_uuid field data. Related to market privacy audit see here
addGlobalContext Dictionary No Add SDK global attributes. Refer to here for adding rules
setServiceName String No Set service name, affecting the service field data in Log and RUM. Default is df_rum_android
setAutoSync Boolean No Whether to automatically sync collected data to the server. Default is true. When false, use FTSdk.flushSyncData() to manage data synchronization manually
setSyncPageSize Int No Set the number of entries per sync request. SyncPageSize.MINI is 5 entries, SyncPageSize.MEDIUM is 10 entries, SyncPageSize.LARGE is 50 entries. Default is SyncPageSize.MEDIUM
setCustomSyncPageSize Enum No Set the number of entries per sync request. Range [5,). Note that larger numbers mean greater computational resources consumed. Default is 10. Note: Only one of setSyncPageSize and setCustomSyncPageSize should be configured
setSyncSleepTime Int No Set the interval between sync requests. Range [0,5000]. Not set by default
enableDataIntegerCompatible Void No Recommended to enable when needing to coexist with web data. This configuration addresses compatibility issues with web data type storage. Enabled by default in version 1.6.9
setNeedTransformOldCache Boolean No Whether to transform old cache data from versions below ft-sdk 1.6.0. Default is false
setCompressIntakeRequests Boolean No Compress uploaded sync data using deflate. Disabled by default. Supported in ft-sdk 1.6.3 and later versions
enableLimitWithDbSize Void No Enable limiting data size using the database. Default limit is 100MB, unit Byte. Larger databases increase disk pressure. Disabled by default.
Note: After enabling, FTLoggerConfig.setLogCacheLimitCount and FTRUMConfig.setRumCacheLimitCount will become ineffective. Supported in ft-sdk 1.6.6 and later versions
setEnableOkhttpRequestTag bool No Automatically add unique ResourceID to Okhttp Request for high concurrency scenarios with identical requests. Supported in ft-sdk 1.6.10 and later versions, ft-plugin 1.3.5 and later versions
setProxy java.net.Proxy No Proxy settings for data network sync requests, only supports okhttp3, supported in ft-sdk 1.6.10 and later versions
setProxyAuthenticator okhttp3.Authenticator No Proxy settings for data sync network requests, only supports okhttp3, supported in ft-sdk 1.6.10 and later versions
setDns okhttp3.Dns No Custom Dns for domain resolution during data sync network requests, only supports okhttp3, supported in ft-sdk 1.6.10 and later versions
setDataModifier DataModifier No Modify individual fields. Supported in ft-sdk 1.6.11 and later versions. Usage examples see here
setLineDataModifier LineDataModifier No Modify individual data lines. Supported in ft-sdk 1.6.11 and later versions. Usage examples see here
setRemoteConfiguration Int No Whether to enable remote configuration for data collection. Default is false. After enabled, SDK initialization or hot start of the application triggers data updates. Supported in ft-sdk 1.6.12 and later versions. Datakit version required >=1.60 or use public dataway
setRemoteConfigMiniUpdateInterval Int No Set the minimum update interval for data updates, unit seconds, default is 12 hours. Supported in ft-sdk 1.6.12 and later versions

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. To enable RUM collection functionality, corresponding to setting RUM appid. How to get appid
setSamplingRate Float No Set the sampling rate, value range [0,1], 0 means no sampling, 1 means full sampling. Default value is 1. Scope applies to all View, Action, LongTask, Error data under the same session_id
setSessionErrorSampleRate Float No Set error sampling rate. When a session is not sampled by setSamplingRate, if an error occurs during the session, data within 1 minute before the error can be collected. Value range [0,1], 0 means no sampling, 1 means full sampling. Default value is 0. Scope applies to all View, Action, LongTask, Error data under the same session_id. Supported in ft-sdk 1.6.11 and later versions
setEnableTrackAppCrash Boolean No Whether to report App crash logs. Default is false, enabling will display error stack data in error analysis.
About converting obfuscated content in crash logs.

In ft-sdk 1.5.1 and later versions, you can set whether to show logcat in Java Crash and Native Crash through extraLogCatWithJavaCrash and extraLogCatWithNativeCrash
setExtraMonitorTypeWithError Array No Set auxiliary monitoring information, add additional monitoring data to Rum crash data, ErrorMonitorType.BATTERY indicates battery level, ErrorMonitorType.MEMORY indicates memory usage, ErrorMonitorType.CPU indicates CPU utilization. Default is not set
setDeviceMetricsMonitorType Array No Set view monitoring information. During the View cycle, add monitoring data. DeviceMetricsMonitorType.BATTERY monitors maximum current output for the current page, DeviceMetricsMonitorType.MEMORY monitors current app memory usage, DeviceMetricsMonitorType.CPU monitors CPU frequency, DeviceMetricsMonitorType.FPS monitors screen frame rate. Monitoring frequency: DetectFrequency.DEFAULT 500 milliseconds, DetectFrequency.FREQUENT 100 milliseconds, DetectFrequency.RARE 1 second. Default is not set
setEnableTrackAppANR Boolean No Whether to enable ANR detection. Default is false.

In ft-sdk 1.5.1 and later versions, you can set whether to show logcat in ANR through extraLogCatWithANR
setEnableTrackAppUIBlock Boolean, long No Whether to enable UI freeze detection. Default is false. In ft-sdk 1.6.4 and later versions, you can control the detection time range through blockDurationMs [100,) in milliseconds. Default is 1 second
setEnableTraceUserAction Boolean No Whether to automatically track user actions. Currently only supports user startup and click operations. Default is false
setEnableTraceUserView Boolean No Whether to automatically track user page operations. Default is false
setEnableTraceUserViewInFragment Boolean No Whether to automatically track Fragment type page data. Default is false. Supported in ft-sdk 1.6.11 and later versions
setEnableTraceUserResource Boolean No Whether to automatically track user network requests. Only supports Okhttp. Default is false
setEnableResourceHostIP Boolean No Whether to collect the IP address of the destination domain of the request. Scope: only affects default collection when EnableTraceUserResource is true. For custom Resource collection, use FTResourceEventListener.FTFactory(true) to enable this feature. Additionally, a single Okhttp instance caches IPs for the same domain. Under unchanged conditions, it generates once only
setResourceUrlHandler Callback No Set filtering conditions for resource URLs. Default is no filter
setOkHttpEventListenerHandler Callback No ASM sets global Okhttp EventListener. Default is not set
setOkHttpResourceContentHandler Callback No ASM sets global FTResourceInterceptor.ContentHandlerHelper. Default is not set. Supported in ft-sdk 1.6.7 and later versions. Custom Resource
addGlobalContext Dictionary No Add custom tags for distinguishing data sources of user monitoring. If tracking functionality is required, parameter key should be track_id and value can be any value. For adding rule notes, please refer to here
setRumCacheLimitCount int No Local cache RUM limit count [10_000,). Default is 100_000. Supported in ft-sdk 1.6.6 and later versions
setEnableTraceWebView Boolean No Configure whether to enable Android SDK to collect WebView data. Default is true. Supported in ft-sdk 1.6.12 and later versions
setAllowWebViewHost Array No Set allowed WebView host addresses for data tracking. Null means all. Default is null. Supported in ft-sdk 1.6.12 and later versions

Log Configuration

FTSdk.initLogWithConfig(new FTLoggerConfig()
    //.setEnableConsoleLog(true,"log prefix")
    .setEnableLinkRumData(true)
    .setEnableCustomLog(true)
    //.setLogLevelFilters(new Status[]{Status.CRITICAL, Status.ERROR})
    .setSamplingRate(0.8f));
   FTSdk.initLogWithConfig(
            FTLoggerConfig()
              //.setEnableConsoleLog(true,"log prefix")
                .setEnableLinkRumData(true)
                .setEnableCustomLog(true)
              //.setLogLevelFilters(arrayOf(Status.CRITICAL,Status.ERROR))
                .setSamplingRate(0.8f)
        )
Method Name Type Required Meaning
setSamplingRate Float No Set the sampling rate, value range [0,1], 0 means no sampling, 1 means full sampling. Default value is 1.
setEnableConsoleLog Boolean No Whether to report console logs. Default is false. The mapping of log levels is as follows
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 very large. To avoid affecting application performance and reduce unnecessary resource consumption, it is recommended to use prefix to filter out valuable logs. Supported in ft-plugin 1.3.5 and later versions to capture Log.println printed logs
setEnableLinkRUMData Boolean No Whether to associate with RUM data. Default is false
setEnableCustomLog Boolean No Whether to upload custom logs. Default is false
setLogLevelFilters Array No Set level log filters. Default is not set
addGlobalContext Dictionary No Add log global attributes. For adding rules, please refer to here
setLogCacheLimitCount Int No Local cache maximum log entry count limit [1000,). The larger the log, the greater the disk cache pressure. Default is 5000
setLogCacheDiscardStrategy LogCacheDiscard No Set log discard strategy when reaching the upper limit. Default is LogCacheDiscard.DISCARD, DISCARD discards appended data, DISCARD_OLDEST discards old data

Trace Configuration

FTSdk.initTraceWithConfig(new FTTraceConfig()
    .setSamplingRate(0.8f)
    .setEnableAutoTrace(true)
    .setEnableLinkRUMData(true));
   FTSdk.initTraceWithConfig(
            FTTraceConfig()
                .setSamplingRate(0.8f)
                .setEnableAutoTrace(true)
                .setEnableLinkRUMData(true)
        )
Method Name Type Required Meaning
setSamplingRate Float No Set the sampling rate, value range [0,1], 0 means no sampling, 1 means full sampling. Default value is 1.
setTraceType TraceType No Set the type of trace. Default is DDTrace. Currently supports Zipkin, Jaeger, DDTrace, Skywalking (8.0+), TraceParent (W3C). If integrating with OpenTelemetry, ensure to check the supported types and agent configurations
setEnableLinkRUMData Boolean No Whether to associate with RUM data. Default is false
setEnableAutoTrace Boolean No Set whether to enable automatic HTTP trace. Currently only supports OKhttp auto-tracking. Default is false
setOkHttpTraceHeaderHandler Callback No ASM sets global FTTraceInterceptor.HeaderHandler. Default is not set. Supported in ft-sdk 1.6.8 and later versions. Example reference Custom Trace

RUM User Data Tracking

In FTRUMConfig, configure enableTraceUserAction, enableTraceUserView, enableTraceUserResource, setEnableTrackAppUIBlock, setEnableTrackAppCrash, and setEnableTrackAppANR to achieve automatic collection of Action, View, Resource, LongTask, Error data. If you want to perform customized collection, you can report data through FTRUMGlobalManager. See the following examples:

Action

Usage Method

    /**
     * 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 be associated with 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>)

The startAction internally calculates the time-consuming algorithm. During the calculation period, it tries to associate with nearby occurring Resource, LongTask, Error data. There is a 100 ms frequent trigger protection. It is recommended to use this for user operation type data. If there is a need for frequent calls, please use addAction. This data will not conflict with startAction and will not be associated with current Resource, LongTask, Error data.

Code Examples

// 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 Method

    /**
     * Start of view
     *
     * @param viewName Current page name
     * @param property Additional attribute parameters (optional)
     */
    public void startView(String viewName, HashMap<String, Object> property)

    /**
     * End of view
     *
     * @param property Additional attribute parameters (optional)
     */
    public void stopView(HashMap<String, Object> property)
     /**
     * Start of view
     *
     * @param viewName Current page name
     * @param property Additional attribute parameters (optional)
     */

    fun startView(viewName: String, property: HashMap<String, Any>)

     /**
     * End of view
     *
     * @param property Additional attribute parameters (optional)
     */
    fun stopView(property: HashMap<String, Any>)

Code Examples

@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 of ft_key_will_change will be modified to ft_value_change when stopView is called
    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 of ft_key_will_change will be modified to ft_value_change when stopView is called

     FTRUMGlobalManager.get().startView("Current Page Name", map)

}

Error

Usage Method

    /**
     * Add error information
     *
     * @param log       Log
     * @param message   Message
     * @param errorType Error type, ErrorType
     * @param state     Program runtime status
     * @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 runtime status
     * @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 runtime status
     * @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 runtime status
     * @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 Examples

// Scenario 1:
FTRUMGlobalManager.get().addError("error log", "error msg", ErrorType.JAVA, AppState.RUN);

// Scenario 2: Delay recording occurred errors, the time here is generally 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 occurred errors, the time here is generally 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 Method

    /**
     * Add long task
     *
     * @param log      Log content
     * @param duration Duration, nanoseconds
     * @param property Additional attribute parameters (optional)
     */
    public void addLongTask(String log, long duration, HashMap<String, Object> property)
    /**
     * Add long task
     *
     * @param log      Log content
     * @param duration Duration, nanoseconds
     * @param property Additional attribute parameters (optional)
     */

    fun addLongTask(log: String, duration: Long, property: HashMap<String, Any>)

Code Examples

// Scenario 1
FTRUMGlobalManager.get().addLongTask("error log", 1000000L);

// Scenario 2: Dynamic parameters
HashMap<String, Object> map = new HashMap<>();
map.put("ft_key", "ft_value");
FTRUMGlobalManager.get().addLongTask("", 1000000L, map);
// Scenario 1
FTRUMGlobalManager.get().addLongTask("error log",1000000L)

// Scenario 2: Dynamic parameters
 val map = HashMap<String, Any>()
 map["ft_key"] = "ft_value"
 FTRUMGlobalManager.get().addLongTask("", 1000000L,map)

Resource

Usage Method

    /**
     * Start of resource
     *
     * @param resourceId Resource Id
     * @param property   Additional attribute parameters (optional)
     */
    public void startResource(String resourceId, HashMap<String, Object> property)

    /**
     * End of resource
     *
     * @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)
/**
 * Start of resource
 *
 * @param resourceId Resource Id (optional)
 */
fun startResource(resourceId: String, property: HashMap<String, Any>)


/**
 * End of resource
 *
 * @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 Examples

// Scenario 1
// Request starts
FTRUMGlobalManager.get().startResource("resourceId");

//...

// Request ends
FTRUMGlobalManager.get().stopResource("resourceId");

// Finally, after the request ends, send the relevant data metrics of the request
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"); //The value of ft_key_will_change will be modified to ft_value_change when stopResource is called
FTRUMGlobalManager.get().stopResource(uuid,map);
// Scenario 1
//Request starts
FTRUMGlobalManager.get().startResource("resourceId")

//Request ends
FTRUMGlobalManager.get().stopResource("resourceId")

//Finally, after the request ends, send the relevant data metrics of the request
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"
)
// The value of ft_key_will_change will be modified to ft_value_change when stopResource is called

FTRUMGlobalManager.get().stopResource(uuid, map)
Method Name Required Meaning Notes
NetStatusBean.fetchStartTime No Request start time
NetStatusBean.tcpStartTime No TCP connection start 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 properties
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 Response body content
ResourceParams.property No Additional properties

Logger Logging

Use FTLogger to output custom logs. You need to enable FTLoggerConfig.setEnableCustomLog(true).

Currently, the log content is limited to 30 KB, and any excess characters will be truncated.

Usage Method

    /**
     * Store a single log data locally for synchronization
     *
     * @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 for synchronization
     *
     * @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 for synchronization
     *
     * @param logDataList {@link LogData} list
     */
    public void logBackground(List<LogData> logDataList)
    /**
     * Store a single log data locally for synchronization
     *
     * @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 for synchronization
     *
     * @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 for synchronization
     *
     * @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 Recovery

Code Examples

// Upload a 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 a 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 Tracing

Configure FTTraceConfig to enable enableAutoTrace for automatically adding trace data, or manually use FTTraceManager to add Propagation Header in HTTP requests, as shown in the following example:

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 Through OKHttp Interceptor

Enable FTRUMConfig's enableTraceUserResource and FTTraceConfig's enableAutoTrace configuration simultaneously; priority is given to loading custom Interceptor configuration.

For ft-sdk < 1.4.1, you need to disable FTRUMConfig's enableTraceUserResource and FTTraceConfig's enableAutoTrace. For ft-sdk > 1.6.7, support for associating custom Trace Header with RUM data is available.

 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 versions above 1.6.7
              @Override
              public String getSpanID() {
                return "span_id";
             }
            // Supported in versions above 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 read part 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(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 consuming large amounts of data
            val body = response.peekBody(33554432)
            extraData["df_response_body"] = body.string()
        }
    }

    override fun onException(e: Exception, extraData: HashMap<String, Any>) {
        // Handle exception cases
    }
}))
.eventListenerFactory(FTResourceEventListener.FTFactory())
.build()

ContentHandlerHelperEx Local Network Error Filtering

ContentHandlerHelperEx is an enhanced class of ContentHandlerHelper, which can filter local network IOException errors.

new FTResourceInterceptor.ContentHandlerHelperEx() {
    //...

    /**
     * Returns exceptions that occur during network connections
     *
     * @param e         The IOException data that occurred during the request
     * @param extraData Additional data
     * @return Whether to filter local network errors of the type network_error. 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 that occur during network connections
    *
    * @param e         The IOException data that occurred during the request
    * @param extraData Additional data
    * @return Whether to filter local network errors of the type network_error. true means override
    */
    override fun onExceptionWithFilter(e: Exception, extraData: HashMap<String, Any>): Boolean {
        return if (e is SocketTimeoutException) {
            true
        } else {
            super.onExceptionWithFilter(e, extraData)
        }
    }
}

Adding ResourceID to OKhttp

To add a uuid to an Okhttp Request, it is recommended to enable it if there are high-frequency concurrent scenarios with the same request. Starting from ft-plugin 1.3.5 and ft-sdk 1.6.10, enabling FTSDKConfig.setEnableOkhttpRequestTag(true) automatically adds ResourceID to the Request.

new Request.Builder()
//...
.tag(ResourceID.class, new ResourceID())//Add unique
Request.Builder()
// ...
.tag(ResourceID::class.java, ResourceID()) 

Binding and Unbinding User Information

Use FTSdk to bind and unbind user information.

Usage Method

   /**
     * Bind user information
     *
     * @param id
     */
    public static void bindRumUserData(@NonNull String id)

    /**
     * Bind user information
     */
    public static void bindRumUserData(@NonNull UserData data)

    /**
     * Unbind user information
     */
    public static void unbindRumUserData()
/**
     * Bind user information
     *
     * @param id User ID
     */
    fun bindRumUserData(id: String)

    /**
     * Bind user information
     *
     * @param data User information
     */
    fun bindRumUserData(data: UserData)

    /**
     * Unbind user information
     */
    fun unbindRumUserData()

UserData

Method Name Meaning Required Notes
setId Set user ID No
setName Set username No
setEmail Set email No
setExts Set user extensions No Refer to here for adding rules

Code Examples

// Can call this method after user login success 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();
// Can call this method after user login success 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()

Closing the SDK

Use FTSdk to close the SDK. If dynamically changing the SDK configuration, it needs to be closed first to avoid generating erroneous data.

FTSdk.shutDown();
FTSdk.shutDown()

Clearing SDK Cache Data

Use FTSdk to clear unreported cached data.

FTSdk.clearAllData();
FTSdk.clearAllData()

Manually Syncing Data

Use FTSdk to manually synchronize data.

You need to manually synchronize data when FTSdk.setAutoSync(false) is set.

FTSdk.flushSyncData();
FTSdk.flushSyncData();

Manually Synchronizing Dynamic Configurations

Use FTSdk to manually synchronize dynamic configurations. When automatic updates do not meet requirements, adjust the update timing by calling it actively.

/**
 * Actively update remote configurations. The invocation frequency is affected by `FTSDKConfig.setRemoteConfigMiniUpdateInterval`.
 */
FTSdk.updateRemoteConfig();
/**
 * Actively update remote configurations. This method ignores the `FTSDKConfig.setRemoteConfigMiniUpdateInterva` configuration.
 *
 * @param remoteConfigMiniUpdateInterval Remote configuration time interval, unit seconds [0,)
 * @param result                         Return update result
 */
FTSdk.updateRemoteConfig(int remoteConfigMiniUpdateInterval, FTRemoteConfigManager.FetchResult result);
/**
 * Actively update remote configurations. The invocation frequency is affected by `FTSDKConfig.setRemoteConfigMiniUpdateInterval`.
 */
FTSdk.updateRemoteConfig()
/**
 * Actively update remote configurations. This method ignores the `FTSDKConfig.setRemoteConfigMiniUpdateInterva` configuration.
 *
 * @param remoteConfigMiniUpdateInterval Remote configuration time interval, unit seconds [0,)
 * @param result                         Return update result
 */
FTSdk.updateRemoteConfig(remoteConfigMiniUpdateInterval:Int,result:FTRemoteConfigManager.FetchResult)

Dynamically Enabling and Disabling Android ID Collection

Use FTSdk to set whether to collect Android ID in the SDK.

// Enable Android ID collection
FTSdk.setEnableAccessAndroidID(true);

// Disable Android ID collection
FTSdk.setEnableAccessAndroidID(false);
// Enable Android ID collection
FTSdk.setEnableAccessAndroidID(true)

// Disable Android ID collection
FTSdk.setEnableAccessAndroidID(false)

Adding Custom Tags

Use FTSdk to dynamically add tags while the SDK is running.

Usage Methods

/**
 * 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 Examples

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】)

The ft-plugin version needs to be above 1.3.0 to support the latest symbol file upload rules. It supports multi-version management of productFlavor. The plugin will execute the upload of symbol files after the gradle task assembleRelease. For detailed configuration, refer to SDK Demo

FTExt {
    //...
    autoUploadMap = true                 // Upload mapping.txt file, default is false
    autoUploadNativeDebugSymbol = true   // Upload c/c++ symbol so files, default is false
    datakitUrl = 'https://datakit.url'  // datakit upload address, no need to configure if generateSourceMapOnly=true
    datawayToken = 'dataway_token'      // space token, no need to configure if generateSourceMapOnly=true
    appId = "appid_xxxxx"               // appid, no need to configure if generateSourceMapOnly=true
    env = 'common'                      // environment, no need to configure if generateSourceMapOnly=true
    // native so specify path, just point to the parent 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, default is false, path example: /app/build/tmp/ft{flavor}SourceMapMerge-release.zip, supported in ft-plugin:1.3.4 and later versions

    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 to enable generateSourceMapOnly = true, execute gradle task assembleRelease to generate, or package into a zip file yourself, then upload it to datakit or upload from Guance 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 uploads, refer to sourcemap upload

Unity Native Symbol Files please refer to the official documentation

Permission Configuration Instructions

Name Required Reason for Use
READ_PHONE_STATE No Used to obtain cellular network device information for mobile phones

For details on how to request dynamic permissions, refer to Android Developer

Plugin AOP Ignore

By adding @IngoreAOP to methods covered by Plugin AOP, you can ignore ASM insertion. If you need to ignore in bulk, you can use ignorePackages in FTExt of ft-plugin.

View.setOnClickListener(new View.OnClickListener() {
        @Override
        @IgnoreAOP
        public void onClick(View v) {

        }
    }
View.setOnClickListener @IngoreAOP{

    }

WebView Data Monitoring

To monitor WebView data, integrate the Web Monitoring SDK on the page accessed by the WebView.

Data Masking

If you wish to fully mask certain fields, it's recommended to use setDataModifier, which offers better performance. If you need detailed rule replacements, opt for setLineDataModifier.

Do not use complex or high-latency methods in callback methods, as this could significantly impact SDK write performance.

FTSdk.install(
    FTSDKConfig.builder("xxx")
    .setDataModifier(new DataModifier() {
    /**
     * Modify a specific field
     * 
     * @param key   Field name
     * @param value Original field value
     * @return New value, returning null means no change
     */
    @Override
    public Object modify(String key, Object value) {
        if (key.equals("device_uuid")) {
            return "xxx";
        }
        return null;
    }
    }).setLineDataModifier(new LineDataModifier() {
    /***
     * Modify a specific line of data
     * 
     * @param measurement Type of data metric view, action, resource,
     *                    longtask, error, df_rum_android_log
     * @param data Key-value pairs of raw data
     * @return Modified key-value pairs (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 Original field value
     * @return New value, returning null means no change
     */
    override fun modify(key: String, value: Any?): Any? {
        return if (key == "device_uuid") {
            "xxx" // Replace with custom device_uuid
        } else {
            null
        }
    }
})
// Modify certain fields in a single data row in batches
.setLineDataModifier(object : LineDataModifier {
    /**
     * Modify a specific line of data
     * 
     * @param measurement Type of data metric view, action, resource,
     *        longtask, error, df_rum_android_log
     * @param data Key-value pairs of raw data
     * @return Modified key-value pairs (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
        }
    }
})

Example of Using Custom Tags

Compilation Configuration Method

  1. Create multiple productFlavors in build.gradle to distinguish tags
android{
    //…
    productFlavors {
        prodTest {
            buildConfigField "String", "CUSTOM_VALUE", "\"Custom Test Value\""
            //…
        }
        prodPublish {
            buildConfigField "String", "CUSTOM_VALUE", "\"Custom Publish Value\""
            //…
        }
    }
}
  1. Add the corresponding BuildConfig constants in RUM configuration
FTSdk.initRUMWithConfig(
        new FTRUMConfig()
            .addGlobalContext(CUSTOM_STATIC_TAG, BuildConfig.CUSTOM_VALUE)
            //... Add other configurations
);
FTSdk.initRUMWithConfig(
            FTRUMConfig()
                .addGlobalContext(CUSTOM_STATIC_TAG, BuildConfig.CUSTOM_VALUE)
                //… Add other configurations
        )

Runtime Reading/Writing Files Method

  1. Through stored file-type data, such as SharedPreferences, configure the use of SDK and add code to retrieve tag data at the configuration location.
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
);
val sp = context.getSharedPreferences(SP_STORE_DATA, MODE_PRIVATE)
val customDynamicValue = sp.getString(CUSTOM_DYNAMIC_TAG, "not set")

// Configure RUM
FTSdk.initRUMWithConfig(
     FTRUMConfig().addGlobalContext(CUSTOM_DYNAMIC_TAG, customDynamicValue!!)
     //… Add other configurations
)
  1. Add a method to change file data anywhere.
public void setDynamicParams(Context context, String value) {
    SharedPreferences sp = context.getSharedPreferences(SP_STORE_DATA, MODE_PRIVATE);
    sp.edit().putString(CUSTOM_DYNAMIC_TAG, value).apply();
}
fun setDynamicParams(context: Context, value: String) {
            val sp = context.getSharedPreferences(SP_STORE_DATA, MODE_PRIVATE)
            sp.edit().putString(CUSTOM_DYNAMIC_TAG, value).apply()

        }
  1. Finally, restart the application. Detailed steps see SDK Demo

SDK Runtime Addition

After the SDK has been initialized, use FTSdk.appendGlobalContext(globalContext), FTSdk.appendRUMGlobalContext(globalContext), FTSdk.appendLogGlobalContext(globalContext) to dynamically add tags. Once set, it takes effect immediately. Subsequent reported RUM or Log data will automatically include these tags. This approach is suitable for scenarios where data needs to be fetched later, such as fetching tag data via a network request.

// Pseudocode for initializing SDK, after fetching parameters from the network, then setting the tags

FTSdk.init() 

getInfoFromNet(info){
    HashMap<String, Object> globalContext = new HashMap<>();
    globalContext.put("delay_key", info.value);
    FTSdk.appendGlobalContext(globalContext)
}

Frequently Asked Questions

Avoid Conflicting Fields by Adding Project Prefixes

To avoid conflicts between custom fields and SDK data, it is recommended to add a prefix like the project abbreviation to tag names, for example df_tag_name. You can check the source code for keys used in the project. When SDK global variables have the same keys as RUM or Log variables, RUM or Log will overwrite the SDK global variables.

SDK Compatibility

Adapting to Market Privacy Audits### 应对市场隐私审核

隐私声明

前往查看

方式 1: SDK AndroidID 配置

SDK 为更好关联相同用户数据,会使用 Android ID。如果需要在应用市场上架,需要通过如下方式对应市场隐私审核。

public class DemoApplication extends Application {
    @Override
    public void onCreate() {
        // 在初始化设置时将 setEnableAccessAndroidID 设置为 false
        FTSDKConfig config = new FTSDKConfig.Builder(DATAKIT_URL)
                .setEnableAccessAndroidID(false)
                .build();
        FTSdk.install(config);

        // ...
    }
}

// 用户同意隐私协议后再开启
FTSdk.setEnableAccessAndroidID(true);
class DemoApplication : Application() {
    override fun onCreate() {

        //在初始化设置时将  setEnableAccessAndroidID 设置为 false
        val config = FTSDKConfig
            .builder(DATAKIT_URL)
            . setEnableAccessAndroidID(false)

        FTSdk.install(config)

        //...
    }
}

//用户同意隐私协议后再开启
FTSdk.setEnableAccessAndroidID(true);

方式 2:延迟初始化 SDK

如果需要在应用中延迟加载 SDK,建议使用如下方式初始化。

// Application
public class DemoApplication extends Application {
    @Override
    public void onCreate() {
        //如果已经同意协议,在 Application 中初始化
        if(agreeProtocol){
            FTSdk.init(); //SDK 初始化伪代码
        }
    }
}

// 隐私声明  Activity 页面
public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        //未阅读隐私声明
        if ( notReadProtocol ) {
            //隐私声明弹出弹窗
            showProtocolView();

            //如果同意隐私声明
            if( agreeProtocol ){
                FTSdk.init(); //SDK 初始化伪代码
            }
        }
    }
}
// Application  
class DemoApplication : Application() {
    override fun onCreate() {
        // 如果已经同意协议,在 Application 中初始化
        if (agreeProtocol) {
            FTSdk.init() //SDK 初始化伪代码
        }
    }
}

// 隐私声明 Activity 页面
class MainActivity : Activity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        // 未阅读隐私声明
        if (notReadProtocol) {
            // 隐私声明弹出弹窗
            showProtocolView()

            // 如果同意隐私声明
            if (agreeProtocol) {
                FTSdk.init() //SDK 初始化伪代码
            }
        }
    }
}

第三方框架

flutterreact-nativeuni-appunity 可以采用与以上原生 Android 相似延迟初始化方式,来应对应用市场隐私审核。

Jetpack Compose 支持

目前暂时不支持自动采集 compose 组件生成的页面,但是可以通过手动 ActionView 的自定义接口,点击事件和页面跳转事件进行追踪,可以参考这里

不使用 ft-plugin 情况下如何接入 SDK

Guance使用的 Androig Grale Plugin Transformation 实现的代码注入,从而实现数据自动收集。但是由于一些兼容性问题,可能存在无法使用 ft-plugin 的问题。受影响包括 RUM ActionResource,和 android.util.Log ,Java 与 Kotlin println 控制台日志自动抓取,以及符号文件的自动上传。

目前针对这种情况,我们有另外一种集成方案,应对方案如下:

// Application
@Override
public void onCreate() {
    super.onCreate();
    //需要在 SDK 初始化前调用
    FTAutoTrack.startApp(null);
    //设置 SDK 配置
    setSDK(this);
}
  //Application
    override fun onCreate() {
        super.onCreate()
    //需要在 SDK 初始化前调用
        FTAutoTrack.startApp(null)
        //设置 SDK 配置
        setSDK(this)

    }
  • 按键等事件需要在触发处自行添加,例如,Button onClick 事件为例,源码示例参考 ManualActivity.kt
view.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        FTRUMGlobalManager.get().startAction("[action button]", "click");
    }
});
    view.setOnClickListener{
        FTRUMGlobalManager.get().startAction("[action button]", "click")
    }
  • OKhttp 通过 addInterceptoreventListener 方式接入 ResourceTrace,示例如下,源码示例参考 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();
val builder = OkHttpClient.Builder()
.addInterceptor(FTTraceInterceptor())
.addInterceptor(FTResourceInterceptor())
.eventListenerFactory(FTResourceEventListener.FTFactory())
//.eventListenerFactory(new FTResourceEventListener.FTFactory(true))
val client = builder.build()
  • 其他网络框架需要自行实现使用 FTRUMGlobalManagerstartResource ,stopResource,addResource, FTTraceManager.getTraceHeader 。具体实现方式,请参考源码示例 ManualActivity.kt

  • WebView 数据采集配置

FTAutoTrack.setUpWebView(webview)
//loadUrl 加载操作以前进行配置
FTAutoTrack.setUpWebView(webview)
//loadUrl 加载操作以前进行配置

Feedback

Is this page helpful? ×