Skip to content

Commit

Permalink
feat(ios): UMP consent SDK on new arch
Browse files Browse the repository at this point in the history
  • Loading branch information
dylancom committed Dec 9, 2024
1 parent 1a503f2 commit 19e9379
Show file tree
Hide file tree
Showing 10 changed files with 416 additions and 344 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ When using The New Architecture, some legacy code will still be used though. See
| iOS | Mobile Ads SDK Methods (Turbo Native Module) | ✅ Complete |
| iOS | Banners (Fabric Native Component) | ✅ Complete |
| iOS | Full Screen Ads (Turbo Native Module) | ✅ Complete |
| iOS | User Messaging Platform (Turbo Native Module) | ⏳ To-Do |
| iOS | User Messaging Platform (Turbo Native Module) | ✅ Complete |
| iOS | EventEmitter (Turbo Native Module) | ⏳ To-Do |
| iOS | Revenue Precision Constants (Turbo Native Module) | ✅ Complete |
| Android | Mobile Ads SDK Methods (Turbo Native Module) | ⏳ To-Do |
Expand Down
15 changes: 13 additions & 2 deletions ios/RNGoogleMobileAds/RNGoogleMobileAdsConsentModule.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
//
/**
* Copyright (c) 2016-present Invertase Limited & Contributors
*
Expand All @@ -16,10 +15,22 @@
*
*/

#if !TARGET_OS_MACCATALYST

#import <Foundation/Foundation.h>

#import <React/RCTBridgeModule.h>
#ifdef RCT_NEW_ARCH_ENABLED

#import <RNGoogleMobileAdsSpec/RNGoogleMobileAdsSpec.h>
@interface RNGoogleMobileAdsConsentModule : NSObject <NativeConsentModuleSpec>

#else

#import <React/RCTBridgeModule.h>
@interface RNGoogleMobileAdsConsentModule : NSObject <RCTBridgeModule>

#endif

@end

#endif
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@
#if !TARGET_OS_MACCATALYST
#include <UserMessagingPlatform/UserMessagingPlatform.h>
#endif
#import "RCTBridgeModule.h"
#ifdef RCT_NEW_ARCH_ENABLED
#import "RNGoogleMobileAdsSpec.h"
#endif
#import "RNGoogleMobileAdsConsentModule.h"
#import "common/RNSharedUtils.h"

