更新记录
1.4.1(2026-10-20) 下载此版本
修复
profileDelete()身份校验放宽为与所有 profile API 一致的 at-least-one 规则:存在anon_id或login_id之一即可生效$exception_frames的in_app判定优先级调整:exceptionConfig.inAppExcludes优先于 `inAppIncludes
1.4.0(2026-10-15) 下载此版本
变更
- 预置属性取值规范对齐:
$language统一规范化为 BCP 47 格式(兼容微信小程序zh_CN下划线、百度小程序zh-cn全小写等各端原始格式);App 端$region统一为 ISO 3166-1 alpha-2 大写(从语言标签显式地区段提取,缺失时按语言推断);小程序 / App 端$network_type统一为小写闭集枚举(wifi/2g/3g/4g/5g/cellular/ethernet),unknown/none等非枚举值不再上报 - 数值精度调整:
$browser_version不再截断为整数版本号,上报完整版本串(如125.0.6678.21);$event_duration与$page_resource_size不再取整,保留最多三位小数 $device_id统一转小写上报与存储(iOSidentifierForVendor等系统来源本身为大写;历史已持久化的大写设备 ID 在读取时归一,存量数据无需迁移)
1.3.1(2026-09-20) 下载此版本
修复
- 修复 App 后台长驻或页面长期驻留场景下,待发送事件超过 7 天有效期后仍可能被发出的错误;发送取数时现在会惰性清理过期数据
平台兼容性
uni-app x(4.0)
| Chrome | Safari | Android | iOS | 鸿蒙 | 微信小程序 |
|---|---|---|---|---|---|
| √ | √ | √ | 15 | √ | √ |
其他
| 多语言 | 暗黑模式 | 宽屏模式 | 蒸汽模式 |
|---|---|---|---|
| √ | √ | √ | √ |
Sensorswave UniApp X 数据采集 SDK
Sensors Wave UniApp X 数据采集 SDK 是一个跨平台的数据埋点采集库,一套代码即可在多个平台自动采集用户行为数据。
以 uni-app-x 的 uni_modules 插件形态发布,业务工程通过 app.use(Sensorswave.plugin, config) 一行接入,应用级预置事件自动采集。
如果你是第一次接触 Sensors Wave,欢迎访问 sensorswave.com 了解产品并创建账号。
源码位于 uni_modules/sensorswave-uniappx/。
特性
- 🌐 跨平台支持:微信 / 支付宝 / 抖音 / 百度小程序、App(iOS / Android / 鸿蒙)、H5
- 🔎 平台运行时探测:通过
uni.getSystemInfoSync()自动识别宿主平台,无需手填platformType/platformName - 🚀 应用级预置事件自动采集:
app.use()后无需在App.uvue手动调用应用级生命周期方法 - 📄 页面级预置事件:由
install()注入的全局 mixin 统一驱动(H5 配合vue-router.afterEach),业务页面零侵入 - 👤 用户体系:匿名 / 登录用户标识、用户属性(profile)增删改、公共属性注册
- 🧪 A/B 测试:功能开关(Feature Gate)、远程配置(Feature Config)、实验分组(Experiment)
- 📡 UTM 追踪:自动解析启动参数中的 UTM 渠道参数并写入首值归因
- 🔒 敏感字段脱敏:自定义事件属性中的敏感信息(token / password / cookie …)自动掩码
- 💾 离线持久化:事件队列持久化存储、批量上报、失败重试,保障数据不丢
- ♻️ 挂起离开恢复:进程被杀后下次启动自动补发未结束会话的离开事件
- 💥 异常采集($Exception):error 级自动捕获(小程序 / H5 / 鸿蒙)+ fatal 级崩溃采集(App 端原生钩子,崩溃前落盘、下次启动补发),支持
trackException手动上报
平台支持
| 平台 | 自动采集事件 |
|---|---|
| 微信小程序 | $MPLaunch $MPShow $MPHide $MPPageView $MPPageLeave $MPShare |
| 支付宝小程序 | 同微信小程序 |
| 抖音小程序 | 同微信小程序 |
| 百度小程序 | 同微信小程序 |
| App iOS / Android / 鸿蒙 | $AppStart $AppEnd $AppPageView $AppPageLeave $AppInstall |
| H5 | $PageView $PageLeave $PageLoad $WebClick |
- 平台在运行时通过
uni.getSystemInfoSync()自动识别,无需手动指定。 - 所有平台上报事件的
$lib预置属性统一为uniappx,用于在数据端标识本采集 SDK。 $WebClick需开启enableClickTrack: true;$MPShare需开启enableShareTrack(默认开启)。- 小程序 / App 端无自动点击采集(uni-app x 编译模型限制),使用手动 API
trackClick(event)上报$MPClick/$AppClick,见 API 方法。
安装
SDK 已发布到 DCloud 插件市场,推荐通过 HBuilderX 一键导入:
- 打开插件市场页面:Sensors Wave uni-app x 数据采集 SDK
- 点击页面上的 使用 HBuilderX 导入插件 按钮
- 在 HBuilderX 弹窗中选择目标 UniApp X 工程,确认导入
- 等待下载完成,插件会自动安装到工程的
uni_modules/目录下
导入完成后,工程结构如下:
your-app/
└── uni_modules/
├── sensorswave-uniappx/ ← 由插件市场自动导入
│ ├── package.json
│ └── utssdk/
└── sw-ios-crash-trigger ← 依赖插件,自动跟随导入
├── package.json
└── utssdk/app-ios/
SDK 以两个插件形态分发:sw-ios-crash-trigger 是 App-iOS 端 fatal 崩溃采集的原生面(iOS 崩溃捕获必须在原生层进行,而编译器规则决定它只能以独立插件形态进基座),已在主插件 package.json 的 uni_modules.dependencies 中声明——HBuilderX 导入主插件时会提示"安装插件三方依赖",确认后自动带入,业务代码无需也无法直接调用它。
无需 npm 安装;uni-app-x 会自动识别 uni_modules 插件。后续插件更新也可在 HBuilderX 中通过插件市场一键升级。
如果你需要本地调试或二次开发,也可以将本仓库的
uni_modules/sensorswave-uniappx/与uni_modules/sw-ios-crash-trigger/两个目录拷贝(或软链)到工程的uni_modules/下,效果一致。
快速开始
推荐通过 Vue 插件 接入,插件会在 app.use() 时自动完成初始化,并注入页面生命周期 mixin,实现无侵入的页面浏览 / 离开采集。
1. 在 main.uts 安装插件
import App from './App.uvue'
import { createSSRApp } from 'vue'
import Sensorswave from '@/uni_modules/sensorswave-uniappx/utssdk/index'
export function createApp() {
const app = createSSRApp(App)
app.use(Sensorswave.plugin, {
sourceToken: 'your_source_token', // 必填:数据源 Token
apiHost: 'https://example.com', // 必填:数据上报地址
autoCapture: true, // 自动采集生命周期(默认 true)
enableClickTrack: true, // 自动采集点击(默认 false)
enableAB: true, // 启用 A/B 测试(默认 false)
debug: false, // 调试日志(默认 false)
})
return { app }
}
2. App.uvue 无需手动调用应用级预置事件
应用级事件(启动 / 前后台切换 / 小程序分享)由 SDK 在 install() 内自动监听与触发,
App.uvue 只需放置与业务身份相关的逻辑:
<script setup lang="uts">
import Sensorswave from '@/uni_modules/sensorswave-uniappx/utssdk/index'
onLaunch((options : any) => {
// 仅在已登录场景下设置 loginId(可选)
Sensorswave.setLoginId('user_123')
})
</script>
不需要调用
Sensorswave.onAppLaunch / onAppShow / onAppHide / onShare—— 它们会被自动触发。 页面级生命周期方法(onPageShow/onPageHide/onPageUnload)也不再对外暴露。
3. 页面级事件接入
通过 Vue 插件接入(推荐)后,页面级事件($PageView / $*PageLeave / $PageLoad)由 install() 注入的全局 mixin 统一驱动,业务页面零侵入:
- H5:全局 mixin +
vue-router.afterEach共同生效 - 小程序 / App:全局 mixin 合并到 App 根组件、页面及所有自定义组件,SDK 内部通过
$scope.route/$page.route/$options.mpType === 'page'过滤出真正的页面实例,避免 App 根组件 / 子组件的onShow误触发$MPPageView/$AppPageView
备选方案:如果你直接调用
Sensorswave.init(sourceToken, config)(不走app.use()),没有app实例注册全局 mixin,需要在每个页面手动集成:
<script setup>(推荐):<script setup lang="uts"> import { useSensorswavePageLifecycle } from '@/uni_modules/sensorswave-uniappx/utssdk/index' useSensorswavePageLifecycle() </script>Options API:
import { SensorswavePageMixin } from '@/uni_modules/sensorswave-uniappx/utssdk/index' export default { mixins: [SensorswavePageMixin], }
4. 在组件中调用
插件安装后,SDK 实例会挂载到 Vue 全局属性 $sensorswave:
- Options API:可通过
this.$sensorswave访问。 <script setup>:没有this,直接import Sensorswave调用单例即可(推荐)。
无论哪种写法,拿到的是同一个 SDK 单例,调用方式完全一致。
import Sensorswave from '@/uni_modules/sensorswave-uniappx/utssdk/index'
// 自定义事件(推荐:使用 trackEvent)
Sensorswave.trackEvent('button_click', { button_name: 'submit', amount: 99 })
⚠️ 导入方式约定:统一使用深路径导入
import Sensorswave from '@/uni_modules/sensorswave-uniappx/utssdk/index',且同一应用内所有文件保持一致(混用不同导入路径会产生两份 SDK 单例,事件分裂)。⚠️
sourceToken和apiHost为必填项,缺失会导致数据无法上报(SDK 会在控制台输出告警)。
配置项
| 配置 | 类型 | 默认值 | 说明 |
|---|---|---|---|
sourceToken |
string |
'' |
必填。数据上报凭证,由服务端分配 |
apiHost |
string |
'' |
必填。数据上报 API 地址 |
debug |
boolean |
false |
是否开启调试模式,输出详细日志 |
autoCapture |
boolean |
true |
是否自动采集生命周期事件(启动、前后台、页面浏览等) |
batchSend |
boolean |
false |
是否启用批量发送(关闭则即时发送) |
maxBatchSize |
number |
10 |
批量发送时每批最大事件数 |
flushInterval |
number |
5000 |
批量发送轮询间隔(毫秒) |
enableClickTrack |
boolean |
false |
是否自动采集元素点击($WebClick),仅 H5 支持。小程序 / App 端点击采集为手动 API trackClick(event),不受本开关限制 |
enableShareTrack |
boolean |
true |
是否自动采集小程序分享(仅 MP) |
enableAB |
boolean |
false |
是否启用 A/B 测试功能 |
enableErrorTrack |
boolean |
false |
是否自动采集 error 级异常($Exception,$exception_level = error)。平台捕获面见异常采集 |
enableCrashTrack |
boolean |
false |
是否采集 fatal 级崩溃($Exception,$exception_level = fatal,仅 App)。iOS 端需自定义基座,见自定义基座与真机调试说明 |
abRefreshInterval |
number |
600000 |
A/B 测试缓存刷新间隔(毫秒,默认 10 分钟,最小 30 秒) |
optOutCapturing |
boolean |
false |
合规:初始化即禁用采集(不发、不读、不写任何埋点数据),满足 GDPR / 隐私法规的「默认不采集」诉求 |
persistOptOut |
boolean |
false |
合规:是否将 opt-out 状态持久化到本地存储,使其跨会话保留(进程重启 / destroy 后重新初始化仍恢复用户的授权决策) |
💡
optOutCapturing/persistOptOut的运行时行为见 合规(禁用采集) 小节。
API 方法
事件追踪
trackEvent(eventName, properties?)
手动上报一个自定义事件。时间戳默认取当前时刻。
eventName(string,必填):事件名称properties(object,可选):事件属性
Sensorswave.trackEvent('OrderSubmit', {
order_id: 'ORDER_001',
amount: 99.9,
currency: 'CNY',
})
track - 高级事件追踪
发送完整的事件对象,支持更精细的控制。此方法允许您手动指定所有事件字段。
参数:
event(必填):完整事件对象,包含以下字段:event(string,必填):事件名称properties(Record<string, any>,可选):事件属性time(number,可选):时间戳(毫秒),缺省时 SDK 取当前时刻anon_id(string,可选):匿名用户 ID,缺省时从 store 读取login_id(string,可选):登录用户 ID。login_id和anon_id至少传一个;都传时优先login_id;都缺省时从 store 兜底trace_id(string,可选):请求追踪 ID,缺省时 SDK 自动生成 UUIDuser_properties(Record<string, any>,可选):用户属性,透传
示例:
Sensorswave.track({
event: 'purchaseCompleted',
properties: {
product_id: '12345',
amount: 99.99,
currency: 'USD'
},
time: Date.now(),
trace_id: 'unique-trace-id-12345',
anon_id: 'anonymous-user-id',
login_id: 'user_12345',
user_properties: {
// $set: 代表插入或者更新一条用户属性信息
$set: {
plan: 'premium',
signup_date: '2024-01-01'
}
}
});
// 也可只传 event 名称,其余字段由 SDK 兜底
Sensorswave.track({ event: 'OrderPaid' });
⚠️ 历史回填不携带
$session_id:显式传入的time早于会话空闲窗口(30 分钟)时,该事件视为跨端补传 / 历史回填,SDK 不会为其注入当前$session_id(历史会话无法重建,宁缺毋错)。time缺省或在 30 分钟内的正常事件不受影响。
trackClick(event) - 手动点击采集(小程序 / App)
在页面点击事件处理器内显式调用并透传事件对象,SDK 从事件中提取元素属性后按平台映射上报:小程序 $MPClick、App(Android / iOS / 鸿蒙)$AppClick。H5 点击由 enableClickTrack 的自动采集通道($WebClick)覆盖,本接口在 H5 为 no-op。
📌 为何是手动 API:uni-app x 的编译模型下,页面点击处理器经 vue 运行时动态闭包分发(uvue 模板事件编译为运行时 invoker,小程序端页面经
Component()注册且业务处理器不落在任何静态可拦截层),不存在可用的全局点击拦截通道——这与原生小程序 SDK 通过代理Page()实现自动点击采集的机制不兼容。因此小程序与 App 端的点击采集为手动 API 形态,需业务在处理器内显式调用。
参数:
event(必填):页面点击事件对象,uvue 事件处理器入参原样透传(@tap="onTap"传入onTap(e)的e)
提取口径:
- 事件类型 ∈
{tap, longtap, longpress}才采集(其余类型静默忽略) - 元素标注遵循
data-sensors-*契约:data-sensors-ignore="true"(小程序端等价dataset.sensorsIgnore)跳过整条事件;data-sensors-name/data-sensors-type/data-sensors-content注入$element_name/$element_type/$element_content - 预置属性六个键恒存在:
$element_id$element_type$element_name$element_content$element_selector(#id.class)$element_path(tagName > .首类名降级语义);元素信息不可读时为空字符串(事件仍发送,页面上下文由预置属性$url_path兜底) - 小程序端从
event.currentTarget的id/class/dataset提取(data-sensors-xxx经 dataset 剑驼峰sensorsXxx读取,剥离前缀后注入$xxx自定义属性) - App 端从
event.currentTarget(UniElement)的getAttribute(...)读取;受 UniElement 无属性枚举 API 限制,自定义属性仅识别data-sensors-{name,type,content,ignore}固定候选集;原生事件实例上属性提取链路失败时自动降级为空元素属性集(待真机 API 面验证后按实测能力扩展)
示例:
// 页面模板:<view id="pay_btn" @tap="onPayTap">支付</view>
function onPayTap(e: any): void {
Sensorswave.trackClick(e)
// ...业务逻辑
}
💡 与
trackException同款语义:不受enableClickTrack开关限制(该开关仅管控 H5 自动采集通道),合规opt-out期间静默不发送,整体静默失败、绝不向业务处理器抛错。💡 普通业务事件请优先使用
trackEvent,仅在需要精确控制time/trace_id/user_properties等字段时使用track。
用户标识
identify(loginId)
设置登录 ID,并发送 $Identify 事件,将匿名行为与登录用户关联。
Sensorswave.identify('user_12345')
setLoginId(loginId)
设置登录 ID,不发送 $Identify 事件。仅需要标识用户、不需要追踪关联事件时使用。
Sensorswave.setLoginId('user_12345')
getLoginId()
获取当前登录用户 ID,未登录或未初始化时返回空字符串。返回 string。
const loginId = Sensorswave.getLoginId()
getAnonId()
获取当前匿名用户 ID,该 ID 在设备首次使用时自动生成并持久化。返回 string。
const anonId = Sensorswave.getAnonId()
getSessionId()
获取当前会话 ID($session_id,uuid v7 格式:时间戳前缀、小写),每个事件自动携带。返回 string。
会话在以下时机滚动新 ID(无需业务干预):
- 首次访问:本地无会话状态时生成
- 30 分钟无活动:超过 30 分钟没有任何事件发送
- 会话时长达到 12 小时:即便活动未中断也会强制滚动
- 调用
reset():登出时强制开启新会话
多个标签页/窗口共享同一会话(H5 经 cookie sw_session 共享,小程序/App 经本地存储共享)。
注意本方法为只读语义:调用本身不会为会话"续命"(活动仅指事件发送),但若会话已过期,
会先生成新会话再返回新 ID。未初始化、禁用采集或销毁后返回空字符串。
const sessionId = Sensorswave.getSessionId()
reset(resetAnonId?)
用户登出时调用,解除登录 ID 与设备的绑定。默认保留匿名 ID,登出后事件改以原匿名 ID 继续标识。
同时会失效 A/B 测试身份缓存,后续实验按新身份重新分组,并强制开启新会话(下一个事件携带新的 $session_id)。
不发送任何服务端事件。
resetAnonId(boolean,可选):是否同时重置匿名 ID,默认false
// 用户登出时
Sensorswave.reset() // 默认保留匿名 ID
// 如果需要同时重置匿名 ID(如公共设备场景)
Sensorswave.reset(true)
用户属性(Profile)
profileSet(properties)
设置用户属性,已存在的属性会被覆盖。
Sensorswave.profileSet({
name: 'alice',
age: 30,
plan: 'premium',
})
profileSetOnce(properties)
首次设置用户属性,已存在的属性不会被覆盖。常用于记录首次注册时间、首次来源等。
Sensorswave.profileSetOnce({
signup_date: '2026-01-15',
initial_referrer: 'google',
})
profileIncrement(properties)
对数值型用户属性进行递增操作,仅支持数值类型,支持正数和负数。
// 递增单个属性
Sensorswave.profileIncrement({ login_count: 1 })
// 递增多个属性
Sensorswave.profileIncrement({
login_count: 1,
points_earned: 100,
})
profileAppend(properties)
向数组类型的用户属性追加元素,不去重。
Sensorswave.profileAppend({
categories_viewed: ['electronics', 'mobile_phones'],
})
profileUnion(properties)
向数组类型的用户属性追加元素,自动去重。
Sensorswave.profileUnion({
interests: ['technology', 'gaming'],
})
profileUnset(keys)
删除指定的用户属性。
keys(string[],必填):要删除的属性名数组
// 删除单个属性
Sensorswave.profileUnset(['temporary_campaign'])
// 删除多个属性
Sensorswave.profileUnset(['old_plan', 'expired_flag'])
profileDelete()
删除当前用户的全部用户属性数据,操作不可恢复。仅对已登录用户有效。
Sensorswave.profileDelete()
公共属性
公共属性会自动附加到后续上报的所有事件上,适合注入全局上下文(如应用版本、环境等)。
值支持静态值(字符串 / 数值 / 布尔等),也支持动态函数——函数会在每次事件构建时调用取最新值,
例如 now: () => Date.now()、$screen: () => getCurrentPage().route 等场景都能正确取到当前时刻 / 当前页。
registerCommonProperties(properties)
注册公共属性,已存在的同名属性会被覆盖。
// 静态公共属性
Sensorswave.registerCommonProperties({
app_version: '1.0.0',
environment: 'production',
app_channel: 'wechat',
})
// 动态公共属性:每次事件上报时实时求值
Sensorswave.registerCommonProperties({
$current_time: () => Date.now(),
$active_page: () => getCurrentPages().pop()?.route ?? '',
})
clearCommonProperties(keys?)
清除已注册的公共属性。不传 keys 时清除全部。
// 清除指定公共属性
Sensorswave.clearCommonProperties(['app_version', 'app_channel'])
// 清除全部公共属性
Sensorswave.clearCommonProperties()
A/B 测试
需在初始化时设置
enableAB: true,否则以下方法将直接返回默认值。
checkFeatureGate(key)
检查功能开关(Feature Gate)是否对当前用户开启。返回 Promise<boolean>。
const enabled = await Sensorswave.checkFeatureGate('new_checkout_flow')
if (enabled) {
showNewCheckout()
}
getFeatureConfig(key)
获取远程配置(Feature Config)。服务端返回的 JSON 字符串会被自动解析。返回 Promise<Record<string, any>>,未启用 A/B 测试时返回空对象 {}。
const config = await Sensorswave.getFeatureConfig('app_settings')
const { theme, layout } = config
getExperiment(key)
获取实验分组(Experiment)。返回 Promise<Record<string, any>>,未命中实验或未启用 A/B 测试时返回空对象。
const exp = await Sensorswave.getExperiment('homepage_layout')
const { layout_type } = exp
异常采集($Exception)
需在初始化时设置
enableErrorTrack: true(error 级)和 / 或enableCrashTrack: true(fatal 级),两者均默认关闭、互不依赖。
error 级自动捕获(enableErrorTrack)
自动采集未捕获的 JS 异常与 Promise 拒绝,上报为 $Exception($exception_level = error)。各平台捕获面:
| 平台 | 捕获机制 |
|---|---|
| 小程序 | uni.onError + uni.onUnhandledRejection(个别平台缺失时静默降级,如支付宝无 onError) |
| H5 | uni.onError(Vue 捕获面)+ window.error / unhandledrejection(逃逸 Vue 的异步错误) |
| App 鸿蒙 | 应用级 onError 钩子(鸿蒙运行时恒装 Vue errorHandler,组件回调内的同步 throw 进程不崩溃) |
| App Android / iOS | 无 JS 级错误钩子(uni-app x 运行时会 catch 住组件回调里的异常仅打日志)——未捕获异常即进程崩溃,走下方 fatal 通道;已捕获的异常(业务 try-catch 拿到的)用 trackException 手动上报 |
fatal 级崩溃采集(enableCrashTrack,仅 App)
通过各平台原生机制捕获「未捕获异常导致进程终止」级崩溃:崩溃瞬间把最小 payload(类型 / message / 堆栈 / 结构化帧)同步落盘,进程死亡;下次启动 SDK 自动补发为 $Exception($exception_level = fatal,事件时间为崩溃时刻而非补发时刻)。
| 平台 | 崩溃捕获机制 | 覆盖范围 |
|---|---|---|
| Android | Thread.setDefaultUncaughtExceptionHandler |
JVM 任意线程未捕获异常 |
| iOS | NSSetUncaughtExceptionHandler(经配套原生插件,见自定义基座与真机调试说明) |
NSException 级未捕获异常;SIGSEGV 等信号级崩溃不覆盖 |
| 鸿蒙 | 双通道:errorManager(未捕获 JS 异常,进程不退出)+ hiAppEvent watcher(系统 faultlog,下次启动回放 C++ crash / 卡死等真崩溃) |
两通道以 ±5s 崩溃时刻窗口判重,防同一崩溃双计 |
约束:待补发记录上限 10 条(超出淘汰最旧)、有效期 7 天;落盘前检查 opt-out 状态(见合规)——Android / 鸿蒙落盘前读持久化 opt-out 标志,iOS 配套原生插件经原生通道同步同一门禁(崩溃早于 init 的窗口内按「未禁用」捕获,补发侧合规门禁兜底不发送)。iOS 崩溃记录同时携带主二进制 debug_id(LC_UUID,dSYM 符号化匹配键)。
trackException(throwable, properties?)
手动上报一条 $Exception($exception_level = error),不受任何开关限制。适合业务 try-catch 拿到异常后主动上报——也是 Android / iOS 端 error 级采集的唯一通道。
try {
riskyBusiness()
} catch (e) {
Sensorswave.trackException(e, { source: 'manual_catch', page: 'OrderPage' })
}
$Exception 事件属性
| 属性 | 说明 |
|---|---|
$exception_level |
error(自动捕获 / 手动上报)或 fatal(崩溃补发) |
$exception_type |
异常类型名(如 TypeError / NSInvalidArgumentException / JVM 全类名) |
$exception_message |
异常 message |
$exception_frames |
结构化堆栈帧(平台家族路由符号化;仅解析出帧时上报,无空数组占位) |
💡 iOS 崩溃(fatal)记录以
callStackSymbols文本栈落盘,补发时解析为结构化帧;主镜像帧回填debug_id(崩溃时刻读主二进制 LC_UUID 随记录落盘,服务端据此匹配已上传 dSYM 完成帧级符号化),系统镜像帧不带debug_id(其符号已可读,无再符号化需求)。
合规(禁用采集)
为满足 GDPR 等隐私法规要求,SDK 提供 opt-out(禁用采集)能力。禁用期间,SDK 不发、不读、不写 任何埋点数据——所有事件上报、用户标识读写、公共属性写入、A/B 查询等对外 API 均为 no-op 且不抛错;唯一例外是 UTM 启动参数仍会静默捕获到内存,以便用户重新授权后补发首触归因。
以下三个方法均可在 init() / app.use() 之前调用(init 时会按优先级合并):
optOutCapturing()
立即禁用所有采集与上报:置内存标记并暂停发送器;若开启 persistOptOut: true,状态会同步写入本地存储(跨会话保留)。可在 init 前调用。
// 例:用户在隐私弹窗中拒绝授权
Sensorswave.optOutCapturing()
optInCapturing()
解除禁用状态,恢复正常的采集与上报流程。若禁用期间首触归因事件($UserSet)从未发送过,则使用禁用期间静默捕获的 UTM 的原始时间补发一次;禁用期间发生的其他事件一律不补发。可在 init 前调用。
// 例:用户在隐私弹窗中同意授权
Sensorswave.optInCapturing()
hasOptedOutCapturing()
查询当前是否处于禁用采集状态。返回 boolean(true = 已禁用,不发不读不写)。
if (Sensorswave.hasOptedOutCapturing()) {
// 当前已禁用采集
}
初始化时的状态合并优先级
init() 阶段会按以下优先级确定最终的 opt-out 状态(高优先级覆盖低优先级):
- init 前 API 已 opt-out(调用过
optOutCapturing())→ 保留禁用状态 - config 显式
optOutCapturing: true→ 强制禁用 persistOptOut: true且本地有持久化值(如destroy后重新初始化)→ 从本地存储恢复用户的授权决策
// 典型用法:默认禁用采集,由用户授权后再开启,且授权决策跨会话保留
app.use(Sensorswave.plugin, {
sourceToken: 'your_source_token',
apiHost: 'https://example.com',
optOutCapturing: true, // 默认禁用,等用户授权
persistOptOut: true, // 授权决策持久化,重启后仍生效
})
// 用户同意授权后开启
Sensorswave.optInCapturing()
⚠️ 授权决策属于合规语义,
destroy()不会 清除本地持久化的 opt-out 状态;重新初始化时若persistOptOut: true,仍会恢复用户上一次的授权选择。iOS 专属:opt-out 状态会经原生通道同步到崩溃捕获配套插件(
init收敛后、optOutCapturing()/optInCapturing()三处状态决议点),禁用期间的 fatal 崩溃不再落盘。时序边界——崩溃早于init的窗口内标志尚未同步,按「未禁用」捕获(宁多捕获不误丢);此类记录由补发侧合规门禁兜底(禁用状态下不发送)。
其他
isInitialized()
查询 SDK 是否已完成初始化。返回 boolean。与只读属性 isInited 等价。
if (Sensorswave.isInitialized()) {
Sensorswave.trackEvent('Ready')
}
isInited
只读属性,判断 SDK 是否已完成初始化。未初始化时为 false。
if (Sensorswave.isInited) {
Sensorswave.trackEvent('Ready')
}
init(sourceToken, config?)
手动初始化 SDK(不使用 Vue 插件)。sourceToken 作为独立参数传入。
⚠️ 直接调用
init()不会注入页面生命周期 mixin,因此页面浏览 / 离开的自动采集将失效。 仅在你不需要自动页面采集、或希望完全控制初始化时机时使用。
Sensorswave.init('your_source_token', {
apiHost: 'https://example.com',
autoCapture: true,
})
destroy()
销毁 SDK 实例:停止批量发送器、销毁所有插件、移除全部事件监听器并重置为未初始化状态。销毁后可重新 init() 或再次 app.use() 安装。
Sensorswave.destroy()
自动采集事件
开启 autoCapture(默认开启)后,SDK 会根据运行平台自动注册对应采集器:
- 小程序:启动、显示 / 隐藏、页面浏览 / 离开(由全局 mixin 驱动)、(默认)分享
- App:启动 / 退出(后台满 30s 才触发
$AppEnd,30s 内回前台视为同会话)、首次安装、UTM 首值归因($UserSet)、页面浏览 / 离开(由全局 mixin 驱动) - H5:页面浏览、页面加载性能、页面离开、(可选)点击
页面浏览 / 离开采集通过 install() 注入的全局 mixin 统一驱动(onLoad / onShow / onHide / onUnload),业务页面零侵入——这是 Vue 插件的标准用法。直接调 init()(不走插件)时无 app 实例,需要改用手动集成,见上方「页面级事件接入」小节。
预置事件一览
| 事件 | 平台 | 触发时机 |
|---|---|---|
$MPLaunch |
小程序 | 启动(自动) |
$AppStart |
App | 启动 / 从后台回前台(自动;30s 内回前台不发) |
$AppInstall |
App | 首次启动(自动) |
$MPShow |
小程序 | 进入前台(自动) |
$MPHide |
小程序 | 进入后台(自动,即时上报) |
$AppEnd |
App | 进入后台满 30s(自动) |
$MPPageView |
小程序 | 页面显示(全局 mixin 自动) |
$AppPageView |
App | 页面显示(全局 mixin 自动) |
$PageView |
H5 | 页面显示(全局 mixin + vue-router 自动) |
$MPPageLeave |
小程序 | 页面离开 / 卸载(全局 mixin 自动,含 $event_duration) |
$AppPageLeave |
App | 页面离开 / 卸载(全局 mixin 自动,含 $event_duration) |
$PageLeave |
H5 | 页面离开 / 卸载(自动,含 $event_duration) |
$PageLoad |
H5 | 页面加载性能(自动) |
$WebClick |
H5 | 元素点击(需 enableClickTrack: true) |
$MPClick |
小程序 | 元素点击(手动 API trackClick(event),uni-app x 编译模型无自动拦截通道) |
$AppClick |
App | 元素点击(手动 API trackClick(event),同上) |
$MPShare |
小程序 | 用户分享(自动包裹 onShareAppMessage) |
$Identify |
全部 | identify() |
$UserSet |
全部 | UTM 首值归因(每次启动 + 首次拿到非空 UTM 时自动发,含 5 个 UTM 键) |
$FeatureImpress / $ExpImpress |
全部 | A/B 曝光(自动,含 user_properties: $feature_/ $exp_ 命中赋值或未命中清空) |
预置属性
SDK 会自动采集一系列以 $ 开头的预置属性并附加到每个事件,包括:
- 设备 / 系统:
$lib(固定uniappx)、$lib_version、$model、$os、$os_version、$screen_width、$screen_height、$timezone_offset、$language(BCP 47 格式,如zh-CN,可能含 Script 段如zh-Hans-CN;兼容各端原始格式统一规范化) - 小程序特有:
$brand、$manufacturer、$network_type(全小写枚举wifi/2g/3g/4g/5g/cellular/ethernet;取不到时为空串)、$scene - App 特有:
$brand、$manufacturer、$device_id(统一小写)、$wifi、$app_version、$app_id、$app_name、$region(ISO 3166-1 alpha-2 大写,如CN;从语言标签显式地区段提取,缺失时按语言推断兜底,未知语言不下发)、$network_type(枚举同小程序) - H5 特有:
$browser、$browser_version、$viewport_width、$viewport_height - 页面信息:
$url、$url_path、$url_query、$title、$referrer(H5 另有$host、$pathname、$referrer_host、$search_engine) - UTM 渠道:
utm_source、utm_medium、utm_campaign、utm_content、utm_term - 会话:
$session_id(uuid v7 格式会话 ID,时间戳前缀、小写;首次访问 / 30 分钟无事件发送 / 持续时长达到 12 小时 / 调用reset()时滚动新会话;H5 多标签页经 cookiesw_session共享同一会话,小程序/App 经本地存储共享,可通过getSessionId()读取;显式time早于 30 分钟空闲窗口的历史回填事件不注入,详见track)
⚠️
$前缀为系统保留,自定义事件属性请勿使用$前缀,以免与预置属性冲突。
数据安全
- 自定义事件属性脱敏:
token、password、secret、cookie、session_id、api_key等 17 类敏感关键词命中的字段,其值在发送前自动掩码为***(保留键名,仅丢弃值)。 - URL 查询参数脱敏:
$url_query中的敏感参数会被整体剔除。 $session_id为 SDK 注入:该预置属性由 SDK 在事件属性脱敏与合并之后写入,业务方在事件属性中传入session类同名键不影响它(同名键仍按敏感词规则掩码)。
鸿蒙适配
App 鸿蒙端需要声明网络与网络信息相关权限,否则事件数据无法上报、$network_type 等属性无法正常采集:
// entry/src/main/module.json5
{
"module": {
"requestPermissions": [
{ "name": "ohos.permission.INTERNET" },
{ "name": "ohos.permission.GET_NETWORK_INFO" }
]
}
}
⚠️ 关键说明:必须配置
ohos.permission.GET_NETWORK_INFO权限才能正确获取网络信息鸿蒙平台上,SDK 通过
uni.getNetworkType()获取当前网络类型以采集$network_type预置属性。若未声明ohos.permission.GET_NETWORK_INFO权限,uni.getNetworkType()将调用失败,导致$network_type始终为空。这是鸿蒙端正确获取网络信息的前提,请务必在module.json5中声明该权限。各权限作用:
ohos.permission.INTERNET:保证事件数据能正常上报ohos.permission.GET_NETWORK_INFO:保证$network_type能正确获取
自定义基座与真机调试说明
uni-app x 的 iOS 端业务层(uvue / uts)始终运行在 JS 引擎上,uts 插件的原生实现只有打进自定义基座(或正式包)才会被编译生效。这决定了各功能在不同运行环境下的可用性:
| 功能 | iOS 标准基座(开发运行) | iOS 自定义基座·模拟器 | iOS 自定义基座·真机 / 正式包 | Android / 鸿蒙(任意运行) |
|---|---|---|---|---|
基础埋点(预置事件 / trackEvent / 用户体系 / A/B / UTM / 公共属性) |
✅ | ✅ | ✅ | ✅ |
trackException 手动上报 |
✅ | ✅ | ✅ | ✅ |
| error 级异常自动采集 | ❌(iOS 无 JS 级捕获面) | ❌ | ❌ | ✅(仅鸿蒙有捕获面) |
| fatal 级崩溃采集(iOS) | ❌ 静默降级 | ⚠️ 仅「模拟派发」链路 | ✅ 完整链路 | —— |
| fatal 级崩溃采集(Android / 鸿蒙) | —— | —— | —— | ✅ 开发运行即可用 |
结论:只有 iOS 的 fatal 崩溃采集链路依赖自定义基座;其中「真实 NSException 派发」的验证还必须真机(模拟器可用模拟派发验证全链,见下)。 Android(Thread.setDefaultUncaughtExceptionHandler)与鸿蒙(errorManager + hiAppEvent)的崩溃采集走 JS 侧可直接编译的通道,开发运行即可验证;鸿蒙的 error 级 / fatal 级双通道同理。
iOS fatal 崩溃采集的接入步骤
iOS 端崩溃捕获需要原生钩子(NSSetUncaughtExceptionHandler),而主插件必须保留 JS 实现(标准基座可用性前提),其原生实现无法进基座——因此 iOS 崩溃捕获链承载在配套原生插件 sw-ios-crash-trigger 中(app-ios-only,无 JS 实现),由它负责崩溃钩子安装、崩溃线程落盘与记录读取;主 SDK 启动时经原生代理拉取记录并补发,业务侧零额外代码。
- 将配套插件
sw-ios-crash-trigger导入工程uni_modules/(与主 SDK 一同分发) - 初始化时开启
enableCrashTrack: true - 打自定义基座(会自动包含该插件的原生实现)
- 真机验证:触发崩溃 → 进程终止 → 重新打开应用 → 启动时补发
$Exception($exception_level = fatal)
⚠️ 未集成配套插件(或标准基座运行)时,iOS fatal 链路静默降级:SDK 其余功能完全不受影响,仅崩溃不落盘、无补发。
许可
Apache-2.0

收藏人数:
下载插件并导入HBuilder
赞赏(0)
下载 5
赞赏 0
下载 12715712
赞赏 1958
赞赏
京公网安备:11010802035340号