Flutter Application Integration¶
Prerequisites¶
Note: If you have enabled the RUM Headless service, the prerequisites have been automatically configured for you. You can directly integrate your application.
- Install DataKit;
- Configure RUM Collector;
- DataKit must be configured as publicly accessible and with IP geolocation database installed.
Application Integration¶
The current Flutter version supports only Android and iOS platforms. Log in to the TrueWatch console, go to the User Analysis page, click on the top-left [Create], and start creating a new application.
Installation¶
Pub.Dev: ft_mobile_agent_flutter
In the project directory, run the following Flutter command in the terminal:
This will add the following line to the pubspec.yaml
file (and implicitly run flutter pub get
):
dependencies:
ft_mobile_agent_flutter: [lastest_version]
# For compatibility with flutter 2.0, use the reference below
ft_mobile_agent_flutter:
git:
url: https://github.com/TrueWatchTech/datakit-flutter.git
ref: [github_legacy_lastest_tag]
Now in your Dart code, you can use:
Additional Android Integration Configuration
- Configure Gradle Plugin ft-plugin to collect App startup events and Android Native related events (page transitions, click events, Native network requests, WebView data).
- Customize
Application
and declare its usage inAndroidMainifest.xml
, as shown below.
import io.flutter.app.FlutterApplication
/**
* To track the number of launches and launch time, customize the Application here.
*/
class CustomApplication : FlutterApplication() {
}
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.truewatch.ft.mobile.sdk.agent_example">
<application android:name=".CustomApplication">
//...
</application>
</manifest>
SDK Initialization¶
Basic Configuration¶
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// Local environment deployment, Datakit deployment
await FTMobileFlutter.sdkConfig(
datakitUrl: datakitUrl
);
// Use public DataWay
await FTMobileFlutter.sdkConfig(
datawayUrl: datawayUrl,
cliToken: cliToken,
);
}
Field | Type | Required | Description |
---|---|---|---|
datakitUrl | String | Yes | The URL address to access datakit, example: http://10.0.0.1:9529, default port is 9529. The device with SDK installed must be able to access this address. Note: Choose either datakit or dataway configuration. |
datawayUrl | String | Yes | The URL address to access dataway, example: http://10.0.0.1:9528, default port is 9528. The device with SDK installed must be able to access this address. Note: Choose either datakit or dataway configuration. |
cliToken | String | Yes | Authentication token, needs to be configured along with datawayUrl |
debug | bool | No | Set whether to allow log printing, default is false |
env | String | No | Environment configuration, default is prod , any character string, it is recommended to use a single word, such as test etc. |
envType | enum EnvType | No | Environment configuration, default is EnvType.prod . Note: Only one of env or envType needs to be configured |
autoSync | bool | No | Whether to enable automatic synchronization, default is true . When set to false , use FTMobileFlutter.flushSyncData() to manage data synchronization manually |
syncPageSize | enum | No | Set the number of items per sync request, SyncPageSize.mini 5 items, SyncPageSize.medium 10 items, SyncPageSize.large 50 items, default is SyncPageSize.medium |
customSyncPageSize | number | No | Set the number of items per sync request. Range [5,), Note: Larger item counts mean more computational resources are used for data synchronization |
syncSleepTime | number | No | Set the intermittent time for synchronization. Range [0,5000], default not set |
globalContext | object | No | Add custom tags. Refer to here for addition rules |
serviceName | String | No | Service name |
enableLimitWithDbSize | boolean | No | Enable db size limit for data, default is 100MB, unit Byte, larger databases increase disk pressure, default is not enabled. Note: After enabling, Log configuration logCacheLimitCount and RUM configuration rumCacheLimitCount will be invalid. Supported by SDK versions 0.5.3-pre.2 and above |
dbCacheLimit | number | No | DB cache size limit. Range [30MB,), default 100MB, unit byte, supported by SDK versions 0.5.3-pre.2 and above |
dbCacheDiscard | string | No | Set data discard rule in the database. Discard strategy: FTDBCacheDiscard.discard discards new data (default), FTDBCacheDiscard.discardOldest discards old data. Supported by SDK versions 0.5.3-pre.2 and above |
compressIntakeRequests | boolean | No | Set whether to compress synchronized data, supported by SDK versions 0.5.3-pre.2 and above, default is disabled |
enableDataIntegerCompatible | boolean | No | It is recommended to enable when coexisting with web data. This configuration handles storage compatibility issues for web data types. Default is enabled for SDK versions 0.5.4-pre.1 and above |
RUM Configuration¶
Field | Type | Required | Description |
---|---|---|---|
androidAppId | String | Yes | appId, applied during monitoring |
iOSAppId | String | Yes | appId, applied during monitoring |
sampleRate | double | No | Sampling rate, range [0,1], 0 means no collection, 1 means full collection, default value is 1. Scope applies to all View, Action, LongTask, Error data under the same session_id |
enableUserResource | bool | No | Whether to enable automatic capture of http Resource data, default is false , achieved by modifying HttpOverrides.global . If the project has customization needs in this aspect, inherit from FTHttpOverrides . |
enableNativeUserAction | bool | No | Whether to perform Native Action tracking, native system Button click events, app startup events, default is false |
enableNativeUserView | bool | No | Whether to perform Native View automatic tracking, pure Flutter applications are recommended to disable, default is false |
enableNativeUserResource | bool | No | Whether to perform Native Resource automatic tracking, pure Flutter applications are recommended to disable, default is false |
errorMonitorType | enum ErrorMonitorType | No | Set auxiliary monitoring information, add additional monitoring data to RUM Error data, ErrorMonitorType.battery for battery level, ErrorMonitorType.memory for memory usage, ErrorMonitorType.cpu for CPU usage |
deviceMetricsMonitorType | enum DeviceMetricsMonitorType | No | In the View lifecycle, add monitoring data, DeviceMetricsMonitorType.battery monitors the maximum output current for the current page, DeviceMetricsMonitorType.memory monitors the memory usage of the current application, DeviceMetricsMonitorType.cpu monitors CPU jumps, DeviceMetricsMonitorType.fps monitors screen frame rate |
globalContext | Map | No | Custom global parameters |
rumDiscardStrategy | string | No | Discard strategy: FTRUMCacheDiscard.discard discards new data (default), FTRUMCacheDiscard.discardOldest discards old data |
rumCacheLimitCount | number | No | Maximum local cache RUM entry limit [10_000,), default is 100_000 |
isInTakeUrl | callBack | No | Set filtering conditions for Resources, default does not filter |
Adding Custom Tags¶
Static Usage¶
- Split the original
main.dart
into two parts: one part ismain()
, the other part isApp()
MaterialApp
component; - Create corresponding entry files for each environment, such as:
main_prod.dart
,main_gray.dart
, etc.; - Perform custom tag configuration in the corresponding environment file. Example:
///main_prod.dart
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// Initialize SDK
await FTMobileFlutter.sdkConfig(
datakitUrl: serverUrl,
debug: true,
);
await FTRUMManager().setConfig(
androidAppId: appAndroidId,
iOSAppId: appIOSId,
globalContext: {CUSTOM_STATIC_TAG:"prod_static_tag"},
);
runApp(MyApp());
};
Dynamic Usage¶
- Use file-type data storage, such as the
shared_preferences
librarySharedPreferences
, configure theSDK
, and add code to retrieve tag data at the configuration point.
final prefs = await SharedPreferences.getInstance();
String customDynamicValue = prefs.getString("customDynamicValue") ?? "not set";
await FTRUMManager().setConfig(
androidAppId: appAndroidId,
iOSAppId: appIOSId,
globalContext: {CUSTOM_DYNAMIC_TAG:customDynamicValue},
//… Add other configurations
);
- Add methods to change file data anywhere.
static Future<void> setDynamicParams(String value) async{
final prefs = await SharedPreferences.getInstance();
prefs.setString(CUSTOM_DYNAMIC_TAG, value);
}
- Finally, restart the application.
Note:
- Special key:
track_id
(used for tracking functionality). - When users add custom tags through
globalContext
that conflict with SDK's own tags, SDK tags will override user settings. It is recommended to prefix tag names with project abbreviations, such asdf_tag_name
.
Log Configuration¶
Field | Type | Required | Description |
---|---|---|---|
sampleRate | double | No | Sampling rate, range [0,1], 0 means no collection, 1 means full collection, default value is 1. |
enableLinkRumData | bool | No | Whether to link with RUM data |
enableCustomLog | bool | No | Whether to enable custom logs |
logLevelFilters | List |
No | Log level filtering |
logCacheLimitCount | int | No | Maximum local cache log entry limit [1000,), larger logs indicate greater disk cache pressure, default is 5000 |
discardStrategy | enum FTLogCacheDiscard | No | Set log discard rules after reaching the limit. Default is FTLogCacheDiscard.discard , discard discards appended data, discardOldest discards old data |
Trace Configuration¶
await FTTracer().setConfig(
enableLinkRUMData: true,
enableAutoTrace:false,
enableNativeAutoTrace: false
);
Field | Type | Required | Description |
---|---|---|---|
sampleRate | double | No | Sampling rate, range [0,1], 0 means no collection, 1 means full collection, default value is 1. |
traceType | enum TraceType | No | Trace type, default is TraceType.ddTrace . |
enableLinkRUMData | bool | No | Whether to link with RUM data, default is false . |
enableAutoTrace | bool | No | Whether to add Trace Header in http requests, default is false , achieved by modifying HttpOverrides.global . If the project has modification requirements in this area, inherit from FTHttpOverrides |
enableNativeAutoTrace | bool | No | Whether to enable native network auto-tracking for iOS NSURLSession and Android OKhttp , default is false . |
RUM User Data Tracking¶
Action¶
Usage Method¶
/// Add action
/// [actionName] action name
/// [actionType] action type
/// [property] Additional attribute parameters (optional)
Future<void> startAction(String actionName, String actionType,
{Map<String, String>? property})
Code Example¶
View¶
Automatic Collection¶
- Method 1: Add
FTRouteObserver
toMaterialApp.navigatorObservers
, set the pages to navigate inMaterialApp.routes
, thekey
inroutes
is the page name (view_name
).
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: HomeRoute(),
navigatorObservers: [
//RUM View: Monitor page lifecycle during route navigation
FTRouteObserver(),
],
routes: <String, WidgetBuilder>{
//Set Route navigation
'logging': (BuildContext context) => Logging(),
'rum': (BuildContext context) => RUM(),
'tracing_custom': (BuildContext context) => CustomTracing(),
'tracing_auto': (BuildContext context) => AutoTracing(),
},
);
}
}
//Navigate to the page named "logging" using this method
Navigator.pushNamed(context, "logging");
- Method 2: Add
FTRouteObserver
toMaterialApp.navigatorObservers
, generate withFTMaterialPageRoute
, where thewidget
class name is the page name (view_name
).
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: HomeRoute(),
navigatorObservers: [
//RUM View: Monitor page lifecycle during route navigation
FTRouteObserver(),
],
);
}
}
//Here the "page name" is NoRouteNamePage
Navigator.of(context).push(FTMaterialPageRoute(builder: (context) =>
new NoRouteNamePage()
- Method 3: Add
FTRouteObserver
toMaterialApp.navigatorObservers
, customize theRouteSettings.name
attribute inRoute
type pages,FTRouteObserver
's collection logic will prioritize getting theRouteSettings.name
assignment. This method also applies to Dialog type pages such asshowDialog()
,showTimePicker()
.
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: HomeRoute(),
navigatorObservers: [
//RUM View: Monitor page lifecycle during route navigation
FTRouteObserver(),
],
);
}
}
//Here the "page name" is "RouteSettingName"
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => new NoRouteNamePage(),
settings: RouteSettings(name: "RouteSettingName"))
-
All three methods can be mixed in the same project.
-
Sleep and Wakeup Event Collection For versions below 0.5.1-pre.1, if you need to collect application sleep and wakeup behaviors, add the following code:
class _HomeState extends State<HomeRoute> {
@override
void initState(){
//Add application sleep and wakeup listeners
FTLifeRecycleHandler().initObserver();
}
@override
void dispose(){
//Remove application sleep and wakeup listeners
FTLifeRecycleHandler().removeObserver();
}
}
Automatic Collection Filtering¶
Only supported in versions 0.5.0-pre.1 and above
FTRouteObserver
MaterialApp(
navigatorObservers: [
// RUM View: routeFilter filters out pages that do not need to participate in monitoring
FTRouteObserver(routeFilter: (Route? route, Route? previousRoute) {
if (filterConfig) {
//Do not collect
return true;
}
return false;
}),
])
Field | Type | Required | Description |
---|---|---|---|
routeFilter | RouteFilter | No | Page method callback, judge based on entering and previous route details, returning true represents filtering out data that meets the condition, otherwise it does not filter |
FTDialogRouteFilterObserver
Filters DialogRoute
type pages, such as showDialog()
, showTimePicker()
.
MaterialApp(
navigatorObservers: [
//RUM View Filter components of DialogRoute type
FTDialogRouteFilterObserver(filterOnlyNoSettingName: true)
])
// Here the Dialog will be collected under the premise that filterOnlyNoSettingName is true.
// view_name is “About”
showAboutDialog(
context: context, routeSettings: RouteSettings(name: "About"));
Field | Type | Required | Description |
---|---|---|---|
filterOnlyNoSettingName | bool | No | Filters only Routes with RouteSettings.name being null |
Custom View¶
Usage Method¶
/// Create a view, this method must be called before [starView], currently there is none in the Flutter route
/// [viewName] Interface name
/// [duration]
Future<void> createView(String viewName, int duration)
/// Start a view
/// [viewName] Interface name
/// [viewReferer] Previous interface name
/// [property] Additional attribute parameters (optional)
Future<void> starView(String viewName, {Map<String, String>? property})
/// Stop a view
/// [property] Additional attribute parameters (optional)
Future<void> stopView({Map<String, String>? property})
Code Example¶
FTRUMManager().createView("Current Page Name", 100000000)
FTRUMManager().starView("Current Page Name");
FTRUMManager().stopView();
Error¶
Automatic Collection¶
void main() async {
runZonedGuarded(() async {
WidgetsFlutterBinding.ensureInitialized();
await FTMobileFlutter.sdkConfig(
datakitUrl: serverUrl,
debug: true,
);
await FTRUMManager().setConfig(
androidAppId: appAndroidId,
iOSAppId: appIOSId,
);
// Flutter exception capture
FlutterError.onError = FTRUMManager().addFlutterError;
runApp(MyApp());
}, (Object error, StackTrace stack) {
//Add Error data
FTRUMManager().addError(error, stack);
});
Custom Error¶
Usage Method¶
///Add custom error
/// [stack] Stack log
/// [message] Error message
/// [appState] Application state
/// [errorType] Custom errorType
/// [property] Additional attribute parameters (optional)
Future<void> addCustomError(String stack, String message,
{Map<String, String>? property, String? errorType})
Code Example¶
Resource¶
Automatic Collection¶
Enable enableUserResource
via the configuration FTRUMManager().setConfig
.
Custom Resource¶
Usage Method¶
///Start resource request
/// [key] Unique id
/// [property] Additional attribute parameters (optional)
Future<void> startResource(String key, {Map<String, String>? property})
///End resource request
/// [key] Unique id
/// [property] Additional attribute parameters (optional)
Future<void> stopResource(String key, {Map<String, String>? property})
/// Send resource data metrics
/// [key] Unique id
/// [url] Request address
/// [httpMethod] Request method
/// [requestHeader] Request header parameters
/// [responseHeader] Response header parameters
/// [responseBody] Response content
/// [resourceStatus] Response status code
Future<void> addResource(
{required String key,
required String url,
required String httpMethod,
required Map<String, dynamic> requestHeader,
Map<String, dynamic>? responseHeader,
String? responseBody = "",
int? resourceStatus})
Code Example¶
/// Use httpClient
void httpClientGetHttp(String url) async {
var httpClient = new HttpClient();
String key = Uuid().v4();
HttpClientResponse? response;
HttpClientRequest? request;
try {
request = await httpClient
.getUrl(Uri.parse(url))
.timeout(Duration(seconds: 10));
FTRUMManager().startResource(key);
response = await request.close();
} finally {
Map<String, dynamic> requestHeader = {};
Map<String, dynamic> responseHeader = {};
request!.headers.forEach((name, values) {
requestHeader[name] = values;
});
var responseBody = "";
if (response != null) {
response.headers.forEach((name, values) {
responseHeader[name] = values;
});
responseBody = await response.transform(Utf8Decoder()).join();
}
FTRUMManager().stopResource(key);
FTRUMManager().addResource(
key: key,
url: request.uri.toString(),
requestHeader: requestHeader,
httpMethod: request.method,
responseHeader: responseHeader,
resourceStatus: response?.statusCode,
responseBody: responseBody,
);
}
}
Logger Log Printing¶
Custom Logs¶
Currently, log content is limited to 30 KB, exceeding characters will be truncated.
Usage Method¶
///Output log
///[content] Log content
///[status] Log status
///[property] Additional attribute parameters (optional)
Future<void> logging(String content, FTLogStatus status, {Map<String, String>? property})
Code Example¶
Log Levels¶
Method Name | Meaning |
---|---|
FTLogStatus.info | Information |
FTLogStatus.warning | Warning |
FTLogStatus.error | Error |
FTLogStatus.critical | Critical |
FTLogStatus.ok | Recovery |
Tracer Network Link Tracing¶
Automatic Collection¶
Enable enableAutoTrace
via the configuration FTTracer().setConfig
.
Custom Tracer¶
Usage Method¶
/// Get trace http request header data
/// [key] Unique id
/// [url] Request address
///
Future<Map<String, String>> getTraceHeader(String url, {String? key})
Code Example¶
/// Use httpClient
void httpClientGetHttp() async {
var url = 'http://www.truewatch.com';
var httpClient = new HttpClient();
String key = DateTime.now().millisecondsSinceEpoch.toString() + url;
var errorMessage = "";
HttpClientRequest request = await httpClient.getUrl(Uri.parse(url));
HttpClientResponse? response;
try {
final traceHeaders =
await FTTracer().getTraceHeader(key, request.uri.toString());
traceHeaders.forEach((key, value) {
request.headers.add(key, value);
});
response = await request.close();
} catch (exception) {
errorMessage = exception.toString();
} finally {
Map<String, dynamic> requestHeader = {};
Map<String, dynamic> responseHeader = {};
request.headers.forEach((name, values) {
requestHeader[name] = values;
});
if (response != null) {
response.headers.forEach((name, values) {
responseHeader[name] = values;
});
}
}
Binding and Unbinding User Information¶
FTMobileFlutter¶
Usage Method¶
///Bind user
///
///[userid] User id
///[userName] Username
///[userEmail] User email
///[userExt] Extended data
static Future<void> bindRUMUserData(String userId,
{String? userName, String? userEmail, Map<String, String>? ext})
///Unbind user
static Future<void> unbindRUMUserData()
Code Example¶
Active Synchronization of Data¶
FTMobileFlutter¶
Usage Method¶
Usage Example¶
WebView Data Monitoring¶
WebView data monitoring requires integrating the Web Monitoring SDK on the accessed WebView page.
Native and Flutter Hybrid Development¶
If your project is natively developed, with some pages or business processes implemented using Flutter, follow these steps for SDK installation and initialization:
- Installation: Installation method remains unchanged
- Initialization: Refer to iOS SDK Initialization Configuration and Android SDK Initialization Configuration for initialization within the native project
- Flutter Configuration:
- View, Resource, Error are configured in the same way as a pure Flutter project
- Flutter Resource and Trace automatic collection uses the following configuration method