跳转至

HarmonyOS 应用接入


通过收集 HarmonyOS 应用的指标数据,以可视化方式分析应用性能。

前置条件

注意:若您开通了 RUM Headless 服务,前置条件已自动帮您配置完成,直接接入应用即可。

应用接入

  1. 进入 用户访问监测 > 新建应用 > HarmonyOS
  2. 输入应用名称和应用 ID;
  3. 选择应用接入方式:
  4. 公网 DataWay:直接接收 RUM 数据,无需安装 DataKit 采集器。
  5. 本地环境部署:满足前置条件后接收 RUM 数据。

安装

* 下载最新 ft_sdk.har 文件:https://static.guance.com/ft-sdk-package/harmony_os_sdk_har/0.1.0-alpha01/ft_sdk.har

HAR 包依赖配置:

根据 HarmonyOS 官方文档(HAR 包导入指南),HAR 文件应放在项目的 libs 目录下。

在项目的 oh-package.json5 中添加依赖:

{
  "dependencies": {
    "ft_sdk": "file:../libs/ft_sdk.har"
  }
}

注意

  • 确保 ft_sdk.har 文件在 libs/ 目录下(如果不存在,请创建该目录)
  • 如果 HAR 文件在根目录,需要移动到 libs/ 目录

然后运行:

ohpm install

安装完成后,HAR 包会被安装到 oh_modules/ft_sdk/ 目录下。

导入说明:

根据 HAR 包的实际结构,使用以下方式导入:

import { FTSDK } from 'ft_sdk/src/main/ets/components/FTSDK';
import { FTSDKConfig, FTRUMConfig, FTLoggerConfig } from 'ft_sdk/src/main/ets/components/Configs';

权限说明:

SDK 模块已自动包含以下权限声明,使用者无需手动配置。当应用集成 SDK 时,这些权限会自动生效:

权限名称 用途说明
ohos.permission.INTERNET 网络访问权限,用于数据上报和网络请求追踪
ohos.permission.GET_WIFI_INFO 获取 WiFi 信息,用于网络类型检测和信号强度采集
ohos.permission.GET_NETWORK_INFO 获取网络信息,用于网络状态监控和类型识别

初始化

EntryAbility.ets 中初始化 SDK:

import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { window } from '@kit.ArkUI';
import { FTSDK } from 'ft_sdk/src/main/ets/components/FTSDK';
import { FTSDKConfig, FTRUMConfig, FTLoggerConfig } from 'ft_sdk/src/main/ets/components/Configs';
import { TraceType } from 'ft_sdk/src/main/ets/components/trace/TraceType';

const DOMAIN = 0x0000;

