Skip to content

Commit 6fa6316

Browse files
refactor: Update internal logic (persistence, networking, utilities)
1 parent 47d593f commit 6fa6316

File tree

9 files changed

+189
-124
lines changed

9 files changed

+189
-124
lines changed

mParticle-Apple-SDK/Kits/MPKitConfiguration.mm

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,7 @@ - (instancetype)initWithDictionary:(NSDictionary *)configurationDictionary {
2323
return nil;
2424
}
2525

26-
NSJSONWritingOptions options = 0;
27-
if (@available(iOS 11.0, tvOS 11.0, *)) {
28-
options = NSJSONWritingSortedKeys;
29-
}
30-
NSData *ekConfigData = [NSJSONSerialization dataWithJSONObject:configurationDictionary options:options error:nil];
26+
NSData *ekConfigData = [NSJSONSerialization dataWithJSONObject:configurationDictionary options:NSJSONWritingSortedKeys error:nil];
3127
NSString *ekConfigString = [[NSString alloc] initWithData:ekConfigData encoding:NSUTF8StringEncoding];
3228
_configurationHash = @([[MPIHasher hashString:ekConfigString] intValue]);
3329

mParticle-Apple-SDK/Location/MPLocationManager.swift

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,15 @@ import UIKit
3131
guard Self._locationManager == nil else {
3232
return Self._locationManager
3333
}
34+
guard CLLocationManager.locationServicesEnabled() else {
35+
return nil
36+
}
37+
38+
let _locationManager = CLLocationManager()
39+
_locationManager.delegate = self
40+
Self._locationManager = _locationManager
3441

35-
let authorizationStatus = CLLocationManager.authorizationStatus()
42+
let authorizationStatus = _locationManager.authorizationStatus
3643
guard authorizationStatus != .restricted, authorizationStatus != .denied else {
3744
if let _ = Self._locationManager {
3845
Self._locationManager = nil
@@ -42,9 +49,6 @@ import UIKit
4249
return nil
4350
}
4451

45-
let _locationManager = CLLocationManager()
46-
_locationManager.delegate = self
47-
Self._locationManager = _locationManager
4852
return Self._locationManager
4953
}
5054

