Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DIA-3046 introduce UsNat for iOS #47

Merged
merged 10 commits into from
Mar 6, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ import UIKit
config = Config(
gdprPmId: nil,
ccpaPmId: nil,
usnatPmId: nil,
transitionCCPAAuth: nil,
supportLegacyUSPString: nil,
vendors: [],
categories: [],
legIntCategories: []
Expand All @@ -22,6 +25,7 @@ import UIKit
case GDPR = 0
case IOS14 = 1
case CCPA = 2
case USNAT = 3
}

enum VendorStatus: String {
Expand All @@ -41,7 +45,8 @@ import UIKit
}

struct Config {
var gdprPmId, ccpaPmId: String?
var gdprPmId, ccpaPmId, usnatPmId: String?
var transitionCCPAAuth, supportLegacyUSPString: Bool?
var vendors: [String] = []
var categories: [String] = []
var legIntCategories: [String] = []
Expand All @@ -52,6 +57,7 @@ import UIKit
var config: Config
lazy var gdprTargetingParams: SPTargetingParams = [:]
lazy var ccpaTargetingParams: SPTargetingParams = [:]
lazy var usnatTargetingParams: SPTargetingParams = [:]

var consentManager: SPSDK?
let logger: OSLogger = OSLogger.standard
Expand All @@ -76,23 +82,38 @@ import UIKit
case .IOS14: break

case .CCPA: ccpaTargetingParams[key]=value

case .USNAT: usnatTargetingParams[key]=value

case .none:
print("Incorrect campaignType on addTargetingParam")
}
}

@objc public func setTransitionCCPAAuth(value: Bool){
print("transitionCCPAAuth set to "+String(value))
config.transitionCCPAAuth = value
}

@objc public func setSupportLegacyUSPString(value: Bool){
print("supportLegacyUSPString set to "+String(value))
config.supportLegacyUSPString = value
}

@objc public func configLib(
accountId: Int,
propertyId: Int,
propertyName: String,
gdpr: Bool,
ccpa: Bool,
usnat: Bool,
language: SPMessageLanguage,
gdprPmId: String,
ccpaPmId: String) {
ccpaPmId: String,
usnatPmId: String) {
self.config.gdprPmId = gdprPmId
self.config.ccpaPmId = ccpaPmId
self.config.usnatPmId = usnatPmId
guard let propName = try? SPPropertyName(propertyName) else {
self.runCallback(callback: self.callbackOnErrorCallback, arg: "`propertyName` invalid!")
return
Expand All @@ -102,8 +123,9 @@ import UIKit
propertyId: propertyId,
propertyName: propName,
campaigns: SPCampaigns(
gdpr: gdpr ? SPCampaign(targetingParams: gdprTargetingParams, groupPmId: gdprPmId) : nil,
ccpa: ccpa ? SPCampaign(targetingParams: ccpaTargetingParams, groupPmId: ccpaPmId) : nil,
gdpr: gdpr ? SPCampaign(targetingParams: gdprTargetingParams) : nil,
ccpa: ccpa ? SPCampaign(targetingParams: ccpaTargetingParams) : nil,
usnat: usnat ? SPCampaign(targetingParams: usnatTargetingParams, transitionCCPAAuth: config.transitionCCPAAuth, supportLegacyUSPString: config.supportLegacyUSPString) : nil,
ios14: SPCampaign()
),
language: language,
Expand Down Expand Up @@ -173,6 +195,16 @@ import UIKit
self.runCallback(callback: self.callbackOnErrorCallback, arg: "Tried to load CCPA pm without ccpa pm id")
}
}

@objc public func onUSNATPrivacyManagerTap() {
if config.usnatPmId != nil {
(consentManager != nil) ?
consentManager?.loadUSNatPrivacyManager(withId: config.usnatPmId!) :
self.runCallback(callback: self.callbackOnErrorCallback, arg: "Library was not initialized correctly!")
} else {
self.runCallback(callback: self.callbackOnErrorCallback, arg: "Tried to load USNAT pm without usnat pm id")
}
}