export default class EntryAbility extends UIAbility {
  async onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): Promise<void> {
    await this.initFTSDK();
  }

  private async initFTSDK(): Promise<void> {
    try {
      // 本地环境部署(Datakit)
      // const sdkConfig = FTSDKConfig.builder(datakitUrl);

      // 公网 DataWay
      const sdkConfig = FTSDKConfig.builder(datawayUrl, clientToken)
        .setDebug(true)
        .setServiceName('Your-App-Name');
        // dbCacheLimit 默认值为 100MB,如需自定义可调用 .setDbCacheLimit(sizeInBytes)
        // rumCacheLimitCount 默认值为 100000,如需自定义可调用 .setRumCacheLimitCount(count)
        // logCacheLimitCount 默认值为 5000,如需自定义可调用 .setLogCacheLimitCount(count)

      await FTSDK.install(sdkConfig, this.context);

    const rumConfig = new FTRUMConfig()
        .setSamplingRate(1.0)
        .setRumAppId('your-app-id')
        .setEnableTraceUserAction(true)
        .setEnableTraceUserView(true)
        .setEnableTraceUserResource(true)
        .setEnableTrackAppANR(true);

    await FTSDK.installRUMConfig(rumConfig);

    const logConfig = new FTLoggerConfig()
      .setSamplingRate(1.0)
      .setEnableCustomLog(true)
      .setLogCacheLimitCount(10000)
      .setEnableLinkRumData(true);

    FTSDK.installLogConfig(logConfig);

      hilog.info(DOMAIN, 'FTSDK', 'FT SDK initialized successfully');
    } catch (error) {
      const errorObj: object = error as object;
      hilog.error(DOMAIN, 'FTSDK', `Failed to initialize FT SDK: ${JSON.stringify(errorObj)}`);
    }
  }

  onWindowStageCreate(windowStage: window.WindowStage): void {
    windowStage.loadContent('pages/Index', (err) => {
      if (err.code) {
        hilog.error(DOMAIN, 'FTSDK', `loadContent failed: ${err.code}`);
        return;
      }
      hilog.info(DOMAIN, 'FTSDK', 'Succeeded in loading the content.');
    });
  }
}
字段 类型 必须 说明
datakitUrl string 本地环境部署(Datakit)上报 URL 地址,例子:http://10.0.0.1:9529,端口默认 9529,安装 SDK 设备需能访问该地址。注意:datakitUrl 和 datawayUrl 配置两者二选一
datawayUrl string 公网 Dataway 上报 URL 地址,从 [用户访问监测] 应用中获取,例子:https://open.dataway.url,安装 SDK 设备需能访问这地址。注意:datakitUrl 和 datawayUrl 配置两者二选一
clientToken string 认证 token,需要与 datawayUrl 同时配置
debug boolean 设置是否允许打印 Debug 日志,默认false
env string 环境,默认prod,任意字符,建议使用单个单词,例如 test
serviceName string 设置所属业务或服务的名称 默认:df_rum_harmonyos
autoSync boolean 是否在采集数据后自动同步到服务器。默认 true。当为 false 时使用 flushSyncData 方法自行管理数据同步
syncPageSize number 设置同步请求条目数。范围 [5,),注意:请求条目数越大,代表数据同步占用更大的计算资源,默认为 10
dbCacheLimit number DB 缓存限制大小。范围 [30MB,),默认 100MB,单位 byte
rumCacheLimitCount number RUM 数据缓存数量限制,默认 100000,最小值 10000
logCacheLimitCount number 日志数据缓存数量限制,默认 5000,最小值 1000
dbCacheDiscard string 设置数据库中数据丢弃规则。
丢弃策略:discard丢弃新数据(默认)、discardOldest丢弃旧数据

RUM 配置

const rumConfig = new FTRUMConfig()
  .setRumAppId('your-app-id')
  .setSamplingRate(1.0)
  .setEnableTraceUserAction(true)
  .setEnableTraceUserView(true)
  .setEnableTraceUserResource(true)
  .setEnableTrackAppANR(true)
  .setEnableTraceWebView(true); // 开启 WebView 数据采集

await FTSDK.installRUMConfig(rumConfig);
方法 类型 必须 说明
setRumAppId string RUM 应用 ID,从 [用户访问监测] 应用中获取
setSamplingRate number RUM 采样率,范围 [0.0, 1.0],默认 1.0(100% 采集)
setEnableTraceUserAction boolean 是否开启自动动作追踪(UI 点击事件),默认 false
setEnableTraceUserView boolean 是否开启页面追踪,默认 false
setEnableTraceUserResource boolean 是否开启资源追踪(HTTP 请求),默认 false
setEnableTrackAppANR boolean 是否开启 ANR 监控,默认 false
setEnableTraceWebView boolean 是否开启 WebView 数据采集,默认 false
setRumCacheLimitCount number RUM 数据缓存数量限制,默认 100000,最小值 10000

日志配置

import { Status } from 'ft_sdk/src/main/ets/components/bean/Status';

const logConfig = new FTLoggerConfig()
  .setSamplingRate(1.0)
  .setEnableCustomLog(true)
  .setLogCacheLimitCount(10000)
  .setLogLevelFiltersString([
    Status.ERROR.name,
    Status.WARNING.name,
    Status.INFO.name,
    Status.DEBUG.name
  ])
  .setEnableLinkRumData(true);