@@ -53,11 +57,6 @@ import UIKit
5357
distanceFilter: CLLocationDistance,
5458
authorizationRequest: MPLocationAuthorizationRequest
5559
) {
56-
let authorizationStatus = CLLocationManager.authorizationStatus()
57-
guard authorizationStatus != .restricted, authorizationStatus != .denied else {
58-
return nil
59-
}
60-
6160
self.authorizationRequest = authorizationRequest
6261
requestedAccuracy = accuracy
6362
requestedDistanceFilter = distanceFilter

mParticle-Apple-SDK/MPStateMachine.m

Lines changed: 50 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -764,61 +764,59 @@ - (void)configureDataBlocking:(nullable NSDictionary *)blockSettings {
764764
- (void)requestAttributionDetailsWithBlock:(void (^ _Nonnull)(void))completionHandler requestsCompleted:(int)requestsCompleted {
765765
#if TARGET_OS_IOS == 1
766766
NSError *error;
767-
if (@available(iOS 14.3, *)) {
768-
NSString *attributionToken = [AAAttribution attributionTokenWithError:&error];
769-
if (!attributionToken) {
770-
completionHandler();
771-
return;
772-
}
767+
NSString *attributionToken = [AAAttribution attributionTokenWithError:&error];
768+
if (!attributionToken) {
769+
completionHandler();
770+
return;
771+
}
772+
773+
if (attributionToken) {
774+
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://api-adservices.apple.com/api/v1/"]];
775+
[request setHTTPMethod:@"POST"];
776+
[request setValue:@"text/plain" forHTTPHeaderField:@"Content-Type"];
777+
[request setHTTPBody:[attributionToken dataUsingEncoding:NSUTF8StringEncoding]];
773778

774-
if (attributionToken) {
775-
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://api-adservices.apple.com/api/v1/"]];
776-
[request setHTTPMethod:@"POST"];
777-
[request setValue:@"text/plain" forHTTPHeaderField:@"Content-Type"];
778-
[request setHTTPBody:[attributionToken dataUsingEncoding:NSUTF8StringEncoding]];
779-
780-
NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration ephemeralSessionConfiguration];
781-
sessionConfiguration.timeoutIntervalForRequest = 30;
782-
sessionConfiguration.timeoutIntervalForResource = 30;
783-
NSURLSession *urlSession = [NSURLSession sessionWithConfiguration:sessionConfiguration
784-
delegate:nil
785-
delegateQueue:nil];
786-
dispatch_async([MParticle messageQueue], ^{
787-
[urlSession dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *urlResponse, NSError *error) {
788-
if (error) {
789-
MPILogError(@"Failed requesting Ads Attribution with error: %@.", [error localizedDescription]);
790-
if (error.code == 1 /* ADClientErrorLimitAdTracking */) {
791-
completionHandler();
792-
} else if ((requestsCompleted + 1) > SEARCH_ADS_ATTRIBUTION_MAX_RETRIES) {
793-
completionHandler();
794-
} else {
795-
// Per Apple docs, "Handle any errors you receive and re-poll for data, if required"
796-
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(SEARCH_ADS_ATTRIBUTION_DELAY_BEFORE_RETRY * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
797-
[self requestAttributionDetailsWithBlock:completionHandler requestsCompleted:(requestsCompleted + 1)];
798-
});
799-
}
800-
} else {
801-
NSDictionary *adAttributionDictionary = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
802-
// Convert the dictionary to the prior format expected by our backend
803-
NSDictionary *finalAttributionDictionary = @{
804-
@"Version4.0": @{
805-
@"iad-attribution": adAttributionDictionary[@"attribution"],
806-
@"iad-org-id": [adAttributionDictionary[@"orgId"] stringValue],
807-
@"iad-campaign-id": [adAttributionDictionary[@"campaignId"] stringValue],
808-
@"iad-conversion-type": adAttributionDictionary[@"conversionType"],
809-
@"iad-click-date": adAttributionDictionary[@"clickDate"],
810-
@"iad-adgroup-id": [adAttributionDictionary[@"adGroupId"] stringValue],
811-
@"iad-country-or-region": adAttributionDictionary[@"countryOrRegion"],
812-
@"iad-keyword-id": [adAttributionDictionary[@"keywordId"] stringValue],
813-
@"iad-ad-id": [adAttributionDictionary[@"adId"] stringValue],
814-
}
815-
};
816-
self.searchAdsInfo = [[finalAttributionDictionary mutableCopy] copy];
779+
NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration ephemeralSessionConfiguration];
780+
sessionConfiguration.timeoutIntervalForRequest = 30;
781+
sessionConfiguration.timeoutIntervalForResource = 30;
782+
NSURLSession *urlSession = [NSURLSession sessionWithConfiguration:sessionConfiguration
783+
delegate:nil
784+
delegateQueue:nil];
785+
dispatch_async([MParticle messageQueue], ^{
786+
[urlSession dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *urlResponse, NSError *error) {
787+
if (error) {
788+
MPILogError(@"Failed requesting Ads Attribution with error: %@.", [error localizedDescription]);
789+
if (error.code == 1 /* ADClientErrorLimitAdTracking */) {
790+
completionHandler();
791+
} else if ((requestsCompleted + 1) > SEARCH_ADS_ATTRIBUTION_MAX_RETRIES) {
817792
completionHandler();
793+
} else {
794+
// Per Apple docs, "Handle any errors you receive and re-poll for data, if required"
795+
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(SEARCH_ADS_ATTRIBUTION_DELAY_BEFORE_RETRY * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
796+
[self requestAttributionDetailsWithBlock:completionHandler requestsCompleted:(requestsCompleted + 1)];
797+
});
818798
}
819-
}];
820-
});
821-
}
799+
} else {
800+
NSDictionary *adAttributionDictionary = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
801+
// Convert the dictionary to the prior format expected by our backend
802+
NSDictionary *finalAttributionDictionary = @{
803+
@"Version4.0": @{
804+
@"iad-attribution": adAttributionDictionary[@"attribution"],
805+
@"iad-org-id": [adAttributionDictionary[@"orgId"] stringValue],
806+
@"iad-campaign-id": [adAttributionDictionary[@"campaignId"] stringValue],
807+
@"iad-conversion-type": adAttributionDictionary[@"conversionType"],
808+
@"iad-click-date": adAttributionDictionary[@"clickDate"],
809+
@"iad-adgroup-id": [adAttributionDictionary[@"adGroupId"] stringValue],
810+
@"iad-country-or-region": adAttributionDictionary[@"countryOrRegion"],
811+
@"iad-keyword-id": [adAttributionDictionary[@"keywordId"] stringValue],
812+
@"iad-ad-id": [adAttributionDictionary[@"adId"] stringValue],
813+
}
814+
};
815+
self.searchAdsInfo = [[finalAttributionDictionary mutableCopy] copy];
816+
completionHandler();
817+
}
818+
}];
819+
});
822820
}
823821
#endif
824822
}

mParticle-Apple-SDK/Network/MPConnector.m

