跳转至

Flutter 应用接入


前置条件

应用接入

当前 Flutter 版本暂只支持 Android 和 iOS 平台。登录 “观测云” 控制台,进入「应用监测」页面,点击右上角「新建应用」,在新窗口输入「应用名称」,点击「创建」,然后相应接入的平台,即可开始配置。

安装

Pub.Dev: ft_mobile_agent_flutter

源码地址https://github.com/GuanceCloud/datakit-flutter

Demo 地址https://github.com/GuanceCloud/datakit-flutter/example

在项目路径下,终端运行 Flutter 命令:

 $ flutter pub add ft_mobile_agent_flutter

这将在包的 pubspec.yaml 中添加这样的一行(并运行一个隐式 flutter pub get ):

dependencies:
  ft_mobile_agent_flutter: ^0.2.7-dev.2

现在在您的 Dart 代码中,您可以使用:

import 'package:ft_mobile_agent_flutter/ft_mobile_agent_flutter.dart';

Android 需要在 app/android 目录下 build.gradle 安装 ft-plugin 配合使用,并在创建自定义 Application,并且 AndroidMainifest.xml 中声明使用,代码如下,详细配置请见 Android SDK 配置,或参考 demo

import io.flutter.app.FlutterApplication

/**
* 如果需要统计【启动次数】和【启动时间】需要在此处添加自定义 Application
*/
class CustomApplication : FlutterApplication() {
}
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.cloudcare.ft.mobile.sdk.agent_example">
  <application android:name=".CustomApplication">
    //...
  </application>
</manifest>

SDK 初始化

基础配置

void main() async {
    WidgetsFlutterBinding.ensureInitialized();
    //初始化 SDK
    await FTMobileFlutter.sdkConfig(
      serverUrl: serverUrl,
      debug: true,
    );
}  
字段 类型 必须 说明
serverUrl String 数据上报地址
useOAID bool 是否使用 OAID 唯一识别,默认false,开启后替换 deviceUUID 进行使用,仅仅作用于 Android 设备
debug bool 设置是否允许打印日志,默认false
datakitUUID String 请求HTTP请求头X-Datakit-UUID 数据采集端 如果用户不设置会自动配置
envType enum EnvType 环境,默认prod

RUM 配置

 await FTRUMManager().setConfig(
        androidAppId: appAndroidId, 
        iOSAppId: appIOSId,
        enableNativeUserAction:false,
        enableNativeUserView: false
    );
字段 类型 必须 说明
androidAppId String appId,监测中申请
iOSAppId String appId,监测中申请
sampleRate double 采样率,(采集率的值范围为>= 0、<= 1,默认值为 1)
enableNativeUserAction bool 是否进行 Native Action 追踪,Button 点击事件,纯 Flutter 应用建议关闭,默认为 false
enableNativeUserView bool 是否进行 Native View 自动追踪,纯 Flutter 应用建议关闭,,默认为 false
enableNativeUserResource bool 是否进行 Native Resource 自动追踪,纯 Flutter 应用建议关闭,默认为 false
monitorType enum MonitorType 监控补充类型
globalContext Map 自定义全局参数

添加自定义标签

静态使用
  1. 拆分原有的 main.dart 为 2 个部分,一部分为 main(),一部分为 App() MaterialApp 组件;
  2. 建立对应各个环境的入口文件,如:main_prod.dart、main_gray.dart 等;
  3. 在对应的环境文件中进行自定义标签配置。例如:
///main_prod.dart
void main() async {
    WidgetsFlutterBinding.ensureInitialized();
    //初始化 SDK
    await FTMobileFlutter.sdkConfig(
      serverUrl: serverUrl,
      debug: true,
    );
    await FTRUMManager().setConfig(
        androidAppId: appAndroidId,
        iOSAppId: appIOSId,
        globalContext: {CUSTOM_STATIC_TAG:"prod_static_tag"},
    );
    runApp(MyApp());
  };
}
动态使用
  1. 通过存文件类型数据,例如 shared_preferencesSharedPreferences,配置使用 SDK,在配置处添加获取标签数据的代码。