@objc public func customConsentToGDPR() {
if let consentManager = consentManager {
Expand Down
20 changes: 18 additions & 2 deletions Assets/ConsentManagementProvider/Plugins/iOS/Source/Unity.mm
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,19 @@ void _addTargetingParamForCampaignType(int campaignType, char* key, char* value)
[swiftBridge addTargetingParamWithCampaignType:campaignType key:[NSString stringWithFormat:@"%s", key] value:[NSString stringWithFormat:@"%s", value]];
}

void _configLib(int accountId, int propertyId, char* propertyName, bool gdpr, bool ccpa, SPMessageLanguage language, char* gdprPmId, char* ccpaPmId)
void _setTransitionCCPAAuth(bool value)
{
[swiftBridge configLibWithAccountId:accountId propertyId:propertyId propertyName:[NSString stringWithFormat:@"%s", propertyName] gdpr:gdpr ccpa:ccpa language:language gdprPmId:[NSString stringWithFormat:@"%s", gdprPmId] ccpaPmId:[NSString stringWithFormat:@"%s", ccpaPmId]];
[swiftBridge setTransitionCCPAAuthWithValue:value];
}

void _setSupportLegacyUSPString(bool value)
{
[swiftBridge setSupportLegacyUSPStringWithValue:value];
}

void _configLib(int accountId, int propertyId, char* propertyName, bool gdpr, bool ccpa, bool usnat, SPMessageLanguage language, char* gdprPmId, char* ccpaPmId, char* usnatPmId)
{
[swiftBridge configLibWithAccountId:accountId propertyId:propertyId propertyName:[NSString stringWithFormat:@"%s", propertyName] gdpr:gdpr ccpa:ccpa usnat:usnat language:language gdprPmId:[NSString stringWithFormat:@"%s", gdprPmId] ccpaPmId:[NSString stringWithFormat:@"%s", ccpaPmId] usnatPmId:[NSString stringWithFormat:@"%s", usnatPmId]];
}

void _loadMessage(char * authId)
Expand All @@ -91,6 +101,12 @@ void _loadCCPAPrivacyManager()
[swiftBridge onCCPAPrivacyManagerTap];
}

void _loadUSNATPrivacyManager()
{
[swiftBridge onUSNATPrivacyManagerTap];
}


void _cleanConsent()
{
[swiftBridge onClearConsentTap];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ public enum CAMPAIGN_TYPE
GDPR = 0,
IOS14 = 1, //exist ios only
CCPA = 2,
// UNKNOWN = 3 //exist ios only
USNAT = 3
}
}
24 changes: 18 additions & 6 deletions Assets/ConsentManagementProvider/Scripts/facade/CMP.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,26 +17,32 @@ public static class CMP

public static bool useGDPR = false;
public static bool useCCPA = false;
public static bool useUSNAT = false;

