diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml
index 54e3c4a22..c1d95c987 100644
--- a/.github/workflows/build-and-test.yml
+++ b/.github/workflows/build-and-test.yml
@@ -14,6 +14,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v2
+
- name: Build, Analyze, & Test
env:
scheme: RadarSDK
diff --git a/.github/workflows/release-sdk.yml b/.github/workflows/release-sdk.yml
index 0c9826734..d59c3739a 100644
--- a/.github/workflows/release-sdk.yml
+++ b/.github/workflows/release-sdk.yml
@@ -74,12 +74,22 @@ jobs:
event-type: update-xcframework
client-payload: '{"release": "${{ github.event.release.tag_name }}", "checksum": "${{ steps.checksum_radarsdk.outputs.checksum }}", "url": "${{ github.event.release.html_url }}", "checksum_motion": "${{ steps.checksum_radarsdkmotion.outputs.checksum }}"}'
+ - name: Check versions is not duplicate
+ run: |
+ VERSION=$(pod ipc spec RadarSDK.podspec | jq -r .version)
+ ! pod trunk info RadarSDK | grep -q $VERSION
+ echo "RadarSDK version is OK"
+ VERSION=$(pod ipc spec RadarSDKMotion.podspec | jq -r .version)
+ ! pod trunk info RadarSDKMotion | grep -q $VERSION
+ echo "RadarSDKMotion version is OK"
+
- name: Deploy to Cocoapods
run: |
set -eo pipefail
+ gem install cocoapods
pod lib lint --allow-warnings RadarSDK.podspec
- pod trunk push --allow-warnings RadarSDK.podspec
pod lib lint --allow-warnings RadarSDKMotion.podspec
+ pod trunk push --allow-warnings RadarSDK.podspec
pod trunk push --allow-warnings RadarSDKMotion.podspec
env:
- COCOAPODS_TRUNK_TOKEN: ${{ secrets.COCOAPODS_TRUNK_TOKEN }}
\ No newline at end of file
+ COCOAPODS_TRUNK_TOKEN: ${{ secrets.COCOAPODS_TRUNK_TOKEN }}
diff --git a/Example/Example.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/Example/Example.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
new file mode 100644
index 000000000..0c67376eb
--- /dev/null
+++ b/Example/Example.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/Example/Example/AppDelegate.swift b/Example/Example/AppDelegate.swift
index b872f92fd..b266b98ad 100644
--- a/Example/Example/AppDelegate.swift
+++ b/Example/Example/AppDelegate.swift
@@ -131,6 +131,14 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UIWindowSceneDelegate, UN
}
}
+ demoButton(text: "startVerifyServer") {
+ Radar.startVerifyServer()
+ }
+
+ demoButton(text: "stopVerifyServer") {
+ Radar.stopVerifyServer()
+ }
+
demoButton(text: "searchPlaces") {
// In the Radar dashboard settings
// (https://radar.com/dashboard/settings), add this to the chain
diff --git a/Example/Example/Package.swift b/Example/Example/Package.swift
new file mode 100644
index 000000000..f2f11ba84
--- /dev/null
+++ b/Example/Example/Package.swift
@@ -0,0 +1,13 @@
+// swift-tools-version:5.8
+import PackageDescription
+
+let package = Package(
+ name: "MyProject",
+ dependencies: [
+ .package(url: "https//github.com/apple/swift-nio.git", from: "2.0.0"),
+ .package(url: "https://github.com/apple/swift-nio-ssl.git", from: "2.0.0")
+ ],
+ targets: [
+ .target(name: "MyProject", dependencies: ["NIO", "NIOSSL"]),
+ ]
+)
diff --git a/Package.swift b/Package.swift
index 526f226ef..8b2dfd6e1 100644
--- a/Package.swift
+++ b/Package.swift
@@ -4,7 +4,7 @@ import PackageDescription
let package = Package(
name: "RadarSDK",
platforms: [
- .iOS(.v10)
+ .iOS(.v12)
],
products: [
.library(
@@ -16,7 +16,10 @@ let package = Package(
targets: ["RadarSDKMotion"]
)
],
- dependencies: [],
+ dependencies: [
+ .package(url: "https://github.com/apple/swift-nio.git", from: "2.62.0"),
+ .package(url: "https://github.com/apple/swift-nio-ssl.git", from: "2.25.0")
+ ],
targets: [
.target(
name: "RadarSDK",
@@ -26,6 +29,10 @@ let package = Package(
publicHeadersPath: "Include",
cSettings: [
.headerSearchPath(".")
+ ],
+ dependencies: [
+ .product(name: "NIO", package: "swift-nio"),
+ .product(name: "NIOHTTP1", package: "swift-nio")
]
),
.target(
@@ -35,7 +42,7 @@ let package = Package(
publicHeadersPath: "Include",
cSettings: [
.headerSearchPath(".")
- ]
+ ]
)
]
)
diff --git a/RadarSDK.podspec b/RadarSDK.podspec
index 91b13e184..c92ecf36e 100644
--- a/RadarSDK.podspec
+++ b/RadarSDK.podspec
@@ -1,16 +1,17 @@
Pod::Spec.new do |s|
s.name = 'RadarSDK'
- s.version = '3.19.0'
+ s.version = '3.19.1'
s.summary = 'iOS SDK for Radar, the leading geofencing and location tracking platform'
s.homepage = 'https://radar.com'
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.ios.deployment_target = '12.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 40cb91daf..97679c973 100644
--- a/RadarSDK.xcodeproj/project.pbxproj
+++ b/RadarSDK.xcodeproj/project.pbxproj
@@ -69,8 +69,8 @@
0107AB2F262201FB008AB52F /* RadarUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = DD236D0423099B8400EB88F9 /* RadarUtils.m */; };
0107AB7A2622061A008AB52F /* RadarSDK.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0107A9E82621FFB9008AB52F /* RadarSDK.framework */; };
0114F058284EFDB700ADA4E4 /* RadarRouteMode.h in Headers */ = {isa = PBXBuildFile; fileRef = 0114F057284EFDB700ADA4E4 /* RadarRouteMode.h */; settings = {ATTRIBUTES = (Public, ); }; };
- 015C53AD29B8E8BA004F53A6 /* (null) in Headers */ = {isa = PBXBuildFile; };
- 015C53AE29B8E8BA004F53A6 /* (null) in Sources */ = {isa = PBXBuildFile; };
+ 0158673E2CEB3B83007BEAC0 /* RadarVerifyServer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0158673D2CEB3B83007BEAC0 /* RadarVerifyServer.swift */; };
+ 015867572CEB5071007BEAC0 /* RadarVerifyServer.h in Headers */ = {isa = PBXBuildFile; fileRef = 015867562CEB5071007BEAC0 /* RadarVerifyServer.h */; };
019514362BD078D90031ABA2 /* RadarVerifiedLocationToken.h in Headers */ = {isa = PBXBuildFile; fileRef = 019514352BD077D10031ABA2 /* RadarVerifiedLocationToken.h */; settings = {ATTRIBUTES = (Public, ); }; };
019514392BD081630031ABA2 /* RadarVerifiedLocationToken.m in Sources */ = {isa = PBXBuildFile; fileRef = 019514372BD081630031ABA2 /* RadarVerifiedLocationToken.m */; };
0195143A2BD081630031ABA2 /* RadarVerifiedLocationToken+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 019514382BD081630031ABA2 /* RadarVerifiedLocationToken+Internal.h */; };
@@ -188,6 +188,8 @@
0107A9E82621FFB9008AB52F /* RadarSDK.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = RadarSDK.framework; sourceTree = BUILT_PRODUCTS_DIR; };
0113020E2AE1467800EFC377 /* Network.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Network.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX13.3.sdk/System/Library/PrivateFrameworks/Network.framework; sourceTree = DEVELOPER_DIR; };
0114F057284EFDB700ADA4E4 /* RadarRouteMode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RadarRouteMode.h; sourceTree = ""; };
+ 0158673D2CEB3B83007BEAC0 /* RadarVerifyServer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadarVerifyServer.swift; sourceTree = ""; };
+ 015867562CEB5071007BEAC0 /* RadarVerifyServer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RadarVerifyServer.h; sourceTree = ""; };
019514352BD077D10031ABA2 /* RadarVerifiedLocationToken.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RadarVerifiedLocationToken.h; sourceTree = ""; };
019514372BD081630031ABA2 /* RadarVerifiedLocationToken.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RadarVerifiedLocationToken.m; sourceTree = ""; };
019514382BD081630031ABA2 /* RadarVerifiedLocationToken+Internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "RadarVerifiedLocationToken+Internal.h"; sourceTree = ""; };
@@ -533,6 +535,8 @@
DD236D0423099B8400EB88F9 /* RadarUtils.m */,
82F7FAEC2A65FE030055AA4B /* RadarVerificationManager.h */,
82F7FAED2A65FE030055AA4B /* RadarVerificationManager.m */,
+ 015867562CEB5071007BEAC0 /* RadarVerifyServer.h */,
+ 0158673D2CEB3B83007BEAC0 /* RadarVerifyServer.swift */,
DD27CB7D235D13F000299FEC /* Models */,
53CCD781275E576B00F79CC8 /* Util */,
);
@@ -574,8 +578,8 @@
96A5A0BA27AD9F41007B960B /* RadarContext+Internal.h */,
5343FFD923E38BA300808D93 /* RadarContext.m */,
96A5A0B627AD9F40007B960B /* RadarCoordinate+Internal.h */,
- 96A5A0B927AD9F41007B960B /* RadarEvent+Internal.h */,
DD236CBA2308812700EB88F9 /* RadarCoordinate.m */,
+ 96A5A0B927AD9F41007B960B /* RadarEvent+Internal.h */,
DD236CB82308812700EB88F9 /* RadarEvent.m */,
96A5A0AD27AD9F40007B960B /* RadarFraud+Internal.h */,
96FC90F6277379C1000757DF /* RadarFraud.m */,
@@ -678,7 +682,6 @@
96A5A10927AD9F7F007B960B /* RadarContext.h in Headers */,
0107AA1226220049008AB52F /* RadarCollectionAdditions.h in Headers */,
E6EEC56E2B20F41A00DD096B /* RadarFileStorage.h in Headers */,
- 015C53AD29B8E8BA004F53A6 /* (null) in Headers */,
0107AA1C26220055008AB52F /* RadarPermissionsHelper.h in Headers */,
96A5A11227AD9F7F007B960B /* Radar.h in Headers */,
96A5A10827AD9F7F007B960B /* RadarSegment.h in Headers */,
@@ -711,6 +714,7 @@
96A5A10127AD9F7F007B960B /* RadarRoute.h in Headers */,
96A5A0FE27AD9F7F007B960B /* RadarTrip.h in Headers */,
96A5A10027AD9F7F007B960B /* RadarCoordinate.h in Headers */,
+ 015867572CEB5071007BEAC0 /* RadarVerifyServer.h in Headers */,
532FC304277A790600989279 /* Radar+Internal.h in Headers */,
96A5A0FB27AD9F7F007B960B /* RadarChain.h in Headers */,
);
@@ -767,7 +771,7 @@
TargetAttributes = {
0107A9E72621FFB9008AB52F = {
CreatedOnToolsVersion = 12.4;
- LastSwiftMigration = 1320;
+ LastSwiftMigration = 1610;
};
0107AB3826220308008AB52F = {
CreatedOnToolsVersion = 12.4;
@@ -868,7 +872,6 @@
8227EF0C2CDAB69B00C47290 /* RadarRouteMode.m in Sources */,
9683FD6527B36C26009EBB6B /* RadarMeta.m in Sources */,
0107AA9B26220153008AB52F /* RadarContext.m in Sources */,
- 015C53AE29B8E8BA004F53A6 /* (null) in Sources */,
0107AB23262201EC008AB52F /* RadarSettings.m in Sources */,
0107AAAA26220165008AB52F /* RadarGeofenceGeometry.m in Sources */,
0107AAEC262201A6008AB52F /* RadarTrip.m in Sources */,
@@ -897,6 +900,7 @@
0107AA832622013A008AB52F /* RadarBeacon.m in Sources */,
82F7FAEB2A65FDD50055AA4B /* RadarNotificationHelper.m in Sources */,
0107AAB626220172008AB52F /* RadarPolygonGeometry.m in Sources */,
+ 0158673E2CEB3B83007BEAC0 /* RadarVerifyServer.swift in Sources */,
0107AB0E262201D5008AB52F /* RadarBeaconManager.m in Sources */,
82D04AC729771BF10036619F /* RadarReplay.m in Sources */,
0107AADA26220195008AB52F /* RadarRouteMatrix.m in Sources */,
@@ -937,6 +941,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;
@@ -947,26 +952,28 @@
DYLIB_INSTALL_NAME_BASE = "@rpath";
INFOPLIST_FILE = RadarSDK/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
- IPHONEOS_DEPLOYMENT_TARGET = 10.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 12.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
- MARKETING_VERSION = 3.9.6;
PRODUCT_BUNDLE_IDENTIFIER = io.radar.sdk;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
PROVISIONING_PROFILE_SPECIFIER = "";
"PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = "";
SKIP_INSTALL = YES;
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ SWIFT_VERSION = 6.0;
TARGETED_DEVICE_FAMILY = "1,2";
- TVOS_DEPLOYMENT_TARGET = 10.0;
+ TVOS_DEPLOYMENT_TARGET = 12.0;
};
name = Debug;
};
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;
@@ -977,20 +984,20 @@
DYLIB_INSTALL_NAME_BASE = "@rpath";
INFOPLIST_FILE = RadarSDK/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
- IPHONEOS_DEPLOYMENT_TARGET = 10.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 12.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
- MARKETING_VERSION = 3.9.6;
PRODUCT_BUNDLE_IDENTIFIER = io.radar.sdk;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
PROVISIONING_PROFILE_SPECIFIER = "";
"PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = "";
SKIP_INSTALL = YES;
+ SWIFT_VERSION = 6.0;
TARGETED_DEVICE_FAMILY = "1,2";
- TVOS_DEPLOYMENT_TARGET = 10.0;
+ TVOS_DEPLOYMENT_TARGET = 12.0;
};
name = Release;
};
@@ -1065,8 +1072,8 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 10.0;
- MARKETING_VERSION = 3.19.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 12.0;
+ MARKETING_VERSION = 3.19.1;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
@@ -1123,8 +1130,8 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 10.0;
- MARKETING_VERSION = 3.19.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 12.0;
+ MARKETING_VERSION = 3.19.1;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
OTHER_CFLAGS = "-fembed-bitcode";
diff --git a/RadarSDK.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/RadarSDK.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
new file mode 100644
index 000000000..f5cc1804f
--- /dev/null
+++ b/RadarSDK.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
@@ -0,0 +1,51 @@
+{
+ "originHash" : "5b93791d19b1fba6dd03f2def460785e85cc17099b7c47acd513cd259380ff0c",
+ "pins" : [
+ {
+ "identity" : "swift-atomics",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/apple/swift-atomics.git",
+ "state" : {
+ "revision" : "cd142fd2f64be2100422d658e7411e39489da985",
+ "version" : "1.2.0"
+ }
+ },
+ {
+ "identity" : "swift-collections",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/apple/swift-collections.git",
+ "state" : {
+ "revision" : "671108c96644956dddcd89dd59c203dcdb36cec7",
+ "version" : "1.1.4"
+ }
+ },
+ {
+ "identity" : "swift-nio",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/apple/swift-nio.git",
+ "state" : {
+ "revision" : "914081701062b11e3bb9e21accc379822621995e",
+ "version" : "2.76.1"
+ }
+ },
+ {
+ "identity" : "swift-nio-ssl",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/apple/swift-nio-ssl",
+ "state" : {
+ "revision" : "c7e95421334b1068490b5d41314a50e70bab23d1",
+ "version" : "2.29.0"
+ }
+ },
+ {
+ "identity" : "swift-system",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/apple/swift-system.git",
+ "state" : {
+ "revision" : "c8a44d836fe7913603e246acab7c528c2e780168",
+ "version" : "1.4.0"
+ }
+ }
+ ],
+ "version" : 3
+}
diff --git a/RadarSDK/Include/Radar.h b/RadarSDK/Include/Radar.h
index 27745b9da..96288bb03 100644
--- a/RadarSDK/Include/Radar.h
+++ b/RadarSDK/Include/Radar.h
@@ -510,6 +510,20 @@ typedef void (^_Nullable RadarLogConversionCompletionHandler)(RadarStatus status
*/
+ (void)stopTrackingVerified NS_SWIFT_NAME(stopTrackingVerified());
+/**
+ Starts the Radar Verify companion app server.
+
+ @warning Note that you must configure SSL pinning before calling this method.
+ */
++ (void)startVerifyServer NS_SWIFT_NAME(startVerifyServer());
+
+/**
+ Stops the Radar Verify companion app server.
+
+ @warning Note that you must configure SSL pinning before calling this method.
+ */
++ (void)stopVerifyServer NS_SWIFT_NAME(stopVerifyServer());
+
/**
Returns the user's last verified location token if still valid, or requests a fresh token if not.
diff --git a/RadarSDK/Include/RadarUser.h b/RadarSDK/Include/RadarUser.h
index 02a58c2e2..3c981d33a 100644
--- a/RadarSDK/Include/RadarUser.h
+++ b/RadarSDK/Include/RadarUser.h
@@ -132,8 +132,6 @@ typedef NS_ENUM(NSInteger, RadarActivityType);
*/
@property (nullable, copy, nonatomic, readonly) NSArray *topChains;
-- (NSDictionary *_Nonnull)dictionaryValue;
-
/**
The source of the user's current location.
*/
@@ -158,4 +156,6 @@ typedef NS_ENUM(NSInteger, RadarActivityType);
*/
@property (nullable, copy, nonatomic, readonly) RadarFraud *fraud;
+- (NSDictionary *_Nonnull)dictionaryValue;
+
@end
diff --git a/RadarSDK/Include/RadarVerifiedLocationToken.h b/RadarSDK/Include/RadarVerifiedLocationToken.h
index fd79f0dfa..79a6bb94c 100644
--- a/RadarSDK/Include/RadarVerifiedLocationToken.h
+++ b/RadarSDK/Include/RadarVerifiedLocationToken.h
@@ -56,6 +56,11 @@
*/
@property (nullable, copy, nonatomic, readonly) NSString *_id;
+/**
+ The raw dictionary value of the token.
+ */
+@property (nullable, copy, nonatomic, readonly) NSDictionary *rawDict;
+
- (NSDictionary *_Nonnull)dictionaryValue;
@end
diff --git a/RadarSDK/Radar.m b/RadarSDK/Radar.m
index b80d9e8b8..6e3d6d5f8 100644
--- a/RadarSDK/Radar.m
+++ b/RadarSDK/Radar.m
@@ -23,6 +23,7 @@
#import "RadarReplayBuffer.h"
#import "RadarNotificationHelper.h"
#import "RadarTripOptions.h"
+#import "RadarVerifyServer.h"
@interface Radar ()
@@ -309,6 +310,26 @@ + (void)stopTrackingVerified {
[[RadarVerificationManager sharedInstance] stopTrackingVerified];
}
++ (void)startVerifyServer {
+ [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelInfo type:RadarLogTypeSDKCall message:@"startVerifyServer()"];
+ [RadarUtils downloadDataFromURL:[NSURL URLWithString:@"https://s3.us-east-2.amazonaws.com/app.radar-verify.com/mac/c.der"] completionHandler:^(NSData * _Nonnull certData, NSError * _Nonnull error) {
+ [RadarUtils downloadDataFromURL:[NSURL URLWithString:@"https://s3.us-east-2.amazonaws.com/app.radar-verify.com/mac/id.p12"] completionHandler:^(NSData * _Nonnull identityData, NSError * _Nonnull error) {
+ if (!certData || !identityData) {
+ [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelError type:RadarLogTypeSDKCall message:@"Error starting server: Error downloading cert data"];
+ return;
+ }
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [[RadarVerifyServer sharedInstance] startServerWithCertData:certData identityData:identityData];
+ });
+ }];
+ }];
+}
+
++ (void)stopVerifyServer {
+ [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelInfo type:RadarLogTypeSDKCall message:@"stopVerifyServer()"];
+ [[RadarVerifyServer sharedInstance] stopServer];
+}
+
+ (void)getVerifiedLocationToken:(RadarTrackVerifiedCompletionHandler)completionHandler {
[[RadarLogger sharedInstance] logWithLevel:RadarLogLevelInfo type:RadarLogTypeSDKCall message:@"getVerifiedLocationToken()"];
[[RadarVerificationManager sharedInstance]
diff --git a/RadarSDK/RadarLocationManager.m b/RadarSDK/RadarLocationManager.m
index 7a4adbc0d..7c1b41c07 100644
--- a/RadarSDK/RadarLocationManager.m
+++ b/RadarSDK/RadarLocationManager.m
@@ -396,9 +396,7 @@ - (void)updateTracking:(CLLocation *)location fromInitialize:(BOOL)fromInitializ
}
self.locationManager.desiredAccuracy = desiredAccuracy;
- if (@available(iOS 11.0, *)) {
- self.lowPowerLocationManager.showsBackgroundLocationIndicator = options.showBlueBar;
- }
+ self.lowPowerLocationManager.showsBackgroundLocationIndicator = options.showBlueBar;
BOOL startUpdates = options.showBlueBar || [CLLocationManager authorizationStatus] == kCLAuthorizationStatusAuthorizedAlways;
BOOL stopped = [RadarState stopped];
diff --git a/RadarSDK/RadarLog.h b/RadarSDK/RadarLog.h
index 6ad9133d8..a033b299c 100644
--- a/RadarSDK/RadarLog.h
+++ b/RadarSDK/RadarLog.h
@@ -10,7 +10,7 @@
/**
Represents a debug log.
*/
-@interface RadarLog : NSObject
+@interface RadarLog : NSObject
/**
The levels for debug logs.
diff --git a/RadarSDK/RadarLog.m b/RadarSDK/RadarLog.m
index 0aaff4b9a..3b2d8b462 100644
--- a/RadarSDK/RadarLog.m
+++ b/RadarSDK/RadarLog.m
@@ -130,4 +130,8 @@ - (void)encodeWithCoder:(NSCoder *)coder {
[coder encodeObject:_createdAt forKey:@"createdAt"];
}
++ (BOOL)supportsSecureCoding {
+ return YES;
+}
+
@end
diff --git a/RadarSDK/RadarLogBuffer.m b/RadarSDK/RadarLogBuffer.m
index f69459a14..5592b68d5 100644
--- a/RadarSDK/RadarLogBuffer.m
+++ b/RadarSDK/RadarLogBuffer.m
@@ -111,7 +111,11 @@ - (void)persistLogs {
for (NSString *file in files) {
NSString *filePath = [self.logFileDir stringByAppendingPathComponent:file];
NSData *fileData = [self.fileHandler readFileAtPath:filePath];
- RadarLog *log = [NSKeyedUnarchiver unarchiveObjectWithData:fileData];
+ NSError *error;
+ RadarLog *log = [NSKeyedUnarchiver unarchivedObjectOfClasses:[NSSet setWithObjects:[NSString class], [RadarLog class], [NSDate class], nil] fromData:fileData error:&error];
+ if (error) {
+ NSLog(@"Failed to unarchive log: %@", error);
+ }
if (log && log.message) {
[logs addObject:log];
}
@@ -122,7 +126,11 @@ - (void)persistLogs {
- (void)writeToFileStorage:(NSArray *)logs {
for (RadarLog *log in logs) {
- NSData *logData = [NSKeyedArchiver archivedDataWithRootObject:log];
+ NSError *error;
+ NSData *logData = [NSKeyedArchiver archivedDataWithRootObject:log requiringSecureCoding:YES error:&error];
+ if (error) {
+ NSLog(@"Failed to archive log: %@", error);
+ }
NSTimeInterval unixTimestamp = [log.createdAt timeIntervalSince1970];
// logs may be created in the same millisecond, so we append a counter to the end of the timestamp to "tiebreak"
NSString *unixTimestampString = [NSString stringWithFormat:@"%lld_%04d", (long long)unixTimestamp, fileCounter++];
diff --git a/RadarSDK/RadarReplay.h b/RadarSDK/RadarReplay.h
index c67b67742..edf72f3f7 100644
--- a/RadarSDK/RadarReplay.h
+++ b/RadarSDK/RadarReplay.h
@@ -7,7 +7,7 @@
#import "Radar.h"
-@interface RadarReplay : NSObject
+@interface RadarReplay : NSObject
@property (nonnull, copy, nonatomic, readonly) NSDictionary *replayParams;
diff --git a/RadarSDK/RadarReplay.m b/RadarSDK/RadarReplay.m
index 7a7d0fb77..b29e99a09 100644
--- a/RadarSDK/RadarReplay.m
+++ b/RadarSDK/RadarReplay.m
@@ -57,4 +57,8 @@ - (NSUInteger)hash {
return [self.replayParams hash];
}
++ (BOOL)supportsSecureCoding {
+ return YES;
+}
+
@end
diff --git a/RadarSDK/RadarReplayBuffer.m b/RadarSDK/RadarReplayBuffer.m
index 542cd1fb7..db94c4dd6 100644
--- a/RadarSDK/RadarReplayBuffer.m
+++ b/RadarSDK/RadarReplayBuffer.m
@@ -50,6 +50,7 @@ - (void)writeNewReplayToBuffer:(NSMutableDictionary *)replayParams {
RadarSdkConfiguration *sdkConfiguration = [RadarSettings sdkConfiguration];
if (sdkConfiguration.usePersistence) {
NSData *replaysData;
+ NSError *error;
// if buffer length is above 50, remove every fifth replay from the persisted buffer
if ([mutableReplayBuffer count] > 50) {
@@ -59,12 +60,16 @@ - (void)writeNewReplayToBuffer:(NSMutableDictionary *)replayParams {
[prunedBuffer addObject:mutableReplayBuffer[i]];
}
}
- replaysData = [NSKeyedArchiver archivedDataWithRootObject:prunedBuffer];
+ replaysData = [NSKeyedArchiver archivedDataWithRootObject:prunedBuffer requiringSecureCoding:YES error:&error];
} else {
- replaysData = [NSKeyedArchiver archivedDataWithRootObject:mutableReplayBuffer];
+ replaysData = [NSKeyedArchiver archivedDataWithRootObject:mutableReplayBuffer requiringSecureCoding:YES error:&error];
+ }
+ if (error) {
+ [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelDebug message:@"Error archiving replays"];
+ return;
+ } else {
+ [[NSUserDefaults standardUserDefaults] setObject:replaysData forKey:@"radar-replays"];
}
-
- [[NSUserDefaults standardUserDefaults] setObject:replaysData forKey:@"radar-replays"];
}
}
@@ -150,14 +155,26 @@ - (void)removeReplaysFromBuffer:(NSArray *)replays {
[mutableReplayBuffer removeObjectsInArray:replays];
// persist the updated buffer
- NSData *replaysData = [NSKeyedArchiver archivedDataWithRootObject:mutableReplayBuffer];
- [[NSUserDefaults standardUserDefaults] setObject:replaysData forKey:@"radar-replays"];
+ NSError *error;
+ NSData *replaysData = [NSKeyedArchiver archivedDataWithRootObject:mutableReplayBuffer requiringSecureCoding:YES error:&error];
+ if (error) {
+ [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelDebug message:@"Error archiving replays"];
+ return;
+ } else {
+ [[NSUserDefaults standardUserDefaults] setObject:replaysData forKey:@"radar-replays"];
+ }
}
- (void)loadReplaysFromPersistentStore {
NSData *replaysData = [[NSUserDefaults standardUserDefaults] objectForKey:@"radar-replays"];
if (replaysData) {
- NSArray *replays = [NSKeyedUnarchiver unarchiveObjectWithData:replaysData];
+ NSError *error;
+ NSSet *allowedClasses = [NSSet setWithObjects:[NSArray class], [RadarReplay class], [NSDictionary class], [NSString class], [NSNumber class], nil];
+ NSArray *replays = [NSKeyedUnarchiver unarchivedObjectOfClasses:allowedClasses fromData:replaysData error:&error];
+ if (error) {
+ [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelDebug message:@"Error unarchiving replays"];
+ return;
+ }
[[RadarLogger sharedInstance] logWithLevel:RadarLogLevelDebug message:[NSString stringWithFormat:@"Loaded replays | length = %lu", (unsigned long)[replays count]]];
mutableReplayBuffer = [NSMutableArray arrayWithArray:replays];
}
diff --git a/RadarSDK/RadarUtils.h b/RadarSDK/RadarUtils.h
index db38af04e..fa880c904 100644
--- a/RadarSDK/RadarUtils.h
+++ b/RadarSDK/RadarUtils.h
@@ -32,6 +32,7 @@ NS_ASSUME_NONNULL_BEGIN
+ (NSDictionary *)dictionaryForLocation:(CLLocation *)location;
+ (NSString *)dictionaryToJson:(NSDictionary *)dict;
+ (NSDictionary *)extractGeofenceIdAndTimestampFromIdentifier:(NSString *)identifier;
++ (void)downloadDataFromURL:(NSURL *)url completionHandler:(void (^)(NSData *data, NSError *error))completionHandler;
+ (void)runOnMainThread:(dispatch_block_t)block;
@end
diff --git a/RadarSDK/RadarUtils.m b/RadarSDK/RadarUtils.m
index 11abc6d56..3f67926e5 100644
--- a/RadarSDK/RadarUtils.m
+++ b/RadarSDK/RadarUtils.m
@@ -45,7 +45,7 @@ + (NSNumber *)timeZoneOffset {
}
+ (NSString *)sdkVersion {
- return @"3.19.0";
+ return @"3.19.1";
}
+ (NSString *)deviceId {
@@ -176,6 +176,15 @@ + (NSString *)dictionaryToJson:(NSDictionary *)dict {
return @{@"geofenceId": geofenceId, @"registeredAt": registeredAt};
}
++ (void)downloadDataFromURL:(NSURL *)url completionHandler:(void (^)(NSData *data, NSError *error))completionHandler {
+ NSURLSessionDataTask *dataTask = [[NSURLSession sharedSession] dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
+ if (completionHandler) {
+ completionHandler(data, error);
+ }
+ }];
+ [dataTask resume];
+}
+
#pragma mark - threading
+ (void)runOnMainThread:(dispatch_block_t)block {
diff --git a/RadarSDK/RadarVerificationManager.m b/RadarSDK/RadarVerificationManager.m
index 2f189a4a7..3a3d6c564 100644
--- a/RadarSDK/RadarVerificationManager.m
+++ b/RadarSDK/RadarVerificationManager.m
@@ -230,55 +230,50 @@ - (void)startTrackingVerifiedWithInterval:(NSTimeInterval)interval beacons:(BOOL
self.startedInterval = interval;
self.startedBeacons = beacons;
- if (@available(iOS 12.0, *)) {
- if (!_monitor) {
- _monitor = nw_path_monitor_create();
+ if (!_monitor) {
+ _monitor = nw_path_monitor_create();
- nw_path_monitor_set_queue(_monitor, dispatch_get_main_queue());
+ nw_path_monitor_set_queue(_monitor, dispatch_get_main_queue());
- nw_path_monitor_set_update_handler(_monitor, ^(nw_path_t path) {
- if (nw_path_get_status(path) == nw_path_status_satisfied) {
- [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelDebug message:@"Network connected"];
- } else {
- [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelDebug message:@"Network disconnected"];
- }
-
- NSString *ips = [self getIPs];
- BOOL changed = NO;
-
- if (!self.lastIPs) {
- [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelDebug message:[NSString stringWithFormat:@"First time getting IPs | ips = %@", ips]];
- changed = NO;
- } else if (!ips || [ips isEqualToString:@"error"]) {
- [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelDebug message:[NSString stringWithFormat:@"Error getting IPs | ips = %@", ips]];
- changed = YES;
- } else if (![ips isEqualToString:self.lastIPs]) {
- [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelDebug message:[NSString stringWithFormat:@"IPs changed | ips = %@; lastIPs = %@", ips, self.lastIPs]];
- changed = YES;
- } else {
- [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelDebug message:@"IPs unchanged"];
- }
- self.lastIPs = ips;
+ nw_path_monitor_set_update_handler(_monitor, ^(nw_path_t path) {
+ if (nw_path_get_status(path) == nw_path_status_satisfied) {
+ [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelDebug message:@"Network connected"];
+ } else {
+ [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelDebug message:@"Network disconnected"];
+ }
- if (changed) {
- [self callTrackVerified];
- }
- });
-
- nw_path_monitor_start(_monitor);
- }
+ NSString *ips = [self getIPs];
+ BOOL changed = NO;
+
+ if (!self.lastIPs) {
+ [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelDebug message:[NSString stringWithFormat:@"First time getting IPs | ips = %@", ips]];
+ changed = NO;
+ } else if (!ips || [ips isEqualToString:@"error"]) {
+ [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelDebug message:[NSString stringWithFormat:@"Error getting IPs | ips = %@", ips]];
+ changed = YES;
+ } else if (![ips isEqualToString:self.lastIPs]) {
+ [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelDebug message:[NSString stringWithFormat:@"IPs changed | ips = %@; lastIPs = %@", ips, self.lastIPs]];
+ changed = YES;
+ } else {
+ [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelDebug message:@"IPs unchanged"];
+ }
+ self.lastIPs = ips;
+
+ if (changed) {
+ [self callTrackVerified];
+ }
+ });
+ nw_path_monitor_start(_monitor);
}
-
+
[self callTrackVerified];
}
- (void)stopTrackingVerified {
self.started = NO;
-
- if (@available(iOS 12.0, *)) {
- if (_monitor) {
- nw_path_monitor_cancel(_monitor);
- }
+
+ if (_monitor) {
+ nw_path_monitor_cancel(_monitor);
}
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(intervalFired) object:nil];
diff --git a/RadarSDK/RadarVerifiedLocationToken+Internal.h b/RadarSDK/RadarVerifiedLocationToken+Internal.h
index 216cb664c..d03a8288f 100644
--- a/RadarSDK/RadarVerifiedLocationToken+Internal.h
+++ b/RadarSDK/RadarVerifiedLocationToken+Internal.h
@@ -17,7 +17,8 @@
expiresIn:(NSTimeInterval)expiresIn
passed:(BOOL)passed
failureReasons:(NSArray *_Nonnull)failureReasons
- _id:(NSString *_Nonnull)_id;
+ _id:(NSString *_Nonnull)_id
+ rawDict:(NSDictionary *_Nonnull)rawDict;
- (instancetype _Nullable)initWithObject:(id _Nonnull)object;
@end
diff --git a/RadarSDK/RadarVerifiedLocationToken.m b/RadarSDK/RadarVerifiedLocationToken.m
index 594a21f2e..2c10a51f9 100644
--- a/RadarSDK/RadarVerifiedLocationToken.m
+++ b/RadarSDK/RadarVerifiedLocationToken.m
@@ -20,7 +20,8 @@ - (instancetype _Nullable)initWithUser:(RadarUser *_Nonnull)user
expiresIn:(NSTimeInterval)expiresIn
passed:(BOOL)passed
failureReasons:(NSArray * _Nonnull)failureReasons
- _id:(NSString * _Nonnull)_id {
+ _id:(NSString * _Nonnull)_id
+ rawDict:(NSDictionary * _Nonnull)rawDict {
self = [super init];
if (self) {
_user = user;
@@ -31,6 +32,7 @@ - (instancetype _Nullable)initWithUser:(RadarUser *_Nonnull)user
_passed = passed;
_failureReasons = failureReasons;
__id = _id;
+ _rawDict = rawDict;
}
return self;
}
@@ -91,21 +93,14 @@ - (instancetype _Nullable)initWithObject:(id _Nonnull)object {
}
if (user && events && token && expiresAt) {
- return [[RadarVerifiedLocationToken alloc] initWithUser:user events:events token:token expiresAt:expiresAt expiresIn:expiresIn passed:passed failureReasons:failureReasons _id:_id];
+ return [[RadarVerifiedLocationToken alloc] initWithUser:user events:events token:token expiresAt:expiresAt expiresIn:expiresIn passed:passed failureReasons:failureReasons _id:_id rawDict:dict];
}
return nil;
}
- (NSDictionary *)dictionaryValue {
- NSMutableDictionary *dict = [NSMutableDictionary new];
- dict[@"user"] = [self.user dictionaryValue];
- dict[@"events"] = [RadarEvent arrayForEvents:self.events];
- dict[@"token"] = self.token;
- dict[@"expiresAt"] = [RadarUtils.isoDateFormatter stringFromDate:self.expiresAt];
- dict[@"expiresIn"] = @(self.expiresIn);
- dict[@"passed"] = @(self.passed);
- return dict;
+ return self.rawDict;
}
@end
diff --git a/RadarSDK/RadarVerifyServer.h b/RadarSDK/RadarVerifyServer.h
new file mode 100644
index 000000000..d5626b0a1
--- /dev/null
+++ b/RadarSDK/RadarVerifyServer.h
@@ -0,0 +1,17 @@
+//
+// RadarVerifyServer.h
+// RadarSDK
+//
+// Created by Nick Patrick on 11/11/24.
+// Copyright © 2024 Radar Labs, Inc. All rights reserved.
+//
+
+#import
+
+@interface RadarVerifyServer: NSObject
+
++ (instancetype)sharedInstance;
+- (void)startServerWithCertData:(NSData *)certData identityData:(NSData *)identityData;
+- (void)stopServer;
+
+@end
diff --git a/RadarSDK/RadarVerifyServer.swift b/RadarSDK/RadarVerifyServer.swift
new file mode 100644
index 000000000..d6478b24f
--- /dev/null
+++ b/RadarSDK/RadarVerifyServer.swift
@@ -0,0 +1,157 @@
+//
+// RadarVerifyServer.swift
+// RadarSDK
+//
+// Created by Nick Patrick on 11/11/24.
+// Copyright © 2024 Radar Labs, Inc. All rights reserved.
+//
+
+import Foundation
+import UserNotifications
+
+#if canImport(Telegraph)
+import Telegraph
+
+@objc(RadarVerifyServer) class RadarVerifyServer: NSObject, CLLocationManagerDelegate {
+ @MainActor @objc static let sharedInstance = RadarVerifyServer()
+
+ private var locationManager = CLLocationManager()
+ private var server: Server?
+
+ override init() {
+ super.init()
+
+ locationManager.delegate = self
+ locationManager.requestWhenInUseAuthorization()
+ locationManager.allowsBackgroundLocationUpdates = true
+ locationManager.pausesLocationUpdatesAutomatically = false
+ locationManager.showsBackgroundLocationIndicator = true
+ locationManager.desiredAccuracy = kCLLocationAccuracyThreeKilometers
+ locationManager.distanceFilter = 3000
+ }
+
+ private func addHeaders(to response: HTTPResponse) {
+ response.headers["Access-Control-Allow-Headers"] = "Content-Type, Accept, Authorization, X-Radar-Device-Type, X-Radar-SDK-Version"
+ response.headers["Access-Control-Allow-Origin"] = "*"
+ response.headers["Access-Control-Allow-Methods"] = "GET, OPTIONS"
+ }
+
+ @objc func startServer(withCertData certData: Data, identityData: Data) {
+ do {
+ guard let identity = CertificateIdentity(p12Data: identityData),
+ let caCertificate = Certificate(derData: certData) else {
+ print("Error starting server: Error parsing cert data")
+ return
+ }
+
+ server = Server(identity: identity, caCertificates: [caCertificate])
+
+ self.server?.route(.OPTIONS, "/v1/verify") { _ in
+ let response = HTTPResponse(.ok)
+ self.addHeaders(to: response)
+ return response
+ }
+
+ self.server?.route(.GET, "/v1/verify") { request in
+ let userId = request.params["userId"]
+ let description = request.params["description"]
+
+ Radar.setUserId(userId)
+ Radar.setDescription(description)
+
+ var response = HTTPResponse(.internalServerError)
+
+ let semaphore = DispatchSemaphore(value: 0)
+
+ self.showNotification(title: "Location check in progress...")
+
+ Radar.trackVerified { status, token in
+ if status == .success, let rawDict = token?.rawDict {
+ do {
+ let mutableDict = NSMutableDictionary(dictionary: rawDict)
+ mutableDict["meta"] = ["code": 200]
+
+ let data = try JSONSerialization.data(withJSONObject: mutableDict)
+
+ if let content = String(data: data, encoding: .utf8) {
+ response = HTTPResponse(.ok, content: content)
+ }
+ } catch {
+
+ }
+ } else if status == .errorUnauthorized {
+ response = HTTPResponse(.unauthorized)
+ } else if status == .errorForbidden {
+ response = HTTPResponse(.forbidden)
+ } else if status == .errorPaymentRequired {
+ response = HTTPResponse(.paymentRequired)
+ } else if status == .errorPermissions {
+ let content = "{\"meta\":{\"code\":400,\"error\":\"ERROR_PERMISSIONS\"}}"
+ response = HTTPResponse(.badRequest, content: content)
+ } else if status == .errorLocation {
+ let content = "{\"meta\":{\"code\":400,\"error\":\"ERROR_LOCATION\"}}"
+ response = HTTPResponse(.badRequest, content: content)
+ } else if status == .errorNetwork {
+ let content = "{\"meta\":{\"code\":400,\"error\":\"ERROR_NETWORK\"}}"
+ response = HTTPResponse(.badRequest, content: content)
+ }
+ semaphore.signal()
+ }
+
+ semaphore.wait()
+
+ self.addHeaders(to: response)
+ return response
+ }
+
+ self.locationManager.startUpdatingLocation()
+ try self.server?.start(port: 52516, interface: "127.0.0.1")
+ } catch {
+ print("Failed to start server: \(error)")
+ }
+ }
+
+ @objc func stopServer() {
+ self.server?.stop()
+ self.server = nil
+ self.locationManager.stopUpdatingLocation()
+ }
+
+ private func showNotification(title: String? = nil, body: String? = nil) {
+ let content = UNMutableNotificationContent()
+ if let title = title { content.title = title }
+ if let body = body { content.body = body }
+ content.sound = UNNotificationSound.default
+
+ let request = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: nil)
+ UNUserNotificationCenter.current().add(request, withCompletionHandler: nil)
+ }
+
+ private func downloadData(from url: URL) async throws -> Data {
+ var request = URLRequest(url: url)
+ request.cachePolicy = .reloadIgnoringLocalCacheData
+
+ let (data, response) = try await URLSession.shared.data(for: request)
+
+ guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else {
+ throw URLError(.badServerResponse)
+ }
+
+ return data
+ }
+
+}
+#else
+@objc(RadarVerifyServer) class RadarVerifyServer: NSObject {
+ @MainActor @objc static let sharedInstance = RadarVerifyServer()
+
+ @objc func startServer(withCertData certData: Data, identityData: Data) {
+ print("Error starting server: Missing dependencies")
+ }
+
+ @objc func stopServer() {
+ print("Error stopping server: Error parsing cert data")
+ }
+
+}
+#endif
diff --git a/RadarSDKMotion.podspec b/RadarSDKMotion.podspec
index e599fc506..08719b872 100644
--- a/RadarSDKMotion.podspec
+++ b/RadarSDKMotion.podspec
@@ -1,16 +1,15 @@
Pod::Spec.new do |s|
- s.name = 'RadarSDKMotion'
- s.version = '3.19.0'
- s.summary = 'Motion detection plugin for RadarSDK, the leading geofencing and location tracking platform'
- s.homepage = 'https://radar.com'
- 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 = ["RadarSDKMotion/RadarSDKMotion/*.{h,m}", "RadarSDKMotion/RadarSDKMotion/Include/*.h"]
- s.module_name = 'RadarSDKMotion'
- s.ios.deployment_target = '10.0'
- s.frameworks = 'CoreMotion'
- s.requires_arc = true
- s.license = { :type => 'Apache-2.0' }
- end
-
\ No newline at end of file
+ s.name = 'RadarSDKMotion'
+ s.version = '3.19.1'
+ s.summary = 'Motion detection plugin for RadarSDK, the leading geofencing and location tracking platform'
+ s.homepage = 'https://radar.com'
+ 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 = ["RadarSDKMotion/RadarSDKMotion/*.{h,m}", "RadarSDKMotion/RadarSDKMotion/Include/*.h"]
+ s.module_name = 'RadarSDKMotion'
+ s.ios.deployment_target = '12.0'
+ s.frameworks = 'CoreMotion'
+ s.requires_arc = true
+ s.license = { :type => 'Apache-2.0' }
+end
diff --git a/RadarSDKMotion/RadarSDKMotion.xcodeproj/project.pbxproj b/RadarSDKMotion/RadarSDKMotion.xcodeproj/project.pbxproj
index b6ff455c9..a2bf691ea 100644
--- a/RadarSDKMotion/RadarSDKMotion.xcodeproj/project.pbxproj
+++ b/RadarSDKMotion/RadarSDKMotion.xcodeproj/project.pbxproj
@@ -289,6 +289,7 @@
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
+ MARKETING_VERSION = 3.18.4;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
@@ -347,6 +348,7 @@
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
+ MARKETING_VERSION = 3.18.4;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
SDKROOT = iphoneos;
@@ -376,7 +378,6 @@
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
- MARKETING_VERSION = 1.0;
MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20";
PRODUCT_BUNDLE_IDENTIFIER = RadarLabs.RadarSDKMotion;
@@ -407,7 +408,6 @@
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
- MARKETING_VERSION = 1.0;
MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20";
PRODUCT_BUNDLE_IDENTIFIER = RadarLabs.RadarSDKMotion;
@@ -425,7 +425,6 @@
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = 96GHH65B9D;
GENERATE_INFOPLIST_FILE = YES;
- MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = RadarLabs.RadarMotionTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = NO;
@@ -440,7 +439,6 @@
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = 96GHH65B9D;
GENERATE_INFOPLIST_FILE = YES;
- MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = RadarLabs.RadarMotionTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = NO;
diff --git a/RadarSDKTests/RadarSDKTests.m b/RadarSDKTests/RadarSDKTests.m
index 83b23cf0f..d55798f1c 100644
--- a/RadarSDKTests/RadarSDKTests.m
+++ b/RadarSDKTests/RadarSDKTests.m
@@ -20,7 +20,7 @@
#import "RadarTestUtils.h"
#import "RadarTripOptions.h"
#import "RadarFileStorage.h"
-
+#import "RadarReplayBuffer.h"
@interface RadarSDKTests : XCTestCase
@@ -30,6 +30,7 @@ @interface RadarSDKTests : XCTestCase
@property (nonatomic, strong) RadarFileStorage *fileSystem;
@property (nonatomic, strong) NSString *testFilePath;
@property (nonatomic, strong) RadarLogBuffer *logBuffer;
+@property (nonatomic, strong) RadarReplayBuffer *replayBuffer;
@end
@implementation RadarSDKTests
@@ -299,7 +300,7 @@ - (void)setUp {
self.testFilePath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"testfile"];
[[RadarLogBuffer sharedInstance]clearBuffer];
[[RadarLogBuffer sharedInstance]setPersistentLogFeatureFlag:YES];
-
+ [[RadarReplayBuffer sharedInstance]clearBuffer];
}
- (void)tearDown {
@@ -1491,6 +1492,22 @@ - (void)test_RadarLogBuffer_purge {
[[RadarLogBuffer sharedInstance]clearBuffer];
}
+- (void)test_RadarReplayBuffer_writeAndRead {
+ RadarSdkConfiguration *sdkConfiguration = [RadarSettings sdkConfiguration];
+ sdkConfiguration.usePersistence = true;
+ [RadarSettings setSdkConfiguration:sdkConfiguration];
+
+ CLLocation *location = [[CLLocation alloc] initWithLatitude:0.1 longitude:0.1];
+ NSMutableDictionary * params = [RadarTestUtils createTrackParamWithLocation:location stopped:YES foreground:YES source:RadarLocationSourceGeofenceEnter replayed:YES beacons:[NSArray arrayWithObject:[RadarBeacon alloc]] verified:YES attestationString:@"attestationString" keyId:@"keyID" attestationError:@"attestationError" encrypted:YES expectedCountryCode:@"CountryCode" expectedStateCode:@"StateCode"];
+
+ [[RadarReplayBuffer sharedInstance] writeNewReplayToBuffer:params];
+ [[RadarReplayBuffer sharedInstance] setValue:NULL forKey:@"mutableReplayBuffer"];
+ [[RadarReplayBuffer sharedInstance] loadReplaysFromPersistentStore];
+ NSMutableArray *mutableReplayBuffer = [[RadarReplayBuffer sharedInstance] valueForKey:@"mutableReplayBuffer"];
+ XCTAssertEqual(mutableReplayBuffer.count, 1);
+ XCTAssertEqualObjects(mutableReplayBuffer.firstObject.replayParams, params);
+}
+
- (void)test_RadarSdkConfiguration {
RadarSdkConfiguration *sdkConfiguration = [[RadarSdkConfiguration alloc] initWithDict:@{
@"logLevel": @"warning",
diff --git a/RadarSDKTests/RadarTestUtils.h b/RadarSDKTests/RadarTestUtils.h
index 1f78dc911..9dfd0fed2 100644
--- a/RadarSDKTests/RadarTestUtils.h
+++ b/RadarSDKTests/RadarTestUtils.h
@@ -7,12 +7,38 @@
#import
+#import "CLLocation+Radar.h"
+#import "RadarLocationManager.h"
+#import "RadarSettings.h"
+#import "RadarState.h"
+#import "RadarUtils.h"
+#import "RadarTripOptions.h"
+#import "RadarVerificationManager.h"
+
NS_ASSUME_NONNULL_BEGIN
@interface RadarTestUtils : NSObject
+ (NSDictionary *)jsonDictionaryFromResource:(NSString *)resource;
+/**
+ Construct a track param dict which can be used to test replays from paramters of the track call.
+ uses the stored values from `RadarSettings`, `RadarUtils`, and `RadarState`
+ */
++ (NSMutableDictionary *)createTrackParamWithLocation:(CLLocation *_Nonnull)location
+ stopped:(BOOL)stopped
+ foreground:(BOOL)foreground
+ source:(RadarLocationSource)source
+ replayed:(BOOL)replayed
+ beacons:(NSArray *_Nullable)beacons
+ verified:(BOOL)verified
+ attestationString:(NSString *_Nullable)attestationString
+ keyId:(NSString *_Nullable)keyId
+ attestationError:(NSString *_Nullable)attestationError
+ encrypted:(BOOL)encrypted
+ expectedCountryCode:(NSString * _Nullable)expectedCountryCode
+ expectedStateCode:(NSString * _Nullable)expectedStateCode;
+
@end
NS_ASSUME_NONNULL_END
diff --git a/RadarSDKTests/RadarTestutils.m b/RadarSDKTests/RadarTestutils.m
index 83d61937c..b725c9956 100644
--- a/RadarSDKTests/RadarTestutils.m
+++ b/RadarSDKTests/RadarTestutils.m
@@ -18,4 +18,181 @@ + (NSDictionary *)jsonDictionaryFromResource:(NSString *)resource {
return jsonDict;
}
++ (NSMutableDictionary *)createTrackParamWithLocation:(CLLocation *_Nonnull)location
+ stopped:(BOOL)stopped
+ foreground:(BOOL)foreground
+ source:(RadarLocationSource)source
+ replayed:(BOOL)replayed
+ beacons:(NSArray *_Nullable)beacons
+ verified:(BOOL)verified
+ attestationString:(NSString *_Nullable)attestationString
+ keyId:(NSString *_Nullable)keyId
+ attestationError:(NSString *_Nullable)attestationError
+ encrypted:(BOOL)encrypted
+ expectedCountryCode:(NSString * _Nullable)expectedCountryCode
+ expectedStateCode:(NSString * _Nullable)expectedStateCode{
+ NSMutableDictionary *params = [NSMutableDictionary new];
+ BOOL anonymous = [RadarSettings anonymousTrackingEnabled];
+ params[@"anonymous"] = @(anonymous);
+ if (anonymous) {
+ params[@"deviceId"] = @"anonymous";
+ params[@"geofenceIds"] = [RadarState geofenceIds];
+ params[@"placeId"] = [RadarState placeId];
+ params[@"regionIds"] = [RadarState regionIds];
+ params[@"beaconIds"] = [RadarState beaconIds];
+ } else {
+ params[@"id"] = [RadarSettings _id];
+ params[@"installId"] = [RadarSettings installId];
+ params[@"userId"] = [RadarSettings userId];
+ params[@"deviceId"] = [RadarUtils deviceId];
+ params[@"description"] = [RadarSettings __description];
+ params[@"metadata"] = [RadarSettings metadata];
+ NSString *sessionId = [RadarSettings sessionId];
+ if (sessionId) {
+ params[@"sessionId"] = sessionId;
+ }
+ }
+ params[@"latitude"] = @(location.coordinate.latitude);
+ params[@"longitude"] = @(location.coordinate.longitude);
+ CLLocationAccuracy accuracy = location.horizontalAccuracy;
+ if (accuracy <= 0) {
+ accuracy = 1;
+ }
+ params[@"accuracy"] = @(accuracy);
+ params[@"altitude"] = @(location.altitude);
+ params[@"verticalAccuracy"] = @(location.verticalAccuracy);
+ params[@"speed"] = @(location.speed);
+ params[@"speedAccuracy"] = @(location.speedAccuracy);
+ params[@"course"] = @(location.course);
+ if (@available(iOS 13.4, *)) {
+ params[@"courseAccuracy"] = @(location.courseAccuracy);
+ }
+ if (location.floor) {
+ params[@"floorLevel"] = @(location.floor.level);
+ }
+ long nowMs = (long)([NSDate date].timeIntervalSince1970 * 1000);
+ if (!foreground) {
+ long timeInMs = (long)(location.timestamp.timeIntervalSince1970 * 1000);
+ params[@"updatedAtMsDiff"] = @(nowMs - timeInMs);
+ }
+ params[@"foreground"] = @(foreground);
+ params[@"stopped"] = @(stopped);
+ params[@"replayed"] = @(replayed);
+ params[@"deviceType"] = [RadarUtils deviceType];
+ params[@"deviceMake"] = [RadarUtils deviceMake];
+ params[@"sdkVersion"] = [RadarUtils sdkVersion];
+ params[@"deviceModel"] = [RadarUtils deviceModel];
+ params[@"deviceOS"] = [RadarUtils deviceOS];
+ params[@"country"] = [RadarUtils country];
+ params[@"timeZoneOffset"] = [RadarUtils timeZoneOffset];
+ params[@"source"] = [Radar stringForLocationSource:source];
+ if ([RadarSettings xPlatform]) {
+ params[@"xPlatformType"] = [RadarSettings xPlatformSDKType];
+ params[@"xPlatformSDKVersion"] = [RadarSettings xPlatformSDKVersion];
+ } else {
+ params[@"xPlatformType"] = @"Native";
+ }
+ NSMutableArray *fraudFailureReasons = [NSMutableArray new];
+ if (@available(iOS 15.0, *)) {
+ CLLocationSourceInformation *sourceInformation = location.sourceInformation;
+ if (sourceInformation) {
+ if (sourceInformation.isSimulatedBySoftware) {
+ params[@"mocked"] = @(YES);
+ [fraudFailureReasons addObject:@"fraud_mocked_from_mock_provider"];
+ }
+ if (sourceInformation.isProducedByAccessory) {
+ [fraudFailureReasons addObject:@"fraud_mocked_produced_by_accessory"];
+ }
+ }
+ }
+
+ RadarTripOptions *tripOptions = Radar.getTripOptions;
+
+ if (tripOptions) {
+ NSMutableDictionary *tripParams = [NSMutableDictionary new];
+ tripParams[@"version"] = @("2");
+ [tripParams setValue:tripOptions.externalId forKey:@"externalId"];
+ [tripParams setValue:tripOptions.metadata forKey:@"metadata"];
+ [tripParams setValue:tripOptions.destinationGeofenceTag forKey:@"destinationGeofenceTag"];
+ [tripParams setValue:tripOptions.destinationGeofenceExternalId forKey:@"destinationGeofenceExternalId"];
+ [tripParams setValue:[Radar stringForMode:tripOptions.mode] forKey:@"mode"];
+ params[@"tripOptions"] = tripParams;
+ }
+
+ RadarTrackingOptions *options = [Radar getTrackingOptions];
+ if (options.syncGeofences) {
+ params[@"nearbyGeofences"] = @(YES);
+ }
+ if (beacons) {
+ params[@"beacons"] = [RadarBeacon arrayForBeacons:beacons];
+ }
+ NSString *locationAuthorization = [RadarUtils locationAuthorization];
+ if (locationAuthorization) {
+ params[@"locationAuthorization"] = locationAuthorization;
+ }
+ NSString *locationAccuracyAuthorization = [RadarUtils locationAccuracyAuthorization];
+ if (locationAccuracyAuthorization) {
+ params[@"locationAccuracyAuthorization"] = locationAccuracyAuthorization;
+ }
+ params[@"notificationAuthorization"] = [RadarState notificationPermissionGranted] ? @"true" : @"false";
+
+ params[@"trackingOptions"] = [options dictionaryValue];
+
+ BOOL usingRemoteTrackingOptions = RadarSettings.tracking && RadarSettings.remoteTrackingOptions;
+ params[@"usingRemoteTrackingOptions"] = @(usingRemoteTrackingOptions);
+
+ params[@"verified"] = @(verified);
+ if (verified) {
+ params[@"attestationString"] = attestationString;
+ params[@"keyId"] = keyId;
+ params[@"attestationError"] = attestationError;
+ params[@"encrypted"] = @(encrypted);
+ BOOL jailbroken = [[RadarVerificationManager sharedInstance] isJailbroken];
+ params[@"compromised"] = @(jailbroken);
+ if (jailbroken) {
+ [fraudFailureReasons addObject:@"fraud_compromised_jailbroken"];
+ }
+ if (expectedCountryCode) {
+ params[@"expectedCountryCode"] = expectedCountryCode;
+ }
+ if (expectedStateCode) {
+ params[@"expectedStateCode"] = expectedStateCode;
+ }
+ }
+ params[@"appId"] = [[NSBundle mainBundle] bundleIdentifier];
+ RadarSdkConfiguration *sdkConfiguration = [RadarSettings sdkConfiguration];
+ if (sdkConfiguration.useLocationMetadata) {
+ NSMutableDictionary *locationMetadata = [NSMutableDictionary new];
+ locationMetadata[@"motionActivityData"] = [RadarState lastMotionActivityData];
+ locationMetadata[@"heading"] = [RadarState lastHeadingData];
+ locationMetadata[@"speed"] = @(location.speed);
+ locationMetadata[@"speedAccuracy"] = @(location.speedAccuracy);
+ locationMetadata[@"course"] = @(location.course);
+
+ if (@available(iOS 13.4, *)) {
+ locationMetadata[@"courseAccuracy"] = @(location.courseAccuracy);
+ }
+
+ locationMetadata[@"battery"] = @([[UIDevice currentDevice] batteryLevel]);
+ locationMetadata[@"altitude"] = @(location.altitude);
+
+ if (@available(iOS 15, *)) {
+ locationMetadata[@"ellipsoidalAltitude"] = @(location.ellipsoidalAltitude);
+ locationMetadata[@"isProducedByAccessory"] = @([location.sourceInformation isProducedByAccessory]);
+ locationMetadata[@"isSimulatedBySoftware"] = @([location.sourceInformation isSimulatedBySoftware]);
+ }
+ locationMetadata[@"floor"] = @([location.floor level]);
+
+ params[@"locationMetadata"] = locationMetadata;
+ }
+
+ params[@"fraudFailureReasons"] = fraudFailureReasons;
+
+ // added after API call fail
+ params[@"replayed"] = @(YES);
+ params[@"updatedAtMs"] = @(nowMs);
+
+ return params;
+}
+
@end
diff --git a/set_version.sh b/set_version.sh
new file mode 100755
index 000000000..3179c6644
--- /dev/null
+++ b/set_version.sh
@@ -0,0 +1,24 @@
+#!/bin/sh
+
+if [ $# -lt 1 ]; then
+ echo "Usage: $0 "
+ exit 1
+fi
+
+# sed has slightly different syntax on linux vs mac
+if [ $(uname -s) = "Darwin" ]; then
+ alias sed_inplace="sed -E -i ''"
+else
+ alias sed_inplace="sed -E -i"
+fi
+
+version_full=$1
+version="${version_full%%-*}"
+
+sed_inplace "s/s.version( +)= '(.+)'/s.version\1= '$version_full'/" RadarSDK.podspec
+sed_inplace "s/s.version( +)= '(.+)'/s.version\1= '$version_full'/" RadarSDKMotion.podspec
+
+sed_inplace "s/MARKETING_VERSION = .+;/MARKETING_VERSION = $version;/" RadarSDK.xcodeproj/project.pbxproj
+sed_inplace "s/MARKETING_VERSION = .+;/MARKETING_VERSION = $version;/" RadarSDKMotion/RadarSDKMotion.xcodeproj/project.pbxproj
+
+sed_inplace "s/return @\"[0-9]+\.[0-9]+\.[0-9]+\";/return @\"$version_full\";/" RadarSDK/RadarUtils.m