Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions demo-ios-objc/demo-ios-objc/AppDelegate.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,8 @@

extern OptableSDK *OPTABLE;

/// SHA256 of the Email, normalized the way the SDK does it for OptableSDKIdentifierType_EmailAddress: whitespace removed, lowercased.
NSString *OptableDemoSHA256Email(NSString *email);

@interface AppDelegate : UIResponder <UIApplicationDelegate>
@end
15 changes: 15 additions & 0 deletions demo-ios-objc/demo-ios-objc/AppDelegate.m
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,24 @@
@import PrebidMobile;
@import GoogleMobileAds;

#import <CommonCrypto/CommonDigest.h>

OptableSDK *OPTABLE = nil;

NSString *OptableDemoSHA256Email(NSString *email) {
NSArray<NSString *> *parts = [email componentsSeparatedByCharactersInSet:NSCharacterSet.whitespaceAndNewlineCharacterSet];
NSData *data = [[[parts componentsJoinedByString:@""] lowercaseString] dataUsingEncoding:NSUTF8StringEncoding];

unsigned char digest[CC_SHA256_DIGEST_LENGTH];
CC_SHA256(data.bytes, (CC_LONG)data.length, digest);

NSMutableString *hex = [NSMutableString stringWithCapacity:CC_SHA256_DIGEST_LENGTH * 2];
for (int i = 0; i < CC_SHA256_DIGEST_LENGTH; i++) {
[hex appendFormat:@"%02x", digest[i]];
}
return hex;
}

@interface AppDelegate ()
@end

