# tingyun_flutter_plugin **Repository Path**: stareyes924/tingyun_flutter_plugin ## Basic Information - **Project Name**: tingyun_flutter_plugin - **Description**: 鸿蒙化 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-01-30 - **Last Updated**: 2026-01-30 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # TingYun_App_Flutter **环境要求** - **Dart Version: >= 2.4.0** - **Flutter Version >= 1.12.0** ## 嵌码步骤 > Flutter 嵌码分为两个部分「原生项目嵌码」和「Flutter插件嵌码」 ### 1、原生项目嵌码 请确保嵌码 APP 原生部分已集成 TingYun_SDK ,如未集成可参照原生项目部署文档完成嵌码 - Android 部署文档 - https://wukongdoc.tingyun.com/app/sdk_deploy/Android/Android_Gradle.html - iOS 部署文档 > 由于「Flutter插件嵌码」会通过 pod install 引入 iOS SDK,所以请从`添加 TingYun SDK`开始嵌码 - https://wukongdoc.tingyun.com/app/sdk_deploy/iOS/deploy.html ### 2、Flutter 插件嵌码 #### 2.1、添加依赖 - ##### 添加依赖 > 在项目的「pubspec.yaml」文件中添加「TingYun Flutter」插件,目前支持【远程依赖】及【本地依赖】两种部署方式 - ##### 远程依赖 ```yaml dependencies: tingyun_flutter_plugin: ^1.0.0 ``` - ##### 本地依赖 ```yaml dependencies: tingyun_flutter_plugin: path: tingyun_flutter_plugin //tingyun_flutter_plugin 需替换为本地 TingYun flutter 插件的目录 ``` - ##### 获取插件 - 添加后需要在项目「根目录下」执行 `flutter packages get` 命令 - ##### 注意:iOS 添加依赖需在项目 ios 目录下执行`pod install` #### 2.2、Flutter 插件初始化 - ##### 初始化插件 需在`runApp()`方法前添加`Tingyun().startWithoutWidget()`方法,为了采集 zone 的错误,需在外层包裹 `runZonedGuarded`,并传入`Tingyun().reportZoneStacktrace` ```dart import 'package:tingyun_flutter_plugin/tingyun_flutter_plugin.dart'; void main() { runZonedGuarded(() async { Tingyun().startWithoutWidget(); runApp(MyApp()); }, Tingyun().reportZoneStacktrace); } ``` - ##### 运行日志 运行项目工程后控制台会显示以下日志: ```yaml tingyun flutter impl start get configure from tingyun:xxx //xxx 为从 native 端 SDK 获取到的功能开关配置情况 //初始化成功时候显示 tingyun flutter plugin success! //初始化失败时显示 tingyun flutter plugin failed to initialize. Error: xxx //xxx 为错误描述 ``` #### 2.3、兼容异常数据 > ##### 由于 Flutter 只允许单一 handler 收集 error 数据,听云提供了相关参数以便兼容 App 自身采集 error 的场景 - ##### 控制参数 我们在`tingyun_flutter_plugin`初始化方法中提供了两个参数,您可以选择传入相关函数来处理 error ```dart /** 因为flutter error 的捕获机制原因,需要提供2个不同的函数来进行处理, onError 是flutter框架没有捕获到的异常的时候,通过runZoned来捕获的error的回调函数 flutterOnError 是flutter框架通过Flutter.onError来捕获异常的回调函数 @onError: 需要传入原型为 void FunctiononError(Object, StackTrace)的函数, @flutterOnError: 需要传入原型为 void FunctionFlutterError(FlutterErrorDetails details)的函数 */ Tingyun().startWithoutWidget(onError: onCustomError, flutterOnError: onCustomFlutterError); ``` - ##### 代码示例 ```dart void main() { runZonedGuarded(() async { Tingyun().startWithoutWidget(onError: onCustomError, flutterOnError: onCustomFlutterError); runApp(MyApp()); }, Tingyun().reportZoneStacktrace); } void onCustomError(Object object, StackTrace stackTrace){ print('onCustomError happened'); } void onCustomFlutterError(FlutterErrorDetails details){ print('onCustomFlutterError happened'); } ``` ### 3、Android WebView 数据采集 > 由于操作系统差异,TIngYun_iOS_SDK 默认支持自动采集 WebView 数据,Android 则需按以下步骤添加相关设置 - ##### 设置 WebChromeClient - Android 采集 WebView 数据需要设置 WebChromeClient,并在 onProgressChanged() 中调用 TingYun_Android_SDK 提供的 initJSMonitor() 方法 - ##### 举例 以【 webview_flutter-0.3.24】为例 - 打开 webview_flutter-0.3.24 android 目录下的 build.gradle 文件并添加 TingYun_Android_SDK 依赖 ```java dependencies { compileOnly "com.networkbench:tingyun-ea-agent-android:2.17.4" } ``` - 在 WebChromeClient 中重写 onProgressChanged(),并添加 TingYun_SDK 的 initJSMonitor() 方法 ```java private class FlutterWebChromeClient extends WebChromeClient { @Override public void onProgressChanged(WebView view, int newProgress) { try { Class.forName("com.networkbench.agent.impl.instrumentation.NBSWebChromeClient"); com.networkbench.agent.impl.instrumentation.NBSWebChromeClient.initJSMonitor(view, newProgress); } catch (ClassNotFoundException e) { e.printStackTrace(); } super.onProgressChanged(view, newProgress); } ... ... } ``` ### 4、FPS数据采集 - 在MyAppState下添加navigatorObservers列表中加上 ```flutter navigatorObservers: [ TYNavigatorObserver.instance ], ``` ​ 示例如下: ```java import 'package:tingyun_flutter_plugin/tingyun_flutter_plugin.dart'; void main() { runZonedGuarded(() async { Tingyun().startWithoutWidget(); runApp(MyApp()); }, Tingyun().reportZoneStacktrace); } class MyApp extends StatefulWidget { @override _MyAppState createState() => _MyAppState(); } class _MyAppState extends State { @override Widget build(BuildContext context) { return MaterialApp( //添加上TYNavigatorObserver到navigatorObservers中 navigatorObservers: [ TYNavigatorObserver.instance ], ); } } ``` ## API接口 ### 1、自定义网络请求 > TingYun_SDK 通过设置 HttpOverrides.global 自动采集网络数据,目前支持「httpClient」以及基于HttpClient 封装的「dio、http」等网络库。 > > 若您的项目设置了 HttpOverrides,将会导致 TingYun_SDK 无法采集网络数据,需要手动埋点采集数据。 - #### 相关接口 ``` /* @url:网络请求的完整 url */ TYWebRequestTiming timing = await Tingyun().createWebRequest(String url);// 创建一条网络性能数据 timing.start();// 请求开始 /* @code:请求的状态码 */ timing.stop(int code);// 请求结束 ``` - #### 代码示例 ```dart var url = "https://www.tingyun.com"; TYWebRequestTiming timing = await Tingyun().createWebRequest(url); timing.start(); var response = await http.get(url) .then((response) { timing.withMetric(WebMetricType.dns,10);// dns 时间 timing.withMetric(WebMetricType.connect,11);// 建连时间 timing.withMetric(WebMetricType.ssl,12);// ssl 时间 timing.withMetric(WebMetricType.firstPackage,13);// 首包时间 timing.withMetric(WebMetricType.remainPackage,14);// 剩余包时间 timing.withMetric(WebMetricType.ipAddress,"192.168.1.111");// 服务端 ip 地址 timing.stop(response.statusCode);// 请求结束 return response; }); ``` ### 2、自定义启动结束点 > **TingYun_SDK 默认计算 SDK 初始化开始至第一个页面加载结束的时间为「冷启动耗时」,研发人员可以根据自身应用需求更改计算「冷启动耗时」的结束点。** - #### 项目要求 - ##### Android 项目 - 采集冷启动(含首次启动)数据需实现自定义的 Application 类 - ##### iOS 项目 - 采集启动数据需要在 main 函数中嵌码 - #### 开启自定义启动开关 > 需在 native 部分初始化 TingYun_SDK 时调用相关接口 - ##### Android 接口 ```java /* @isCustom:是否启用自定义启动,默认 false,如需开启,置为 true */ NBSAppAgent.isCustomAppStart(boolean isCustom); ``` - ##### iOS 接口 ```objc /** 是否启用自定义启动,在启动SDK之前调用,默认 NO,如需开启,置为 YES */ + (void)customLanuchEnd:(BOOL)enable; ``` - ##### 代码示例 - Android 示例 ```java public class MyApplication extends Application { @Override public void onCreate() { NBSAppAgent.setLicenseKey("AppKey") .isCustomAppStart(true)//在初始化SDK时调用,开启自定义启动时间功能 .start(this.getApplicationContext()); } } ``` - iOS 示例 ```objc int main(int argc, char* argv[]) { @autoreleasepool { [NBSAppAgent customLanuchEnd:YES]; [NBSAppAgent setRedirectURL:@"Dc_Redirect"]; [NBSAppAgent startWithAppID:@"AppKey"]; return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); } } ``` - #### 设置自定义启动的结束点 > 需要开启「自定义启动开关」,当自定义启动开关设置为 true 时,自定义启动结束点的接口设置才会生效 - ##### 相关接口 ```dart Tingyun().setCustomOnResumeEndIns(); ``` - ##### 代码示例 ```dart Widget build(BuildContext context) { Tingyun().setCustomOnResumeEndIns(); return Scaffold( body:Column( crossAxisAlignment: CrossAxisAlignment.center, ..... )); } ``` ### 3、自定义用户操作 > 支持通过埋点方式采集操作数据,可支持 root 和 sub 两层 trace(注意:这里两层是指 sub trace 允许有多个并非两个)。 - #### 接口限制 - ##### 操作数据截至到 root 节点结束 - ##### 多组埋点 root 节点不能交叉调用 - #### 相关接口 ```dart /* @name:操作名称 */ TingyunRootAction rootAction = Tingyun().enterAction(String name);//创建一个操作 /* @name:子 Action 名称 */ TingyunAction subAction = rootAction.enterAction(String name);//创建一个子 Action subAction.leaveAction();//子 Action 完成 /* @props:附加信息 @tag:tag 标识 */ rootAction.leaveAction({Map props, String tag = ""});//操作完成 ``` - #### 代码示例 ```dart TingyunRootAction rootAction = Tingyun().enterAction('my button enter'); TingyunAction subAction1 = rootAction.enterAction('sub1 button enter'); subAction1.leaveAction(); TingyunAction subAction2 = rootAction.enterAction('sub2 button enter'); subAction2.leaveAction(); rootAction.leaveAction(props:{"key1":"value1","key2":"value2"},tag: "tag"); ``` ### 4、自定义错误 > 使用「自定义错误」接口可以采集研发人员「try / catch 异常」和「业务错误」并在听云平台「异常分析」→「错误」中进行展示,可以帮助研发人员收集异常和错误。 - #### 相关接口 ```dart /* @message:不可以传空,最大长度 1024 字节,超出截取前 1024 字节 @stackTrace:上传 exception 取到抛出时的堆栈 @props:value 值支持 Number, String, Array, Map 类型,最大限制128k,若超出最大限制上传为空 */ Tingyun().reportError(String message, String stackTrace, {Map props}); ``` - #### 代码示例 ```dart try { throw new StateError('This is an async Dart exception.'); } catch (exception, stack) { Tingyun().reportError(exception.toString(), stack.toString(),props: {"ke y1":"value1","key2":"value2"}); } ``` ### 5、设置用户标识 > 通过添加「用户标识」可在听云报表平台通过该标识检索到具体用户的性能问题 - #### 相关接口 ```dart /* @userIdentifier:最多包含64个字符,超出截取前64字符,支持中文、英文、数字、下划线,但不能包含空格或其他的转义字符 */ Tingyun().setUserIdentifier(String userIdentifier); ``` - #### 代码示例 ```dart Tingyun().setUserIdentifier("zhangsan@tingyun.com"); ``` ### 6、记录用户路径(面包屑) > **研发人员可以在应用程序的任意位置调用「面包屑」接口进行埋点。当应用程序发生崩溃时,SDK 会按代码的触发顺序收集埋点信息并在崩溃轨迹中高亮显示,以协助研发人员在应用崩溃时了解代码调用逻辑。** - #### 相关接口 ```dart /* @breadcrumb:自定义信息,最多包含100个字符,超出截取前100字符,支持中文、英文、数字、下划线 */ Tingyun().leaveBreadcrumb(String breadcrumb); ``` - #### 代码示例 ```dart Tingyun().leaveBreadcrumb("添加购物车"); ``` ### 7、自定义附加信息 > **在应用发生崩溃的时候,研发人员往往需要更多的信息以收集现场环境,可以通过调用「自定义崩溃附加信息」接口上传额外信息,协助分析崩溃问题。** - #### 相关接口 ```dart /* 只保留最新的10条数据,随崩溃上传 @key:key 值 @value:value 值,最大长度限制100,超出则截取前100 */ Tingyun().setUserCrashMessage(String key, String value); ``` - #### 代码示例 ```dart Tingyun().setUserCrashMessage("当前页面", "Main"); ``` ## 功能支持列表 | 模块 | 支持类性 | 采集数据 | 不支持类型 | 备注 | | --------------- | :----------------------------------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | | 网络模块 | 1. dio
2. http
3. httpclient | 1. 响应时间
2. DNS时间
3. 首包时间(响应时间-DNS时间) | 1. 建联时间
2. SSL时间
3. 剩余包时间
4. 客户端时间
5. 传输字节数
6. 网络错误 | 1. 响应时间不包含读流时间
2. 可以通过网络埋点接口获取包含读流的响应时间 | | 崩溃/卡顿/error | 1. 崩溃
2. Flutter error | 1. 崩溃/error堆栈
2. 崩溃/error轨迹
3.设备附加信息
4.用户自定义信息
5.面包屑 | 不支持卡顿采集 | 由于 Flutter 只能单一 handler 采集 error 数据,所以为了兼容 App 自身 error 处理,可以在听云Flutter初始化方法中传入自身error处理方法来处理相关 error,具体见部署文档「初始化补充说明」 | | webview模块 | 1. WKWebview数据获取「iOS」
2. 原生webview和腾讯X5「Android」 | 1. 主页面网络性能数据,如页面加载时间,白屏时间,首屏时间,可交互时间
2. 页面资源性能数据
3. js错误统计 | 1. 不支持WKWebview网络数据获取「iOS」
2. 不支持UIWebview页面性能数据「iOS」 | 1. 通过注入听云Web探针获取webview性能数据
2. 由于苹果要求iOS已不在采集UIWebview页面性能数据
3. Android不支持自动采集webview数据,需要在对应flutter webview plugin中添加initJSMonitor()方法,具体见部署文档「WebView 数据采集」 | | 启动体验 | 1. 首次启动
2. 冷启动
3. 热启动 | 1. 启动耗时
2. 启动次数
3. 启动期间的崩溃
4. 事件性能数据:网络、数据库、image、json、Storage、用户自定义函数
5. 设备附加信息 | | 1. 以下情况采集不到启动数据:
**iOS:**
1). 不在main函数嵌码
2). rootVC是UIViewController
3). 启动过程中被权限弹窗打断
**Android:**
1). 没有使用自定义application类
2. 首次/冷启动耗时默认只计算初始化到第一页面加载结束;可以调用接口自定义启动结束点,具体见部署文档「自定义启动结束点」 | | 操作体验 | 自定义Action | 1. 自定义Action耗时
2. 事件性能数据:网络「Android」
3. 设备附加信息 | 不支持自动采集操作体验数据 | 1. 可以通过自定义Action来定义一个操作来获取性能耗时
| | 页面体验 | | | 不支持页面体验数据采集 | 1. 可以通过自定义Action来定义一个页面获取性能耗时 | | 拨测模块 | 1. TCPPing
2. ICMPPIng
3. 单文件下载
4. MTR | 1. ping耗时
2. 丢包率
3. CDN厂商
4. 单文件下载耗时 | 单文件下载不支持使用自签名证书的HTTPS文件下载 | |