Lines changed: 33 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -109,42 +109,56 @@ - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didRece
109109
[protectionSpace receivesCredentialSecurely] &&
110110
serverTrust)
111111
{
112-
SecTrustCallback evaluateResult = ^(SecTrustRef _Nonnull trustRef, SecTrustResultType trustResult) {
112+
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
113113
BOOL trustChallenge = NO;
114+
CFErrorRef error = NULL;
114115

115-
if (trustResult == kSecTrustResultUnspecified || trustResult == kSecTrustResultProceed) {
116-
CFIndex certificateCount = SecTrustGetCertificateCount(trustRef);
117-
CFIndex certIdx = certificateCount - 1; //The Root Cert is always the last Cert in the chain
118-
119-
SecCertificateRef certificate = SecTrustGetCertificateAtIndex(trustRef, certIdx);
120-
CFDataRef certificateDataRef = SecCertificateCopyData(certificate);
116+
// Evaluate trust synchronously (iOS 12+)
117+
BOOL trustResult = SecTrustEvaluateWithError(serverTrust, &error);
118+
119+
if (trustResult) {
120+
// Get certificate chain (iOS 15+)
121+
CFArrayRef certificateChain = SecTrustCopyCertificateChain(serverTrust);
121122

122-
if (certificateDataRef != NULL) {
123-
NSData *certificateData = (__bridge NSData *)certificateDataRef;
123+
if (certificateChain != NULL) {
124+
CFIndex certificateCount = CFArrayGetCount(certificateChain);
125+
CFIndex certIdx = certificateCount - 1; //The Root Cert is always the last Cert in the chain
124126

125-
if (certificateData) {
126-
NSString *certificateEncodedString = [certificateData base64EncodedStringWithOptions:0];
127-
trustChallenge = [mpStoredCertificates containsObject:certificateEncodedString];
127+
SecCertificateRef certificate = (SecCertificateRef)CFArrayGetValueAtIndex(certificateChain, certIdx);
128+
CFDataRef certificateDataRef = SecCertificateCopyData(certificate);
129+
130+
if (certificateDataRef != NULL) {
131+
NSData *certificateData = (__bridge NSData *)certificateDataRef;
128132

129-
if (!trustChallenge && networkOptions.certificates.count > 0) {
130-
trustChallenge = [networkOptions.certificates containsObject:certificateData];
133+
if (certificateData) {
134+
NSString *certificateEncodedString = [certificateData base64EncodedStringWithOptions:0];
135+
trustChallenge = [mpStoredCertificates containsObject:certificateEncodedString];
136+
137+
if (!trustChallenge && networkOptions.certificates.count > 0) {
138+
trustChallenge = [networkOptions.certificates containsObject:certificateData];
139+
}
131140
}
141+
142+
CFRelease(certificateDataRef);
132143
}
133144

134-
CFRelease(certificateDataRef);
145+
CFRelease(certificateChain);
135146
}
136147
}
137148

149+
if (error) {
150+
CFRelease(error);
151+
}
152+
138153
BOOL shouldDisablePinning = (networkOptions.pinningDisabledInDevelopment && [MParticle sharedInstance].environment == MPEnvironmentDevelopment) || networkOptions.pinningDisabled;
154+
139155
if (trustChallenge || shouldDisablePinning) {
140-
NSURLCredential *urlCredential = [NSURLCredential credentialForTrust:trustRef];
156+
NSURLCredential *urlCredential = [NSURLCredential credentialForTrust:serverTrust];
141157
completionHandler(NSURLSessionAuthChallengeUseCredential, urlCredential);
142158
} else {
143159
completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil);
144160
}
145-
};
146-
147-
SecTrustEvaluateAsync(serverTrust, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), evaluateResult);
161+
});
148162
}
149163
}
150164

mParticle-Apple-SDK/Persistence/MPDatabaseMigrationController.m

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -347,11 +347,11 @@ - (void)migrateUploadsFromDatabase:(sqlite3 *)oldDatabase version:(NSNumber *)ol
347347
}
348348

