feat: update
This commit is contained in:
parent
d7ebceabeb
commit
c4dbf83e7d
|
|
@ -0,0 +1,415 @@
|
|||
//
|
||||
// YXTracking.swift
|
||||
// YXTrackingSDK
|
||||
//
|
||||
// Created by 1234 on 2026/1/27.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
/// 远轩埋点SDK实现类 四种上报机制
|
||||
/// 1、初始化时触发:用户在初始化SDK时,会将缓存的事件数据上报。
|
||||
/// 2、定时/定量触发:数据条数达到阈值(默认20条)或定时器到期(默认600秒)时会将缓存的事件数据上报。
|
||||
/// 3、事件触发:用户在添加事件时可选择立即上报。
|
||||
/// 4、应用进入后台和即将被系统终止时触发:用户在应用内停留一段时间后,手动切换到其他应用或桌面时,或即将被系统终止时,会将缓存的事件数据上报。
|
||||
public class YXTracking: NSObject {
|
||||
|
||||
static let shared = YXTracking()
|
||||
|
||||
private var host: String = "" // 主机地址
|
||||
|
||||
private var cacheCount: Int = 20 // 缓存数量
|
||||
|
||||
private var pushInterval: Int = 600 // 上报周期(单位:秒)
|
||||
|
||||
private var enableLog: Bool = false // 是否开启调试日志
|
||||
|
||||
private var eventRequestResult: EventRequestResult = EventRequestResult() // 事件请求参数
|
||||
|
||||
private var systemAllDimInfoResponseResult: SystemAllDimInfoResponseResult = SystemAllDimInfoResponseResult() // 系统所有维度信息
|
||||
|
||||
/// 初始化SDK
|
||||
/// - Parameters:
|
||||
/// - host: 主机地址
|
||||
/// - systemCode: 系统编码
|
||||
/// - cacheCount: 缓存数量(可选)
|
||||
/// - pushInterval: 上报周期(可选)
|
||||
/// - enableLog: 是否开启调试日志(可选)
|
||||
/// - Returns: 无返回值
|
||||
public class func initWithSystemCode(host: String, systemCode: String, cacheCount: Int?, pushInterval: Int?, enableLog: Bool?) {
|
||||
// 校验主机地址是否为空
|
||||
if host.isEmpty {
|
||||
YXTracking.shared.error(message: "SDK config failed, host is empty!");
|
||||
return;
|
||||
}
|
||||
// 校验系统编码是否为空
|
||||
if systemCode.isEmpty {
|
||||
YXTracking.shared.error(message: "SDK config failed, system code is empty!");
|
||||
return;
|
||||
}
|
||||
|
||||
// 设置主机地址和缓存数量、上报周期、是否开启调试日志
|
||||
YXTracking.shared.host = host
|
||||
if cacheCount != nil {
|
||||
YXTracking.shared.cacheCount = cacheCount!
|
||||
}
|
||||
if pushInterval != nil {
|
||||
YXTracking.shared.cacheCount = pushInterval!
|
||||
}
|
||||
if enableLog != nil {
|
||||
YXTracking.shared.enableLog = enableLog!
|
||||
}
|
||||
|
||||
// 打印日志信息
|
||||
YXTracking.shared.log(message: "SDK config success!");
|
||||
|
||||
// 添加应用进入后台和即将被系统终止的通知监听 应用进入后台时或即将被系统终止时触发缓存事件推送
|
||||
YXTracking.shared.addEnterBackgroundNotificationObserver()
|
||||
YXTracking.shared.addWillTerminateNotificationObserver()
|
||||
|
||||
// 重置事件请求参数中的系统编码和客户端类型
|
||||
YXTracking.shared.eventRequestResult.system_code = systemCode
|
||||
YXTracking.shared.eventRequestResult.clientType = 2
|
||||
|
||||
// 获取设备信息
|
||||
YXTracking.shared.getDeviceInfo()
|
||||
|
||||
// 获取系统所有维度信息
|
||||
YXTracking.shared.getSystemAllDimInfo()
|
||||
}
|
||||
|
||||
/// 添加事件
|
||||
/// - Parameters:
|
||||
/// - eventType: 事件类型
|
||||
/// - page: 事件页面controller名称
|
||||
/// - buttonId: 事件按钮名称
|
||||
/// - url: 事件action
|
||||
/// - customTags: 自定义标签数组(可选)
|
||||
/// - pushNow: 是否立即推送
|
||||
/// - Returns: 无返回值
|
||||
public class func addEvent(eventType: String, page: String, buttonId: String, url: String, customTags: Array<String>?, pushNow: Bool) {
|
||||
// 校验事件类型是否在系统维度信息中存在
|
||||
if let systemEventTypes = YXTracking.shared.systemAllDimInfoResponseResult.systemEventTypes,
|
||||
systemEventTypes.count > 0 {
|
||||
guard !eventType.isEmpty else {
|
||||
YXTracking.shared.error(message: "SDK push event error, event type is empty!");
|
||||
return
|
||||
}
|
||||
|
||||
if !systemEventTypes.contains(where: { $0.event_code == eventType }) {
|
||||
YXTracking.shared.error(message: "SDK push event error, event type not in systemEventTypes!");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
YXTracking.shared.error(message: "SDK push event error, systemEventTypes is empty!");
|
||||
return
|
||||
}
|
||||
|
||||
// 重置事件请求参数中的事件类型
|
||||
YXTracking.shared.eventRequestResult.eventType = eventType
|
||||
|
||||
// 重置事件请求参数中的事件参数
|
||||
let eventParams = EventParams(page: page, buttonId: buttonId, url: url)
|
||||
YXTracking.shared.eventRequestResult.eventParams = eventParams
|
||||
|
||||
// 重置事件请求参数中的自定义标签
|
||||
YXTracking.shared.eventRequestResult.customTags = customTags
|
||||
|
||||
// 重置事件请求参数中的时间戳
|
||||
YXTracking.shared.getTimestamp()
|
||||
|
||||
// 打印日志信息
|
||||
YXTracking.shared.log(message: "SDK add event success\nEvent Request Parameter:\n\(YXTracking.shared.eventRequestResult)");
|
||||
|
||||
// 缓存事件数据或立即推送事件数据
|
||||
if pushNow {
|
||||
YXTracking.shared.pushEvent(event: YXTracking.shared.eventRequestResult)
|
||||
} else {
|
||||
YXTrackingSQLiteManager.addTrackingData(data: YXTracking.shared.eventRequestResult)
|
||||
YXTracking.shared.checkEventCount()
|
||||
}
|
||||
}
|
||||
|
||||
/// 设置用户信息
|
||||
/// - Parameters:
|
||||
/// - userInfo: 用户信息
|
||||
/// - Returns: 无返回值
|
||||
public class func setUserInfo(userId: Int64, userName: String, account: String) {
|
||||
let userInfo = UserInfo(userId: userId, userName: userName, account: account)
|
||||
YXTracking.shared.eventRequestResult.userInfo = userInfo
|
||||
|
||||
YXTracking.shared.log(message: "SDK config user info success\nUser info:\n\(userInfo)");
|
||||
}
|
||||
|
||||
/// 清空用户信息
|
||||
public class func clearUserInfo() {
|
||||
YXTracking.shared.eventRequestResult.userInfo = nil
|
||||
|
||||
YXTracking.shared.log(message: "SDK clear user info success!");
|
||||
}
|
||||
|
||||
/// 获取设备信息
|
||||
func getDeviceInfo() {
|
||||
let device = UIDevice.current
|
||||
|
||||
let os = "\(device.systemName) \(device.systemVersion)"
|
||||
|
||||
let localizedModel = device.localizedModel
|
||||
|
||||
let screenWidthPoints = UIScreen.main.bounds.width
|
||||
let screenHeightPoints = UIScreen.main.bounds.height
|
||||
let scale = UIScreen.main.scale
|
||||
let screenWidthPixels = screenWidthPoints * scale
|
||||
let screenHeightPixels = screenHeightPoints * scale
|
||||
let screenResolution = "\(Int(screenWidthPixels))x\(Int(screenHeightPixels))"
|
||||
|
||||
let deviceInfo = DeviceInfo(os: os, model: localizedModel, screenResolution: screenResolution)
|
||||
YXTracking.shared.eventRequestResult.deviceInfo = deviceInfo
|
||||
|
||||
YXTracking.shared.debug(message: "SDK config device info success\nDevice info:\n\(deviceInfo)");
|
||||
}
|
||||
|
||||
/// 获取时间戳
|
||||
func getTimestamp() {
|
||||
let currentDate = Date()
|
||||
|
||||
let unixTimestamp = currentDate.timeIntervalSince1970
|
||||
let milliseconds = Int64(unixTimestamp * 1000)
|
||||
|
||||
let customFormatter = ISO8601DateFormatter()
|
||||
customFormatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
|
||||
customFormatter.timeZone = TimeZone.current
|
||||
let isoStringWithMilliseconds = customFormatter.string(from: currentDate)
|
||||
|
||||
YXTracking.shared.eventRequestResult.clientTimestamp = milliseconds
|
||||
YXTracking.shared.eventRequestResult.timestamp = isoStringWithMilliseconds
|
||||
}
|
||||
|
||||
/// 判断数据库数量是否达到缓存上限,如已达到,则推送缓存事件
|
||||
func checkEventCount() {
|
||||
let count = YXTrackingSQLiteManager.getTrackingDataCount()
|
||||
if count >= cacheCount {
|
||||
YXTracking.pushEventList()
|
||||
}
|
||||
}
|
||||
|
||||
/// 开启定时推送本地缓存的事件日志列表
|
||||
func startThreadPool() {
|
||||
let queue = DispatchQueue(label: "com.yx.tracking", qos: .userInitiated)
|
||||
queue.async { [self] in
|
||||
while true {
|
||||
YXTracking.pushEventList()
|
||||
sleep(UInt32(pushInterval))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 根据系统编码获取系统所有维度信息
|
||||
func getSystemAllDimInfo() {
|
||||
let systemCode = YXTracking.shared.eventRequestResult.system_code ?? ""
|
||||
guard !systemCode.isEmpty else { return }
|
||||
|
||||
let urlString = "\(host)/api/ExternalEventlogs/GetSystemAllDimInfo?systemCode=\(systemCode)"
|
||||
guard let url = URL(string: urlString) else {
|
||||
return
|
||||
}
|
||||
|
||||
let task = URLSession.shared.dataTask(with: url) { [self] data, response, error in
|
||||
if let error = error {
|
||||
YXTracking.shared.error(message: error.localizedDescription)
|
||||
return
|
||||
}
|
||||
|
||||
guard let data = data else {
|
||||
return
|
||||
}
|
||||
|
||||
let json = try? JSONSerialization.jsonObject(with: data, options: [])
|
||||
if let dictionary = json as? [String: Any] {
|
||||
if let code = dictionary["code"] as? Int, code == 200 {
|
||||
if let result = dictionary["data"] as? Dictionary<String, Any>,
|
||||
let resultData = try? JSONSerialization.data(withJSONObject: result) {
|
||||
do {
|
||||
let resultModel = try JSONDecoder().decode(SystemAllDimInfoResponseResult.self, from: resultData)
|
||||
systemAllDimInfoResponseResult = resultModel
|
||||
|
||||
YXTracking.shared.log(message: "SDK init success\nSystem All Dim Info:\n\(systemAllDimInfoResponseResult)");
|
||||
|
||||
// 初始化成功后 推送本地缓存的事件日志列表
|
||||
YXTracking.pushEventList()
|
||||
|
||||
// 开启线程池,定时推送本地缓存的事件日志列表
|
||||
YXTracking.shared.startThreadPool()
|
||||
} catch {
|
||||
YXTracking.shared.error(message: "SDK init fail!");
|
||||
}
|
||||
} else {
|
||||
YXTracking.shared.error(message: "无法创建Data对象!")
|
||||
}
|
||||
} else {
|
||||
YXTracking.shared.error(message: "SDK init fail,error code: \(dictionary["code"] ?? "未知")")
|
||||
}
|
||||
}
|
||||
}
|
||||
task.resume()
|
||||
}
|
||||
|
||||
/// 推送单条日志
|
||||
/// - Parameters:
|
||||
/// - event: 事件对象
|
||||
/// - Returns: 无返回值
|
||||
func pushEvent(event: EventRequestResult) {
|
||||
let urlString = "\(host)/api/ExternalEventlogs/AddEventLog"
|
||||
guard let url = URL(string: urlString) else {
|
||||
return
|
||||
}
|
||||
|
||||
// 创建URL请求
|
||||
var request = URLRequest(url: url)
|
||||
request.httpMethod = "POST"
|
||||
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
|
||||
|
||||
// 将event对象转换为JSON数据
|
||||
let jsonEncoder = JSONEncoder()
|
||||
do {
|
||||
let jsonData = try jsonEncoder.encode(event)
|
||||
request.httpBody = jsonData
|
||||
} catch {
|
||||
YXTracking.shared.error(message: "SDK push event error encoding\n\(error)");
|
||||
return
|
||||
}
|
||||
|
||||
// 发送请求
|
||||
let task = URLSession.shared.dataTask(with: request) { data, response, error in
|
||||
if let error = error {
|
||||
YXTracking.shared.error(message: "SDK push event error sending\n\(error)");
|
||||
return
|
||||
}
|
||||
|
||||
guard let data = data else {
|
||||
return
|
||||
}
|
||||
|
||||
let json = try? JSONSerialization.jsonObject(with: data, options: [])
|
||||
if let dictionary = json as? [String: Any] {
|
||||
if let code = dictionary["code"] as? Int, code == 200 {
|
||||
YXTracking.shared.success(message: "SDK push event success Response:\n\(String(data: data, encoding: .utf8) ?? "")");
|
||||
} else {
|
||||
YXTrackingSQLiteManager.addTrackingData(data: YXTracking.shared.eventRequestResult)
|
||||
YXTracking.shared.error(message: "SDK push event fail Response:\n\(String(data: data, encoding: .utf8) ?? "")");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
task.resume()
|
||||
}
|
||||
|
||||
/// 推送多条日志
|
||||
public class func pushEventList() {
|
||||
let count = YXTrackingSQLiteManager.getTrackingDataCount()
|
||||
guard count > 0 else { return }
|
||||
|
||||
let urlString = "\(YXTracking.shared.host)/api/ExternalEventlogs/AddEventListLog"
|
||||
guard let url = URL(string: urlString) else {
|
||||
return
|
||||
}
|
||||
|
||||
// 创建URL请求
|
||||
var request = URLRequest(url: url)
|
||||
request.httpMethod = "POST"
|
||||
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
|
||||
|
||||
// 读取数据库数据
|
||||
let eventList = YXTrackingSQLiteManager.readTrackingData()
|
||||
var event: [EventRequestResult] = []
|
||||
for item in eventList {
|
||||
event.append(item)
|
||||
}
|
||||
|
||||
// 将event list对象转换为JSON数据
|
||||
let jsonEncoder = JSONEncoder()
|
||||
do {
|
||||
let jsonData = try jsonEncoder.encode(event)
|
||||
request.httpBody = jsonData
|
||||
} catch {
|
||||
YXTracking.shared.error(message: "SDK push event list error encoding\n\(error)");
|
||||
return
|
||||
}
|
||||
|
||||
// 发送请求
|
||||
let task = URLSession.shared.dataTask(with: request) { data, response, error in
|
||||
if let error = error {
|
||||
YXTracking.shared.error(message: "SDK push event list error sending\n\(error)");
|
||||
return
|
||||
}
|
||||
|
||||
guard let data = data else {
|
||||
return
|
||||
}
|
||||
|
||||
let json = try? JSONSerialization.jsonObject(with: data, options: [])
|
||||
if let dictionary = json as? [String: Any] {
|
||||
if let code = dictionary["code"] as? Int, code == 200 {
|
||||
YXTrackingSQLiteManager.deleteTrackingData()
|
||||
YXTracking.shared.success(message: "SDK push event list success Response:\n\(String(data: data, encoding: .utf8) ?? "")");
|
||||
} else {
|
||||
YXTracking.shared.error(message: "SDK push event fail Response:\n\(String(data: data, encoding: .utf8) ?? "")");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
task.resume()
|
||||
}
|
||||
|
||||
// 监听应用切换到后台
|
||||
func addEnterBackgroundNotificationObserver() {
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(onPushEventList), name: UIApplication.didEnterBackgroundNotification, object: nil)
|
||||
}
|
||||
|
||||
// 监听系统即将终止应用程序
|
||||
func addWillTerminateNotificationObserver() {
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(onPushEventList), name: UIApplication.willTerminateNotification, object: nil)
|
||||
}
|
||||
|
||||
// 监听回调:推送事件列表
|
||||
@objc func onPushEventList() {
|
||||
YXTracking.pushEventList()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// 扩展
|
||||
extension YXTracking {
|
||||
|
||||
/// 日志打印
|
||||
func log(message: String) {
|
||||
guard YXTracking.shared.enableLog else { return }
|
||||
print("ℹ️ [YXTracking LOG] \(message)")
|
||||
}
|
||||
|
||||
func debug(message: String) {
|
||||
guard YXTracking.shared.enableLog else { return }
|
||||
print("🐛 [YXTracking DEBUG] \(message)")
|
||||
}
|
||||
|
||||
func warning(message: String) {
|
||||
guard YXTracking.shared.enableLog else { return }
|
||||
print("⚠️ [YXTracking WARNING] \(message)")
|
||||
}
|
||||
|
||||
func success(message: String) {
|
||||
guard YXTracking.shared.enableLog else { return }
|
||||
print("✅ [YXTracking SUCCESS] \(message)")
|
||||
}
|
||||
|
||||
func error(message: String) {
|
||||
guard YXTracking.shared.enableLog else { return }
|
||||
print("❌ [YXTracking ERROR] \(message)")
|
||||
}
|
||||
|
||||
func fatal(message: String) {
|
||||
guard YXTracking.shared.enableLog else { return }
|
||||
print("💀 [YXTracking FATAL] \(message)")
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -6,8 +6,42 @@
|
|||
objectVersion = 77;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXAggregateTarget section */
|
||||
7C1AA9712F288FED00382E10 /* YXTrackingSDKAggregate */ = {
|
||||
isa = PBXAggregateTarget;
|
||||
buildConfigurationList = 7C1AA9722F288FED00382E10 /* Build configuration list for PBXAggregateTarget "YXTrackingSDKAggregate" */;
|
||||
buildPhases = (
|
||||
7C1AA9772F28900800382E10 /* ShellScript */,
|
||||
);
|
||||
dependencies = (
|
||||
7C1AA9762F288FFF00382E10 /* PBXTargetDependency */,
|
||||
);
|
||||
name = YXTrackingSDKAggregate;
|
||||
packageProductDependencies = (
|
||||
);
|
||||
productName = YXTrackingSDKAggregate;
|
||||
};
|
||||
/* End PBXAggregateTarget section */
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
7C1AA9792F2892D700382E10 /* YXTracking.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C1AA9782F2892D700382E10 /* YXTracking.swift */; };
|
||||
7C84FBDD2F35D11600A0FC52 /* YXTrackingSQLiteManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C84FBDC2F35D11600A0FC52 /* YXTrackingSQLiteManager.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
7C1AA9752F288FFF00382E10 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 7C1AA9562F288F6300382E10 /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 7C1AA95E2F288F6300382E10;
|
||||
remoteInfo = YXTrackingSDK;
|
||||
};
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
7C1AA95F2F288F6300382E10 /* YXTrackingSDK.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = YXTrackingSDK.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
7C1AA9782F2892D700382E10 /* YXTracking.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = YXTracking.swift; sourceTree = "<group>"; };
|
||||
7C84FBDC2F35D11600A0FC52 /* YXTrackingSQLiteManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = YXTrackingSQLiteManager.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFileSystemSynchronizedRootGroup section */
|
||||
|
|
@ -32,6 +66,8 @@
|
|||
7C1AA9552F288F6300382E10 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
7C1AA9782F2892D700382E10 /* YXTracking.swift */,
|
||||
7C84FBDC2F35D11600A0FC52 /* YXTrackingSQLiteManager.swift */,
|
||||
7C1AA9612F288F6300382E10 /* YXTrackingSDK */,
|
||||
7C1AA9602F288F6300382E10 /* Products */,
|
||||
);
|
||||
|
|
@ -94,6 +130,9 @@
|
|||
7C1AA95E2F288F6300382E10 = {
|
||||
CreatedOnToolsVersion = 26.1.1;
|
||||
};
|
||||
7C1AA9712F288FED00382E10 = {
|
||||
CreatedOnToolsVersion = 26.1.1;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 7C1AA9592F288F6300382E10 /* Build configuration list for PBXProject "YXTrackingSDK" */;
|
||||
|
|
@ -111,6 +150,7 @@
|
|||
projectRoot = "";
|
||||
targets = (
|
||||
7C1AA95E2F288F6300382E10 /* YXTrackingSDK */,
|
||||
7C1AA9712F288FED00382E10 /* YXTrackingSDKAggregate */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
|
@ -125,16 +165,46 @@
|
|||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXShellScriptBuildPhase section */
|
||||
7C1AA9772F28900800382E10 /* ShellScript */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
outputFileListPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "# Type a script or drag a script file from your workspace to insert its path.\n#!/bin/sh\n#要build的target名\nTARGET_NAME=${PROJECT_NAME}\nif [[ $1 ]]\nthen\nTARGET_NAME=$1\nfi\nUNIVERSAL_OUTPUT_FOLDER=\"${SRCROOT}/${PROJECT_NAME}/\"\n \n#创建输出目录,并删除之前的framework文件\nmkdir -p \"${UNIVERSAL_OUTPUT_FOLDER}\"\nrm -rf \"${UNIVERSAL_OUTPUT_FOLDER}/${TARGET_NAME}.framework\"\n \n#分别编译模拟器和真机的Framework\nxcodebuild -target \"${TARGET_NAME}\" ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphoneos BUILD_DIR=\"${BUILD_DIR}\" BUILD_ROOT=\"${BUILD_ROOT}\" clean build\nxcodebuild -target \"${TARGET_NAME}\" ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphonesimulator BUILD_DIR=\"${BUILD_DIR}\" BUILD_ROOT=\"${BUILD_ROOT}\" clean build\n \n#拷贝framework到univer目录\ncp -R \"${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${TARGET_NAME}.framework\" \"${UNIVERSAL_OUTPUT_FOLDER}\"\n \nlipo \"${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${TARGET_NAME}.framework/${TARGET_NAME}\" -remove arm64 -output \"${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${TARGET_NAME}.framework/${TARGET_NAME}\"\n \n \n#合并framework,输出最终的framework到build目录\nlipo -create -output \"${UNIVERSAL_OUTPUT_FOLDER}/${TARGET_NAME}.framework/${TARGET_NAME}\" \"${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${TARGET_NAME}.framework/${TARGET_NAME}\" \"${BUILD_DIR}/${CONFIGURATION}-iphoneos/${TARGET_NAME}.framework/${TARGET_NAME}\"\n \n#删除编译之后生成的无关的配置文件\ndir_path=\"${UNIVERSAL_OUTPUT_FOLDER}/${TARGET_NAME}.framework/\"\nfor file in ls $dir_path\ndo\nif [[ ${file} =~ \".xcconfig\" ]]\nthen\nrm -f \"${dir_path}/${file}\"\nfi\ndone\n#判断build文件夹是否存在,存在则删除\nif [ -d \"${SRCROOT}/build\" ]\nthen\nrm -rf \"${SRCROOT}/build\"\nfi\nrm -rf \"${BUILD_DIR}/${CONFIGURATION}-iphonesimulator\" \"${BUILD_DIR}/${CONFIGURATION}-iphoneos\"\n#打开合并后的文件夹\nopen \"${UNIVERSAL_OUTPUT_FOLDER}\"\n";
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
7C1AA95B2F288F6300382E10 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
7C1AA9792F2892D700382E10 /* YXTracking.swift in Sources */,
|
||||
7C84FBDD2F35D11600A0FC52 /* YXTrackingSQLiteManager.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXTargetDependency section */
|
||||
7C1AA9762F288FFF00382E10 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = 7C1AA95E2F288F6300382E10 /* YXTrackingSDK */;
|
||||
targetProxy = 7C1AA9752F288FFF00382E10 /* PBXContainerItemProxy */;
|
||||
};
|
||||
/* End PBXTargetDependency section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
7C1AA9662F288F6300382E10 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
|
|
@ -269,26 +339,36 @@
|
|||
BUILD_LIBRARY_FOR_DISTRIBUTION = YES;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEFINES_MODULE = YES;
|
||||
DEVELOPMENT_TEAM = Z778GC45N8;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
ENABLE_MODULE_VERIFIER = YES;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
GENERATE_PRELINK_OBJECT_FILE = YES;
|
||||
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
"@loader_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.0;
|
||||
MACH_O_TYPE = staticlib;
|
||||
MARKETING_VERSION = 1.0.0;
|
||||
MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
|
||||
MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20";
|
||||
OTHER_LDFLAGS = "-ObjC";
|
||||
OTHER_LIBTOOLFLAGS = "";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.yuanxuan.YXTrackingSDK;
|
||||
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
|
||||
SKIP_INSTALL = YES;
|
||||
STRING_CATALOG_GENERATE_SYMBOLS = YES;
|
||||
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
||||
SUPPORTS_MACCATALYST = NO;
|
||||
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
|
||||
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
|
||||
SWIFT_APPROACHABLE_CONCURRENCY = YES;
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
SWIFT_INSTALL_MODULE = YES;
|
||||
|
|
@ -305,26 +385,36 @@
|
|||
BUILD_LIBRARY_FOR_DISTRIBUTION = YES;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEFINES_MODULE = YES;
|
||||
DEVELOPMENT_TEAM = Z778GC45N8;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
ENABLE_MODULE_VERIFIER = YES;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
GENERATE_PRELINK_OBJECT_FILE = YES;
|
||||
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
"@loader_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.0;
|
||||
MACH_O_TYPE = staticlib;
|
||||
MARKETING_VERSION = 1.0.0;
|
||||
MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
|
||||
MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20";
|
||||
OTHER_LDFLAGS = "-ObjC";
|
||||
OTHER_LIBTOOLFLAGS = "";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.yuanxuan.YXTrackingSDK;
|
||||
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
|
||||
SKIP_INSTALL = YES;
|
||||
STRING_CATALOG_GENERATE_SYMBOLS = YES;
|
||||
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
||||
SUPPORTS_MACCATALYST = NO;
|
||||
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
|
||||
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
|
||||
SWIFT_APPROACHABLE_CONCURRENCY = YES;
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
SWIFT_INSTALL_MODULE = YES;
|
||||
|
|
@ -335,6 +425,24 @@
|
|||
};
|
||||
name = Release;
|
||||
};
|
||||
7C1AA9732F288FED00382E10 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEVELOPMENT_TEAM = Z778GC45N8;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
7C1AA9742F288FED00382E10 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEVELOPMENT_TEAM = Z778GC45N8;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
|
|
@ -356,6 +464,15 @@
|
|||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
7C1AA9722F288FED00382E10 /* Build configuration list for PBXAggregateTarget "YXTrackingSDKAggregate" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
7C1AA9732F288FED00382E10 /* Debug */,
|
||||
7C1AA9742F288FED00382E10 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = 7C1AA9562F288F6300382E10 /* Project object */;
|
||||
Binary file not shown.
|
|
@ -0,0 +1,67 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "2610"
|
||||
version = "1.7">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES"
|
||||
buildArchitectures = "Automatic">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "7C1AA95E2F288F6300382E10"
|
||||
BuildableName = "YXTrackingSDK.framework"
|
||||
BlueprintName = "YXTrackingSDK"
|
||||
ReferencedContainer = "container:YXTrackingSDK.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
shouldAutocreateTestPlan = "YES">
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Release"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "7C1AA95E2F288F6300382E10"
|
||||
BuildableName = "YXTrackingSDK.framework"
|
||||
BlueprintName = "YXTrackingSDK"
|
||||
ReferencedContainer = "container:YXTrackingSDK.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
||||
|
|
@ -9,6 +9,19 @@
|
|||
<key>orderHint</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<key>YXTrackingSDKAggregate.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>1</integer>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>SuppressBuildableAutocreation</key>
|
||||
<dict>
|
||||
<key>7C1AA95E2F288F6300382E10</key>
|
||||
<dict>
|
||||
<key>primary</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
//
|
||||
// YXTracking.swift
|
||||
// YXTrackingSDK
|
||||
//
|
||||
// Created by 1234 on 2026/1/27.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class YXTracking: NSObject {
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
//
|
||||
// YXTrackingSDK.swift
|
||||
// YXTrackingSDK
|
||||
//
|
||||
// Created by 1234 on 2026/1/27.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
/// 定义一个结构体来存储用户信息
|
||||
public struct UserInfo: Codable {
|
||||
var userId: Int64? // 用户ID
|
||||
var userName: String? // 用户名称
|
||||
var account: String? // 账号
|
||||
}
|
||||
|
||||
/// 定义一个结构体来存储事件参数
|
||||
public struct EventParams: Codable {
|
||||
var page: String? // 事件页面controller名称
|
||||
var buttonId: String? // 事件按钮名称
|
||||
var url: String? // 事件action
|
||||
}
|
||||
|
||||
/// 定义一个结构体来存储设备信息
|
||||
public struct DeviceInfo: Codable {
|
||||
var os: String? // 操作系统
|
||||
var model: String? // 设备型号
|
||||
var screenResolution: String? // 屏幕分辨率
|
||||
}
|
||||
|
||||
/// 定义一个结构体来存储事件请求参数
|
||||
public struct EventRequestResult: Codable {
|
||||
var system_code: String? // 系统id(关联 dim_system.system_code)
|
||||
var eventType: String? // 事件类型(关联 dim_event_type.event_code)
|
||||
var userInfo: UserInfo? // 用户信息
|
||||
var clientType: Int32? // 数据埋点 客户端类型枚举 1、Android 2、iOS 3、PC 4、H5
|
||||
var clientTimestamp: Int64? // 事件发生时间(ISO8601格式) 毫秒时间戳
|
||||
var timestamp: String? // 事件发生时间(ISO8601格式)
|
||||
var deviceInfo: DeviceInfo? // 设备信息
|
||||
var eventParams: EventParams? // 事件参数
|
||||
var customTags: Array<String>? // 自定义标签(可选)
|
||||
}
|
||||
|
||||
/// 定义一个结构体来存储系统信息
|
||||
public struct SystemInfo: Codable {
|
||||
var id: Int64? // ID
|
||||
var createTime: String? // 创建时间
|
||||
var modifyTime: String? // 修改时间
|
||||
var system_code: String? // 系统唯一标识
|
||||
var description: String? // 系统描述
|
||||
}
|
||||
|
||||
/// 定义一个结构体来存储接入系统事件类型信息
|
||||
public struct SystemEventType: Codable {
|
||||
var id: Int64? // ID
|
||||
var createTime: String? // 创建时间
|
||||
var modifyTime: String? // 修改时间
|
||||
var system_id: Int64? // 所属系统ID(关联dim_system.system_id)
|
||||
var event_code: String? // 事件编码(如button_click、page_view)
|
||||
var event_name: String? // 事件名称(如按钮点击、页面访问)
|
||||
var description: String? // 事件描述
|
||||
var system_name: String? // 所属系统名称
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// 定义一个结构体来存储系统自定义标签信息
|
||||
public struct SystemCustonTag: Codable {
|
||||
var id: Int64? // ID
|
||||
var createTime: String? // 创建时间
|
||||
var modifyTime: String? // 修改时间
|
||||
var system_id: Int64? // 所属系统ID(关联dim_system.system_id)
|
||||
var tag_name: String? // 标签名称(如promotion_id、source_channel)
|
||||
var description: String? // 标签描述
|
||||
var is_required: Bool? // 是否为必传标签
|
||||
var system_name: String? // 所属系统
|
||||
}
|
||||
|
||||
/// 定义一个结构体来存储系统所有维度信息响应结果
|
||||
public struct SystemAllDimInfoResponseResult: Codable {
|
||||
var systemInfo: SystemInfo? // 接入系统
|
||||
var systemEventTypes: Array<SystemEventType>? // 接入系统事件类型
|
||||
var SystemCustonTas: Array<SystemCustonTag>? // 接入系统自定义标签
|
||||
}
|
||||
|
||||
Binary file not shown.
|
|
@ -1,9 +0,0 @@
|
|||
//
|
||||
// YXTrackingSDK.swift
|
||||
// YXTrackingSDK
|
||||
//
|
||||
// Created by 1234 on 2026/1/27.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
|
|
@ -6,7 +6,214 @@
|
|||
//
|
||||
|
||||
import UIKit
|
||||
import SQLite3
|
||||
|
||||
class YXTrackingSQLiteManager: NSObject {
|
||||
|
||||
// 添加跟踪数据到数据库
|
||||
class func addTrackingData(data: EventRequestResult) {
|
||||
// 创建数据库连接
|
||||
let dbPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first!
|
||||
let path = URL(fileURLWithPath: dbPath).appendingPathComponent("tracking.sqlite").path
|
||||
var db: OpaquePointer? = nil
|
||||
if sqlite3_open(path, &db) != SQLITE_OK {
|
||||
YXTracking.shared.error(message: "SDK sqlite open failed!");
|
||||
return
|
||||
}
|
||||
|
||||
YXTracking.shared.success(message: "SDK sqlite open success!");
|
||||
|
||||
// 创建表
|
||||
let createTableSQL = """
|
||||
CREATE TABLE IF NOT EXISTS tracking_data (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
system_code TEXT,
|
||||
event_type TEXT,
|
||||
user_info BLOB,
|
||||
client_type INT,
|
||||
client_timestamp INT64,
|
||||
timestamp TEXT,
|
||||
device_info BLOB,
|
||||
event_params BLOB,
|
||||
custom_tags BLOB
|
||||
)
|
||||
"""
|
||||
if sqlite3_exec(db, createTableSQL, nil, nil, nil) != SQLITE_OK {
|
||||
YXTracking.shared.error(message: "SDK sqlite create table failed!");
|
||||
return
|
||||
}
|
||||
|
||||
YXTracking.shared.success(message: "SDK sqlite create table success!");
|
||||
|
||||
// 插入数据
|
||||
let encoder = JSONEncoder()
|
||||
let insertSQL = "INSERT INTO tracking_data (system_code, event_type, user_info, client_type, client_timestamp, timestamp, device_info, event_params, custom_tags) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"
|
||||
var statement: OpaquePointer? = nil
|
||||
if sqlite3_prepare_v2(db, insertSQL, -1, &statement, nil) == SQLITE_OK {
|
||||
let system_code = data.system_code ?? ""
|
||||
let event_type = data.eventType ?? ""
|
||||
let user_info = (data.userInfo != nil) ? try! encoder.encode(data.userInfo) : nil
|
||||
let client_type = data.clientType ?? 0
|
||||
let client_timestamp = data.clientTimestamp ?? 0
|
||||
let timestamp = data.timestamp ?? ""
|
||||
let device_info = try! encoder.encode(data.deviceInfo)
|
||||
let event_params = try! encoder.encode(data.eventParams)
|
||||
let custom_tags = try! JSONSerialization.data(withJSONObject: data.customTags ?? [], options: [])
|
||||
if sqlite3_bind_text(statement, 1, system_code, -1, nil) != SQLITE_OK || sqlite3_bind_text(statement, 2, event_type, -1, nil) != SQLITE_OK || ((data.userInfo != nil) ? (sqlite3_bind_blob(statement, 3, user_info! as CFTypeRef as? UnsafeRawPointer, Int32(user_info!.count), nil) != SQLITE_OK) : (sqlite3_bind_null(statement, 3) != SQLITE_OK)) || sqlite3_bind_int(statement, 4, client_type) != SQLITE_OK || sqlite3_bind_int64(statement, 5, client_timestamp) != SQLITE_OK || sqlite3_bind_text(statement, 6, timestamp, -1, nil) != SQLITE_OK || sqlite3_bind_blob(statement, 7, device_info as CFTypeRef as? UnsafeRawPointer, Int32(device_info.count), nil) != SQLITE_OK || sqlite3_bind_blob(statement, 8, event_params as CFTypeRef as? UnsafeRawPointer, Int32(event_params.count), nil) != SQLITE_OK || sqlite3_bind_blob(statement, 9, custom_tags as CFTypeRef as? UnsafeRawPointer, Int32(custom_tags.count), nil) != SQLITE_OK {
|
||||
YXTracking.shared.error(message: "SDK sqlite bind parameter failed!");
|
||||
return
|
||||
} else if sqlite3_step(statement) != SQLITE_DONE {
|
||||
YXTracking.shared.error(message: "SDK sqlite insert data failed!");
|
||||
return
|
||||
}
|
||||
|
||||
YXTracking.shared.success(message: "SDK sqlite bind parameter success!");
|
||||
} else {
|
||||
YXTracking.shared.error(message: "SDK sqlite preparing to insert data failed!");
|
||||
return
|
||||
}
|
||||
|
||||
YXTracking.shared.success(message: "SDK sqlite insert data success!");
|
||||
|
||||
// 关闭数据库连接
|
||||
do {
|
||||
sqlite3_close(db)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 读取跟踪数据
|
||||
class func readTrackingData() -> [EventRequestResult] {
|
||||
var trackingData: [EventRequestResult] = []
|
||||
// 创建数据库连接
|
||||
let dbPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first!
|
||||
let path = URL(fileURLWithPath: dbPath).appendingPathComponent("tracking.sqlite").path
|
||||
var db: OpaquePointer? = nil
|
||||
if sqlite3_open(path, &db) != SQLITE_OK {
|
||||
YXTracking.shared.error(message: "SDK sqlite open failed!");
|
||||
return trackingData
|
||||
}
|
||||
|
||||
// 查询数据
|
||||
let decoder = JSONDecoder()
|
||||
let querySQL = "SELECT system_code, event_type, user_info, client_type, client_timestamp, timestamp, device_info, event_params, custom_tags FROM tracking_data"
|
||||
var statement: OpaquePointer? = nil
|
||||
if sqlite3_prepare_v2(db, querySQL, -1, &statement, nil) == SQLITE_OK {
|
||||
while (sqlite3_step(statement) == SQLITE_ROW) {
|
||||
// 获取数据并转换为EventRequestResult
|
||||
let system_code = String(cString: sqlite3_column_text(statement, 1))
|
||||
let event_type = String(cString: sqlite3_column_text(statement, 2))
|
||||
var user_info = UserInfo(userId: nil, userName: nil, account: nil)
|
||||
if sqlite3_column_type(statement, 3) != SQLITE_NULL {
|
||||
if let user_info_blob = sqlite3_column_blob(statement, 3) {
|
||||
let user_info_blob_length = sqlite3_column_bytes(statement, 3)
|
||||
let data = Data(bytes: user_info_blob, count: Int(user_info_blob_length))
|
||||
user_info = try! decoder.decode(UserInfo.self, from: data)
|
||||
}
|
||||
}
|
||||
let client_type = sqlite3_column_int(statement, 4)
|
||||
let client_timestamp = sqlite3_column_int64(statement, 5)
|
||||
let timestamp = String(cString: sqlite3_column_text(statement, 6))
|
||||
var device_info = DeviceInfo(os: nil, model: nil, screenResolution: nil)
|
||||
if sqlite3_column_type(statement, 7) != SQLITE_NULL {
|
||||
if let device_info_blob = sqlite3_column_blob(statement, 7) {
|
||||
let device_info_blob_length = sqlite3_column_bytes(statement, 7)
|
||||
let data = Data(bytes: device_info_blob, count: Int(device_info_blob_length))
|
||||
device_info = try! decoder.decode(DeviceInfo.self, from: data)
|
||||
}
|
||||
}
|
||||
var event_params = EventParams(page: nil, buttonId: nil, url: nil)
|
||||
if sqlite3_column_type(statement, 8) != SQLITE_NULL {
|
||||
if let event_params_blob = sqlite3_column_blob(statement, 8) {
|
||||
let event_params_blob_length = sqlite3_column_bytes(statement, 8)
|
||||
let data = Data(bytes: event_params_blob, count: Int(event_params_blob_length))
|
||||
event_params = try! decoder.decode(EventParams.self, from: data)
|
||||
}
|
||||
}
|
||||
var custom_tags = Array<String>()
|
||||
if sqlite3_column_type(statement, 9) != SQLITE_NULL {
|
||||
if let custom_tags_blob = sqlite3_column_blob(statement, 9) {
|
||||
let custom_tags_blob_length = sqlite3_column_bytes(statement, 9)
|
||||
let data = Data(bytes: custom_tags_blob, count: Int(custom_tags_blob_length))
|
||||
custom_tags = try! decoder.decode([String].self, from: data)
|
||||
}
|
||||
}
|
||||
|
||||
let event = EventRequestResult(system_code: system_code,
|
||||
eventType: event_type,
|
||||
userInfo: user_info,
|
||||
clientType: client_type,
|
||||
clientTimestamp: client_timestamp,
|
||||
timestamp: timestamp,
|
||||
deviceInfo: device_info,
|
||||
eventParams: event_params,
|
||||
customTags: custom_tags)
|
||||
trackingData.append(event)
|
||||
}
|
||||
sqlite3_finalize(statement)
|
||||
} else {
|
||||
YXTracking.shared.error(message: "SDK sqlite read data failed!");
|
||||
}
|
||||
|
||||
// 关闭数据库连接
|
||||
do {
|
||||
sqlite3_close(db)
|
||||
}
|
||||
return trackingData
|
||||
}
|
||||
|
||||
// 删除跟踪数据
|
||||
class func deleteTrackingData() {
|
||||
// 创建数据库连接
|
||||
let dbPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first!
|
||||
let path = URL(fileURLWithPath: dbPath).appendingPathComponent("tracking.sqlite").path
|
||||
var db: OpaquePointer? = nil
|
||||
if sqlite3_open(path, &db) != SQLITE_OK {
|
||||
YXTracking.shared.error(message: "SDK sqlite open failed!");
|
||||
return
|
||||
}
|
||||
|
||||
// 删除数据
|
||||
let deleteSQL = "DELETE FROM tracking_data"
|
||||
if sqlite3_exec(db, deleteSQL, nil, nil, nil) != SQLITE_OK {
|
||||
YXTracking.shared.error(message: "SDK sqlite delete data failed!");
|
||||
}
|
||||
|
||||
// 关闭数据库连接
|
||||
do {
|
||||
sqlite3_close(db)
|
||||
}
|
||||
}
|
||||
|
||||
// 获取数据库缓存条数
|
||||
class func getTrackingDataCount() -> Int {
|
||||
// 创建数据库连接
|
||||
let dbPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first!
|
||||
let path = URL(fileURLWithPath: dbPath).appendingPathComponent("tracking.sqlite").path
|
||||
var db: OpaquePointer? = nil
|
||||
if sqlite3_open(path, &db) != SQLITE_OK {
|
||||
YXTracking.shared.error(message: "SDK sqlite open failed!");
|
||||
return -1
|
||||
}
|
||||
|
||||
// 查询数据
|
||||
var dataCount = -1
|
||||
let querySQL = "SELECT COUNT(*) FROM tracking_data"
|
||||
var statement: OpaquePointer? = nil
|
||||
if sqlite3_prepare_v2(db, querySQL, -1, &statement, nil) == SQLITE_OK {
|
||||
sqlite3_step(statement)
|
||||
dataCount = Int(sqlite3_column_int64(statement, 0))
|
||||
sqlite3_finalize(statement)
|
||||
} else {
|
||||
YXTracking.shared.error(message: "SDK sqlite read data failed!");
|
||||
}
|
||||
|
||||
// 关闭数据库连接
|
||||
do {
|
||||
sqlite3_close(db)
|
||||
}
|
||||
|
||||
return dataCount
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue