Title: iOS SDK Locale: zh URL: https://sensorswave.com/docs/data-integration/client-sdks/ios/ Description: iOS SDK 集成指南和 API 参考 Sensors Wave iOS SDK 是专为 iOS 应用设计的客户端数据采集和 A/B 实验工具。 ## 核心功能 iOS SDK 提供以下核心能力: - **事件追踪**:手动追踪自定义事件和用户行为 - **自动埋点**:自动采集应用启动、页面浏览、点击等事件 - **用户识别**:支持匿名用户和登录用户身份关联 - **用户属性管理**:完整的用户属性操作(设置、追加、增量更新等) - **A/B 测试集成**:支持功能开关(Feature Gate)和实验变量获取 - **批量发送**:优化网络请求性能,批量发送事件数据 - **公共属性**:支持静态公共属性,自动附加到所有事件 - **线程安全**:所有操作均保证线程安全 ## 安装 ### CocoaPods 集成(推荐) 在您的 `Podfile` 中添加: ```ruby pod 'SensorswaveSDK' ``` 然后在终端运行: ```bash pod install ``` ### 手动集成 1. 从 [GitHub](https://github.com/sensorswave/ios-sdk) 获取 SDK 的二进制包 将 SensorswaveSDK > xcframework 目录下的 SensorswaveSDK.xcframework 包拖到 Xcode 项目,并选中 Copy items if needed 2. 在项目设置中添加以下框架: - `Foundation.framework` - `UIKit.framework` - `CoreTelephony.framework` ## 快速开始 ### 基础初始化 在 `AppDelegate.swift` 中的 `application(_:didFinishLaunchingWithOptions:)` 方法中初始化 SDK: ```swift @main class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // 创建配置 let config = SensorswaveConfig() config.debug = false config.apiHost = "https://your-api-host.com" config.autoCapture = true // 初始化 SDK Sensorswave.getInstance().setup( sourceToken: "your-source-token", config: config ) return true } } ``` ### 发送第一个事件 初始化完成后,您可以立即开始追踪事件: ```swift // 追踪用户点击按钮 Sensorswave.getInstance().trackEvent(eventName: "ButtonClick", properties: [ "button_name": "submit", "page": "home" ]) ``` ## 配置选项 `SensorswaveConfig` 支持以下配置选项: | 配置项 | 类型 | 默认值 | 说明 | |--------|------|--------|------| | `debug` | `Bool` | `false` | 是否开启调试模式,开启后在控制台输出详细日志 | | `apiHost` | `String` | `''` | **必填**,数据上报的 API 地址 | | `autoCapture` | `Bool` | `true` | 是否开启自动埋点,自动采集应用启动、页面浏览等事件 | | `enableClickTrack` | `Bool` | `false` | 是否开启点击自动追踪 | | `batchSend` | `Bool` | `false` | 是否使用批量发送,收集 20 条事件或 5 秒后批量发送 | | `enableAB` | `Bool` | `false` | 是否开启 A/B 测试功能 | | `abRefreshInterval` | `TimeInterval` | `600000` | A/B 测试配置刷新间隔(毫秒),默认 10 分钟,最小 30 秒 | ### 完整配置示例 ```swift let config = SensorswaveConfig() config.debug = true // 开发环境开启调试 config.apiHost = "https://your-api-host.com" config.autoCapture = true // 开启自动埋点 config.enableClickTrack = true // 开启点击追踪 config.batchSend = true // 批量发送优化性能 config.enableAB = true // 开启 A/B 测试 config.abRefreshInterval = 10 * 60 * 1000 // A/B 测试数据每 10 分钟刷新 Sensorswave.getInstance().setup( sourceToken: "your-source-token", config: config ) ``` > **提示**:在生产环境中建议关闭 `debug` 模式,以避免在控制台输出过多日志。 ## API 方法 ### 事件追踪 #### trackEvent - 追踪自定义事件 手动追踪自定义事件及其属性。 **参数**: - `eventName` (String,必填):事件名称 - `properties` (Dictionary,可选):事件属性,键值对形式 **示例**: ```swift // 追踪按钮点击 Sensorswave.getInstance().trackEvent(eventName: "ButtonClick", properties: [ "button_name": "submit", "page": "home" ]) ``` **实际场景示例**: ```swift // 电商场景:用户浏览商品 Sensorswave.getInstance().trackEvent(eventName: "ProductView", properties: [ "product_id": "12345", "product_name": "无线蓝牙耳机", "category": "电子产品", "price": 299.00, "currency": "CNY" ]) // 电商场景:用户加入购物车 Sensorswave.getInstance().trackEvent(eventName: "AddToCart", properties: [ "product_id": "12345", "quantity": 1, "price": 299.00 ]) // 内容场景:文章阅读 Sensorswave.getInstance().trackEvent(eventName: "article_read", properties: [ "article_id": "article_001", "title": "Swift 性能优化技巧", "category": "技术博客", "read_duration": 120 // 阅读时长(秒) ]) ``` #### track - 高级事件追踪 发送完整的事件对象,支持更精细的控制。此方法允许您手动指定所有事件字段。 **参数**: - `event` (AdvanceEvent,必填):完整事件对象,包含以下字段: - `event` (String,必填):事件名称 - `properties` (Dictionary,可选):事件属性 - `time` (Int64,必填):时间戳(毫秒) - `anon_id` (String,可选):匿名用户 ID - `login_id` (String,可选):登录用户 ID。login_id 和 anon_id 必须传一个,同时传递时,优先使用 login_id - `trace_id` (String,必填):请求追踪 ID - `user_properties` (Dictionary,可选):用户属性 **示例**: ```swift Sensorswave.getInstance().track(event: [ "event": "purchase_completed", "properties": [ "product_id": "12345", "amount": 99.99, "currency": "USD" ], "time": Int64(Date().timeIntervalSince1970 * 1000), "trace_id": UUID().uuidString, "login_id": "user_12345", "user_properties": [ "plan": "premium", "signup_date": "2024-01-01" ] ]) ``` > **注意**:`track` 方法是高级功能,大多数场景下使用 `trackEvent` 即可满足需求。 ### 用户识别 #### identify - 设置登录用户 ID 设置登录用户 ID 并发送绑定事件,将匿名行为与已识别用户关联。 **参数**: - `loginId` (String,必填):用户的唯一标识符(如邮箱、用户 ID、用户名) **示例**: ```swift // 用户登录后设置用户 ID Sensorswave.getInstance().identify(loginId: "user_12345") ``` **完整登录流程示例**: ```swift // 用户登录流程 func handleUserLogin(email: String, password: String) { // 调用登录 API loginUser(email: email, password: password) { result in switch result { case .success(let userId): // 设置用户 ID 并关联匿名行为 Sensorswave.getInstance().identify(loginId: userId) // 追踪登录事件 Sensorswave.getInstance().trackEvent(eventName: "user_login", properties: [ "login_method": "email" ]) case .failure(let error): print("登录失败: \(error)") } } } ``` > **重要提醒**:如果 `loginId` 包含隐私信息(如手机号、邮箱、身份证号等),请务必在加密后再进行传输,避免敏感信息明文上报。 #### setLoginId - 仅设置登录 ID 设置登录用户 ID,但不发送绑定事件。如果您只想识别用户但不需要关联用户,可以使用此方法。 **参数**: - `loginId` (String,必填):用户的唯一标识符 **示例**: ```swift Sensorswave.getInstance().setLoginId(loginId: "user_12345") ``` > **重要提醒**:如果 `loginId` 包含隐私信息(如手机号、邮箱、身份证号等),请务必在加密后再进行传输,避免敏感信息明文上报。 > **使用建议**:通常情况下推荐使用 `identify` 方法,因为它会记录用户身份关联事件,有助于后续分析。 ### 用户属性 用户属性用于描述用户的特征,如会员等级、注册时间、偏好设置等。与事件属性不同,用户属性会持久化保存并与用户关联。 #### setProfile - 设置用户属性 设置用户属性,如果属性已存在则覆盖。 **参数**: - `properties` (Dictionary,必填):要设置的用户属性 **示例**: ```swift // 用户完成注册后,设置用户属性 Sensorswave.getInstance().setProfile(properties: [ "name": "张三", "age": 30, "plan": "premium" ]) ``` #### setOnceProfile - 仅首次设置 设置用户属性,仅在属性不存在时设置,已存在的属性不会被覆盖。 **参数**: - `properties` (Dictionary,必填):要设置的用户属性 **示例**: ```swift // 记录用户首次访问信息(仅记录一次,后续不会覆盖) Sensorswave.getInstance().setOnceProfile(properties: [ "signup_date": "2024-01-15", "initial_referrer": "google", "initial_campaign": "spring_sale" ]) ``` #### profileIncrement - 增量更新数值属性 对数值类型的用户属性进行增减操作。仅支持数值属性。 **参数**: - `properties` (Dictionary,必填):要增减的属性及其数值 **示例**: ```swift // 增加单个属性 Sensorswave.getInstance().profileIncrement(properties: [ "login_count": 1 ]) // 增加多个属性 Sensorswave.getInstance().profileIncrement(properties: [ "login_count": 1, "points_earned": 100, "purchases_count": 1 ]) ``` #### profileAppend - 追加到数组属性 向数组类型的用户属性追加新值,不进行去重。 **参数**: - `properties` (Dictionary,必填):要追加的属性及其数组值 **示例**: ```swift Sensorswave.getInstance().profileAppend(properties: [ "categories_viewed": ["electronics", "mobile_phones"], "tags": ["new_customer", "q1_2024"] ]) ``` #### profileUnion - 追加到集合属性(去重) 向数组类型的用户属性追加新值,自动去重。 **参数**: - `properties` (Dictionary,必填):要追加的属性及其数组值 **示例**: ```swift // 第一次调用 Sensorswave.getInstance().profileUnion(properties: [ "interests": ["technology", "gaming"] ]) // 第二次调用,'technology' 不会重复添加 Sensorswave.getInstance().profileUnion(properties: [ "interests": ["technology", "music"] // 只会增加 'music' ]) ``` #### profileUnset - 删除指定属性 将指定的用户属性设置为 null。 **参数**: - `key` (String,可选):要置为 null 的单个属性名 - `keys` ([String],可选):要置为 null 的多个属性名数组 **示例**: ```swift // 处理单个属性 Sensorswave.getInstance().profileUnset(key: "temporary_campaign") // 处理多个属性 Sensorswave.getInstance().profileUnset(keys: ["old_plan", "expired_flag", "temp_id"]) ``` #### profileDelete - 删除所有用户属性 删除当前用户的所有用户属性数据。此操作不可撤销。 **示例**: ```swift // 用户注销账号时,删除所有用户属性 Sensorswave.getInstance().profileDelete() ``` > **警告**:`profileDelete` 会删除所有用户属性,请谨慎使用。 #### 用户属性使用示例 **会员升级场景**: ```swift func handleMembershipUpgrade(newPlan: String) { // 更新会员等级和升级时间 Sensorswave.getInstance().setProfile(properties: [ "plan": newPlan, "upgrade_time": ISO8601DateFormatter().string(from: Date()) ]) // 增加升级次数 Sensorswave.getInstance().profileIncrement(properties: [ "upgrade_count": 1 ]) // 追踪升级事件 Sensorswave.getInstance().trackEvent(eventName: "membership_upgrade", properties: [ "from_plan": "basic", "to_plan": newPlan ]) } ``` ### 公共属性 公共属性会自动添加到所有事件中,适用于需要在每个事件中都包含的通用信息。iOS SDK 目前支持静态公共属性。 #### registerCommonProperties - 注册公共属性 注册静态公共属性,这些属性将自动包含在所有事件中。 **参数**: - `properties` (Dictionary,必填):要注册的属性 **示例**: ```swift Sensorswave.getInstance().registerCommonProperties(properties: [ // 静态属性 "app_version": "1.0.0", "environment": "production", "user_role": "guest" ]) ``` #### clearCommonProperties - 清除公共属性 移除指定的已注册公共属性。 **参数**: - `keys` ([String],必填):要移除的属性名数组 **示例**: ```swift Sensorswave.getInstance().clearCommonProperties(keys: ["app_version", "user_role"]) ``` > **注意**:iOS SDK 目前只支持静态属性。公共属性会增加每个事件的数据量,建议仅添加确实需要的通用属性。 ### A/B 测试 iOS SDK 内置了 A/B 测试支持,可以获取功能开关状态和实验变量。 #### 开启 A/B 测试功能 ```swift config.enableAB = true config.abRefreshInterval = 10 * 60 * 1000 // 配置刷新间隔(10 分钟) ``` #### checkFeatureGate - 检查功能开关 检查功能开关(Feature Flag)是否为当前用户启用。通过回调函数返回结果。 **参数**: - `key` (String,必填):功能开关的 Key - `callback` (Bool -> Void,必填):回调函数,返回功能开关状态 **示例**: ```swift // 检查功能是否启用 Sensorswave.getInstance().checkFeatureGate(key: "new_checkout_flow") { isEnabled in DispatchQueue.main.async { if isEnabled { // 显示新功能 self.showNewCheckout() } else { // 显示旧功能 self.showOldCheckout() } } } ``` #### getExperiment - 获取实验变量 获取当前用户的实验变量数据。通过回调函数返回实验配置对象。 **参数**: - `key` (String,必填):实验的 Key - `callback` ([String: Any]? -> Void,必填):回调函数,返回实验配置 **示例**: ```swift // 获取实验配置 Sensorswave.getInstance().getExperiment(key: "pricing_display") { config in DispatchQueue.main.async { guard let config = config else { // 使用默认配置 self.applyDefaultPricing() return } // 应用实验配置 if let priceFormat = config["price_format"] as? String, let discountType = config["discount_type"] as? String { self.updatePricingDisplay(format: priceFormat, discount: discountType) } } } ``` **完整 A/B 测试示例**: ```swift // 电商首页 CTA 按钮 A/B 测试 func initHomepageCTA() { Sensorswave.getInstance().getExperiment(key: "homepage_cta_test") { config in DispatchQueue.main.async { guard let config = config else { // 使用默认配置 self.applyDefaultCTA() return } // 应用实验配置 let buttonText = (config["button_text"] as? String) ?? "立即购买" let buttonColor = (config["button_color"] as? String) ?? "#ff6600" let buttonSize = (config["button_size"] as? String) ?? "16" self.updateCTAButton( text: buttonText, color: UIColor(hex: buttonColor), fontSize: CGFloat(Float(buttonSize) ?? 16) ) } } } // 页面加载时初始化 override func viewDidLoad() { super.viewDidLoad() initHomepageCTA() } ``` > **提示**:A/B 测试功能需要在 SensorsWave 后台配置实验和功能开关后才能使用。 ## 自动埋点 开启自动埋点后,SDK 会自动采集以下事件类型: | 事件名称 | 说明 | 触发时机 | |---------|------|---------| | `$AppStart` | 应用启动 | 应用启动时 | | `$AppEnd` | 应用结束 | 应用结束时 | | `$AppInstall` | 应用首次安装 | 应用首次安装时(仅一次) | | `$AppPageView` | 页面浏览 | 用户访问页面时 | | `$AppPageLeave` | 页面离开 | 用户离开页面时 | | `$AppClick` | 元素点击 | 用户点击元素时(需开启 `enableClickTrack`) | ### 开启自动埋点 ```swift let config = SensorswaveConfig() config.autoCapture = true // 开启自动埋点 config.enableClickTrack = true // 开启点击自动追踪 Sensorswave.getInstance().setup( sourceToken: "your-source-token", config: config ) ``` ### 追踪页面浏览 SDK 会自动追踪页面浏览(`autoCapture = true` 时),SDK 会自动发送 $AppPageView 事件 > **提示**:自动埋点功能可以大幅减少手动编码工作量,但会增加一定的数据量。建议根据实际需求选择性开启。 ## 批量发送 启用批量发送可以减少网络请求次数,提高性能: ```swift config.batchSend = true ``` **批量发送行为**: - 收集 10 条事件后立即发送 - 或 5 秒定时发送 - 使用线程安全的队列管理 **优势**: - 减少网络请求次数 - 节省电池消耗 - 提高发送效率 ## 注意事项 ### 性能优化 - 批量发送功能默认未开启,建议在生产环境中开启以优化性能 - 自动埋点会增加一定性能开销,仅在需要时开启 - 关闭调试模式以减少日志输出 ### 数据安全 - 不要在事件属性中传递敏感信息(如密码、信用卡号、身份证号) - Source Token 应妥善保管,避免在公开代码仓库中暴露 - 所有数据通过 HTTPS 加密传输 ### 线程安全 SDK 中的所有操作都是线程安全的: - **PersistentQueue** - 使用 `NSLock` 保护所有队列操作 - **网络请求** - 支持多线程并发 - **用户属性** - 使用同步机制保证数据一致性 ### 错误处理和重试 SDK 内置了智能的错误处理和重试机制: 1. **持久化队列** - 失败的请求会保存到本地 2. **指数退避重试** - 使用指数退避算法 3. **应用重启恢复** - 应用重启后会自动发送之前失败的请求 ## 常见问题 ### 为什么我的数据没有上报成功? 检查以下几点: 1. **Source Token 是否正确**:确认 `sourceToken` 参数是否正确 2. **数据上报地址是否正确**:确认 `apiHost` 配置是否正确 3. **网络连接**:确认设备网络连接正常 4. **调试模式**:开启 `debug = true` 查看控制台日志 ### 如何启用调试模式? ```swift let config = SensorswaveConfig() config.debug = true ``` 启用后会在控制台输出详细的日志信息,方便调试。 ### 如何追踪用户行为? ```swift // 用户登录 Sensorswave.getInstance().identify(loginId: "user123") // 追踪购买行为 Sensorswave.getInstance().trackEvent(eventName: "Purchase", properties: [ "product_id": "12345", "amount": 99.99 ]) // 设置用户属性 Sensorswave.getInstance().setProfile(properties: [ "total_spent": 999.99, "purchase_count": 15 ]) ``` ### 如何处理网络失败? SDK 会自动处理网络失败: - 失败的请求会保存到本地队列 - 应用重启后会自动重试 - 使用指数退避策略避免服务器压力 ### 如何使用 A/B 测试? ```swift // 1. 启用 A/B 测试 config.enableAB = true // 2. 检查功能开关 Sensorswave.getInstance().checkFeatureGate(key: "new_feature") { isEnabled in DispatchQueue.main.async { if isEnabled { self.enableNewFeature() } } } // 3. 获取实验配置 Sensorswave.getInstance().getExperiment(key: "pricing_display") { config in DispatchQueue.main.async { if let config = config, let price = config["price"] as? Double { self.updatePrice(price) } } } ``` ## 最佳实践 ### 初始化时机 在 `application(_:didFinishLaunchingWithOptions:)` 中尽早初始化 SDK: ```swift func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // 尽早初始化 SDK let config = SensorswaveConfig() config.debug = false config.apiHost = "https://api.example.com" config.batchSend = true Sensorswave.getInstance().setup( sourceToken: "your-source-token", config: config ) return true } ``` ### 事件属性规范 **推荐做法**: ```swift // 推荐:使用有意义的属性名 Sensorswave.getInstance().trackEvent(eventName: "ProductView", properties: [ "product_id": "12345", "product_name": "iPhone 15 Pro", "category": "electronics", "price": 999.99, "in_stock": true ]) ``` **避免的做法**: ```swift // 不推荐:属性名不明确 Sensorswave.getInstance().trackEvent(eventName: "event", properties: [ "data": "some data", "info": "test" ]) ``` **属性命名规范**: - 使用蛇形命名(snake_case):`button_name` 而不是 `buttonName` - 使用有意义的名称:`product_id` 而不是 `id` - 避免使用系统保留字(以 `$` 开头的属性) ### 生产环境配置 ```swift let config = SensorswaveConfig() config.debug = false // 关闭调试 config.batchSend = true // 启用批量发送 config.autoCapture = true // 开启自动埋点 ``` ## 相关文档 - [埋点方案选择](../tracking-strategy.mdx):了解服务端埋点和客户端埋点的优劣 - [如何正确的标识用户](../user-identification.mdx):用户身份识别的最佳实践 - [数据模型](../data-model.mdx):理解 SensorsWave 的数据结构 - [事件和属性](../events-and-properties.mdx):事件设计规范和最佳实践 --- **最后更新时间**:2026 年 2 月 27 日 **许可证**:Apache-2.0