跳到主要内容
版本:3.7.0

原生应用

集成

一、预置Bonree SDK环境

拷贝bonree_sdk-signed.har到工程级目录中的hars文件夹

image-202402021355460101

二、添加bonree_sdk-signed.har

2.1 在工程的oh-package.json5中dependencies字段增加har包依赖 "@bonree/agent": "file:./hars/bonree_sdk-signed.har"

配置示例如下:

{
"modelVersion": "5.0.0",
"description": "Please describe the basic information.",
"dependencies": {
"@bonree/agent": "file:./hars/bonree_sdk-signed.har" // 这里要添加配置,用于引用SDK
},
"devDependencies": {
"@ohos/hypium": "1.0.18",
"@ohos/hamock": "1.0.0"
}
}

image-202402021355460201

2.2 使用ohmurl新的拼接和解析方式

将工程级build-profile.json5中的useNormalizedOHMUrl修改为true, 若没有该配置项请手动添加。

{
"app": {
"products": [
{
"buildOption": {
"strictMode": {
"useNormalizedOHMUrl": true
}
}
}
]
}
}

三、Sync & Rebuid 项目

第一步:

点击右上角的 [ Sync Now ]

image-202402021355460301

若未出现,可使用 DevEco Studio 快捷键解决, 选择 Run 'ohpm install'

image-202402021355460302

第二步:

Rebuild项目,确保配置生效。

image-202402021355460303

接入

一、配置授权信息

检查应用程序module.json5配置文件,尽量确保已引入如下授权:

//下列权限都是必要权限,详情可参阅《隐私政策》中权限说明部分:
ohos.permission.INTERNET 发送网络数据
ohos.permission.GET_NETWORK_INFO 获取网络状态信息

二、初始化SDK

<#Config地址#><#AppID#> 请于平台上获取,获取方式参见《如何查询AppID和Config地址?》。如有问题请联系技术支持。

请在入口entry moudle自定义AbilityStage中的onCreate函数中,添加如下代码:

Bonree.withAppID("<#AppID#>")
.withConfigAddress("<#Config地址#>")
.start(this.context.getApplicationContext());

样例代码

import { Bonree } from '@bonree/agent'
import AbilityStage from '@ohos.app.ability.AbilityStage'

export default class EntryAbilityStage extends AbilityStage {

onCreate() {
this.initBonreeSdk();
}

private initBonreeSdk() {
Bonree.withAppID("<#AppID#>")
.withConfigAddress("<#Config地址#>")
.start(this.context.getApplicationContext());
}
}

三、Web数据采集

3.1原生应用采集

3.1.1 采集Web性能数据

在javaScriptOnDocumentStart、onControllerAttached中分別添加BonreeTrace.Web.getScriptItem(controller)、BonreeTrace.Web.onControllerAttachedHilt(controller)

import { BonreeTrace } from '@bonree/agent';

Web()
.javaScriptOnDocumentStart([BonreeTrace.Web.getScriptItem(this.controller)])// this.controller:必须是当前Web绑定的WebviewController
.onControllerAttached(() => {
BonreeTrace.Web.onControllerAttachedHilt(this.controller); // this.controller:必须是当前Web绑定的WebviewController
})

3.1.2 采集Web异常数据

在onErrorReceive、onHttpErrorReceive、onSslErrorEventReceive中添加对应方法

import { BonreeTrace } from '@bonree/agent';

Web()
.onErrorReceive((event) => {
if (!event) {
return;
}
BonreeTrace.Web.onErrorReceive(event.request, event.error, this.controller.getWebId()); // this.controller:必须是当前Web绑定的WebviewController
})
.onHttpErrorReceive((event) => {
if (!event) {
return;
}
BonreeTrace.Web.onHttpErrorReceive(event.request, event.response, this.controller.getWebId()); // this.controller:必须是当前Web绑定的WebviewController
})
.onSslErrorEventReceive((event) => {
BonreeTrace.Web.onSslErrorEventReceive(event.error, this.controller.getWebId()); // this.controller:必须是当前Web绑定的WebviewController
})