final prefs = await SharedPreferences.getInstance();
String customDynamicValue = prefs.getString("customDynamicValue")?? "not set";

 await FTRUMManager().setConfig(
        androidAppId: appAndroidId,
        iOSAppId: appIOSId,
        globalContext: {CUSTOM_DYNAMIC_TAG:customDynamicValue},
        //… 添加其他配置
    );
  1. 在任意处添加改变文件数据的方法。
 static Future<void> setDynamicParams(String value) async{
    final prefs = await SharedPreferences.getInstance();
    prefs.setString(CUSTOM_DYNAMIC_TAG, value);
  }
  1. 最后重启应用。

注意:

  1. 特殊 key : track_id (用于追踪功能)
  2. 当用户通过 globalContext 添加自定义标签与 SDK 自有标签相同时,SDK 的标签会覆盖用户设置的,建议标签命名添加项目缩写的前缀,例如 df_tag_name。项目中使用 key 值可查询源码

Log 配置

 await FTLogger().logConfig(
   serviceName: "flutter_agent", 
   enableCustomLog: true
 );
字段 类型 必须 说明
sampleRate double 采样率,采集率的值范围为>= 0、<= 1,默认值为 1
serviceName String 服务名
enableLinkRumData bool 是否与 RUM 关联
enableCustomLog bool 是否开启自定义日志
discardStrategy enum FTLogCacheDiscard 日志丢弃策略,默认FTLogCacheDiscard.discard
logLevelFilters List 日志等级过滤

Trace 配置

await FTTracer().setConfig(
  enableLinkRUMData: true,
  enableAutoTrace:false,
  enableNativeAutoTrace: false
);
字段 类型 必须 说明
sampleRate double 采样率,采集率的值范围为>= 0、<= 1,默认值为 1
serviceName String 服务名
traceType enum TraceType 链路类型,默认TraceType.ddTrace
enableLinkRUMData bool 是否与 RUM 数据关联,默认false
enableAutoTrace bool 是否开启 flutter 网络追踪,默认false
enableNativeAutoTrace bool 是否开启原生网络自动追踪 iOS NSURLSession ,Android OKhttp,默认false

RUM 用户数据追踪

Action

FTRUMManager().startAction("action name", "action type");

View

FTRUMManager().createView("Current Page Name",100000000)

FTRUMManager().starView("Current Page Name");

FTRUMManager().stopView();

如果需要采集应用休眠和唤醒行为需要添加如下代码:

class _HomeState extends State<HomeRoute> {

    @override
    void initState(){

        //添加应用休眠和唤醒监听
        FTLifeRecycleHandler().initObserver();
    }

    @override
    void dispose(){

        //移除应用休眠和唤醒监听
        FTLifeRecycleHandler().removeObserver();
    }
}

Error

/// flutter 自动采集 error
void main() async {
  runZonedGuarded(() async {
    WidgetsFlutterBinding.ensureInitialized();
    await FTMobileFlutter.sdkConfig(
      serverUrl: serverUrl,
      debug: true,
    );
    await FTRUMManager().setConfig(
        androidAppId: appAndroidId,
        iOSAppId: appIOSId,
        enableNativeUserAction:false,
        enableNativeUserView: false
    );

    // Flutter 框架异常捕获
    FlutterError.onError = FTRUMManager().addFlutterError;
    runApp(MyApp());
  }, (Object error, StackTrace stack) {
    //其它异常捕获与日志收集
    FTRUMManager().addError(error, stack);
  });


 ///自定义 error
 FTRUMManager().addCustomError("error stack", "error message");

Resource

/// 使用 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,
      );
    }
  }

使用 http 库与 dio 库,可参考 example

Logger 日志打印

FTLogger().logging("info log content", FTLogStatus.info);

日志等级

方法名 含义
FTLogStatus.info 提示
FTLogStatus.warning 警告
FTLogStatus.error 错误
FTLogStatus.critical 严重
FTLogStatus.ok 恢复

Tracer 网络链路追踪

/// 使用 httpClient    
void httpClientGetHttp() async {
    var url = 'http://www.google.cn';
    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;
        });
      }
    }
  }

使用 http 库与 dio 库,可参考 example

用户信息绑定与解绑

 FTMobileFlutter.bindUser("flutterUser");

 FTMobileFlutter.unbindUser();

常见问题