From 4cb0cf9cbcf074d1d538e5f898a538b641982763 Mon Sep 17 00:00:00 2001 From: Soner Yuksel Date: Fri, 6 Oct 2023 12:03:23 -0400 Subject: [PATCH] Adding Ad Attribution Json Object Datas --- App/iOS/Delegates/SceneDelegate.swift | 33 +++++++----- Sources/Growth/URP/ReferralData.swift | 56 ++++++++++++++++++++ Sources/Growth/URP/UrpService.swift | 13 ++--- Sources/Growth/URP/UserReferralProgram.swift | 6 +-- 4 files changed, 83 insertions(+), 25 deletions(-) diff --git a/App/iOS/Delegates/SceneDelegate.swift b/App/iOS/Delegates/SceneDelegate.swift index 54b7d86a2c2..0e1943affda 100644 --- a/App/iOS/Delegates/SceneDelegate.swift +++ b/App/iOS/Delegates/SceneDelegate.swift @@ -536,34 +536,39 @@ extension BrowserViewController { // Case 2: User Referral on Brave side if Preferences.URP.referralLookupOutstanding.value == true { urp.adCampaignLookup() { [weak self] response, error in - // Checking referral code from User Referral program exists If not send 001 - // Prefix this code with BRV for organic iOS installs - var referralCode = "BRV\(UserReferralProgram.getReferralCode() ?? "001")" + guard let self = self else { return } - if error == nil, response?.0 == true, let campaignId = response?.1 { - // Adding ASA User refcode prefix to indicate - // Apple Ads Attribution is true - referralCode = "ASA\(String(campaignId))" - } - - self?.performProgramReferralLookup(urp, refCode: referralCode) + let refCode = self.generateReferralCode(attributionData: response, fetchError: error) + self.performProgramReferralLookup(urp, refCode: refCode) } } else { urp.pingIfEnoughTimePassed() } } + private func generateReferralCode(attributionData: AdAttributionData?, fetchError: Error?) -> String { + // Checking referral code from User Referral program exists If not send 001 + // Prefix this code with BRV for organic iOS installs + var referralCode = "BRV\(UserReferralProgram.getReferralCode() ?? "001")" + + if fetchError == nil, attributionData?.attribution == true, let campaignId = attributionData?.campaignId { + // Adding ASA User refcode prefix to indicate + // Apple Ads Attribution is true + referralCode = "ASA\(String(campaignId))" + } + + return referralCode + } + private func performProgramReferralLookup(_ urp: UserReferralProgram, refCode: String?) { urp.referralLookup(refCode: refCode) { referralCode, offerUrl in // Attempting to send ping after first urp lookup. // This way we can grab the referral code if it exists, see issue #2586. AppState.shared.dau.sendPingToServer() - if let code = referralCode { - let retryTime = AppConstants.buildChannel.isPublic ? 1.days : 10.minutes - let retryDeadline = Date() + retryTime + let retryTime = AppConstants.buildChannel.isPublic ? 1.days : 10.minutes + let retryDeadline = Date() + retryTime Preferences.NewTabPage.superReferrerThemeRetryDeadline.value = retryDeadline - } guard let url = offerUrl?.asURL else { return } self.openReferralLink(url: url) diff --git a/Sources/Growth/URP/ReferralData.swift b/Sources/Growth/URP/ReferralData.swift index ae8e4332222..955769569ab 100644 --- a/Sources/Growth/URP/ReferralData.swift +++ b/Sources/Growth/URP/ReferralData.swift @@ -34,3 +34,59 @@ struct ReferralData { self.offerPage = json["offer_page_url"].string } } + +public struct AdAttributionData { + + public let attribution: Bool + public let organizationId: Int? + public let conversionType: String? + public let campaignId: Int + public let countryOrRegion: String? + + init(attribution: Bool, organizationId: Int? = nil, conversionType: String? = nil, campaignId: Int, countryOrRegion: String? = nil) { + self.attribution = attribution + self.organizationId = organizationId + self.conversionType = conversionType + self.campaignId = campaignId + self.countryOrRegion = countryOrRegion + } +} + +enum SerializationError: Error { + case missing(String) + case invalid(String, Any) +} + +extension AdAttributionData { + init(json: [String: Any]?) throws { + guard let json = json else { + throw SerializationError.invalid("Invalid json Dictionary", "") + } + + guard let attribution = json["attribution"] as? Bool else { + Logger.module.error("Failed to unwrap json to Ad Attribution property.") + UrpLog.log("Failed to unwrap json to Ad Attribution property. \(json)") + + throw SerializationError.missing("Attribution Context") + } + + guard let campaignId = json["campaignId"] as? Int else { + Logger.module.error("Failed to unwrap json to Campaign Id property.") + UrpLog.log("Failed to unwrap json to Campaign Id property. \(json)") + + throw SerializationError.missing("Campaign Id") + } + + if let conversionType = json["conversionType"] as? String { + guard conversionType == "Download" || conversionType == "Redownload" else { + throw SerializationError.invalid("Conversion Type", conversionType) + } + } + + self.attribution = attribution + self.organizationId = json["orgId"] as? Int + self.conversionType = json["conversionType"] as? String + self.campaignId = campaignId + self.countryOrRegion = json["countryOrRegion"] as? String + } +} diff --git a/Sources/Growth/URP/UrpService.swift b/Sources/Growth/URP/UrpService.swift index bece84d33f1..1d15af655e2 100644 --- a/Sources/Growth/URP/UrpService.swift +++ b/Sources/Growth/URP/UrpService.swift @@ -78,7 +78,7 @@ struct UrpService { } } - @MainActor func adCampaignTokenLookupQueue2(adAttributionToken: String) async throws -> (Bool?, Int?) { + @MainActor func adCampaignTokenLookupQueue(adAttributionToken: String) async throws -> (AdAttributionData?) { guard let endPoint = URL(string: adServicesURL) else { Logger.module.error("AdServicesURLString can not be resolved: \(adServicesURL)") throw URLError(.badURL) @@ -91,19 +91,16 @@ struct UrpService { UrpLog.log("Ad Attribution response: \(result)") if let resultData = result as? Data { - let jsonResponseDictionary = try JSONSerialization.jsonObject(with: resultData, options: []) as? [String: Any] + let jsonResponse = try JSONSerialization.jsonObject(with: resultData, options: []) as? [String: Any] + let adAttributionData = try AdAttributionData(json: jsonResponse) - if let jsonResponse = jsonResponseDictionary, - let attribution = jsonResponse["attribution"] as? Bool, - let campaignId = jsonResponse["campaignId"] as? Int { - return (attribution, campaignId) - } + return adAttributionData } } catch { throw error } - return (nil, nil) + return (nil) } func checkIfAuthorizedForGrant(with downloadId: String, completion: @escaping (Bool?, UrpError?) -> Void) { diff --git a/Sources/Growth/URP/UserReferralProgram.swift b/Sources/Growth/URP/UserReferralProgram.swift index cf4e499f4f6..656708bbe51 100644 --- a/Sources/Growth/URP/UserReferralProgram.swift +++ b/Sources/Growth/URP/UserReferralProgram.swift @@ -121,15 +121,15 @@ public class UserReferralProgram { service.referralCodeLookup(refCode: refCode, completion: referralBlock) } - public func adCampaignLookup(completion: @escaping ((Bool?, Int?)?, Error?) -> Void) { + public func adCampaignLookup(completion: @escaping ((AdAttributionData)?, Error?) -> Void) { // Fetching ad attibution token do { let adAttributionToken = try AAAttribution.attributionToken() Task { @MainActor in do { - let result = try await service.adCampaignTokenLookupQueue2(adAttributionToken: adAttributionToken) - completion((result.0, result.1), nil) + let result = try await service.adCampaignTokenLookupQueue(adAttributionToken: adAttributionToken) + completion(result, nil) } catch { Logger.module.info("Could not retrieve ad campaign attibution from ad services") completion(nil, error)