3.2mPaaS应用采集

3.2.1 采集Web性能数据与异常数据

  1. 采集Web性能数据与异常数据需要在应用启动时初始化Bonree SDK,并实现H5WebClientProvider接口。调用接口注册时,可参考示例 ExampleWebclientProviderImpl 类,实际使用时需填写您自己实现的类,示例注册代码如下:HRiver.setProvider(H5WebClientProvider.name, new ExampleWebclientProviderImpl())
  2. 若要采集Web性能数据,需在 onPageBeginonControllerAttached 方法中分别添加对应的方法调用:BonreeTrace.Web.getScriptItem(controller)BonreeTrace.Web.onControllerAttachedHilt(controller)
  3. 若要采集Web异常数据,需在 onErrorReceiveonHttpErrorReceiveonSslErrorEventReceive 方法中分别添加对应的处理方法:BonreeTrace.Web.onErrorReceive(request, error, controller.getWebId())BonreeTrace.Web.onHttpErrorReceive(request, response, controller.getWebId())BonreeTrace.Web.onSslErrorEventReceive(error, controller.getWebId())
import { BonreeTrace } from "@bonree/agent";
import { H5WebClientProvider, Page } from "@mpaas/hriver";

export class ExampleWebclientProviderImpl extends H5WebClientProvider {
onHttpErrorReceive(page: Page | undefined, request: WebResourceRequest | undefined,
response: WebResourceResponse | undefined): void {
const controller = page?.webcontroller;
if (request && response && controller) {
try {
BonreeTrace.Web.onHttpErrorReceive(request, response, controller.getWebId());
} catch (error) {
}
}
}

onSslErrorEventReceive(page: Page | undefined, handler: SslErrorHandler, error: SslError): void {
const controller = page?.webcontroller;
try {
if (error && controller) {
BonreeTrace.Web.onSslErrorEventReceive(error, controller.getWebId());
}
} catch (error) {
}
}

onErrorReceive(page: Page | undefined, request: WebResourceRequest | undefined,
error: WebResourceError | undefined): boolean {
const controller = page?.webcontroller;
if (request && error && controller) {
try {
BonreeTrace.Web.onErrorReceive(request, error, controller.getWebId());
} catch (error) {
}
}
return false;
}

onPageBegin(page: Page | undefined, url: string | undefined): void {
const controller = page?.webcontroller;
if (controller) {
page.webcontroller?.runJavaScript(BonreeTrace.Web.getScriptItem(controller).script)
}
}

onControllerAttached(page: Page | undefined): void {
const controller = page?.webcontroller;
if (controller) {
BonreeTrace.Web.onControllerAttachedHilt(controller);
}
}
}

四、视图/启动数据采集

重要说明:

1.暂不支持子窗口中的视图数据采集,子窗口中的视图忽略本步骤。

2.使用uiObserver.off()和UIObserver.off()系列接口时务必传入callback,若off时不传callback会取消掉所有的注册,导致SDK数据采集异常。

4.1 Ability 数据采集

在UIAbility的子类声明上添加 @BonreeTrace.InjectAbility 装饰器

import { BonreeTrace } from '@bonree/agent';

@BonreeTrace.InjectAbility
export default class EntryAbility extends UIAbility {
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {

}

onWindowStageCreate(windowStage: window.WindowStage): void {

}

onForeground(): void {

}

onBackground(): void {

}

onWindowStageDestroy(): void {

}

onDestroy() {

}
}

4.2 AbilityStage 数据采集

在AbilityStage的子类声明上添加 @BonreeTrace.InjectStage 装饰器

import { BonreeTrace } from '@bonree/agent';

@BonreeTrace.InjectStage
export default class EntryAbilityStage extends AbilityStage {

onCreate() {
}

onMemoryLevel(level: AbilityConstant.MemoryLevel): void {
}
}

4.3 UI页面/Page 数据采集