public static void Initialize(
List<SpCampaign> spCampaigns,
int accountId,
int propertyId,
string propertyName,
bool gdpr,
bool ccpa,
bool gdpr,
bool ccpa,
bool usnat,
MESSAGE_LANGUAGE language,
string gdprPmId,
string ccpaPmId,
string usnatPmId,
CAMPAIGN_ENV campaignsEnvironment,
long messageTimeoutInSeconds = 3)
long messageTimeoutInSeconds = 3,
bool? transitionCCPAAuth = null,
bool? supportLegacyUSPString = null)
{
if(!IsSpCampaignsValid(spCampaigns))
{
return;
}
useGDPR = gdpr;
useCCPA = ccpa;
useUSNAT = usnat;
#if UNITY_ANDROID
CreateBroadcastExecutorGO();
//excluding ios14 campaign if any
Expand All @@ -45,6 +51,7 @@ public static void Initialize(
{
return;
}
//TO-DO add usnat
ConsentWrapperAndroid.Instance.InitializeLib(
spCampaigns: spCampaigns,
accountId: accountId,
Expand All @@ -60,14 +67,18 @@ public static void Initialize(
accountId,
propertyId,
propertyName,
gdpr,
ccpa,
gdpr,
ccpa,
usnat,
language,
gdprPmId,
ccpaPmId,
usnatPmId,
spCampaigns,
campaignsEnvironment,
messageTimeoutInSeconds);
messageTimeoutInSeconds,
transitionCCPAAuth,
supportLegacyUSPString);
#endif
}

Expand Down Expand Up @@ -121,6 +132,7 @@ public static void LoadPrivacyManager(CAMPAIGN_TYPE campaignType, string pmId, P
switch (campaignType){
case CAMPAIGN_TYPE.GDPR: ConsentWrapperIOS.Instance.LoadGDPRPrivacyManager(); break;
case CAMPAIGN_TYPE.CCPA: ConsentWrapperIOS.Instance.LoadCCPAPrivacyManager(); break;
case CAMPAIGN_TYPE.USNAT: ConsentWrapperIOS.Instance.LoadUSNATPrivacyManager(); break;
}
#endif
}
Expand Down
85 changes: 68 additions & 17 deletions Assets/ConsentManagementProvider/Scripts/json/JsonUnwrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
using System.IO;
using NewtonsoftJson = Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Linq;
using System.Collections;

namespace ConsentManagementProviderLib.Json
{
Expand All @@ -23,8 +25,9 @@ public static SpConsents UnwrapSpConsentsAndroid(string json)

SpGdprConsent unwrappedGdpr = CMP.useGDPR ? UnwrapSpGdprConsentAndroid(wrapped.gdpr) : null;
SpCcpaConsent unwrappedCcpa = CMP.useCCPA ? UnwrapSpCcpaConsentAndroid(wrapped.ccpa) : null;
SpUsnatConsent unwrappedUsnat = CMP.useUSNAT ? null : null; //TODO parse

return new SpConsents(unwrappedGdpr, unwrappedCcpa);
return new SpConsents(unwrappedGdpr, unwrappedCcpa, unwrappedUsnat);
}
catch (NewtonsoftJson.JsonException ex)
{
Expand Down Expand Up @@ -174,8 +177,9 @@ public static SpConsents UnwrapSpConsents(string json)

SpGdprConsent unwrappedGdpr = CMP.useGDPR ? UnwrapSpGdprConsent(wrapped.gdpr) : null;
SpCcpaConsent unwrappedCcpa = CMP.useCCPA ? UnwrapSpCcpaConsent(wrapped.ccpa) : null;
SpUsnatConsent unwrappedUsnat = CMP.useUSNAT ? UnwrapSpUsnatConsent(wrapped.usnat) : null;

return new SpConsents(unwrappedGdpr, unwrappedCcpa);
return new SpConsents(unwrappedGdpr, unwrappedCcpa, unwrappedUsnat);
}
catch (NewtonsoftJson.JsonException ex)
{
Expand Down Expand Up @@ -260,30 +264,36 @@ private static GdprConsent UnwrapGdprConsent(GdprConsentWrapper wrapped)

private static ConsentStatus UnwrapConsentStatus(ConsentStatusWrapper wrappedconsentStatus)
{
GranularStatus granularStatus = null;
Nevazhnovu marked this conversation as resolved.
Show resolved Hide resolved
GranularStatus _granularStatus = null;
if (wrappedconsentStatus.granularStatus != null)
{
granularStatus = new GranularStatus(
_granularStatus = new GranularStatus(
wrappedconsentStatus.granularStatus.vendorConsent,
wrappedconsentStatus.granularStatus.vendorLegInt,
wrappedconsentStatus.granularStatus.purposeConsent,
wrappedconsentStatus.granularStatus.purposeLegInt,
wrappedconsentStatus.granularStatus.previousOptInAll,
wrappedconsentStatus.granularStatus.defaultConsent
wrappedconsentStatus.granularStatus.defaultConsent,
wrappedconsentStatus.granularStatus.sellStatus,
wrappedconsentStatus.granularStatus.shareStatus,
wrappedconsentStatus.granularStatus.sensitiveDataStatus,
wrappedconsentStatus.granularStatus.gpcStatus
);
}
ConsentStatus consentStatus = new ConsentStatus(
wrappedconsentStatus.rejectedAny,
wrappedconsentStatus.rejectedLI,
wrappedconsentStatus.consentedAll,
wrappedconsentStatus.consentedToAny,
wrappedconsentStatus.vendorListAdditions,
wrappedconsentStatus.legalBasisChanges,
wrappedconsentStatus.hasConsentData,
granularStatus,
wrappedconsentStatus.rejectedVendors,
wrappedconsentStatus.rejectedCategories
);
ConsentStatus consentStatus = new ConsentStatus{
rejectedAny = wrappedconsentStatus.rejectedAny,
rejectedLI = wrappedconsentStatus.rejectedLI,
consentedAll = wrappedconsentStatus.consentedAll,
consentedToAll = wrappedconsentStatus.consentedToAll,
consentedToAny = wrappedconsentStatus.consentedToAny,
rejectedAll = wrappedconsentStatus.rejectedAll,
vendorListAdditions = wrappedconsentStatus.vendorListAdditions,
legalBasisChanges = wrappedconsentStatus.legalBasisChanges,
granularStatus = _granularStatus,
hasConsentData = wrappedconsentStatus.hasConsentData,
rejectedVendors = wrappedconsentStatus.rejectedVendors,
rejectedCategories = wrappedconsentStatus.rejectedCategories
};
return consentStatus;
}

Expand Down Expand Up @@ -315,6 +325,47 @@ private static CcpaConsent UnwrapCcpaConsent(CcpaConsentWrapper wrapped)
webConsentPayload: wrapped.webConsentPayload,
consentStatus: _consentStatus);
}

private static SpUsnatConsent UnwrapSpUsnatConsent(SpUsnatConsentWrapper wrappedUsnat)
{
if (wrappedUsnat == null)
{
CmpDebugUtil.LogError("The USNAT consent wrapper cannot be null.");
return null;
}

bool applies = wrappedUsnat.applies;
UsnatConsent consent = UnwrapUsnatConsent(wrappedUsnat.consents);
return new SpUsnatConsent(applies, consent);
}

private static UsnatConsent UnwrapUsnatConsent(UsnatConsentWrapper wrapped)
{
ConsentStatus _consentStatus = UnwrapConsentStatus(wrapped.consentStatus);

List<ConsentString> _consentStrings = new List<ConsentString>();
foreach (ConsentStringWrapper _string in wrapped.consentStrings)
{
_consentStrings.Add(new ConsentString(_string.consentString, _string.sectionId, _string.sectionName));
}
List<Consentable> _vendors = new List<Consentable>();
foreach (ConsentableWrapper _consentable in wrapped.vendors)
{
_vendors.Add(new Consentable{id = _consentable.id, consented = _consentable.consented});
}
List<Consentable> _categories = new List<Consentable>();
foreach (ConsentableWrapper _consentable in wrapped.categories)
{
_categories.Add(new Consentable{id = _consentable.id, consented = _consentable.consented});
}

return new UsnatConsent(uuid: wrapped.uuid,
applies: wrapped.applies,
consentStrings: _consentStrings,
vendors: _vendors,
categories: _categories,
consentStatus: _consentStatus);
}
#endregion
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,19 @@ namespace ConsentManagementProviderLib.Json
{
internal class ConsentStatusWrapper
{
#nullable enable
public bool? rejectedAny;
public bool? rejectedLI;
public bool? consentedAll;
public bool? consentedToAll;
public bool? consentedToAny;
public bool? rejectedAll;
public bool? vendorListAdditions;
public bool? legalBasisChanges;
public GranularStatusWrapper? granularStatus;
public object? rejectedVendors;
public object? rejectedCategories;
#nullable disable
public bool hasConsentData;
public object rejectedVendors;
public object rejectedCategories;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ namespace ConsentManagementProviderLib.Json
{
internal class GCMDataWrapper
{
#nullable enable
public SPGCMData.Status? ad_storage, analytics_storage, ad_user_data, ad_personalization;
#nullable disable
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ internal class GdprConsentWrapper
public bool applies;
public string webConsentPayload;
public ConsentStatusWrapper consentStatus;
#nullable enable
public GCMDataWrapper? gcmStatus;
#nullable disable
}
}
Loading