diff --git a/Adjust.podspec b/Adjust.podspec index 5467deb9d..f4750526b 100644 --- a/Adjust.podspec +++ b/Adjust.podspec @@ -1,11 +1,11 @@ Pod::Spec.new do |s| s.name = "Adjust" - s.version = "4.0.8" + s.version = "4.1.0" s.summary = "This is the iOS SDK of adjust. You can read more about it at http://adjust.com." s.homepage = "http://adjust.com" s.license = { :type => 'MIT', :file => 'MIT-LICENSE' } s.author = { "Christian Wellenbrock" => "welle@adjust.com" } - s.source = { :git => "https://github.com/adjust/ios_sdk.git", :tag => "v4.0.8" } + s.source = { :git => "https://github.com/adjust/ios_sdk.git", :tag => "v4.1.0" } s.platform = :ios, '4.3' s.framework = 'SystemConfiguration' s.weak_framework = 'AdSupport', 'iAd' diff --git a/Adjust.xcodeproj/project.pbxproj b/Adjust.xcodeproj/project.pbxproj index 42c3b9288..9d32ec8cb 100644 --- a/Adjust.xcodeproj/project.pbxproj +++ b/Adjust.xcodeproj/project.pbxproj @@ -26,6 +26,9 @@ 969952D21A01309200928462 /* ADJAttribution.m in Sources */ = {isa = PBXBuildFile; fileRef = 969952D11A01309200928462 /* ADJAttribution.m */; }; 96C0EFE01A3EF47A00B39F31 /* NSString+ADJAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 96CD2BDD1A13BFC600A40AFB /* NSString+ADJAdditions.m */; }; 96C0EFE11A3EF47A00B39F31 /* UIDevice+ADJAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 96CD2BDF1A13BFC600A40AFB /* UIDevice+ADJAdditions.m */; }; + 96C93DC51AC41A8300B53F56 /* Adjust.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 96E5E34C18BBB48A008E7B30 /* Adjust.h */; }; + 96C93DF51AC47F2E00B53F56 /* NSData+ADJAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 96C93DF41AC47F2E00B53F56 /* NSData+ADJAdditions.m */; }; + 96C93DF61AC47FE000B53F56 /* NSData+ADJAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 96C93DF41AC47F2E00B53F56 /* NSData+ADJAdditions.m */; }; 96CD2BE01A13BFC600A40AFB /* NSString+ADJAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 96CD2BDD1A13BFC600A40AFB /* NSString+ADJAdditions.m */; }; 96CD2BE11A13BFC600A40AFB /* UIDevice+ADJAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 96CD2BDF1A13BFC600A40AFB /* UIDevice+ADJAdditions.m */; }; 96E5E38118BBB48A008E7B30 /* Adjust.m in Sources */ = {isa = PBXBuildFile; fileRef = 96E5E34D18BBB48A008E7B30 /* Adjust.m */; }; @@ -86,6 +89,7 @@ dstPath = "include/$(PRODUCT_NAME)"; dstSubfolderSpec = 16; files = ( + 96C93DC51AC41A8300B53F56 /* Adjust.h in CopyFiles */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -113,6 +117,8 @@ 969952CE1A012F5300928462 /* ADJAttributionHandler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ADJAttributionHandler.m; sourceTree = ""; }; 969952D01A01309200928462 /* ADJAttribution.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ADJAttribution.h; sourceTree = ""; }; 969952D11A01309200928462 /* ADJAttribution.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ADJAttribution.m; sourceTree = ""; }; + 96C93DF31AC47F2E00B53F56 /* NSData+ADJAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSData+ADJAdditions.h"; sourceTree = ""; }; + 96C93DF41AC47F2E00B53F56 /* NSData+ADJAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSData+ADJAdditions.m"; sourceTree = ""; }; 96CD2BDC1A13BFC600A40AFB /* NSString+ADJAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+ADJAdditions.h"; sourceTree = ""; }; 96CD2BDD1A13BFC600A40AFB /* NSString+ADJAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+ADJAdditions.m"; sourceTree = ""; }; 96CD2BDE1A13BFC600A40AFB /* UIDevice+ADJAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIDevice+ADJAdditions.h"; sourceTree = ""; }; @@ -245,6 +251,8 @@ 96CD2BDD1A13BFC600A40AFB /* NSString+ADJAdditions.m */, 96CD2BDE1A13BFC600A40AFB /* UIDevice+ADJAdditions.h */, 96CD2BDF1A13BFC600A40AFB /* UIDevice+ADJAdditions.m */, + 96C93DF31AC47F2E00B53F56 /* NSData+ADJAdditions.h */, + 96C93DF41AC47F2E00B53F56 /* NSData+ADJAdditions.m */, ); path = ADJAdditions; sourceTree = ""; @@ -433,6 +441,7 @@ 96E5E39918BBB48A008E7B30 /* ADJUtil.m in Sources */, 96E5E39818BBB48A008E7B30 /* ADJTimer.m in Sources */, 96E5E38C18BBB48A008E7B30 /* ADJActivityKind.m in Sources */, + 96C93DF51AC47F2E00B53F56 /* NSData+ADJAdditions.m in Sources */, 96E5E38D18BBB48A008E7B30 /* ADJActivityPackage.m in Sources */, 965307F61A000DA400107FF9 /* ADJDeviceInfo.m in Sources */, 969952D21A01309200928462 /* ADJAttribution.m in Sources */, @@ -464,6 +473,7 @@ 96E5E3B418BBB49E008E7B30 /* ADJRequestHandlerMock.m in Sources */, 96E5E3B518BBB49E008E7B30 /* AIRequestHandlerTests.m in Sources */, 96ED00391A38A4CD00209110 /* ADJAttributionHandlerMock.m in Sources */, + 96C93DF61AC47FE000B53F56 /* NSData+ADJAdditions.m in Sources */, 96E5E3B218BBB49E008E7B30 /* ADJPackageHandlerMock.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/Adjust/ADJAdditions/NSData+ADJAdditions.h b/Adjust/ADJAdditions/NSData+ADJAdditions.h new file mode 100644 index 000000000..0958f3fce --- /dev/null +++ b/Adjust/ADJAdditions/NSData+ADJAdditions.h @@ -0,0 +1,15 @@ +// +// NSData+ADJAdditions.h +// adjust +// +// Created by Pedro Filipe on 26/03/15. +// Copyright (c) 2015 adjust GmbH. All rights reserved. +// + +#import + +@interface NSData(ADJAdditions) + +- (NSString *)adjEncodeBase64; + +@end \ No newline at end of file diff --git a/Adjust/ADJAdditions/NSData+ADJAdditions.m b/Adjust/ADJAdditions/NSData+ADJAdditions.m new file mode 100644 index 000000000..03228ccd3 --- /dev/null +++ b/Adjust/ADJAdditions/NSData+ADJAdditions.m @@ -0,0 +1,64 @@ +// +// NSData+ADJAdditions.m +// adjust +// +// Created by Pedro Filipe on 26/03/15. +// Copyright (c) 2015 adjust GmbH. All rights reserved. +// + +#import "NSData+ADJAdditions.h" + +@implementation NSData(ADJAdditions) + +static const char _base64EncodingTable[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +// http://stackoverflow.com/a/4727124 +- (NSString *)adjEncodeBase64 { + const unsigned char * objRawData = self.bytes; + char * objPointer; + char * strResult; + + // Get the Raw Data length and ensure we actually have data + NSUInteger intLength = self.length; + if (intLength == 0) return nil; + + // Setup the String-based Result placeholder and pointer within that placeholder + strResult = (char *)calloc((((intLength + 2) / 3) * 4) + 1, sizeof(char)); + objPointer = strResult; + + // Iterate through everything + while (intLength > 2) { // keep going until we have less than 24 bits + *objPointer++ = _base64EncodingTable[objRawData[0] >> 2]; + *objPointer++ = _base64EncodingTable[((objRawData[0] & 0x03) << 4) + (objRawData[1] >> 4)]; + *objPointer++ = _base64EncodingTable[((objRawData[1] & 0x0f) << 2) + (objRawData[2] >> 6)]; + *objPointer++ = _base64EncodingTable[objRawData[2] & 0x3f]; + + // we just handled 3 octets (24 bits) of data + objRawData += 3; + intLength -= 3; + } + + // now deal with the tail end of things + if (intLength != 0) { + *objPointer++ = _base64EncodingTable[objRawData[0] >> 2]; + if (intLength > 1) { + *objPointer++ = _base64EncodingTable[((objRawData[0] & 0x03) << 4) + (objRawData[1] >> 4)]; + *objPointer++ = _base64EncodingTable[(objRawData[1] & 0x0f) << 2]; + *objPointer++ = '='; + } else { + *objPointer++ = _base64EncodingTable[(objRawData[0] & 0x03) << 4]; + *objPointer++ = '='; + *objPointer++ = '='; + } + } + + // Terminate the string-based result + *objPointer = '\0'; + + // Return the results as an NSString object + NSString *encodedString = [NSString stringWithCString:strResult encoding:NSASCIIStringEncoding]; + free(strResult); + return encodedString; +} + +@end \ No newline at end of file diff --git a/Adjust/ADJEvent.h b/Adjust/ADJEvent.h index a79766f6c..c94d468f3 100644 --- a/Adjust/ADJEvent.h +++ b/Adjust/ADJEvent.h @@ -14,8 +14,9 @@ @property (nonatomic, copy, readonly) NSNumber* revenue; @property (nonatomic, readonly) NSDictionary* callbackParameters; @property (nonatomic, readonly) NSDictionary* partnerParameters; -@property (nonatomic, copy) NSString* transactionId; +@property (nonatomic, copy, readonly) NSString* transactionId; @property (nonatomic, copy, readonly) NSString* currency; +@property (nonatomic, copy, readonly) NSData* receipt; /** * Create Event object with Event Token. @@ -69,10 +70,19 @@ * A transaction ID can be used to avoid duplicate revenue events. The last ten * transaction identifiers are remembered. * - * @param The identifier used to avoid duplicate revenue events + * @param transactionId The identifier used to avoid duplicate revenue events */ - (void) setTransactionId:(NSString *)transactionId; - (BOOL) isValid; +/** + * + * Validate a in-app-purchase receipt. + * + * @param receipt The receipt to validate + * @param transactionId The identifier used to validate the receipt and to avoid duplicate revenue events + */ +- (void) setReceipt:(NSData *)receipt transactionId:(NSString *)transactionId; + @end diff --git a/Adjust/ADJEvent.m b/Adjust/ADJEvent.m index 6212ca062..d05630dd7 100644 --- a/Adjust/ADJEvent.m +++ b/Adjust/ADJEvent.m @@ -146,10 +146,26 @@ - (BOOL) checkRevenue:(NSNumber*) revenue - (BOOL) isValid { if (![self checkEventToken:self.eventToken]) return NO; if (![self checkRevenue:self.revenue currency:self.currency]) return NO; + if (![self checkReceipt:self.receipt transactionId:self.transactionId]) return NO; return YES; } +- (void) setReceipt:(NSData *)receipt transactionId:(NSString *)transactionId { + if (![self checkReceipt:receipt transactionId:transactionId]) return; + + _receipt = receipt; + _transactionId = transactionId; +} + +- (BOOL) checkReceipt:(NSData *)receipt transactionId:(NSString *)transactionId { + if (receipt != nil && transactionId == nil) { + [self.logger error:@"Missing transactionId"]; + return NO; + } + return YES; +} + - (BOOL) isValidParameter:(NSString *)attribute attributeType:(NSString *)attributeType parameterName:(NSString *)parameterName @@ -178,7 +194,13 @@ -(id)copyWithZone:(NSZone *)zone } copy.callbackMutableParameters = [self.callbackMutableParameters copyWithZone:zone]; copy.partnerMutableParameters = [self.partnerMutableParameters copyWithZone:zone]; - copy.transactionId = [self.transactionId copyWithZone:zone]; + if (self.transactionId != nil) { + if (self.receipt != nil) { + [copy setReceipt:self.receipt transactionId:self.transactionId]; + } else { + [copy setTransactionId:self.transactionId]; + } + } } return copy; } diff --git a/Adjust/ADJPackageBuilder.m b/Adjust/ADJPackageBuilder.m index 358598d83..36e5c3e02 100644 --- a/Adjust/ADJPackageBuilder.m +++ b/Adjust/ADJPackageBuilder.m @@ -10,6 +10,7 @@ #import "ADJActivityPackage.h" #import "ADJUtil.h" #import "ADJAttribution.h" +#import "NSData+ADJAdditions.h" #pragma mark - @implementation ADJPackageBuilder @@ -51,6 +52,12 @@ - (ADJActivityPackage *)buildEventPackage:(ADJEvent *) event{ [self parameters:parameters setDictionaryJson:event.callbackParameters forKey:@"callback_params"]; [self parameters:parameters setDictionaryJson:event.partnerParameters forKey:@"partner_params"]; + if (event.receipt != nil) { + NSString *receiptBase64 = [event.receipt adjEncodeBase64]; + [self parameters:parameters setString:receiptBase64 forKey:@"receipt"]; + [self parameters:parameters setString:event.transactionId forKey:@"transaction_id"]; + } + ADJActivityPackage *eventPackage = [self defaultActivityPackage]; eventPackage.path = @"/event"; eventPackage.activityKind = ADJActivityKindEvent; diff --git a/Adjust/ADJUtil.m b/Adjust/ADJUtil.m index 93b41969f..28fa49bd6 100644 --- a/Adjust/ADJUtil.m +++ b/Adjust/ADJUtil.m @@ -16,7 +16,7 @@ #include static NSString * const kBaseUrl = @"https://app.adjust.com"; -static NSString * const kClientSdk = @"ios4.0.8"; +static NSString * const kClientSdk = @"ios4.1.0"; static NSString * const kDateFormat = @"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'Z"; static NSDateFormatter *dateFormat; diff --git a/AdjustTests/ADJActivityHandlerTests.m b/AdjustTests/ADJActivityHandlerTests.m index 25bacebc3..6ae3ba038 100644 --- a/AdjustTests/ADJActivityHandlerTests.m +++ b/AdjustTests/ADJActivityHandlerTests.m @@ -121,7 +121,7 @@ - (void)testFirstRun ADJActivityPackage *activityPackage = (ADJActivityPackage *) self.packageHandlerMock.packageQueue[0]; // check the Sdk version is being tested - XCTAssertEqual(@"ios4.0.8", activityPackage.clientSdk, @"%@", activityPackage.extendedString); + XCTAssertEqual(@"ios4.1.0", activityPackage.clientSdk, @"%@", activityPackage.extendedString); // check the server url XCTAssertEqual(@"https://app.adjust.com", ADJUtil.baseUrl); @@ -358,6 +358,9 @@ - (void)testEventsBuffered { // add revenue [thirdEvent setRevenue:0 currency:@"USD"]; + // add receipt information + [thirdEvent setReceipt:[@"{ \"transaction-id\" = \"t_id_2\"; }" dataUsingEncoding:NSUTF8StringEncoding] transactionId:@"t_id_2"]; + // track the third event [activityHandler trackEvent:thirdEvent]; @@ -449,6 +452,9 @@ - (void)testEventsBuffered { XCTAssert([(NSString *)firstEventPackageParameters[@"revenue"] isEqualToString:@"0.0001"], @"%@", firstEventPackage.extendedString); XCTAssert([(NSString *)firstEventPackageParameters[@"currency"] isEqualToString:@"EUR"], @"%@", firstEventPackage.extendedString); + // check the that the transaction id was not injected + XCTAssertNil(firstEventPackageParameters[@"transaction_id"], @"%@", firstEventPackage.extendedString); + // check the injected parameters XCTAssert([(NSString *)firstEventPackageParameters[@"callback_params"] isEqualToString:@"{\"keyCall\":\"valueCall2\",\"fooCall\":\"barCall\"}"], @"%@", firstEventPackage.extendedString); @@ -473,6 +479,10 @@ - (void)testEventsBuffered { XCTAssert([(NSString *)thirdEventPackageParameters[@"revenue"] isEqualToString:@"0"], @"%@", thirdEventPackage.extendedString); XCTAssert([(NSString *)thirdEventPackageParameters[@"currency"] isEqualToString:@"USD"], @"%@", thirdEventPackage.extendedString); + // check the receipt and transaction_id + XCTAssert([(NSString *)thirdEventPackageParameters[@"receipt"] isEqualToString:@"eyAidHJhbnNhY3Rpb24taWQiID0gInRfaWRfMiI7IH0="], @"%@", thirdEventPackage.extendedString); + XCTAssert([(NSString *)thirdEventPackageParameters[@"transaction_id"] isEqualToString:@"t_id_2"], @"%@", thirdEventPackage.extendedString); + // check the that the parameters were not injected XCTAssertNil(thirdEventPackageParameters[@"callback_params"], @"%@", thirdEventPackage.extendedString); XCTAssertNil(thirdEventPackageParameters[@"partner_params"], @"%@", thirdEventPackage.extendedString); @@ -611,6 +621,8 @@ - (void)testChecks { [firstEvent setRevenue:0 currency:@""]; [firstEvent setRevenue:-0.0001 currency:@"EUR"]; + [firstEvent setReceipt:@"value" transactionId:nil]; + [activityHandler trackEvent:firstEvent]; [NSThread sleepForTimeInterval:2]; @@ -646,6 +658,8 @@ - (void)testChecks { // check revenue is invalid XCTAssert([self.loggerMock containsMessage:ADJLogLevelError beginsWith:@"Invalid amount -0.0001"], @"%@", self.loggerMock); + // check the receipt had a nil transaction id + XCTAssert([self.loggerMock containsMessage:ADJLogLevelError beginsWith:@"Missing transactionId"], @"%@", self.loggerMock); // check the first parameters ADJActivityPackage *firstEventPackage = (ADJActivityPackage *) self.packageHandlerMock.packageQueue[1]; diff --git a/README.md b/README.md index 665b79ae1..52fbebcff 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ If you're using [CocoaPods][cocoapods], you can add the following line to your `Podfile` and continue with [step 3](#step3): ```ruby -pod 'Adjust', :git => 'git://github.com/adjust/ios_sdk.git', :tag => 'v4.0.8' +pod 'Adjust', :git => 'git://github.com/adjust/ios_sdk.git', :tag => 'v4.1.0' ``` ### 1. Get the SDK @@ -201,7 +201,7 @@ that you have set in your adjust dashboard.** You can read more about revenue and event tracking in the [event tracking guide.][event-tracking] -#### Revenue deduplication +#### Revenue deduplication You can also pass in an optional transaction ID to avoid tracking duplicate revenues. The last ten transaction IDs are remembered and revenue events with @@ -232,6 +232,25 @@ tracking revenue that is not actually being generated. } ``` +#### Receipt verification + +If you track in-app purchases, you can also attach the receipt to the tracked +event. In that case our servers will verify that receipt with Apple and discard +the event if the verification failed. To make this work, you also need to send +us the transaction ID of the purchase. The transaction ID will also be used for +SDK side deduplication as explained [above](#deduplication): + +```objc +NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL]; +NSData *receipt = [NSData dataWithContentsOfURL:receiptURL]; + +ADJEvent *event = [ADJEvent eventWithEventToken:...]; +[event setRevenue:... currency:...]; +[event setReceipt:receipt transactionId:transaction.transactionIdentifier]; + +[Adjust trackEvent:event]; +``` + ### 7. Set up deep link reattributions You can set up the adjust SDK to handle deep links that are used to open your diff --git a/VERSION b/VERSION index a2cec7aff..ee74734aa 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -4.0.8 +4.1.0 diff --git a/doc/migrate.md b/doc/migrate.md index f0ed1e81c..2e7517535 100644 --- a/doc/migrate.md +++ b/doc/migrate.md @@ -1,4 +1,4 @@ -## Migrate your adjust SDK for iOS to v4.0.8 from v3.4.0 +## Migrate your adjust SDK for iOS to v4.1.0 from v3.4.0 ### Initial setup diff --git a/example/example.xcodeproj/project.pbxproj b/example/example.xcodeproj/project.pbxproj index ee1507e9d..2397060fc 100644 --- a/example/example.xcodeproj/project.pbxproj +++ b/example/example.xcodeproj/project.pbxproj @@ -33,8 +33,9 @@ 960FCF8D1A1B9B7D00282BD4 /* ADJAttributionHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 960FCF761A1B9B7D00282BD4 /* ADJAttributionHandler.m */; }; 960FCF8E1A1B9B7D00282BD4 /* ADJAttribution.m in Sources */ = {isa = PBXBuildFile; fileRef = 960FCF781A1B9B7D00282BD4 /* ADJAttribution.m */; }; 960FCF8F1A1B9B7D00282BD4 /* ADJConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 960FCF7A1A1B9B7D00282BD4 /* ADJConfig.m */; }; - 96332C8F1A891E1100D38FAF /* AdSupport.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 96332C8E1A891E1100D38FAF /* AdSupport.framework */; }; - 96332C911A891E1800D38FAF /* iAd.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 96332C901A891E1800D38FAF /* iAd.framework */; }; + 96332C8F1A891E1100D38FAF /* AdSupport.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 96332C8E1A891E1100D38FAF /* AdSupport.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; + 96332C911A891E1800D38FAF /* iAd.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 96332C901A891E1800D38FAF /* iAd.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; + 96C93DF91AC4828B00B53F56 /* NSData+ADJAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 96C93DF81AC4828B00B53F56 /* NSData+ADJAdditions.m */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -101,6 +102,8 @@ 960FCF7A1A1B9B7D00282BD4 /* ADJConfig.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ADJConfig.m; sourceTree = ""; }; 96332C8E1A891E1100D38FAF /* AdSupport.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AdSupport.framework; path = System/Library/Frameworks/AdSupport.framework; sourceTree = SDKROOT; }; 96332C901A891E1800D38FAF /* iAd.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = iAd.framework; path = System/Library/Frameworks/iAd.framework; sourceTree = SDKROOT; }; + 96C93DF71AC4828B00B53F56 /* NSData+ADJAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSData+ADJAdditions.h"; sourceTree = ""; }; + 96C93DF81AC4828B00B53F56 /* NSData+ADJAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSData+ADJAdditions.m"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -188,6 +191,8 @@ 960FCF561A1B9B7D00282BD4 /* ADJAdditions */ = { isa = PBXGroup; children = ( + 96C93DF71AC4828B00B53F56 /* NSData+ADJAdditions.h */, + 96C93DF81AC4828B00B53F56 /* NSData+ADJAdditions.m */, 960FCF521A1B9B7D00282BD4 /* NSString+ADJAdditions.h */, 960FCF531A1B9B7D00282BD4 /* NSString+ADJAdditions.m */, 960FCF541A1B9B7D00282BD4 /* UIDevice+ADJAdditions.h */, @@ -288,6 +293,7 @@ TargetAttributes = { 960FCF1F1A1B9ACE00282BD4 = { CreatedOnToolsVersion = 6.1; + DevelopmentTeam = QGUGW9AUMK; }; 960FCF381A1B9ACE00282BD4 = { CreatedOnToolsVersion = 6.1; @@ -342,6 +348,7 @@ 960FCF891A1B9B7D00282BD4 /* ADJUtil.m in Sources */, 960FCF8B1A1B9B7D00282BD4 /* ADJDeviceInfo.m in Sources */, 960FCF851A1B9B7D00282BD4 /* ADJPackageBuilder.m in Sources */, + 96C93DF91AC4828B00B53F56 /* NSData+ADJAdditions.m in Sources */, 960FCF8E1A1B9B7D00282BD4 /* ADJAttribution.m in Sources */, 960FCF821A1B9B7D00282BD4 /* ADJActivityState.m in Sources */, 960FCF2C1A1B9ACE00282BD4 /* ViewController.m in Sources */,