在所有@Entry装饰的自定义组件下面添加 BonreeTrace.InjectPage(Index) 接口调用并传入当前结构, Page生命周期( aboutToAppear,onPageShow,onPageHide,aboutToDisappear)函数尽量复写,否则影响快照数据采集和性能准确性

import { BonreeTrace } from '@bonree/agent';

@Entry
@Component
struct Index {
build() {
}

aboutToAppear(): void {
}

onPageShow(): void {
}

onPageHide(): void {
}

aboutToDisappear(): void {
}
}

BonreeTrace.InjectPage(Index)

五、网络采集

目前支持采集框架 hms.collaboration.rcpohos.net.httpohos.net.webSocketohos.net.socket.TCPSocketohos/axiosmPaaS/rpc,当采集对应网络框架时,需要使用 BonreeTrace 引用这些框架类,各网络框架API使用同官网文档,如下是每个网络采集示例。

5.1 'hms.collaboration.rcp'

重要说明: rcp共有两种方案, 属于互斥方案, 当您集成时只能二选一

方案一:

仅需要在rcp.createSessionAPI前添加BonreeTrace开头引用。

import { rcp } from '@kit.RemoteCommunicationKit';
import { BonreeTrace } from '@bonree/agent';

// 示例1: 无参数传递
let session1 = BonreeTrace.rcp.createSession(); // 这里要添加 BonreeTrace 开头引用

// 示例2: 有参数传递
let session = BonreeTrace.rcp.createSession({}); // 这里要添加 BonreeTrace 开头引用

方案二:

需要在调用rcp.createSession(sessionConfiguration)中的sessionConfiguration.interceptors增加拦截器AgentRcpInterceptor

import { rcp } from '@kit.RemoteCommunicationKit';
import { BonreeTrace } from '@bonree/agent';

// 示例
const sessionConfig: rcp.SessionConfiguration = {
// 这里要添加 BonreeTrace.rcp.AgentRcpInterceptor 拦截器
interceptors: [new BonreeTrace.rcp.AgentRcpInterceptor()]
};
let session = rcp.createSession(sessionConfig);

5.2 'ohos.net.http'

重要说明: http共有两种方案, 属于互斥方案, 当您集成时只能二选一

方案一(推荐):

仅需要在http.createHttpAPI前添加BonreeTrace开头引用。

import { http } from '@kit.NetworkKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { BonreeTrace } from '@bonree/agent';

let httpRequest = BonreeTrace.http.createHttp(); // 这里要添加 BonreeTrace 开头引用
let options: http.HttpRequestOptions = {};
let promise = httpRequest.request(
'request url', options
);
promise.then((responseData: http.HttpResponse) => {
}).catch((err: BusinessError) => {
})

方案二:

第一步(可选配置):端对端的全链路打通需要在请求头中插入Bonree的自定义业务请求头,如不需要全链路业务可跳过此步骤。

API重要说明: 自定义业务请求头是根据URL规则返回,每条网络请求自定义头都需要重新获取赋值,非同一个requestUrl的API调用结果严禁复用!

  function getInsertHeaderMap(requestUrl: string): Map<string, string> | undefined
参数说明参数限制失败结果
requestUrl请求URL(必要)string类型。有效请求地址当次获取无效
import http from '@ohos.net.http'
import { BonreeTrace } from '@bonree/agent'

let httpRequest = http.createHttp();
let customHeaders: Record<string, string> = {};
// 这里要添加 获取端到端请求头,若您没有端到端业务,可跳过
BonreeTrace.http.getInsertHeaderMap("本次请求的URL")?.forEach((value, key) => {
customHeaders[key] = value;
})
let options: http.HttpRequestOptions = {
header: customHeaders,
};
let promise = httpRequest.request("本次请求的URL", options);

第二步(必要配置):采集正常/异常网络数据