FTSDK.installLogConfig(logConfig);
方法 类型 必须 说明
setSamplingRate number 日志采样率,范围 [0.0, 1.0],默认 1.0(100% 采集)
setEnableCustomLog boolean 是否启用自定义日志,默认 false
setLogCacheLimitCount number 日志数据缓存数量限制,默认 5000,最小值 1000
setLogLevelFiltersString string[] 日志级别过滤,可选值:ERRORWARNINGINFODEBUG
setEnableLinkRumData boolean 是否关联 RUM 数据,默认 false

Trace 配置

import { TraceType } from 'ft_sdk/src/main/ets/components/trace/TraceType';

const traceConfig = new FTTraceConfig()
  .setSamplingRate(0.8)
  .setTraceType(TraceType.DDTRACE)
  .setEnableAutoTrace(true)
  .setEnableLinkRUMData(true);

FTSDK.installTraceConfig(traceConfig);
方法 类型 必须 说明
setSamplingRate number 设置采集率,取值范围 [0,1],0 表示不采集,1 表示全采集,默认值为 1
setTraceType TraceType 设置链路追踪的类型,默认为 DDTRACE,目前支持 ZIPKIN_MULTI_HEADERZIPKIN_SINGLE_HEADERJAEGERDDTRACESKYWALKINGTRACEPARENT (W3C),如果接入 OpenTelemetry 选择对应链路类型时,请注意查阅支持类型及 agent 相关配置
setEnableLinkRUMData boolean 是否与 RUM 数据关联,默认为 false
setEnableAutoTrace boolean 设置是否开启自动 http trace,目前支持 RCP 的自动追踪,默认为 false
setHeaderHandler HeaderHandler 设置全局 FTTraceHeaderHandler,默认不设置,用于自定义 Trace Header

RUM 用户数据追踪

View

使用方法

startView(viewName: string, property?: Record<string, object>): void
stopView(property?: Record<string, object>): void
updateLoadTime(loadTime: number): void

代码示例

import { FTRUMGlobalManager } from 'ft_sdk/src/main/ets/components/rum/FTRUMGlobalManager';

// 场景 1
FTRUMGlobalManager.getInstance().startView('ProductPage');

// 场景 2: 动态参数
// PropertyWrapper class must be defined (ArkTS requirement)
class PropertyWrapper {
  value: string | number | boolean;
  constructor(v: string | number | boolean) {
    this.value = v;
  }
}

class ViewProperty {
  private properties: Map<string, string | number | boolean> = new Map();

  set(key: string, value: string | number | boolean): void {
    this.properties.set(key, value);
  }

  toObject(): Record<string, object> {
    const result: Record<string, object> = {} as Record<string, object>;
    this.properties.forEach((value, key) => {
      result[key] = new PropertyWrapper(value) as object;
    });
    return result;
  }
}

const viewProperty = new ViewProperty();
viewProperty.set('page_category', 'product');
viewProperty.set('page_id', '12345');
FTRUMGlobalManager.getInstance().startView('ProductPage', viewProperty.toObject());

FTRUMGlobalManager.getInstance().updateLoadTime(100000000);

// 场景 1
FTRUMGlobalManager.getInstance().stopView();

// 场景 2: 动态参数
const stopViewProperty = new ViewProperty();
stopViewProperty.set('view_duration', 1000);
FTRUMGlobalManager.getInstance().stopView(stopViewProperty.toObject());

Action

使用方法

addAction(actionName: string, actionType: string, duration: number, startTime: number, property?: Record<string, object>): void

代码示例

import { FTRUMGlobalManager } from 'ft_sdk/src/main/ets/components/rum/FTRUMGlobalManager';

// 场景 1: 直接完成
FTRUMGlobalManager.getInstance().addAction('buy_button_click', 'click');

// 场景 2: 动态参数
// PropertyWrapper class must be defined (ArkTS requirement)
class PropertyWrapper {
  value: string | number | boolean;
  constructor(v: string | number | boolean) {
    this.value = v;
  }
}

class ActionProperty {
  private properties: Map<string, string | number | boolean> = new Map();

  set(key: string, value: string | number | boolean): void {
    this.properties.set(key, value);
  }

