From 8163f171d2947e1f1f0768cc0115057d7103419f Mon Sep 17 00:00:00 2001 From: Haoyi Date: Fri, 8 Aug 2025 18:12:14 +0800 Subject: [PATCH] v0.4.4 Signed-off-by: Haoyi --- CHANGELOG.md | 49 ++++++++++++++++ .../GuruAnalytics.xcodeproj/project.pbxproj | 4 ++ Example/GuruAnalytics/AppDelegate.swift | 3 +- .../MyPlayground.playground/Contents.swift | 26 ++++++++- .../contents.xcworkspacedata | 7 +++ Example/GuruAnalytics/ViewController.swift | 20 ++++++- Example/Podfile | 2 +- .../Classes/Interface/GuruAnalytics.swift | 15 ++++- .../Classes/Internal/DataModel/Models.swift | 29 ++++++++-- .../Classes/Internal/Database/Manager.swift | 3 +- .../Internal/GuruAnalytics+Internal.swift | 1 + .../Classes/Internal/Utility/Constants.swift | 56 ++++++++++++++++++- .../Utility/FoundationExtensions.swift | 43 ++++++++++++++ GuruAnalyticsLib.podspec | 4 +- 14 files changed, 244 insertions(+), 18 deletions(-) create mode 100644 Example/GuruAnalytics/MyPlayground.playground/playground.xcworkspace/contents.xcworkspacedata create mode 100644 GuruAnalytics/Classes/Internal/Utility/FoundationExtensions.swift diff --git a/CHANGELOG.md b/CHANGELOG.md index d0930b8..0c84d3f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,48 @@ +## v0.4.3 +- fix + - 事件参数值字符串中包含“‘”单引号sql报错 +- feature + - 增加事件参数 + - deviceInfo.appsflyerId + - 增加设置appsflyerId接口 + - setAppFlyersId(_ appFlyersId: String?) -> Void + +## v0.4.2 +- fix + - 临时回滚 0.4.0,排查solitare collection ATP DAU下降问题。 + +## v0.4.1 +- fix + - x.0的数值类型转换成整型问题 + +## v0.4.0 +- feature + - 支持 AppExtension 上报打点 +- 如在AppExtension 中使用,需在Podfile 中添加以下代码: +```swift +installer.pods_project.targets.each do |target| + flutter_additional_ios_build_settings(target) + target.build_configurations.each do |config| + if target.name == 'GuruAnalyticsLib' + config.build_settings['APPLICATION_EXTENSION_API_ONLY'] = 'NO' + end + end +end +``` + +## v0.3.9 +- feature + - 增加事件参数 + - deviceInfo.guruAnalyticsVersion + - deviceInfo.gurusdkVersion + - 增加设置中台版本接口 + - 初始化方法增加guruSDKVersion参数 initializeLib(..., guruSDKVersion: String) + - setGuruSDKVersion(_ version: String) -> Void + +## v0.3.8.1 +- fix + - x.0的数值类型转换成整型问题 + ## v0.3.8 - fix - 隐私文件增加divice id声明 @@ -15,6 +60,10 @@ - deviceInfo.sdkVersion - info.vendorId +## v0.3.6.1 +- fix: + - 更新privacy manifest文件,移除tracking domains下的空条目。 + ## v0.3.6 - fix: - 增加第三方依赖库版本约束 diff --git a/Example/GuruAnalytics.xcodeproj/project.pbxproj b/Example/GuruAnalytics.xcodeproj/project.pbxproj index ce1e7e9..12aef38 100644 --- a/Example/GuruAnalytics.xcodeproj/project.pbxproj +++ b/Example/GuruAnalytics.xcodeproj/project.pbxproj @@ -370,6 +370,8 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; DEVELOPMENT_TEAM = 69MW7VVKA9; INFOPLIST_FILE = GuruAnalytics/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = GuruAnalytics; + IPHONEOS_DEPLOYMENT_TARGET = 15.6; IPHONEOS_DEPLOYMENT_TARGET = 11.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -390,6 +392,8 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; DEVELOPMENT_TEAM = 69MW7VVKA9; INFOPLIST_FILE = GuruAnalytics/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = GuruAnalytics; + IPHONEOS_DEPLOYMENT_TARGET = 15.6; IPHONEOS_DEPLOYMENT_TARGET = 11.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", diff --git a/Example/GuruAnalytics/AppDelegate.swift b/Example/GuruAnalytics/AppDelegate.swift index fd0d2d8..2675d0f 100644 --- a/Example/GuruAnalytics/AppDelegate.swift +++ b/Example/GuruAnalytics/AppDelegate.swift @@ -27,7 +27,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate { batchLimit: 25, initializeTimeout: 5, saasXAPPID: "test_app_id", - saasXDEVICEINFO: "appIdentifier=test.app.example;appVersion=1.0;deviceType=apple;deviceCountry=CN") + saasXDEVICEINFO: "appIdentifier=test.app.example;appVersion=1.0;deviceType=apple;deviceCountry=CN", + guruSDKVersion: "1.0.0") GuruAnalytics.setUserID("100004") GuruAnalytics.setAdjustId("xsdfal021sxasdfl") GuruAnalytics.setDeviceId(UUID().uuidString) diff --git a/Example/GuruAnalytics/MyPlayground.playground/Contents.swift b/Example/GuruAnalytics/MyPlayground.playground/Contents.swift index 2af6dde..3971679 100644 --- a/Example/GuruAnalytics/MyPlayground.playground/Contents.swift +++ b/Example/GuruAnalytics/MyPlayground.playground/Contents.swift @@ -1,7 +1,31 @@ -import UIKit +import Foundation var greeting = "Hello, playground" let sss = ["1", "2", "3"].map({ "'\($0)'" }).joined(separator: ",") print("value in (\(sss))") + +let number = NSNumber(7.0) +let number2 = NSNumber(7) + + + +print("number is double: \(number is Double)") +print("number is int: \(number is Int)") +print("number value: \(number)") +print("number type: \(number.objCType)") + extension NSNumber { + var type: CFNumberType { + return CFNumberGetType(self as CFNumber) + } + } + +print("number type: \(number.type)") +print("number2 type: \(number2.type)") + +let number3 = 7.0 + +print("number3 is Double: \(number3 is Double)") +print("number3 is Int: \(number3 is Int)") +print("number3 is NSNumber: \(number3 is NSNumber)") diff --git a/Example/GuruAnalytics/MyPlayground.playground/playground.xcworkspace/contents.xcworkspacedata b/Example/GuruAnalytics/MyPlayground.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/Example/GuruAnalytics/MyPlayground.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Example/GuruAnalytics/ViewController.swift b/Example/GuruAnalytics/ViewController.swift index c6d3892..64cebaa 100644 --- a/Example/GuruAnalytics/ViewController.swift +++ b/Example/GuruAnalytics/ViewController.swift @@ -23,15 +23,31 @@ class ViewController: UIViewController { @IBAction func setFirebaseId(_ sender: Any) { GuruAnalytics.setFirebaseId("2312:3XSFA0211231") + GuruAnalytics.setAppFlyersId("app_flyers_id:133323") } @IBAction func create(_ sender: Any) { GuruAnalytics.setScreen("home") GuruAnalytics.logEvent("crate_clk_" + String(Int(Date().timeIntervalSince1970)), parameters: ["category": "category_\(Int.random(in: 0...100000))", - "int_v_test": 2147483647, "double_v_test": 200.1, + "int_v_test": 2147483647, "double_v_test_1": 200.1, + "double_v_test_2": NSNumber(7.00), + "double_v_test_3": 7.00, "string_v_test": "400", - "long_v_test": Int64(1)]) + "long_v_test": Int64(1), + "long_v_test2": Int64.max, + "long_v_test3": Int64.min, + "value": 0.0]) + GuruAnalytics.logEvent("spend_virtual_currency", + parameters: ["theme_name": "theme_bg_0029", + "theme_category": "theme", + "virtural_currency_name": "coins", + "value": 100, + "balance": 33810, + "scene": "theme", + "level_name": "Instance of I'm 'SettingIntDat'", + ]) + } @IBAction func deleteItem(_ sender: Any) { diff --git a/Example/Podfile b/Example/Podfile index eb06f26..2c49ae0 100644 --- a/Example/Podfile +++ b/Example/Podfile @@ -7,7 +7,7 @@ platform :ios, '11.0' target 'GuruAnalytics_Example' do pod 'GuruAnalyticsLib', :path => '../' -# pod 'GuruAnalyticsLib', '0.3.8' +# pod 'GuruAnalyticsLib', '0.4.2' end post_install do |installer| diff --git a/GuruAnalytics/Classes/Interface/GuruAnalytics.swift b/GuruAnalytics/Classes/Interface/GuruAnalytics.swift index 15b4435..04821c7 100644 --- a/GuruAnalytics/Classes/Interface/GuruAnalytics.swift +++ b/GuruAnalytics/Classes/Interface/GuruAnalytics.swift @@ -34,7 +34,8 @@ public class GuruAnalytics: NSObject { initializeTimeout: Double = 5, saasXAPPID: String, saasXDEVICEINFO: String, - loggerDebug: Bool = true) { + loggerDebug: Bool = true, + guruSDKVersion: String) { Self.uploadPeriodInSecond = uploadPeriodInSecond Self.batchLimit = batchLimit Self.eventExpiredSeconds = eventExpiredSeconds @@ -42,6 +43,7 @@ public class GuruAnalytics: NSObject { Self.saasXAPPID = saasXAPPID Self.saasXDEVICEINFO = saasXDEVICEINFO Self.loggerDebug = loggerDebug + Constants.guruSDKVersion = guruSDKVersion _ = Manager.shared } @@ -81,6 +83,12 @@ public class GuruAnalytics: NSObject { setUserProperty(firebaseId, forName: .firebaseId) } + /// 设置appsflyerId + @objc + public class func setAppFlyersId(_ appFlyersId: String?) { + setUserProperty(appFlyersId, forName: .appsflyerId) + } + /// screen name @objc public class func setScreen(_ name: String) { @@ -155,4 +163,9 @@ public class GuruAnalytics: NSObject { enableUpload = isOn } + /// 设置中台库版本 + @objc + public class func setGuruSDKVersion(_ version: String) -> Void { + Constants.guruSDKVersion = version + } } diff --git a/GuruAnalytics/Classes/Internal/DataModel/Models.swift b/GuruAnalytics/Classes/Internal/DataModel/Models.swift index 805b660..458f844 100644 --- a/GuruAnalytics/Classes/Internal/DataModel/Models.swift +++ b/GuruAnalytics/Classes/Internal/DataModel/Models.swift @@ -157,21 +157,35 @@ extension Entity { } static func normalizeValue(_ value: Any) -> EventValue { + + var preprocessedValue = value + + if let val = preprocessedValue as? NSNumber { + preprocessedValue = val.numricValue + } + let eventValue: EventValue - if let value = value as? String { - eventValue = Entity.EventValue(stringValue: String(value.prefix(maxParameterStringValueLength))) - } else if let value = value as? Int { + if let value = preprocessedValue as? String { + eventValue = Entity.EventValue(stringValue: normalizeStringValue(String(value.prefix(maxParameterStringValueLength)))) + } else if let value = preprocessedValue as? Int { eventValue = Entity.EventValue(longValue: Int64(value)) - } else if let value = value as? Int64 { + } else if let value = preprocessedValue as? Int64 { eventValue = Entity.EventValue(longValue: value) - } else if let value = value as? Double { + } else if let value = preprocessedValue as? Double { eventValue = Entity.EventValue(doubleValue: value) } else { - eventValue = Entity.EventValue(stringValue: String("\(value)".prefix(maxParameterStringValueLength))) + eventValue = Entity.EventValue(stringValue: normalizeStringValue(String("\(value)".prefix(maxParameterStringValueLength)))) } return eventValue } + static func normalizeStringValue(_ value: String) -> String { + let normalizedString = value.replacingOccurrences(of: "'", with: "''") + cdPrint("original string value: \(value)") + cdPrint("normalized string value: \(normalizedString)") + return normalizedString + } + static func normalizeKey(_ key: String) -> String? { var mutableKey = key @@ -205,6 +219,8 @@ extension Entity { let adId: String? ///用户的pseudo_id let firebaseId: String? + ///appsFlyerId + let appsflyerId: String? ///IDFV let vendorId: String? = UIDevice().identifierForVendor?.uuidString @@ -216,6 +232,7 @@ extension Entity { case adId case firebaseId case vendorId + case appsflyerId } } diff --git a/GuruAnalytics/Classes/Internal/Database/Manager.swift b/GuruAnalytics/Classes/Internal/Database/Manager.swift index e16f3da..93dda90 100644 --- a/GuruAnalytics/Classes/Internal/Database/Manager.swift +++ b/GuruAnalytics/Classes/Internal/Database/Manager.swift @@ -270,7 +270,8 @@ internal extension Manager { deviceId: userProperty.removeValue(forKey: PropertyName.deviceId.rawValue), adjustId: userProperty.removeValue(forKey: PropertyName.adjustId.rawValue), adId: userProperty.removeValue(forKey: PropertyName.adId.rawValue), - firebaseId: userProperty.removeValue(forKey: PropertyName.firebaseId.rawValue) + firebaseId: userProperty.removeValue(forKey: PropertyName.firebaseId.rawValue), + appsflyerId: userProperty.removeValue(forKey: PropertyName.appsflyerId.rawValue) ) let event = try Entity.Event(timestamp: timestamp, diff --git a/GuruAnalytics/Classes/Internal/GuruAnalytics+Internal.swift b/GuruAnalytics/Classes/Internal/GuruAnalytics+Internal.swift index 598cf3c..02b9ac8 100644 --- a/GuruAnalytics/Classes/Internal/GuruAnalytics+Internal.swift +++ b/GuruAnalytics/Classes/Internal/GuruAnalytics+Internal.swift @@ -18,6 +18,7 @@ internal extension GuruAnalytics { case firebaseId case screen = "screen_name" case firstOpenTime = "first_open_time" + case appsflyerId } ///built-in events diff --git a/GuruAnalytics/Classes/Internal/Utility/Constants.swift b/GuruAnalytics/Classes/Internal/Utility/Constants.swift index 84152a0..70f2d95 100755 --- a/GuruAnalytics/Classes/Internal/Utility/Constants.swift +++ b/GuruAnalytics/Classes/Internal/Utility/Constants.swift @@ -26,7 +26,7 @@ internal struct Constants { return shortVersion }() - private static let sdkVersion: String = { + private static let guruAnalyticsSDKVersion: String = { guard let infoDict = Bundle(for: Manager.self).infoDictionary, let currentVersion = infoDict["CFBundleShortVersionString"] as? String else { return "" @@ -34,6 +34,9 @@ internal struct Constants { return currentVersion }() + /// 中台库版本,由外部更新 + static var guruSDKVersion: String = ""; + private static let preferredLocale: Locale = { guard let preferredIdentifier = Locale.preferredLanguages.first else { return Locale.current @@ -92,7 +95,8 @@ internal struct Constants { "screenW": Int(screenSize.w), "osVersion": systemVersion, "language" : languageCode, - "sdkVersion" : sdkVersion, + "guruAnalyticsVersion" : guruAnalyticsSDKVersion, + "gurusdkVersion" : guruSDKVersion, ] } @@ -102,6 +106,50 @@ internal struct Constants { /// - returns: raw `String` of device type, e.g. iPhone5,1 /// private static func hardwareString() -> String { + var name: [Int32] = [CTL_HW, HW_MACHINE] + var size: size_t = 0 + + // 🛡️ 安全检查1:获取缓冲区大小 + guard sysctl(&name, 2, nil, &size, nil, 0) == 0, + size > 0 && size < 256 else { + return "iPhone14,1" // 安全默认值 + } + + // 🛡️ 安全检查2:创建缓冲区 + let bufferSize = Int(size) + 1 + var hw_machine = [CChar](repeating: 0, count: bufferSize) + var actualSize = size + + // 🛡️ 安全检查3:获取数据 + guard sysctl(&name, 2, &hw_machine, &actualSize, nil, 0) == 0 else { + return "iPhone14,1" // 安全默认值 + } + + // 🛡️ 安全检查4:确保null终止(防止越界) + let safeIndex = min(Int(actualSize), bufferSize - 1) + hw_machine[safeIndex] = 0 + + var hardware: String = String(cString: hw_machine) + + // 🛡️ 安全检查5:验证结果 + if hardware.isEmpty { + return "iPhone14,1" // 安全默认值 + } + + // Check for simulator + if hardware == "x86_64" || hardware == "i386" || hardware == "arm64" { + if let deviceID = ProcessInfo.processInfo.environment["SIMULATOR_MODEL_IDENTIFIER"] { + hardware = deviceID + } else { + hardware = "Simulator" + } + } + + return hardware + } + + //这里不可用,有崩溃!!!用上边的方法!! + private static func hardwareStringError() -> String { var name: [Int32] = [CTL_HW, HW_MACHINE] var size: Int = 2 sysctl(&name, 2, nil, &size, nil, 0) @@ -116,10 +164,12 @@ internal struct Constants { hardware = deviceID } } - + return hardware } + + /// This method returns the Platform enum depending upon harware string /// /// diff --git a/GuruAnalytics/Classes/Internal/Utility/FoundationExtensions.swift b/GuruAnalytics/Classes/Internal/Utility/FoundationExtensions.swift new file mode 100644 index 0000000..5432b11 --- /dev/null +++ b/GuruAnalytics/Classes/Internal/Utility/FoundationExtensions.swift @@ -0,0 +1,43 @@ +// +// Untitled.swift +// Pods +// +// Created by mayue on 2025/1/14. +// + +extension NSNumber { + var valueType: CFNumberType { + return CFNumberGetType(self as CFNumber) + } + + var numricValue: Any { + switch valueType { + case .sInt8Type, + .sInt16Type, + .sInt32Type, + .charType, + .shortType, + .intType, + .longType, + .cfIndexType, + .nsIntegerType: + return intValue; + + case + .sInt64Type, + .longLongType: + return int64Value; + + case .float32Type, + .float64Type, + .floatType, + .doubleType, + .cgFloatType, + .maxType: + return doubleValue; + + @unknown default: + return doubleValue; + } + } +} diff --git a/GuruAnalyticsLib.podspec b/GuruAnalyticsLib.podspec index d1c3c63..69a47e3 100644 --- a/GuruAnalyticsLib.podspec +++ b/GuruAnalyticsLib.podspec @@ -8,7 +8,7 @@ Pod::Spec.new do |s| s.name = 'GuruAnalyticsLib' - s.version = '0.3.8' + s.version = '0.4.4' s.summary = 'A short description of GuruAnalytics.' # This description is used to generate tags and improve search results. @@ -25,7 +25,7 @@ TODO: Add long description of the pod here. # s.screenshots = 'www.example.com/screenshots_1', 'www.example.com/screenshots_2' s.license = { :type => 'MIT', :file => 'LICENSE' } s.author = { 'devSC' => 'xiaochong2154@163.com' } - s.source = { :git => 'git@github.com:castbox/GuruAnalytics_iOS.git', :tag => s.version.to_s } + s.source = { :git => 'git@git.chengdu.pundit.company:castbox/GuruAnalytics_iOS.git', :tag => s.version.to_s } # s.social_media_url = 'https://twitter.com/' s.ios.deployment_target = '11.0'