function handleSuccess(requestUrl: string, method: string, responseCode: number, requestDataSizeByte: number,
downloadSizeByte: number, timing: OhosHttp.PerformanceTiming, remoteAddressIP?: string,
requestHeader?: Record<string, Object>, responseHeader?: Record<string, Object>, resourceType?: string,
optionsUsingProtocol?: string, requestBody?: string)
参数说明参数限制失败结果
requestUrl请求URL(必要)string类型。有效请求地址当次网络事件不采集
method请求方法(必要)string类型。非http请求方法,传空字符串即可当次网络事件不采集
responseCode响应码(必要)number类型当次网络事件不采集
requestDataSizeByte请求上传数据大小(必要)number类型(单位Byte)当次网络事件不采集
downloadSizeByte下载大小(必要)number类型(单位Byte)当次网络事件不采集
timingHTTP 请求各个阶段所花费的时间(必要)http.PerformanceTiming类型当次网络事件不采集
remoteAddressIP目标地址IPstring类型当次网络事件缺失相关字段
requestHeader请求headerRecord<string, Object>类型当次网络事件缺失相关字段
responseHeader响应headerRecord<string, Object>类型当次网络事件缺失相关字段
resourceType资源类型string类型。遵循MIME类型的Content-Type字段当次网络事件缺失相关字段
optionsUsingProtocol协议类型string类型。示例:http.HttpProtocol.HTTP2.toString()值无效则会根据url自动获取
requestBody请求内容string类型当次网络事件缺失相关字段
function handleError(requestUrl: string, method: string, requestDataSizeByte: number, errorParam: Error,
requestHeader?: Record<string, Object>)
参数说明参数限制失败结果
requestUrl请求URL(必要)string类型。有效请求地址当次网络事件不采集
method请求方法(必要)string类型。非http请求方法,传空字符串即可当次网络事件不采集
requestDataSizeByte请求上传数据大小(必要)number类型(单位Byte)当次网络事件不采集
errorParam网络Error错误(必要)BusinessError类型当次网络事件不采集
requestHeader请求headerRecord<string, Object>类型当次网络事件缺失相关字段

示例如下:

promise.then((responseData: http.HttpResponse) => {
BonreeTrace.http.handleSuccess("本次请求的URL", "GET", responseData.responseCode, requestDataSize, downloadSize, responseData.performanceTiming);
}).catch((err: BusinessError) => {
BonreeTrace.http.handleError("本次请求的URL", "GET", 0, err);
});

5.3 'ohos.net.webSocket'

仅需要在webSocket.createWebSocketAPI前添加BonreeTrace开头引用。

import { webSocket } from '@kit.NetworkKit';
import { BonreeTrace } from '@bonree/agent';

let webSocketInstance: webSocket.WebSocket = BonreeTrace.webSocket.createWebSocket(); // 这里要添加 BonreeTrace 开头引用

5.4 'ohos.net.socket.TCPSocket'

仅需要在调用socket.constructTCPSocketInstanceAPI前添加BonreeTrace开头引用。

import { socket } from '@kit.NetworkKit';
import { BonreeTrace } from '@bonree/agent';

let tcpSocketInstance: BonreeTrace.socket.TCPSocket = BonreeTrace.socket.constructTCPSocketInstance(); // 这里要添加 BonreeTrace 开头引用

5.5 'ohos/axios'

仅支持 >=2.2.1 版本

第一步(可选配置):端对端的全链路打通需要在请求头中插入Bonree的自定义业务请求头,如不需要全链路业务可跳过此步骤。

API重要说明: 自定义业务请求头是根据URL规则返回,每条网络请求自定义头都需要重新获取赋值,非同一个requestUrl的API调用结果严禁复用!

function getInsertHeaderMap(requestUrl: string): Map<string, string> | undefined
参数说明参数限制失败结果
requestUrl请求URL(必要)string类型。有效请求地址当次获取无效
//示例通过`AxiosRequestConfig`插入请求头,您也可以通过实现请求拦截器处理`InternalAxiosRequestConfig.headers`进行插头操作
import axios, {
AxiosError,
AxiosHeaders,
AxiosResponse,
AxiosRequestConfig,
InternalAxiosRequestConfig
} from '@ohos/axios'
import { BonreeTrace } from '@bonree/agent'