Expand Down Expand Up @@ -92,7 +94,8 @@ - (NSDictionary *)getConsentInformation {
UMPRequestParameters *parameters = [[UMPRequestParameters alloc] init];
UMPDebugSettings *debugSettings = [[UMPDebugSettings alloc] init];

debugSettings.geography = [options[@"debugGeography"] integerValue] ?: UMPDebugGeographyDisabled;
debugSettings.geography =
(UMPDebugGeography)([options[@"debugGeography"] integerValue] ?: UMPDebugGeographyDisabled);
debugSettings.testDeviceIdentifiers =
[options valueForKeyPath:@"testDeviceIdentifiers"] ?: [[NSMutableArray alloc] init];

Expand All @@ -117,6 +120,105 @@ - (NSDictionary *)getConsentInformation {
}

RCT_EXPORT_METHOD(showForm : (RCTPromiseResolveBlock)resolve : (RCTPromiseRejectBlock)reject) {
[self showForm:resolve reject:reject];
}

RCT_EXPORT_METHOD(showPrivacyOptionsForm
: (RCTPromiseResolveBlock)resolve
: (RCTPromiseRejectBlock)reject) {
[self showPrivacyOptionsForm:resolve reject:reject];
}

RCT_EXPORT_METHOD(loadAndShowConsentFormIfRequired
: (RCTPromiseResolveBlock)resolve
: (RCTPromiseRejectBlock)reject) {
[self loadAndShowConsentFormIfRequired:resolve reject:reject];
}

RCT_EXPORT_METHOD(reset) {
#if !TARGET_OS_MACCATALYST
[UMPConsentInformation.sharedInstance reset];
#endif
}

RCT_EXPORT_METHOD(getConsentInfo
: (RCTPromiseResolveBlock)resolve
: (RCTPromiseRejectBlock)reject) {
[self getConsentInfo:resolve reject:reject];
}

RCT_EXPORT_METHOD(getTCString : (RCTPromiseResolveBlock)resolve : (RCTPromiseRejectBlock)reject) {
[self getTCString:resolve reject:reject];
}

RCT_EXPORT_METHOD(getGdprApplies
: (RCTPromiseResolveBlock)resolve
: (RCTPromiseRejectBlock)reject) {
[self getGdprApplies:resolve reject:reject];
}

RCT_EXPORT_METHOD(getPurposeConsents
: (RCTPromiseResolveBlock)resolve
: (RCTPromiseRejectBlock)reject) {
[self getPurposeConsents:resolve reject:reject];
}

RCT_EXPORT_METHOD(getPurposeLegitimateInterests
: (RCTPromiseResolveBlock)resolve
: (RCTPromiseRejectBlock)reject) {
[self getPurposeLegitimateInterests:resolve reject:reject];
}

#ifdef RCT_NEW_ARCH_ENABLED
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
(const facebook::react::ObjCTurboModule::InitParams &)params {
return std::make_shared<facebook::react::NativeConsentModuleSpecJSI>(params);
}
#endif

#ifdef RCT_NEW_ARCH_ENABLED
- (void)requestInfoUpdate:(JS::NativeConsentModule::AdsConsentInfoOptions &)options
resolve:(RCTPromiseResolveBlock)resolve
reject:(RCTPromiseRejectBlock)reject {
#if !TARGET_OS_MACCATALYST
UMPRequestParameters *parameters = [[UMPRequestParameters alloc] init];
UMPDebugSettings *debugSettings = [[UMPDebugSettings alloc] init];

debugSettings.geography =
static_cast<UMPDebugGeography>(options.debugGeography().value_or(UMPDebugGeographyDisabled));
debugSettings.testDeviceIdentifiers = options.testDeviceIdentifiers().has_value()
? ^{
NSMutableArray *array = [[NSMutableArray alloc] init];
FB::LazyVector<NSString *, id> identifiers = options.testDeviceIdentifiers().value();
for (NSUInteger i = 0; i < identifiers.size(); i++) {
[array addObject:identifiers[i]]; // Direct access by index
}
return array;
}()
: [[NSMutableArray alloc] init];

parameters.debugSettings = debugSettings;
parameters.tagForUnderAgeOfConsent = options.tagForUnderAgeOfConsent().value_or(FALSE);

[UMPConsentInformation.sharedInstance
requestConsentInfoUpdateWithParameters:parameters
completionHandler:^(NSError *_Nullable error) {
if (error) {
[RNSharedUtils
rejectPromiseWithUserInfo:reject
userInfo:[@{
@"code" : @"consent-update-failed",
@"message" : error.localizedDescription,
} mutableCopy]];
} else {
resolve([self getConsentInformation]);
}
}];
#endif
}
#endif

- (void)showForm:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
#if !TARGET_OS_MACCATALYST
[UMPConsentForm loadWithCompletionHandler:^(UMPConsentForm *form, NSError *loadError) {
if (loadError) {
Expand Down Expand Up @@ -145,9 +247,8 @@ - (NSDictionary *)getConsentInformation {
#endif
}

RCT_EXPORT_METHOD(showPrivacyOptionsForm
: (RCTPromiseResolveBlock)resolve
: (RCTPromiseRejectBlock)reject) {
- (void)showPrivacyOptionsForm:(RCTPromiseResolveBlock)resolve
reject:(RCTPromiseRejectBlock)reject {
#if !TARGET_OS_MACCATALYST
[UMPConsentForm
presentPrivacyOptionsFormFromViewController:[UIApplication sharedApplication]
Expand All @@ -168,9 +269,8 @@ - (NSDictionary *)getConsentInformation {
#endif
}

RCT_EXPORT_METHOD(loadAndShowConsentFormIfRequired
: (RCTPromiseResolveBlock)resolve
: (RCTPromiseRejectBlock)reject) {
- (void)loadAndShowConsentFormIfRequired:(RCTPromiseResolveBlock)resolve
reject:(RCTPromiseRejectBlock)reject {
#if !TARGET_OS_MACCATALYST
[UMPConsentForm
loadAndPresentIfRequiredFromViewController:[UIApplication sharedApplication]
Expand All @@ -191,21 +291,13 @@ - (NSDictionary *)getConsentInformation {
#endif
}

RCT_EXPORT_METHOD(reset) {
#if !TARGET_OS_MACCATALYST
[UMPConsentInformation.sharedInstance reset];
#endif
}

RCT_EXPORT_METHOD(getConsentInfo
: (RCTPromiseResolveBlock)resolve
: (RCTPromiseRejectBlock)reject) {
- (void)getConsentInfo:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
#if !TARGET_OS_MACCATALYST
resolve([self getConsentInformation]);
#endif
}

RCT_EXPORT_METHOD(getTCString : (RCTPromiseResolveBlock)resolve : (RCTPromiseRejectBlock)reject) {
- (void)getTCString:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
@try {
// https://github.com/InteractiveAdvertisingBureau/GDPR-Transparency-and-Consent-Framework/blob/master/TCFv2/IAB%20Tech%20Lab%20-%20CMP%20API%20v2.md#in-app-details
NSString *tcString = [[NSUserDefaults standardUserDefaults] objectForKey:@"IABTCF_TCString"];
Expand All @@ -219,9 +311,7 @@ - (NSDictionary *)getConsentInformation {
}
}

RCT_EXPORT_METHOD(getGdprApplies
: (RCTPromiseResolveBlock)resolve
: (RCTPromiseRejectBlock)reject) {
- (void)getGdprApplies:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
@try {
BOOL gdprApplies = [[NSUserDefaults standardUserDefaults] boolForKey:@"IABTCF_gdprApplies"];
resolve(@(gdprApplies));
Expand All @@ -234,9 +324,7 @@ - (NSDictionary *)getConsentInformation {
}
}

RCT_EXPORT_METHOD(getPurposeConsents
: (RCTPromiseResolveBlock)resolve
: (RCTPromiseRejectBlock)reject) {
- (void)getPurposeConsents:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
@try {
NSString *purposeConsents =
[[NSUserDefaults standardUserDefaults] stringForKey:@"IABTCF_PurposeConsents"];
Expand All @@ -250,9 +338,8 @@ - (NSDictionary *)getConsentInformation {
}
}

RCT_EXPORT_METHOD(getPurposeLegitimateInterests
: (RCTPromiseResolveBlock)resolve
: (RCTPromiseRejectBlock)reject) {
- (void)getPurposeLegitimateInterests:(RCTPromiseResolveBlock)resolve
reject:(RCTPromiseRejectBlock)reject {
@try {
NSString *purposeLegitimateInterests =
[[NSUserDefaults standardUserDefaults] stringForKey:@"IABTCF_PurposeLegitimateInterests"];
Expand Down
38 changes: 17 additions & 21 deletions src/AdsConsent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,22 +16,18 @@
*/

import { TCModel, TCString } from '@iabtcf/core';
import { NativeModules } from 'react-native';
import { AdsConsentDebugGeography } from './AdsConsentDebugGeography';
import { AdsConsentPurposes } from './AdsConsentPurposes';
import { AdsConsentSpecialFeatures } from './AdsConsentSpecialFeatures';
import { isPropertySet, isArray, isBoolean, isObject, isString } from './common';
import {
AdsConsentInfo,
AdsConsentInfoOptions,
AdsConsentInterface,
AdsConsentUserChoices,
} from './types/AdsConsent.interface';

const native = NativeModules.RNGoogleMobileAdsConsentModule;
AdsConsentDebugGeography,
AdsConsentInfoOptions,
} from './specs/modules/NativeConsentModule';
import native from './specs/modules/NativeConsentModule';

export const AdsConsent: AdsConsentInterface = {
requestInfoUpdate(options: AdsConsentInfoOptions = {}): Promise<AdsConsentInfo> {
requestInfoUpdate(options: AdsConsentInfoOptions = {}) {
if (!isObject(options)) {
throw new Error("AdsConsent.requestInfoUpdate(*) 'options' expected an object value.");
}
Expand Down Expand Up @@ -75,53 +71,53 @@ export const AdsConsent: AdsConsentInterface = {
return native.requestInfoUpdate(options);
},

showForm(): Promise<AdsConsentInfo> {
showForm() {
return native.showForm();
},

showPrivacyOptionsForm(): Promise<AdsConsentInfo> {
showPrivacyOptionsForm() {
return native.showPrivacyOptionsForm();
},

loadAndShowConsentFormIfRequired(): Promise<AdsConsentInfo> {
loadAndShowConsentFormIfRequired() {
return native.loadAndShowConsentFormIfRequired();
},

getConsentInfo(): Promise<AdsConsentInfo> {
getConsentInfo() {
return native.getConsentInfo();
},

async gatherConsent(options: AdsConsentInfoOptions = {}): Promise<AdsConsentInfo> {
async gatherConsent(options: AdsConsentInfoOptions = {}) {
await this.requestInfoUpdate(options);
return this.loadAndShowConsentFormIfRequired();
},

reset(): void {
reset() {
return native.reset();
},

getTCString(): Promise<string> {
getTCString() {
return native.getTCString();
},

async getTCModel(): Promise<TCModel> {
async getTCModel() {
const tcString = await native.getTCString();
return TCString.decode(tcString);
},

getGdprApplies(): Promise<boolean> {
getGdprApplies() {
return native.getGdprApplies();
},

getPurposeConsents(): Promise<string> {
getPurposeConsents() {
return native.getPurposeConsents();
},

getPurposeLegitimateInterests(): Promise<string> {
getPurposeLegitimateInterests() {
return native.getPurposeLegitimateInterests();
},

async getUserChoices(): Promise<AdsConsentUserChoices> {
async getUserChoices() {
const tcString = await native.getTCString();

let tcModel: TCModel;
Expand Down
38 changes: 0 additions & 38 deletions src/AdsConsentDebugGeography.ts

This file was deleted.

Loading

0 comments on commit 19e9379

Please sign in to comment.