  toObject(): Record<string, object> {
    const result: Record<string, object> = {} as Record<string, object>;
    this.properties.forEach((value, key) => {
      result[key] = new PropertyWrapper(value) as object;
    });
    return result;
  }
}

const actionProperty = new ActionProperty();
actionProperty.set('product_id', '12345');
actionProperty.set('product_name', 'iPhone 15');
FTRUMGlobalManager.getInstance().addActionWithProperty('buy_button_click', 'click', actionProperty.toObject());

// 场景 3: 开始 Action(包含时长计算机制)
FTRUMGlobalManager.getInstance().startAction('buy_button_click', 'click');
// ... 执行操作 ...
FTRUMGlobalManager.getInstance().stopAction();

自动追踪:

在 RUM 配置中开启 enableTraceUserAction 后,SDK 会自动追踪 UI 组件的点击事件。为 Button 组件添加 customProperty 以获取按钮文本:

Button('Buy Now')
  .id('buy-btn')
  .customProperty('buy-btn', 'Buy Now')
  .onClick(() => {
    // 点击事件会自动被追踪
  })

Resource

使用方法

startResource(resourceId: string, property?: Record<string, object>): void
stopResource(resourceId: string): void
addResource(resourceId: string, resourceParams: ResourceParams, netStatusBean?: NetStatusBean): void

自动追踪:

在 RUM 配置中开启 enableTraceUserResource 后,SDK 会自动追踪通过 RCP 发送的 HTTP 请求。

代码示例

import { FTRUMGlobalManager } from 'ft_sdk/src/main/ets/components/rum/FTRUMGlobalManager';
import { ResourceParams } from 'ft_sdk/src/main/ets/components/rum/bean/ResourceParams';
import { NetStatusBean } from 'ft_sdk/src/main/ets/components/rum/bean/NetStatusBean';

const resourceId = 'https://api.example.com/data';

// 开始资源追踪
FTRUMGlobalManager.getInstance().startResource(resourceId);

const resourceParams = new ResourceParams();
resourceParams.setUrl(resourceId);
resourceParams.setResourceStatus(200);
resourceParams.setResponseContentLength(1024);
resourceParams.resourceType = 'xhr';

const netStatusBean = new NetStatusBean();
netStatusBean.setResourceHostIP('192.168.1.1');
netStatusBean.setDNSTime(10000000);
netStatusBean.setTcpTime(20000000);
netStatusBean.setTTFB(50000000);
netStatusBean.setResponseTime(100000000);

// 结束资源追踪并添加资源数据
FTRUMGlobalManager.getInstance().stopResource(resourceId);
FTRUMGlobalManager.getInstance().addResource(resourceId, resourceParams, netStatusBean);

Error

使用方法

addError(log: string, message: string, errorType: ErrorType, appState: AppState, property?: Record<string, object>): void

代码示例

import { FTRUMGlobalManager } from 'ft_sdk/src/main/ets/components/rum';
import { ErrorType, AppState } from 'ft_sdk/src/main/ets/components/rum';

const rumManager = FTRUMGlobalManager.getInstance();

// Option 1: Use ErrorProperty class (recommended for ArkTS)
// Note: ErrorProperty is a helper class, you can create your own or use Map
// PropertyWrapper class must be defined outside the method (ArkTS requirement)
class PropertyWrapper {
  value: string | number | boolean;
  constructor(v: string | number | boolean) {
    this.value = v;
  }
}

class ErrorProperty {
  private properties: Map<string, string | number | boolean> = new Map();

  set(key: string, value: string | number | boolean): void {
    this.properties.set(key, value);
  }

  toObject(): Record<string, object> {
    const result: Record<string, object> = {} as Record<string, object>;
    this.properties.forEach((value, key) => {
      // Create wrapper object using class (ArkTS requirement)
      result[key] = new PropertyWrapper(value) as object;
    });
    return result;
  }
}

const property = new ErrorProperty();
property.set('error_code', 'ERR_001');
property.set('user_id', 'test_user');

rumManager.addError(
  'Error stack trace:\n  at ProductPage.onClick\n  at Button.onClick',
  'Failed to load product data',
  ErrorType.CUSTOM,
  AppState.RUN,
  property.toObject()
);

// Option 2: Pass null if no properties needed
rumManager.addError(
  'Error stack trace:\n  at ProductPage.onClick\n  at Button.onClick',
  'Failed to load product data',
  ErrorType.CUSTOM,
  AppState.RUN
);

自动追踪:

在 RUM 配置中开启 enableTrackAppCrashenableTrackAppANR 后,SDK 会自动捕获应用崩溃和 ANR 事件。

LongTask

使用方法

addLongTask(taskName: string, duration: number, property?: Record<string, string | number | boolean>): void

代码示例

import { FTRUMGlobalManager } from 'ft_sdk/src/main/ets/components/rum';

const rumManager = FTRUMGlobalManager.getInstance();

// Option 1: Use Map for properties (recommended for ArkTS)
const property = new Map<string, string | number | boolean>();
property.set('task_type', 'data_processing');
property.set('data_size', 10000);

// Convert Map to Record (ArkTS compatible)
const propertyRecord: Record<string, string | number | boolean> = {} as Record<string, string | number | boolean>;
property.forEach((value, key) => {
  propertyRecord[key] = value;
});

const duration = 500000000;
rumManager.addLongTask('Data Processing', duration, propertyRecord);

// Option 2: Pass empty object or omit property parameter
rumManager.addLongTask('Data Processing', duration);

日志功能

自定义日志

使用方法

FTLogger.getInstance().logBackground(content: string, status: Status): void
FTLogger.getInstance().logBackground(content: string, status: Status, property?: Map<string, object>): void
FTLogger.getInstance().logBackground(content: string, status: string, property?: Map<string, object>): void

代码示例

import { FTLogger } from 'ft_sdk/src/main/ets/components/log/FTLogger';
import { Status } from 'ft_sdk/src/main/ets/components/bean/Status';

// 上传单个日志
FTLogger.getInstance().logBackground('Failed to load product data', Status.ERROR);

// 传递参数
const property = new Map<string, object>();
property.set('error_code', 'ERR_001');
property.set('user_id', 'test_user');
FTLogger.getInstance().logBackground('Network request timeout', Status.WARN, property);

// 使用字符串状态
FTLogger.getInstance().logBackground('User logged in successfully', 'info');

注意: - FTLogger 是提供给外部用户使用的公共日志 API - 如需启用 SDK 内部调试日志,请使用 FTSDKConfig.setDebug(true) 配置

Tracer 网络链路追踪

Trace 配置 中开启 enableAutoTrace 后,SDK 会自动为 HTTP 请求注入链路追踪 Headers。也可以手动使用 FTTraceManager 在 HTTP 请求中添加 Propagation Header

自动追踪

在 Trace 配置中开启 enableAutoTrace 后,SDK 会自动为通过 RCP 发送的 HTTP 请求注入 Trace Headers:

import http from '@ohos.net.http';

const httpRequest = http.createHttp();
const response = await httpRequest.request('https://api.example.com/data', {
  method: http.RequestMethod.GET
});
// Trace Headers 会自动注入到请求中

手动获取 Trace Header

如果使用其他网络框架,可以手动获取 Trace Header 并添加到请求中:

import { FTTraceManager } from 'ft_sdk/src/main/ets/components/trace/FTTraceManager';
import http from '@ohos.net.http';

const url = 'https://api.example.com/data';
const resourceId = 'unique-resource-id'; // 用于标识资源的唯一 ID

// 获取链路头参数
const traceHeaders: Record<string, string> = FTTraceManager.getInstance().getTraceHeader(resourceId, url);

// 将 Trace Headers 添加到请求中
const httpRequest = http.createHttp();
const response = await httpRequest.request(url, {
  method: http.RequestMethod.GET,
  header: traceHeaders
});

Trace 类型