349349
if (oldVersionValue < 31) {
350-
@try {
351-
NSData *uploadSettingsData = [NSKeyedArchiver archivedDataWithRootObject:uploadSettings];
352-
sqlite3_bind_blob(insertStatementHandle, 8, uploadSettingsData.bytes, (int)uploadSettingsData.length, SQLITE_TRANSIENT);
353-
} @catch(NSException *exception) {
354-
MPILogError(@"Error while migrating upload record: %@: %@", exception.name, exception.reason);
350+
NSError *error;
351+
NSData *uploadSettingsData = [NSKeyedArchiver archivedDataWithRootObject:uploadSettings requiringSecureCoding:YES error:&error];
352+
sqlite3_bind_blob(insertStatementHandle, 8, uploadSettingsData.bytes, (int)uploadSettingsData.length, SQLITE_TRANSIENT);
353+
if (error != nil) {
354+
MPILogError(@"Error while migrating upload record: %ld: %@", error.code, error.localizedDescription);
355355
sqlite3_reset(insertStatementHandle);
356356
continue;
357357
}

mParticle-Apple-SDK/Persistence/MPPersistenceController.mm

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1265,8 +1265,10 @@ - (MPMessage *)fetchSessionEndMessageInSession:(MPSession *)session {
12651265
while (sqlite3_step(preparedStatement) == SQLITE_ROW) {
12661266
NSData *uploadSettingsData = dataValue(preparedStatement, 8);
12671267
if (uploadSettingsData) {
1268-
@try {
1269-
MPUploadSettings *uploadSettings = [NSKeyedUnarchiver unarchiveObjectWithData:uploadSettingsData];
1268+
NSError *error = nil;
1269+
MPUploadSettings *uploadSettings = [NSKeyedUnarchiver unarchivedObjectOfClass:[MPUploadSettings class] fromData:uploadSettingsData error:&error];
1270+
1271+
if (uploadSettings && !error) {
12701272
MPUpload *upload = [[MPUpload alloc] initWithSessionId:@(int64Value(preparedStatement, 4))
12711273
uploadId:int64Value(preparedStatement, 0)
12721274
UUID:stringValue(preparedStatement, 1)
@@ -1277,8 +1279,8 @@ - (MPMessage *)fetchSessionEndMessageInSession:(MPSession *)session {
12771279
dataPlanVersion:intValue(preparedStatement, 7) ? @(intValue(preparedStatement, 7)) : nil
12781280
uploadSettings:uploadSettings];
12791281
uploadsVector.push_back(upload);
1280-
} @catch(NSException *exception) {
1281-
MPILogError(@"Error while fetching upload: %@: %@", exception.name, exception.reason);
1282+
} else {
1283+
MPILogError(@"Error unarchiving upload settings: %@", error);
12821284
}
12831285
}
12841286
}
@@ -1708,15 +1710,17 @@ - (void)saveUpload:(nonnull MPUpload *)upload {
17081710
sqlite3_bind_null(preparedStatement, 7);
17091711
}
17101712

1711-
@try {
1712-
NSData *uploadSettingsData = [NSKeyedArchiver archivedDataWithRootObject:upload.uploadSettings];
1713-
sqlite3_bind_blob(preparedStatement, 8, uploadSettingsData.bytes, (int)uploadSettingsData.length, SQLITE_TRANSIENT);
1714-
} @catch(NSException *exception) {
1715-
MPILogError(@"Error while storing upload: %@: %@", exception.name, exception.reason);
1713+
NSError *error = nil;
1714+
NSData *uploadSettingsData = [NSKeyedArchiver archivedDataWithRootObject:upload.uploadSettings requiringSecureCoding:YES error:&error];
1715+
1716+
if (!uploadSettingsData || error) {
1717+
MPILogError(@"Error archiving upload settings: %@", error);
17161718
sqlite3_clear_bindings(preparedStatement);
17171719
sqlite3_finalize(preparedStatement);
17181720
return;
17191721
}
1722+
1723+
sqlite3_bind_blob(preparedStatement, 8, uploadSettingsData.bytes, (int)uploadSettingsData.length, SQLITE_TRANSIENT);
17201724

17211725
if (sqlite3_step(preparedStatement) != SQLITE_DONE) {
17221726
MPILogError(@"Error while storing upload: %s", sqlite3_errmsg(mParticleDB));

mParticle-Apple-SDK/Utils/MPDevice.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -84,11 +84,11 @@ public class MPDevice: NSObject, NSCopying {
8484
}
8585

8686
@objc public var radioAccessTechnology: String {
87-
if let radioAccessTechnology = CTTelephonyNetworkInfo().currentRadioAccessTechnology {
88-
if let range = radioAccessTechnology.range(of: "CTRadioAccessTechnology") {
89-
if !range.isEmpty {
90-
return String(radioAccessTechnology[...range.upperBound])
91-
}
87+
let networkInfo = CTTelephonyNetworkInfo()
88+
89+
if let radioAccessTechnologies = networkInfo.serviceCurrentRadioAccessTechnology {
90+
if let defaultService = radioAccessTechnologies.first {
91+
return defaultService.value
9292
}
9393
}
9494
return "None"
@@ -232,7 +232,7 @@ public class MPDevice: NSObject, NSCopying {
232232
}
233233

234234
@objc public var isTablet: Bool {
235-
let isTablet = UI_USER_INTERFACE_IDIOM() == .pad
235+
let isTablet = UIDevice.current.userInterfaceIdiom == .pad
236236
return isTablet
237237
}
238238

0 commit comments

Comments
 (0)