let customHeaders: AxiosHeaders = new AxiosHeaders();
// 先获取Bonree全链路业务请求头
BonreeTrace.axios.getInsertHeaderMap("本次请求的URL")?.forEach((value, key) => {
customHeaders.set(key, value);
});
// 通过AxiosRequestConfig插入到实际请求头中
let requestConfig: AxiosRequestConfig = {
method: this.currMethod,
headers: customHeaders,
params: this.currRequestParam
}
axios.get("本次请求的URL", requestConfig);

第二步(必要配置):采集正常/异常网络数据

function handleSuccess(requestUrl: string, method: string, responseCode: number, requestDataSizeByte: number,
downloadSizeByte: number, timingParam: object, remoteAddressIP?: string,
requestHeader?: Record<string, Object>, responseHeader?: Record<string, Object>, resourceType?: string,
requestBody?: string)
参数说明参数限制失败结果
requestUrl请求URL(必要)string类型。有效请求地址当次网络事件不采集
method请求方法(必要)string类型。非http请求方法,传空字符串即可当次网络事件不采集
responseCode响应码(必要)number类型当次网络事件不采集
requestDataSizeByte请求上传数据大小(必要)number类型(单位Byte)当次网络事件不采集
downloadSizeByte下载大小(必要)number类型(单位Byte)当次网络事件不采集
timingParamaxios 请求各个阶段所花费的时间(必要)http.PerformanceTiming类型当次网络事件不采集
remoteAddressIP目标地址IPstring类型当次网络事件缺失相关字段
requestHeader请求headerRecord<string, Object>类型当次网络事件缺失相关字段
responseHeader响应headerRecord<string, Object>类型当次网络事件缺失相关字段
resourceType资源类型string类型。遵循MIME类型的Content-Type字段当次网络事件缺失相关字段
requestBody请求内容string类型当次网络事件缺失相关字段
function handleError(requestUrl: string, method: string, requestDataSizeByte: number, errorParam: Error,
requestHeader?: Record<string, Object>)

参数说明参数限制失败结果
requestUrl请求URL(必要)string类型。有效请求地址当次网络事件不采集
method请求方法(必要)string类型。非http请求方法,传空字符串即可当次网络事件不采集
requestDataSizeByte请求上传数据大小(必要)number类型(单位Byte)当次网络事件不采集
errorParam网络Error错误(必要)BusinessError类型当次网络事件不采集
requestHeader请求headerRecord<string, Object>类型当次网络事件缺失相关字段

示例如下:

axios.get("本次请求的URL",requestConfig).then((responseData: AxiosResponse) => {
BonreeTrace.axios.handleSuccess("本次请求的URL", "GET", responseData.status, requestDataSize, downloadSize, responseData.performanceTiming);
}).catch((err: BusinessError) => {
BonreeTrace.axios.handleError("本次请求的URL", "GET", 0, err);
});

5.6 'mPaaS/rpc'

第一步(可选配置):端对端的全链路打通需要在请求头中插入Bonree的自定义业务请求头,如不需要全链路业务可跳过此步骤。

API重要说明: 自定义业务请求头是根据URL规则返回,每条网络请求自定义头都需要重新获取赋值,非同一个requestUrl的API调用结果严禁复用!

function getInsertHeaderMap(requestUrl: string): Map<string, string> | undefined
参数说明参数限制失败结果
requestUrl请求URL(必要)string类型。有效请求地址当次获取无效

以下以 ExampleRpcInterceptor 为例,实际使用时请替换为您实现的拦截器类名

  1. 添加RpcInterceptor接口实现类
import { MPRpc, RpcInterceptor, RpcInvokeContext } from '@mpaas/rpc'
import { BonreeTrace } from '@bonree/agent';

