diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 54e3c4a22..337277402 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -9,7 +9,7 @@ on: jobs: build: name: Build and analyse default scheme using xcodebuild command - runs-on: macos-latest + runs-on: macos-15 # public preview, we want xcode 16.0 for swift testing steps: - name: Checkout @@ -18,4 +18,4 @@ jobs: env: scheme: RadarSDK run: | - xcodebuild clean build analyze test -scheme RadarSDK -workspace Example/Example.xcodeproj/project.xcworkspace -destination 'name=iPhone 15 Pro' | xcpretty && exit ${PIPESTATUS[0]} + xcodebuild clean build analyze test -scheme RadarSDK -workspace Example/Example.xcodeproj/project.xcworkspace -destination 'name=iPhone 16' | xcpretty && exit ${PIPESTATUS[0]} diff --git a/Example/Example/AppDelegate.swift b/Example/Example/AppDelegate.swift index 242ce587f..322baa607 100644 --- a/Example/Example/AppDelegate.swift +++ b/Example/Example/AppDelegate.swift @@ -29,7 +29,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UIWindowSceneDelegate, UN let radarInitializeOptions = RadarInitializeOptions() // Uncomment to enable automatic setup for notification conversions // radarInitializeOptions.autoSetupNotificationConversion = true - Radar.initialize(publishableKey: "prj_test_pk_0000000000000", options: radarInitializeOptions ) + Radar.initialize(publishableKey: "prj_test_pk_0000000000000000000000000000000000000000", options: radarInitializeOptions ) Radar.setUserId("testUserId") Radar.setMetadata([ "foo": "bar" ]) Radar.setDelegate(self) @@ -113,13 +113,13 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UIWindowSceneDelegate, UN demoButton(text: "getVerifiedLocationToken") { Radar.getVerifiedLocationToken() { (status, token) in - print("getVerifiedLocationToken: status = \(status); token = \(token?.dictionaryValue())") + print("getVerifiedLocationToken: status = \(Radar.stringForStatus(status)); token = \(String(describing: token?.dictionaryValue()))") } } demoButton(text: "trackVerified") { Radar.trackVerified() { (status, token) in - print("TrackVerified: status = \(status); token = \(token?.dictionaryValue())") + print("TrackVerified: status = \(Radar.stringForStatus(status)); token = \(String(describing: token?.dictionaryValue()))") } } diff --git a/RadarSDK.podspec b/RadarSDK.podspec index e1020f081..dbea10243 100644 --- a/RadarSDK.podspec +++ b/RadarSDK.podspec @@ -6,11 +6,12 @@ Pod::Spec.new do |s| s.author = { 'Radar Labs, Inc.' => 'support@radar.com' } s.platform = :ios s.source = { :git => 'https://github.com/radarlabs/radar-sdk-ios.git', :tag => s.version.to_s } - s.source_files = ["RadarSDK/*.{h,m}", "RadarSDK/Internal/*.{h,m}", "RadarSDK/Include/*.h"] + s.source_files = ["RadarSDK/*.{h,m,swift}", "RadarSDK/Include/*.h"] s.module_name = 'RadarSDK' s.ios.deployment_target = '10.0' s.frameworks = 'CoreLocation' s.requires_arc = true s.license = { :type => 'Apache-2.0' } s.resource_bundles = {'RadarSDK' => ['RadarSDK/PrivacyInfo.xcprivacy']} + s.swift_version = '5.0' end diff --git a/RadarSDK.xcodeproj/project.pbxproj b/RadarSDK.xcodeproj/project.pbxproj index b0d123452..48b858eb0 100644 --- a/RadarSDK.xcodeproj/project.pbxproj +++ b/RadarSDK.xcodeproj/project.pbxproj @@ -179,6 +179,10 @@ F65AF72C2C10B242002BA009 /* get_config_response.json in Resources */ = {isa = PBXBuildFile; fileRef = F65AF72B2C10B242002BA009 /* get_config_response.json */; }; F667F8272BFBF3C8001F2F67 /* RadarSdkConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = F667F8262BFBF3C8001F2F67 /* RadarSdkConfiguration.m */; }; F667F8292BFBF3D1001F2F67 /* RadarSdkConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = F667F8282BFBF3D1001F2F67 /* RadarSdkConfiguration.h */; }; + F69AA9602CE52FB1009CF18B /* RadarTelemetry.h in Headers */ = {isa = PBXBuildFile; fileRef = F69AA95F2CE52FAC009CF18B /* RadarTelemetry.h */; }; + F69AA9622CE52FC6009CF18B /* RadarTelemetry.swift in Sources */ = {isa = PBXBuildFile; fileRef = F69AA9612CE52FC6009CF18B /* RadarTelemetry.swift */; }; + F69AA9652CE53E08009CF18B /* RadarSDKTestsSwift.swift in Sources */ = {isa = PBXBuildFile; fileRef = F69AA9642CE53E08009CF18B /* RadarSDKTestsSwift.swift */; }; + F69AA9662CE53FAE009CF18B /* RadarTelemetry.swift in Sources */ = {isa = PBXBuildFile; fileRef = F69AA9612CE52FC6009CF18B /* RadarTelemetry.swift */; }; F6F959802C3D7D9900BC30FE /* RadarTimeZone.h in Headers */ = {isa = PBXBuildFile; fileRef = F6F9597F2C3D7D9900BC30FE /* RadarTimeZone.h */; settings = {ATTRIBUTES = (Public, ); }; }; F6F959822C3D7EA200BC30FE /* RadarTimeZone+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = F6F959812C3D7EA200BC30FE /* RadarTimeZone+Internal.h */; }; F6F959842C3D7EDE00BC30FE /* RadarTimeZone.m in Sources */ = {isa = PBXBuildFile; fileRef = F6F959832C3D7EDE00BC30FE /* RadarTimeZone.m */; }; @@ -356,6 +360,10 @@ F65AF72B2C10B242002BA009 /* get_config_response.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = get_config_response.json; sourceTree = ""; }; F667F8262BFBF3C8001F2F67 /* RadarSdkConfiguration.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RadarSdkConfiguration.m; sourceTree = ""; }; F667F8282BFBF3D1001F2F67 /* RadarSdkConfiguration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RadarSdkConfiguration.h; sourceTree = ""; }; + F69AA95F2CE52FAC009CF18B /* RadarTelemetry.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RadarTelemetry.h; sourceTree = ""; }; + F69AA9612CE52FC6009CF18B /* RadarTelemetry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadarTelemetry.swift; sourceTree = ""; }; + F69AA9632CE53E07009CF18B /* RadarSDKTests-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "RadarSDKTests-Bridging-Header.h"; sourceTree = ""; }; + F69AA9642CE53E08009CF18B /* RadarSDKTestsSwift.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadarSDKTestsSwift.swift; sourceTree = ""; }; F6F9597F2C3D7D9900BC30FE /* RadarTimeZone.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RadarTimeZone.h; sourceTree = ""; }; F6F959812C3D7EA200BC30FE /* RadarTimeZone+Internal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "RadarTimeZone+Internal.h"; sourceTree = ""; }; F6F959832C3D7EDE00BC30FE /* RadarTimeZone.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RadarTimeZone.m; sourceTree = ""; }; @@ -502,6 +510,8 @@ E6EEC56F2B20F45D00DD096B /* RadarFileStorage.m */, 96A5A11727ADA02E007B960B /* RadarDelegateHolder.h */, DD4C104925D87E3E009C2E36 /* RadarDelegateHolder.m */, + F69AA95F2CE52FAC009CF18B /* RadarTelemetry.h */, + F69AA9612CE52FC6009CF18B /* RadarTelemetry.swift */, DD236CF723088F8400EB88F9 /* RadarLocationManager.h */, DD236CF823088F8400EB88F9 /* RadarLocationManager.m */, 96A5A11527ADA02E007B960B /* RadarLog.h */, @@ -542,6 +552,7 @@ DD236C822308797B00EB88F9 /* RadarSDKTests */ = { isa = PBXGroup; children = ( + F69AA9632CE53E07009CF18B /* RadarSDKTests-Bridging-Header.h */, 96B465BB27D6732500D7119B /* CLLocation+RadarTests.m */, DD8E2F7824018C37002D51AB /* CLLocationManagerMock.h */, DD8E2F7924018C37002D51AB /* CLLocationManagerMock.m */, @@ -551,6 +562,7 @@ DD8E2F7524018C25002D51AB /* RadarAPIHelperMock.h */, DD8E2F7624018C25002D51AB /* RadarAPIHelperMock.m */, DD8E2F7224018C17002D51AB /* RadarPermissionsHelperMock.h */, + F69AA9642CE53E08009CF18B /* RadarSDKTestsSwift.swift */, DD8E2F7324018C17002D51AB /* RadarPermissionsHelperMock.m */, DD103210237E0C47003DD408 /* RadarSDKTests.m */, DD8E2F6F24018BF8002D51AB /* RadarTestUtils.h */, @@ -672,6 +684,7 @@ 96A5A10427AD9F7F007B960B /* RadarDelegate.h in Headers */, 01F810702AF0119800BD7088 /* RadarVerifiedDelegate.h in Headers */, 96A5A0CA27AD9F41007B960B /* RadarTrip+Internal.h in Headers */, + F69AA9602CE52FB1009CF18B /* RadarTelemetry.h in Headers */, 96A5A0FF27AD9F7F007B960B /* RadarGeofenceGeometry.h in Headers */, 96A5A0CB27AD9F41007B960B /* RadarRoute+Internal.h in Headers */, 96A5A10527AD9F7F007B960B /* RadarTrackingOptions.h in Headers */, @@ -767,14 +780,14 @@ TargetAttributes = { 0107A9E72621FFB9008AB52F = { CreatedOnToolsVersion = 12.4; - LastSwiftMigration = 1320; + LastSwiftMigration = 1610; }; 0107AB3826220308008AB52F = { CreatedOnToolsVersion = 12.4; }; DD236C7D2308797B00EB88F9 = { CreatedOnToolsVersion = 11.0; - LastSwiftMigration = 1320; + LastSwiftMigration = 1610; }; }; }; @@ -886,6 +899,7 @@ 96FC90F7277379C1000757DF /* RadarFraud.m in Sources */, F6F959842C3D7EDE00BC30FE /* RadarTimeZone.m in Sources */, 0107AB1D262201E5008AB52F /* RadarLocationManager.m in Sources */, + F69AA9622CE52FC6009CF18B /* RadarTelemetry.swift in Sources */, 0107AAB02622016B008AB52F /* RadarPlace.m in Sources */, 0107AAE6262201A1008AB52F /* RadarSegment.m in Sources */, 0107AB20262201E9008AB52F /* RadarPermissionsHelper.m in Sources */, @@ -922,8 +936,10 @@ DD8E2F7424018C17002D51AB /* RadarPermissionsHelperMock.m in Sources */, DD8E2F7724018C25002D51AB /* RadarAPIHelperMock.m in Sources */, E658DB0A2CB462AA004E0F01 /* RadarOperatingHour.m in Sources */, + F69AA9652CE53E08009CF18B /* RadarSDKTestsSwift.swift in Sources */, 96B465BC27D6732500D7119B /* CLLocation+RadarTests.m in Sources */, E6B93B742C90E5B8003CB858 /* RadarInitializeOptions.m in Sources */, + F69AA9662CE53FAE009CF18B /* RadarTelemetry.swift in Sources */, DD103211237E0C47003DD408 /* RadarSDKTests.m in Sources */, DD8E2F7124018BF9002D51AB /* RadarTestUtils.m in Sources */, DD8E2F7D24018C54002D51AB /* CLVisitMock.m in Sources */, @@ -937,6 +953,7 @@ 0107A9ED2621FFB9008AB52F /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_ENABLE_MODULES = YES; CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO; CODE_SIGN_STYLE = Manual; CURRENT_PROJECT_VERSION = 1; @@ -959,6 +976,8 @@ PROVISIONING_PROFILE_SPECIFIER = ""; "PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = ""; SKIP_INSTALL = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; TVOS_DEPLOYMENT_TARGET = 10.0; }; @@ -967,6 +986,7 @@ 0107A9EE2621FFB9008AB52F /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_ENABLE_MODULES = YES; CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO; CODE_SIGN_STYLE = Manual; CURRENT_PROJECT_VERSION = 1; @@ -989,6 +1009,7 @@ PROVISIONING_PROFILE_SPECIFIER = ""; "PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = ""; SKIP_INSTALL = YES; + SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; TVOS_DEPLOYMENT_TARGET = 10.0; }; @@ -1143,6 +1164,7 @@ DEVELOPMENT_TEAM = 96GHH65B9D; HEADER_SEARCH_PATHS = "$(SRCROOT)/RadarSDK"; INFOPLIST_FILE = RadarSDKTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 15.6; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -1151,6 +1173,7 @@ OTHER_LDFLAGS = "-ObjC"; PRODUCT_BUNDLE_IDENTIFIER = io.radar.RadarSDKTests; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "RadarSDKTests/RadarSDKTests-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -1165,6 +1188,7 @@ DEVELOPMENT_TEAM = 96GHH65B9D; HEADER_SEARCH_PATHS = "$(SRCROOT)/RadarSDK"; INFOPLIST_FILE = RadarSDKTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 15.6; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -1173,6 +1197,7 @@ OTHER_LDFLAGS = "-ObjC"; PRODUCT_BUNDLE_IDENTIFIER = io.radar.RadarSDKTests; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "RadarSDKTests/RadarSDKTests-Bridging-Header.h"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; diff --git a/RadarSDK/Include/Radar.h b/RadarSDK/Include/Radar.h index 06e165956..73f4fbc62 100644 --- a/RadarSDK/Include/Radar.h +++ b/RadarSDK/Include/Radar.h @@ -128,6 +128,8 @@ typedef NS_ENUM(NSInteger, RadarLogType) { RadarLogTypeAppLifecycleEvent = 4, /// Permission Event RadarLogTypePermissionEvent = 5, + /// Telemetry + RadarLogTypeTelemetry = 6, }; /** diff --git a/RadarSDK/Radar.m b/RadarSDK/Radar.m index 247056401..18932edaf 100644 --- a/RadarSDK/Radar.m +++ b/RadarSDK/Radar.m @@ -23,6 +23,7 @@ #import "RadarReplayBuffer.h" #import "RadarNotificationHelper.h" #import "RadarTripOptions.h" +#import "RadarTelemetry.h" @interface Radar () @@ -175,10 +176,17 @@ + (void)trackOnceWithCompletionHandler:(RadarTrackCompletionHandler)completionHa } + (void)trackOnceWithDesiredAccuracy:(RadarTrackingOptionsDesiredAccuracy)desiredAccuracy beacons:(BOOL)beacons completionHandler:(RadarTrackCompletionHandler)completionHandler { + + RadarTelemetry* telemetry = [[RadarTelemetry alloc] init]; + [telemetry start:@"total"]; + [telemetry start:@"getLocation"]; + [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelInfo type:RadarLogTypeSDKCall message:@"trackOnce()"]; [[RadarLocationManager sharedInstance] getLocationWithDesiredAccuracy:desiredAccuracy completionHandler:^(RadarStatus status, CLLocation *_Nullable location, BOOL stopped) { + [telemetry end:@"getLocation"]; + if (status != RadarStatusSuccess) { if (completionHandler) { [RadarUtils runOnMainThread:^{ @@ -190,6 +198,7 @@ + (void)trackOnceWithDesiredAccuracy:(RadarTrackingOptionsDesiredAccuracy)desire } void (^callTrackAPI)(NSArray *_Nullable) = ^(NSArray *_Nullable beacons) { + [telemetry start:@"trackAPI"]; [[RadarAPIClient sharedInstance] trackWithLocation:location stopped:stopped @@ -199,6 +208,9 @@ + (void)trackOnceWithDesiredAccuracy:(RadarTrackingOptionsDesiredAccuracy)desire beacons:beacons completionHandler:^(RadarStatus status, NSDictionary *_Nullable res, NSArray *_Nullable events, RadarUser *_Nullable user, NSArray *_Nullable nearbyGeofences, RadarConfig *_Nullable config, RadarVerifiedLocationToken *_Nullable token) { + [telemetry end:@"trackAPI"]; + [telemetry end:@"total"]; + if (status == RadarStatusSuccess) { [[RadarLocationManager sharedInstance] replaceSyncedGeofences:nearbyGeofences]; if (config != nil) { @@ -207,6 +219,11 @@ + (void)trackOnceWithDesiredAccuracy:(RadarTrackingOptionsDesiredAccuracy)desire } + [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelInfo + type:RadarLogTypeTelemetry + message:[NSString stringWithFormat:@"trackOnce | %@", + [telemetry formatted]]]; + if (completionHandler) { [RadarUtils runOnMainThread:^{ completionHandler(status, location, events, user); @@ -216,18 +233,22 @@ + (void)trackOnceWithDesiredAccuracy:(RadarTrackingOptionsDesiredAccuracy)desire }; if (beacons) { + [telemetry start:@"getBeacons"]; [[RadarAPIClient sharedInstance] searchBeaconsNear:location radius:1000 limit:10 completionHandler:^(RadarStatus status, NSDictionary *_Nullable res, NSArray *_Nullable beacons, NSArray *_Nullable beaconUUIDs) { + [telemetry end:@"getBeacons"]; if (beaconUUIDs && beaconUUIDs.count) { [[RadarLocationManager sharedInstance] replaceSyncedBeaconUUIDs:beaconUUIDs]; [RadarUtils runOnMainThread:^{ + [telemetry start:@"rangeBeacons"]; [[RadarBeaconManager sharedInstance] rangeBeaconUUIDs:beaconUUIDs completionHandler:^(RadarStatus status, NSArray *_Nullable beacons) { + [telemetry end:@"rangeBeacons"]; if (status != RadarStatusSuccess || !beacons) { callTrackAPI(nil); @@ -241,8 +262,10 @@ + (void)trackOnceWithDesiredAccuracy:(RadarTrackingOptionsDesiredAccuracy)desire [[RadarLocationManager sharedInstance] replaceSyncedBeacons:beacons]; [RadarUtils runOnMainThread:^{ + [telemetry start:@"rangeBeacons"]; [[RadarBeaconManager sharedInstance] rangeBeacons:beacons completionHandler:^(RadarStatus status, NSArray *_Nullable beacons) { + [telemetry end:@"rangeBeacons"]; if (status != RadarStatusSuccess || !beacons) { callTrackAPI(nil); diff --git a/RadarSDK/RadarAPIClient.m b/RadarSDK/RadarAPIClient.m index 189d15068..b085ef5ea 100644 --- a/RadarSDK/RadarAPIClient.m +++ b/RadarSDK/RadarAPIClient.m @@ -33,6 +33,7 @@ #import "RadarUtils.h" #import "RadarVerificationManager.h" #import "RadarVerifiedLocationToken+Internal.h" + #import @implementation RadarAPIClient diff --git a/RadarSDK/RadarLog.m b/RadarSDK/RadarLog.m index 0aaff4b9a..41ecc2f84 100644 --- a/RadarSDK/RadarLog.m +++ b/RadarSDK/RadarLog.m @@ -80,6 +80,9 @@ + (NSString *)stringForLogType:(RadarLogType)type { case RadarLogTypePermissionEvent: str = @"PERMISSION_EVENT"; break; + case RadarLogTypeTelemetry: + str = @"TELEMETRY"; + break; } return str; } diff --git a/RadarSDK/RadarTelemetry.h b/RadarSDK/RadarTelemetry.h new file mode 100644 index 000000000..ea1c0483a --- /dev/null +++ b/RadarSDK/RadarTelemetry.h @@ -0,0 +1,18 @@ +// +// RadarProfiler.h +// RadarSDK +// +// Copyright © 2024 Radar Labs, Inc. All rights reserved. +// + +#import + + +@interface RadarTelemetry: NSObject + +- (void)start:(NSString*_Nullable)tag; +- (void)end:(NSString*_Nullable)tag; +- (double)get:(NSString*_Nullable)tag; +- (NSString*_Nonnull)formatted; + +@end diff --git a/RadarSDK/RadarTelemetry.swift b/RadarSDK/RadarTelemetry.swift new file mode 100644 index 000000000..30eb8798a --- /dev/null +++ b/RadarSDK/RadarTelemetry.swift @@ -0,0 +1,39 @@ +// +// RadarProfiler.swift +// RadarSDK +// +// Copyright © 2024 Radar Labs, Inc. All rights reserved. +// + +import Foundation + +@objc(RadarTelemetry) class RadarTelemetry: NSObject { + + var startTimes = [String:Double]() + var endTimes = [String:Double]() + + @objc func start(_ tag: String = "") { + startTimes[tag] = CFAbsoluteTimeGetCurrent() + } + + @objc func end(_ tag: String = "") { + if (startTimes[tag] != nil) { + endTimes[tag] = CFAbsoluteTimeGetCurrent() + } + } + + @objc func get(_ tag: String = "") -> Double { + if let start = startTimes[tag], + let end = endTimes[tag] { + return (end - start) + } else { + return 0; + } + } + + @objc func formatted() -> String { + return endTimes.map { (tag, end) in + String(format: "%@: %.3f", tag, end - startTimes[tag]!) + }.joined(separator: ", ") + } +} diff --git a/RadarSDK/RadarVerificationManager.m b/RadarSDK/RadarVerificationManager.m index 2f189a4a7..59404ea4f 100644 --- a/RadarSDK/RadarVerificationManager.m +++ b/RadarSDK/RadarVerificationManager.m @@ -21,6 +21,7 @@ #import "RadarLogger.h" #import "RadarState.h" #import "RadarUtils.h" +#import "RadarTelemetry.h" #include #include @@ -74,10 +75,15 @@ - (void)trackVerifiedWithCompletionHandler:(RadarTrackVerifiedCompletionHandler) - (void)trackVerifiedWithBeacons:(BOOL)beacons completionHandler:(RadarTrackVerifiedCompletionHandler)completionHandler { BOOL lastTokenBeacons = beacons; + RadarTelemetry* telemetry = [[RadarTelemetry alloc] init]; + [telemetry start:@"total"]; + [telemetry start:@"getConfig"]; + [[RadarAPIClient sharedInstance] getConfigForUsage:@"verify" verified:YES completionHandler:^(RadarStatus status, RadarConfig *_Nullable config) { + [telemetry end:@"getConfig"]; if (status != RadarStatusSuccess || !config) { if (completionHandler) { [RadarUtils runOnMainThread:^{ @@ -87,9 +93,11 @@ - (void)trackVerifiedWithBeacons:(BOOL)beacons completionHandler:(RadarTrackVeri return; } + [telemetry start:@"getLocation"]; [[RadarLocationManager sharedInstance] getLocationWithDesiredAccuracy:RadarTrackingOptionsDesiredAccuracyMedium completionHandler:^(RadarStatus status, CLLocation *_Nullable location, BOOL stopped) { + [telemetry end:@"getLocation"]; if (status != RadarStatusSuccess) { if (completionHandler) { [RadarUtils runOnMainThread:^{ @@ -100,9 +108,13 @@ - (void)trackVerifiedWithBeacons:(BOOL)beacons completionHandler:(RadarTrackVeri return; } + + [telemetry start:@"getAttestToken"]; [self getAttestationWithNonce:config.nonce completionHandler:^(NSString *_Nullable attestationString, NSString *_Nullable keyId, NSString *_Nullable attestationError) { + [telemetry end:@"getAttestToken"]; void (^callTrackAPI)(NSArray *_Nullable) = ^(NSArray *_Nullable beacons) { + [telemetry start:@"trackAPI"]; [[RadarAPIClient sharedInstance] trackWithLocation:location stopped:RadarState.stopped @@ -120,6 +132,13 @@ - (void)trackVerifiedWithBeacons:(BOOL)beacons completionHandler:(RadarTrackVeri completionHandler:^(RadarStatus status, NSDictionary *_Nullable res, NSArray *_Nullable events, RadarUser *_Nullable user, NSArray *_Nullable nearbyGeofences, RadarConfig *_Nullable config, RadarVerifiedLocationToken *_Nullable token) { + [telemetry end:@"trackAPI"]; + [telemetry end:@"total"]; + [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelInfo + type:RadarLogTypeTelemetry + message:[NSString stringWithFormat:@"trackVerified | %@", + [telemetry formatted]]]; + if (status == RadarStatusSuccess && config != nil) { [[RadarLocationManager sharedInstance] updateTrackingFromMeta:config.meta]; } @@ -137,17 +156,21 @@ - (void)trackVerifiedWithBeacons:(BOOL)beacons completionHandler:(RadarTrackVeri }; if (beacons) { + [telemetry start:@"getBeacons"]; [[RadarAPIClient sharedInstance] searchBeaconsNear:location radius:1000 limit:10 completionHandler:^(RadarStatus status, NSDictionary *_Nullable res, NSArray *_Nullable beacons, NSArray *_Nullable beaconUUIDs) { + [telemetry end:@"getBeacons"]; if (beaconUUIDs && beaconUUIDs.count) { + [telemetry start:@"rangeBeacons"]; [RadarUtils runOnMainThread:^{ [[RadarBeaconManager sharedInstance] rangeBeaconUUIDs:beaconUUIDs completionHandler:^(RadarStatus status, NSArray *_Nullable beacons) { + [telemetry end:@"rangeBeacons"]; if (status != RadarStatusSuccess || !beacons) { callTrackAPI(nil); @@ -158,10 +181,12 @@ - (void)trackVerifiedWithBeacons:(BOOL)beacons completionHandler:(RadarTrackVeri }]; }]; } else if (beacons && beacons.count) { + [telemetry start:@"rangeBeacons"]; [RadarUtils runOnMainThread:^{ [[RadarBeaconManager sharedInstance] rangeBeacons:beacons completionHandler:^(RadarStatus status, NSArray *_Nullable beacons) { + [telemetry end:@"rangeBeacons"]; if (status != RadarStatusSuccess || !beacons) { callTrackAPI(nil); diff --git a/RadarSDKTests/RadarSDKTests-Bridging-Header.h b/RadarSDKTests/RadarSDKTests-Bridging-Header.h new file mode 100644 index 000000000..1b2cb5d6d --- /dev/null +++ b/RadarSDKTests/RadarSDKTests-Bridging-Header.h @@ -0,0 +1,4 @@ +// +// Use this file to import your target's public headers that you would like to expose to Swift. +// + diff --git a/RadarSDKTests/RadarSDKTestsSwift.swift b/RadarSDKTests/RadarSDKTestsSwift.swift new file mode 100644 index 000000000..be75114f6 --- /dev/null +++ b/RadarSDKTests/RadarSDKTestsSwift.swift @@ -0,0 +1,39 @@ +// +// RadarSDKTests.swift +// RadarSDKTests +// +// Copyright © 2024 Radar Labs, Inc. All rights reserved. +// + +import Foundation +import Testing + +@Suite("SDK Tests") +struct RadarSDKTestsSwift { + + @Test func test_profiler() async throws { + let telemetry = RadarTelemetry() + telemetry.start("total") + telemetry.start("test") + + usleep(1500000) + + telemetry.end("test") + + #expect(telemetry.formatted() == String(format: "test: %.3f", telemetry.get("test"))) + + telemetry.start("other") + + usleep(1000000) + + telemetry.end("other") + telemetry.end("total") + + #expect(telemetry.get("other") < telemetry.get("test")) + #expect(telemetry.get("total") >= telemetry.get("test") + telemetry.get("other")) + + #expect(telemetry.formatted().contains(String(format: "other: %.3f", telemetry.get("other")))) + #expect(telemetry.formatted().contains(String(format: "total: %.3f", telemetry.get("total")))) + #expect(telemetry.formatted().contains(String(format: "test: %.3f", telemetry.get("test")))) + } +}