Expand Down
50 changes: 48 additions & 2 deletions demo-ios-objc/demo-ios-objc/Base.lproj/Main.storyboard
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,44 @@
<action selector="dispatchIdentify:" destination="BYZ-38-t0r" eventType="touchUpInside" id="Sae-rS-iHh"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="hEm-Bt-n01">
<rect key="frame" x="20" y="325" width="353" height="48"/>
<constraints>
<constraint firstAttribute="height" constant="48" id="hEm-Hc-n04"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<state key="normal" title="Identify (hashed email)"/>
<buttonConfiguration key="configuration" style="tinted" title="Identify (hashed email)">
<fontDescription key="titleFontDescription" type="system" weight="medium" pointSize="20"/>
</buttonConfiguration>
<connections>
<action selector="dispatchIdentifyHashed:" destination="BYZ-38-t0r" eventType="touchUpInside" id="hEm-Ac-n16"/>
</connections>
</button>
<textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="https://example.com/?oeid=&lt;sha256&gt;" textAlignment="natural" minimumFontSize="12" translatesAutoresizingMaskIntoConstraints="NO" id="uRl-Tf-n02">
<rect key="frame" x="20" y="403" width="353" height="45"/>
<constraints>
<constraint firstAttribute="height" constant="45" id="uRl-Hc-n05"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits" autocorrectionType="no" keyboardType="URL"/>
</textField>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="uRl-Bt-n03">
<rect key="frame" x="20" y="458" width="353" height="48"/>
<constraints>
<constraint firstAttribute="height" constant="48" id="uRb-Hc-n06"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<state key="normal" title="Identify from URL"/>
<buttonConfiguration key="configuration" style="tinted" title="Identify from URL">
<fontDescription key="titleFontDescription" type="system" weight="medium" pointSize="20"/>
</buttonConfiguration>
<connections>
<action selector="dispatchIdentifyFromURL:" destination="BYZ-38-t0r" eventType="touchUpInside" id="uRb-Ac-n17"/>
</connections>
</button>
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" editable="NO" textAlignment="natural" translatesAutoresizingMaskIntoConstraints="NO" id="pQa-vV-MeS">
<rect key="frame" x="20" y="330" width="353" height="385"/>
<rect key="frame" x="20" y="521" width="353" height="194"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<color key="textColor" systemColor="labelColor"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
Expand All @@ -68,8 +104,17 @@
<constraint firstItem="6Tk-OE-BBY" firstAttribute="trailing" secondItem="b7v-UN-xAf" secondAttribute="trailing" constant="20" id="IJw-hW-0Hm"/>
<constraint firstItem="pQa-vV-MeS" firstAttribute="centerX" secondItem="8bC-Xf-vdC" secondAttribute="centerX" id="MEG-Mb-Lj2"/>
<constraint firstItem="b7v-UN-xAf" firstAttribute="centerX" secondItem="8bC-Xf-vdC" secondAttribute="centerX" id="MO0-3A-9Nh"/>
<constraint firstItem="pQa-vV-MeS" firstAttribute="top" secondItem="b7v-UN-xAf" secondAttribute="bottom" constant="15" id="RHm-FX-7iM"/>
<constraint firstItem="pQa-vV-MeS" firstAttribute="top" secondItem="uRl-Bt-n03" secondAttribute="bottom" constant="15" id="RHm-FX-7iM"/>
<constraint firstItem="AKp-3F-KNX" firstAttribute="top" secondItem="6Tk-OE-BBY" secondAttribute="top" constant="20" id="SNe-0s-I2Q"/>
<constraint firstItem="hEm-Bt-n01" firstAttribute="top" secondItem="b7v-UN-xAf" secondAttribute="bottom" constant="10" id="hEm-Tp-n07"/>
<constraint firstItem="hEm-Bt-n01" firstAttribute="leading" secondItem="6Tk-OE-BBY" secondAttribute="leading" constant="20" id="hEm-Ld-n08"/>
<constraint firstItem="6Tk-OE-BBY" firstAttribute="trailing" secondItem="hEm-Bt-n01" secondAttribute="trailing" constant="20" id="hEm-Tr-n09"/>
<constraint firstItem="uRl-Tf-n02" firstAttribute="top" secondItem="hEm-Bt-n01" secondAttribute="bottom" constant="30" id="uRl-Tp-n10"/>
<constraint firstItem="uRl-Tf-n02" firstAttribute="leading" secondItem="6Tk-OE-BBY" secondAttribute="leading" constant="20" id="uRl-Ld-n11"/>
<constraint firstItem="6Tk-OE-BBY" firstAttribute="trailing" secondItem="uRl-Tf-n02" secondAttribute="trailing" constant="20" id="uRl-Tr-n12"/>
<constraint firstItem="uRl-Bt-n03" firstAttribute="top" secondItem="uRl-Tf-n02" secondAttribute="bottom" constant="10" id="uRb-Tp-n13"/>
<constraint firstItem="uRl-Bt-n03" firstAttribute="leading" secondItem="6Tk-OE-BBY" secondAttribute="leading" constant="20" id="uRb-Ld-n14"/>
<constraint firstItem="6Tk-OE-BBY" firstAttribute="trailing" secondItem="uRl-Bt-n03" secondAttribute="trailing" constant="20" id="uRb-Tr-n15"/>
<constraint firstItem="AKp-3F-KNX" firstAttribute="leading" secondItem="6Tk-OE-BBY" secondAttribute="leading" constant="20" id="UII-5h-4Jn"/>
<constraint firstItem="6Tk-OE-BBY" firstAttribute="trailing" secondItem="pQa-vV-MeS" secondAttribute="trailing" constant="20" id="aUv-ov-L1P"/>
<constraint firstItem="6Tk-OE-BBY" firstAttribute="bottom" secondItem="pQa-vV-MeS" secondAttribute="bottom" constant="20" id="hrC-Rt-ujv"/>
Expand All @@ -81,6 +126,7 @@
<outlet property="identifyButton" destination="b7v-UN-xAf" id="JgO-1H-l2i"/>
<outlet property="identifyInput" destination="0Py-KR-2hS" id="Uda-2S-GRy"/>
<outlet property="identifyOutput" destination="pQa-vV-MeS" id="XQe-0Z-PkW"/>
<outlet property="identifyURLInput" destination="uRl-Tf-n02" id="uRl-Ot-n19"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
Expand Down
10 changes: 6 additions & 4 deletions demo-ios-objc/demo-ios-objc/GAMBannerViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,10 @@ - (IBAction)loadBannerWithTargeting:(id)sender {
[OPTABLE witnessWithEvent: @"GAMBannerViewController.loadBannerClicked"
properties: @{ @"example": @"value" }
error: &error];
// `id` and `neighbors` are sent as given, so Email addresses and phone numbers must be hashed first.
[OPTABLE profileWithTraits: @{ @"example": @"value", @"anotherExample": @123, @"thirdExample": @YES }
id: NULL
neighbors: NULL
id: @"c:demo-user-1234"
neighbors: @[[@"e:" stringByAppendingString:OptableDemoSHA256Email(@"some.email@address.com")]]
error: &error];
}

Expand All @@ -85,9 +86,10 @@ - (IBAction)loadBannerWithTargetingFromCache:(id)sender {
[OPTABLE witnessWithEvent: @"GAMBannerViewController.loadBannerClicked"
properties: @{ @"example": @"value" }
error: &error];
// `id` and `neighbors` are sent as given, so Email addresses and phone numbers must be hashed first.
[OPTABLE profileWithTraits: @{ @"example": @"value", @"anotherExample": @123, @"thirdExample": @YES }
id: NULL
neighbors: NULL
id: @"c:demo-user-1234"
neighbors: @[[@"e:" stringByAppendingString:OptableDemoSHA256Email(@"some.email@address.com")]]
error: &error];
}

