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

[WEB-862] AppTrackingTransparency Authorization #1772

Merged
merged 6 commits into from
Jan 19, 2023
Merged
Show file tree
Hide file tree
Changes from 4 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
39 changes: 39 additions & 0 deletions Kickstarter-iOS/AppDelegateViewModel.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import AppboyKit
import AppTrackingTransparency
import KsApi
import Library
import Prelude
Expand All @@ -18,6 +19,12 @@ public enum NotificationAuthorizationStatus {
case provisional
}

public enum ATTrackingAuthorizationStatus {
msadoon marked this conversation as resolved.
Show resolved Hide resolved
case authorized
case denied
case notDetermined
}

public protocol AppDelegateViewModelInputs {
/// Call when the application is handed off to.
func applicationContinueUserActivity(_ userActivity: NSUserActivity) -> Bool
Expand Down Expand Up @@ -180,6 +187,9 @@ public protocol AppDelegateViewModelOutputs {
/// Emits when we should register the device push token in Segment Analytics.
var registerPushTokenInSegment: Signal<Data, Never> { get }

/// Emits when application didFinishLaunchingWithOptions.
var requestATTrackingAuthorizationStatus: Signal<ATTrackingAuthorizationStatus, Never> { get }

/// Emits when our config updates with the enabled state for Semgent Analytics.
var segmentIsEnabled: Signal<Bool, Never> { get }

Expand Down Expand Up @@ -785,6 +795,13 @@ public final class AppDelegateViewModel: AppDelegateViewModelType, AppDelegateVi
self.brazeWillDisplayInAppMessageReturnProperty <~ self.brazeWillDisplayInAppMessageProperty.signal
.skipNil()
.map { _ in .displayInAppMessageNow }

self.requestATTrackingAuthorizationStatus = self.applicationLaunchOptionsProperty.signal
.skipNil()
.map { _ -> ATTrackingAuthorizationStatus in
guard featureConsentManagementDialogEnabled() else { return .notDetermined }
return atTrackingAuthorizationStatus()
}
}

public var inputs: AppDelegateViewModelInputs { return self }
Expand Down Expand Up @@ -956,6 +973,7 @@ public final class AppDelegateViewModel: AppDelegateViewModelType, AppDelegateVi
public let pushTokenRegistrationStarted: Signal<(), Never>
public let pushTokenSuccessfullyRegistered: Signal<String, Never>
public let registerPushTokenInSegment: Signal<Data, Never>
public let requestATTrackingAuthorizationStatus: Signal<ATTrackingAuthorizationStatus, Never>
public let segmentIsEnabled: Signal<Bool, Never>
public let setApplicationShortcutItems: Signal<[ShortcutItem], Never>
public let showAlert: Signal<Notification, Never>
Expand All @@ -965,6 +983,27 @@ public final class AppDelegateViewModel: AppDelegateViewModelType, AppDelegateVi
public let updateConfigInEnvironment: Signal<Config, Never>
}

private func atTrackingAuthorizationStatus() -> ATTrackingAuthorizationStatus {
msadoon marked this conversation as resolved.
Show resolved Hide resolved
var authorizationStatus: ATTrackingAuthorizationStatus = .notDetermined

DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
msadoon marked this conversation as resolved.
Show resolved Hide resolved
msadoon marked this conversation as resolved.
Show resolved Hide resolved
ATTrackingManager.requestTrackingAuthorization(completionHandler: { status in
switch status {
case .notDetermined:
authorizationStatus = .notDetermined
case .authorized:
authorizationStatus = .authorized
case .denied:
authorizationStatus = .denied
default:
msadoon marked this conversation as resolved.
Show resolved Hide resolved
authorizationStatus = .denied
}
})
}

return authorizationStatus
}

/// Handles the deeplink route with both an id and text based name for a deeplink to categories.
private func deepLinkCategories(rawParams: [String: String]) -> (Param?, Param?) {
let parentCategoryParams = rawParams["parent_category_id"]
Expand Down
9 changes: 9 additions & 0 deletions Kickstarter-iOS/AppDelegateViewModelTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ final class AppDelegateViewModelTests: TestCase {
private let pushRegistrationStarted = TestObserver<(), Never>()
private let pushTokenSuccessfullyRegistered = TestObserver<String, Never>()
private let registerPushTokenInSegment = TestObserver<Data, Never>()
private let requestATTrackingAuthorizationStatus = TestObserver<ATTrackingAuthorizationStatus, Never>()
private let setApplicationShortcutItems = TestObserver<[ShortcutItem], Never>()
private let segmentIsEnabled = TestObserver<Bool, Never>()
private let showAlert = TestObserver<Notification, Never>()
Expand Down Expand Up @@ -96,6 +97,8 @@ final class AppDelegateViewModelTests: TestCase {
self.vm.outputs.pushTokenRegistrationStarted.observe(self.pushRegistrationStarted.observer)
self.vm.outputs.pushTokenSuccessfullyRegistered.observe(self.pushTokenSuccessfullyRegistered.observer)
self.vm.outputs.registerPushTokenInSegment.observe(self.registerPushTokenInSegment.observer)
self.vm.outputs.requestATTrackingAuthorizationStatus
.observe(self.requestATTrackingAuthorizationStatus.observer)
self.vm.outputs.setApplicationShortcutItems.observe(self.setApplicationShortcutItems.observer)
self.vm.outputs.showAlert.observe(self.showAlert.observer)
self.vm.outputs.segmentIsEnabled.observe(self.segmentIsEnabled.observer)
Expand Down Expand Up @@ -3004,6 +3007,12 @@ final class AppDelegateViewModelTests: TestCase {
self.updateCurrentUserInEnvironment.assertValues([user, updatedUser])
}
}

func testRequestATTrackingAuthorizationStatus_CalledOnceOnDidFinishLaunching() {
self.vm.inputs.applicationDidFinishLaunching(application: UIApplication.shared, launchOptions: nil)

self.requestATTrackingAuthorizationStatus.assertValueCount(1)
msadoon marked this conversation as resolved.
Show resolved Hide resolved
}
}

private let backingForCreatorPushData: [String: Any] = [
Expand Down
2 changes: 2 additions & 0 deletions Kickstarter-iOS/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSUserTrackingUsageDescription</key>
<string>We use personal data to provide a good experience on Kickstarter, and to help connect you with projects you&apos;ll love.</string>
msadoon marked this conversation as resolved.
Show resolved Hide resolved
msadoon marked this conversation as resolved.
Show resolved Hide resolved
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
Expand Down