Trace 类型 协议 主要 Headers
DDTRACE DataDog Trace x-datadog-trace-id, x-datadog-parent-id, x-datadog-origin, x-datadog-sampling-priority
ZIPKIN_MULTI_HEADER Zipkin Multi-Header X-B3-TraceId, X-B3-SpanId, X-B3-ParentSpanId, X-B3-Sampled
ZIPKIN_SINGLE_HEADER Zipkin Single-Header (b3) b3
JAEGER Jaeger uber-trace-id
TRACEPARENT W3C Trace Context traceparent, tracestate
SKYWALKING SkyWalking sw8

用户数据绑定

使用方法

/**
 * 绑定用户信息(仅用户 ID)
 * @param id 用户 ID
 */
static bindRumUserDataById(id: string): void

/**
 * 绑定用户信息(完整用户数据)
 * @param userData 用户数据对象
 */
static async bindRumUserData(userData: UserData): Promise<void>

/**
 * 解绑用户信息
 */
static async unbindRumUserData(): Promise<void>

UserData

方法名 含义 必须 注意
setId 设置用户 ID
setName 设置用户名
setEmail 设置邮箱
setExts 设置用户扩展 添加规则请查阅此处

代码示例

import { FTSDK } from 'ft_sdk/src/main/ets/components/FTSDK';
import { UserData } from 'ft_sdk/src/main/ets/components/rum/bean/UserData';

// 方式一:仅绑定用户 ID(推荐用于快速绑定)
FTSDK.bindRumUserDataById('user_001');

// 方式二:绑定完整用户信息(推荐用于需要更多用户信息的场景)
  const userData = new UserData();
userData.setId('user_001');
userData.setName('test.user');
userData.setEmail('test@mail.com');
const exts: Record<string, string> = {
  'ft_key': 'ft_value',
  'user_type': 'vip'
};
userData.setExts(exts);
await FTSDK.bindRumUserData(userData);

// 解绑用户信息(用户退出登录时调用)
await FTSDK.unbindRumUserData();

添加自定义标签

import { FTSDK } from 'ft_sdk/src/main/ets/components/FTSDK';

const globalContext = new Map<string, string>();
globalContext.set('platform', 'harmonyos');
globalContext.set('version', '1.0.0');
FTSDK.appendGlobalContext(globalContext);

const rumGlobalContext = new Map<string, string>();
rumGlobalContext.set('user_type', 'vip');
rumGlobalContext.set('channel', 'official');
FTSDK.appendRUMGlobalContext(rumGlobalContext);

主动同步数据

当配置 autoSyncfalse 时,需要主动触发数据同步:

import { FTSDK } from 'ft_sdk/src/main/ets/components/FTSDK';

FTSDK.flushSyncData();

清理 SDK 缓存数据

import { FTSDK } from 'ft_sdk/src/main/ets/components/FTSDK';

await FTSDK.clearAllData();

注意clearAllData() 会删除所有未上报的缓存数据,包括: - 同步数据表(sync_data_flat)中的所有数据 - RUM 视图数据表(rum_view)中的所有数据 - RUM 动作数据表(rum_action)中的所有数据

WebView 集成

在 RUM 配置中开启 enableTraceWebView 后,SDK 会自动采集 WebView 中的 RUM 数据。

在 WebView 页面中使用

import { FTWebViewHandler } from 'ft_sdk/src/main/ets/components/web/FTWebViewHandler';
import { webview } from '@kit.ArkWeb';

@Component
export struct MyWebViewPage {
  @State webController: webview.WebviewController = new webview.WebviewController();
  private webViewHandler: FTWebViewHandler = new FTWebViewHandler();

  aboutToAppear() {
    // 只需要传入 webController,配置会从应用入口的 RUM 配置中读取
    this.webViewHandler.setWebView(this.webController);
  }

  aboutToDisappear() {
    this.webViewHandler.clearWebController();
  }

  build() {
    Web({ 
      src: 'https://example.com', 
      controller: this.webController 
    })
    .javaScriptAccess(true)
    .javaScriptProxy(this.webViewHandler.getJavaScriptProxy(this.webController))
  }
}

文档评价

文档内容是否对您有帮助? ×