Expand Down
3 changes: 3 additions & 0 deletions demo-ios-objc/demo-ios-objc/IdentifyViewController.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
@property (weak, nonatomic) IBOutlet UITextField *identifyInput;
@property (weak, nonatomic) IBOutlet UIButton *identifyButton;
@property (weak, nonatomic) IBOutlet UITextView *identifyOutput;
@property (weak, nonatomic) IBOutlet UITextField *identifyURLInput;

- (IBAction)dispatchIdentify:(id)sender;
- (IBAction)dispatchIdentifyHashed:(id)sender;
- (IBAction)dispatchIdentifyFromURL:(id)sender;
@end
32 changes: 32 additions & 0 deletions demo-ios-objc/demo-ios-objc/IdentifyViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ - (void)viewDidLoad {
[super viewDidLoad];

_identifyInput.delegate = self;
_identifyURLInput.delegate = self;

// A link like the ones in a newsletter Email, carrying the SHA256 of the reader's Email address
_identifyURLInput.text = [NSString stringWithFormat:@"https://example.com/newsletter?oeid=%@", OptableDemoSHA256Email(@"some.email@address.com")];

OptableSDKDelegate *delegate = (OptableSDKDelegate *)OPTABLE.delegate;
delegate.identifyOutput = self.identifyOutput;
Expand Down Expand Up @@ -71,6 +75,34 @@ - (IBAction)dispatchIdentify:(id)sender {
}];
}

// dispatchIdentifyHashed: sends the Email as a SHA256 hashed in the app, as you would with a hash from your own backend.
// OptableSDKIdentifierType_HEM sends it as given; passing a hash as OptableSDKIdentifierType_EmailAddress would hash it a second time.
- (IBAction)dispatchIdentifyHashed:(id)sender {
[self.view endEditing: TRUE];

// An empty Email would otherwise be sent as the SHA256 of an empty string
NSString *email = [_identifyInput.text ?: @"" stringByTrimmingCharactersInSet:NSCharacterSet.whitespaceAndNewlineCharacterSet];
if (email.length == 0) {
_identifyOutput.text = @"Enter an Email to send it hashed.";
return;
}

NSError *error = nil;
[OPTABLE identify: @[
[OptableSDKIdentifier identifierWithType:OptableSDKIdentifierType_HEM value:OptableDemoSHA256Email(email)],
]
error: &error];
}

// dispatchIdentifyFromURL: passes a link to tryIdentifyFromURL:, as you would from a universal link handler.
// If the link has an `oeid` query parameter holding a SHA256, the SDK calls /identify with it; otherwise it does nothing.
- (IBAction)dispatchIdentifyFromURL:(id)sender {
[self.view endEditing: TRUE];

NSError *error = nil;
[OPTABLE tryIdentifyFromURL: _identifyURLInput.text ?: @"" error: &error];
}

// MARK: - UITextFieldDelegate
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
[textField resignFirstResponder];
Expand Down
10 changes: 6 additions & 4 deletions demo-ios-objc/demo-ios-objc/PrebidBannerViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,10 @@ - (IBAction)loadBannerWithTargeting:(id)sender {
[OPTABLE witnessWithEvent: @"PrebidBannerViewController.loadBannerClicked"
properties: @{ @"example": @"value" }
error: &error];
// `id` and `neighbors` are sent as given, so Email addresses and phone numbers must be hashed first.
[OPTABLE profileWithTraits: @{ @"example": @"value", @"anotherExample": @123, @"thirdExample": @YES }
id: NULL
neighbors: NULL
id: @"c:demo-user-1234"
neighbors: @[[@"e:" stringByAppendingString:OptableDemoSHA256Email(@"some.email@address.com")]]
error: &error];
}

Expand All @@ -94,9 +95,10 @@ - (IBAction)loadBannerWithTargetingFromCache:(id)sender {
[OPTABLE witnessWithEvent: @"PrebidBannerViewController.loadBannerClicked"
properties: @{ @"example": @"value" }
error: &error];
// `id` and `neighbors` are sent as given, so Email addresses and phone numbers must be hashed first.
[OPTABLE profileWithTraits: @{ @"example": @"value", @"anotherExample": @123, @"thirdExample": @YES }
id: NULL
neighbors: NULL
id: @"c:demo-user-1234"
neighbors: @[[@"e:" stringByAppendingString:OptableDemoSHA256Email(@"some.email@address.com")]]
error: &error];
}

Expand Down
Loading