export class ExampleRpcInterceptor implements RpcInterceptor {
preHandle(rpcInvokeContext: RpcInvokeContext): boolean {
//这里要添加 获取端到端请求头,若您没有端到端业务,可跳过
BonreeTrace.mPaaSRpc.getInsertHeaderMap("本次请求的URL")?.forEach((value, key) => {
rpcInvokeContext.addHeader(key, value);
});
return true;
}
}
  1. 在应用启动阶段添加全局拦截器配置
import { MPRpc } from '@mpaas/rpc'
MPRpc.addGlobalInterceptor(new ExampleRpcInterceptor());

第二步(必要配置):采集正常/异常网络数据

function handleSuccess(requestUrl: string, requestHeader: Map<string, string>, responseHeader: object,
method?: string, remoteAddressIP?: string, timing?: OhosHttp.PerformanceTiming, requestDataSizeByte?: number,
downloadSizeByte?: number, requestBody?: string)
参数说明参数限制失败结果
requestUrl请求URL(必要)string类型。有效请求地址当次网络事件不采集
requestHeader请求header(必要)Map<string, string>类型当次网络事件缺失相关字段
responseHeader响应header(必要)object类型当次网络事件缺失相关字段
method请求方法string类型。非http请求方法,传空字符串即可默认请求方法为 post
remoteAddressIP目标地址IPstring类型当次网络事件缺失相关字段
timing请求各个阶段所花费的时间http.PerformanceTiming类型相关字段的值为0
requestDataSizeByte请求上传数据大小number类型(单位Byte)相关字段的值为0
downloadSizeByte下载大小number类型(单位Byte)相关字段的值为0
requestBody请求内容string类型当次网络事件缺失相关字段
function handleError(requestUrl: string, error: Error, requestHeader: Map<string, string>,
responseHeader?: object, method?: string, requestDataSizeByte?: number)
参数说明参数限制失败结果
requestUrl请求URL(必要)string类型。有效请求地址当次网络事件不采集
error错误信息(必要)Error类型当次网络事件不采集
requestHeader请求header(必要)Map<string, string>类型当次网络事件缺失相关字段
responseHeader响应headerobject类型当次网络事件缺失相关字段
method请求方法string类型。非http请求方法,传空字符串即可默认请求方法为 post
requestDataSizeByte请求上传数据大小number类型(单位Byte)相关字段的值为0

以下以 ExampleRpcInterceptor 为例,实际使用时请替换为您实现的拦截器类名

  1. 添加RpcInterceptor接口实现类
export class ExampleRpcInterceptor implements RpcInterceptor {
preHandle(rpcInvokeContext: RpcInvokeContext): boolean {
//这里要添加 获取端到端请求头,若您没有端到端业务,可跳过
BonreeTrace.mPaaSRpc.getInsertHeaderMap("本次请求的URL")?.forEach((value, key) => {
rpcInvokeContext.addHeader(key, value);
});
return true;
}

postHandle(rpcInvokeContext: RpcInvokeContext): boolean {
BonreeTrace.mPaaSRpc.handleSuccess("本次请求的URL", rpcInvokeContext.getRequestHeader(),
rpcInvokeContext.getResponseHeader());
return true;
}

handleException(rpcInvokeContext: RpcInvokeContext, exception: RPCException): boolean {
BonreeTrace.mPaaSRpc.handleError("本次请求的URL", exception, rpcInvokeContext.getRequestHeader());
throw exception
}
}
  1. 在应用启动阶段添加全局拦截器配置
import { MPRpc } from '@mpaas/rpc'
MPRpc.addGlobalInterceptor(new ExampleRpcInterceptor());

六、嵌码验证

启动已嵌码的APP,查看hilog日志,搜索过滤BRSDK-Agent标签,出现如下log则表示嵌码成功且数据开始采集:

BRSDK-Agent   I   starting...         (注:BRAgent 集成成功)
BRSDK-Agent I Bonree token***** (注:BRAgent 启动成功)
BRSDK-Agent I BRAgent connect server success (注:BRAgent 数据设置成功)
BRSDK-Agent I BRAgent v*** (注: ***为当前zip包文件名后所对应的BRAgent版本)

image-202402021422250301