Skip to content

Commit

Permalink
[NTV-647] Braze In-App Notification Fix (#1791)
Browse files Browse the repository at this point in the history
* fix for in-app notifications, pns also work. Only thing that is broken is deeplinking from within an in-app notification.

* in-app notifications fix. deeplinks route correctly now within the app from an in-app notification.

* added a test for the new in app notification signal.
  • Loading branch information
msadoon committed Feb 14, 2023
1 parent ae5792e commit 7586740
Show file tree
Hide file tree
Showing 6 changed files with 82 additions and 79 deletions.
20 changes: 15 additions & 5 deletions Kickstarter-iOS/AppDelegate.swift
Expand Up @@ -264,15 +264,15 @@ internal final class AppDelegate: UIResponder, UIApplicationDelegate {
.observeValues { [weak self] writeKey in
guard let strongSelf = self else { return }

let factoryInstance = SEGAppboyIntegrationFactory.instance()
factoryInstance?.saveLaunchOptions(launchOptions)
factoryInstance?.appboyOptions = [
let (configuration, appBoyInstance) = Analytics.configuredClient(withWriteKey: writeKey)

appBoyInstance?.saveLaunchOptions(launchOptions)
appBoyInstance?.appboyOptions = [
ABKInAppMessageControllerDelegateKey: strongSelf,
ABKURLDelegateKey: strongSelf,
ABKMinimumTriggerTimeIntervalKey: 5
]

let configuration = Analytics.configuredClient(withWriteKey: writeKey, braze: factoryInstance)

Analytics.setup(with: configuration)

AppEnvironment.current.ksrAnalytics.configureSegmentClient(Analytics.shared())
Expand Down Expand Up @@ -526,3 +526,13 @@ extension AppDelegate: ABKInAppMessageControllerDelegate {
return self.viewModel.inputs.brazeWillDisplayInAppMessage(inAppMessage)
}
}

// MARK: - ABKURLDelegate

extension AppDelegate: ABKURLDelegate {
func handleAppboyURL(_ url: URL?, from _: ABKChannel, withExtras _: [AnyHashable: Any]?) -> Bool {
self.viewModel.inputs.urlFromBrazeInAppNotification(url)

return true
}
}
12 changes: 12 additions & 0 deletions Kickstarter-iOS/AppDelegateViewModel.swift
Expand Up @@ -86,6 +86,9 @@ public protocol AppDelegateViewModelInputs {
/// Call when the contextual PushNotification dialog should be presented.
func showNotificationDialog(notification: Notification)

/// Call when Braze in-app notifications send a valid URL.
func urlFromBrazeInAppNotification(_ url: URL?)

/// Call when the controller has received a user session ended notification.
func userSessionEnded()

Expand Down Expand Up @@ -344,6 +347,9 @@ public final class AppDelegateViewModel: AppDelegateViewModelType, AppDelegateVi
.skipNil()
.map(Navigation.deepLinkMatch)

let deepLinkFromBrazeInAppNotification = self.brazeInAppNotificationURLProperty.signal.skipNil()
.map(Navigation.deepLinkMatch)

let continueUserActivity = self.applicationContinueUserActivityProperty.signal.skipNil()

let continueUserActivityWithNavigation = continueUserActivity
Expand Down Expand Up @@ -381,6 +387,7 @@ public final class AppDelegateViewModel: AppDelegateViewModelType, AppDelegateVi
deepLinkFromUrl,
deepLinkFromNotification,
deepLinkFromBrazeNotification,
deepLinkFromBrazeInAppNotification,
deepLinkFromShortcut
)
.skipNil()
Expand Down Expand Up @@ -927,6 +934,11 @@ public final class AppDelegateViewModel: AppDelegateViewModelType, AppDelegateVi
self.userSessionStartedProperty.value = ()
}

fileprivate let brazeInAppNotificationURLProperty = MutableProperty<URL?>(nil)
public func urlFromBrazeInAppNotification(_ url: URL?) {
self.brazeInAppNotificationURLProperty.value = url
}

fileprivate let applicationDidFinishLaunchingReturnValueProperty = MutableProperty(true)
public var applicationDidFinishLaunchingReturnValue: Bool {
return self.applicationDidFinishLaunchingReturnValueProperty.value
Expand Down
19 changes: 19 additions & 0 deletions Kickstarter-iOS/AppDelegateViewModelTests.swift
Expand Up @@ -3017,6 +3017,25 @@ final class AppDelegateViewModelTests: TestCase {

self.requestATTrackingAuthorizationStatus.assertValueCount(1)
}

func testPresentViewController_BrazeInAppNotificationDeeplink_ProjectCommentThread_Success() {
self.vm.inputs.applicationDidFinishLaunching(
application: UIApplication.shared,
launchOptions: [:]
)

withEnvironment(apiService: MockService(fetchCommentRepliesEnvelopeResult: .success(CommentRepliesEnvelope
.successfulRepliesTemplate), fetchProjectResult: .success(.template))) {
let url =
"https://\(AppEnvironment.current.apiService.serverConfig.webBaseUrl.host ?? "")/projects/fjorden/fjorden-iphone-photography-reinvented/"

self.presentViewController.assertValues([])

self.vm.inputs.urlFromBrazeInAppNotification(URL(string: url)!)

self.presentViewController.assertValues([1])
}
}
}

private let backingForCreatorPushData: [String: Any] = [
Expand Down
91 changes: 25 additions & 66 deletions Kickstarter.xcodeproj/project.pbxproj
Expand Up @@ -247,6 +247,8 @@
1937A71F28C94FFC00DD732D /* SettingsFormFieldView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7790DF882200D3BD005DBB11 /* SettingsFormFieldView.xib */; };
1937A72328C9570A00DD732D /* ErroredBackingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1937A72228C9570900DD732D /* ErroredBackingView.swift */; };
1937A72628C959DD00DD732D /* FundingGraphViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7ED205B1E83240D00BFFA01 /* FundingGraphViewTests.swift */; };
1938951B29959D6400FF1D16 /* AppboySegment in Frameworks */ = {isa = PBXBuildFile; productRef = 1938951A29959D6400FF1D16 /* AppboySegment */; };
1938951D29959D9800FF1D16 /* AppboySegment in Frameworks */ = {isa = PBXBuildFile; productRef = 1938951C29959D9800FF1D16 /* AppboySegment */; };
194154CE28D8ED69004648C8 /* CreatePaymentSourceSetupIntentInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 194154CD28D8ED69004648C8 /* CreatePaymentSourceSetupIntentInput.swift */; };
194154D128D8FBAA004648C8 /* CreatePaymentSourceSetupIntentClientSecret+Constructor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 194154CF28D8F2DE004648C8 /* CreatePaymentSourceSetupIntentClientSecret+Constructor.swift */; };
194154D328D928C9004648C8 /* CreatePaymentSourceSetupIntentInputTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 194154D228D928C9004648C8 /* CreatePaymentSourceSetupIntentInputTests.swift */; };
Expand Down Expand Up @@ -493,12 +495,6 @@
60DA512928CA580B002E2DF1 /* Optimizely in Frameworks */ = {isa = PBXBuildFile; productRef = 60DA512828CA580B002E2DF1 /* Optimizely */; };
60EAD1B528D0EE45009F9474 /* iOSSnapshotTestCase in Embed Frameworks */ = {isa = PBXBuildFile; productRef = 60EAD1B328D0EE45009F9474 /* iOSSnapshotTestCase */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
60EAD1C728D25A36009F9474 /* AppCenterDistribute in Frameworks */ = {isa = PBXBuildFile; productRef = 60EAD1C628D25A36009F9474 /* AppCenterDistribute */; };
70CEC164298B2A2A0009D67A /* AppboyKit in Frameworks */ = {isa = PBXBuildFile; productRef = 70CEC163298B2A2A0009D67A /* AppboyKit */; };
70CEC166298B2A2A0009D67A /* AppboyUI in Frameworks */ = {isa = PBXBuildFile; productRef = 70CEC165298B2A2A0009D67A /* AppboyUI */; };
70CEC168298B2A770009D67A /* AppboyKit in Frameworks */ = {isa = PBXBuildFile; productRef = 70CEC167298B2A770009D67A /* AppboyKit */; };
70CEC16A298B2A810009D67A /* AppboyUI in Frameworks */ = {isa = PBXBuildFile; productRef = 70CEC169298B2A810009D67A /* AppboyUI */; };
70CEC16D298B2ACA0009D67A /* AppboySegment in Frameworks */ = {isa = PBXBuildFile; productRef = 70CEC16C298B2ACA0009D67A /* AppboySegment */; };
70CEC16F298B2B010009D67A /* AppboySegment in Frameworks */ = {isa = PBXBuildFile; productRef = 70CEC16E298B2B010009D67A /* AppboySegment */; };
770187C022FDCFCA0019129D /* PledgeViewControllerMessageDisplaying.swift in Sources */ = {isa = PBXBuildFile; fileRef = 770187BE22FDCF960019129D /* PledgeViewControllerMessageDisplaying.swift */; };
7703B42223217D4F00169EF3 /* EnvironmentType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7703B42123217D4F00169EF3 /* EnvironmentType.swift */; };
7703B4242321844900169EF3 /* PKPaymentRequest+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7703B4232321844900169EF3 /* PKPaymentRequest+Helpers.swift */; };
Expand Down Expand Up @@ -3179,20 +3175,18 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
70CEC168298B2A770009D67A /* AppboyKit in Frameworks */,
60DA50FE28C38DDB002E2DF1 /* AlamofireImage in Frameworks */,
60DA512928CA580B002E2DF1 /* Optimizely in Frameworks */,
06634FC72807A4EB00950F60 /* Prelude_UIKit in Frameworks */,
191A4B4028FF386C009D62A5 /* ReactiveSwift in Frameworks */,
D0D10BB81EEB394D005EBAD0 /* KsApi.framework in Frameworks */,
198E574B28E2705100D5B8A9 /* PerimeterX in Frameworks */,
1981AC90289075D900BB4897 /* Stripe in Frameworks */,
1938951D29959D9800FF1D16 /* AppboySegment in Frameworks */,
60DA510F28C7E04B002E2DF1 /* Kingfisher in Frameworks */,
191A4B4228FF3897009D62A5 /* ReactiveExtensions in Frameworks */,
70CEC16A298B2A810009D67A /* AppboyUI in Frameworks */,
606754BF28CF91DD0033CD5E /* FacebookLogin in Frameworks */,
606754BD28CF91D60033CD5E /* FacebookCore in Frameworks */,
70CEC16F298B2B010009D67A /* AppboySegment in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -3223,17 +3217,15 @@
buildActionMask = 2147483647;
files = (
19BF226528D10497007F4197 /* FirebasePerformance in Frameworks */,
70CEC166298B2A2A0009D67A /* AppboyUI in Frameworks */,
19BF226128D10497007F4197 /* FirebaseAnalytics in Frameworks */,
70CEC16D298B2ACA0009D67A /* AppboySegment in Frameworks */,
60EAD1C728D25A36009F9474 /* AppCenterDistribute in Frameworks */,
06EA2D4C280F76B700F4DE2E /* Prelude in Frameworks */,
A73924001D27230B004524C3 /* Kickstarter_Framework.framework in Frameworks */,
1938951B29959D6400FF1D16 /* AppboySegment in Frameworks */,
191EDC6728E29BB9009B41B2 /* PerimeterX in Frameworks */,
19BF226328D10497007F4197 /* FirebaseCrashlytics in Frameworks */,
1905787B28F8CD2500428375 /* ReactiveSwift in Frameworks */,
1998BCA828F60E8900D04077 /* ReactiveExtensions in Frameworks */,
70CEC164298B2A2A0009D67A /* AppboyKit in Frameworks */,
D0B45B6B1EF858C00020A8DA /* KsApi.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down Expand Up @@ -7232,9 +7224,7 @@
198E574A28E2705100D5B8A9 /* PerimeterX */,
191A4B3F28FF386C009D62A5 /* ReactiveSwift */,
191A4B4128FF3897009D62A5 /* ReactiveExtensions */,
70CEC167298B2A770009D67A /* AppboyKit */,
70CEC169298B2A810009D67A /* AppboyUI */,
70CEC16E298B2B010009D67A /* AppboySegment */,
1938951C29959D9800FF1D16 /* AppboySegment */,
);
productName = "Library-iOS";
productReference = A755113C1C8642B3005355CF /* Library.framework */;
Expand Down Expand Up @@ -7314,9 +7304,7 @@
191EDC6628E29BB9009B41B2 /* PerimeterX */,
1998BCA728F60E8900D04077 /* ReactiveExtensions */,
1905787A28F8CD2500428375 /* ReactiveSwift */,
70CEC163298B2A2A0009D67A /* AppboyKit */,
70CEC165298B2A2A0009D67A /* AppboyUI */,
70CEC16C298B2ACA0009D67A /* AppboySegment */,
1938951A29959D6400FF1D16 /* AppboySegment */,
);
productName = Kickstarter;
productReference = A7D1F9451C850B7C000D41D5 /* KickDebug.app */;
Expand Down Expand Up @@ -7477,8 +7465,7 @@
602C97D628DB787900919CA8 /* XCRemoteSwiftPackageReference "px-iOS-Framework" */,
194C593E28F5E7FF00453249 /* XCRemoteSwiftPackageReference "Kickstarter-ReactiveExtensions" */,
1905787928F8CD2500428375 /* XCRemoteSwiftPackageReference "ReactiveSwift" */,
70CEC162298B2A290009D67A /* XCRemoteSwiftPackageReference "braze-ios-sdk" */,
70CEC16B298B2AC90009D67A /* XCRemoteSwiftPackageReference "appboy-segment-ios" */,
1938951929959D6400FF1D16 /* XCRemoteSwiftPackageReference "appboy-segment-ios" */,
);
productRefGroup = A7E06C7A1C5A6EB300EBDCC2 /* Products */;
projectDirPath = "";
Expand Down Expand Up @@ -10407,6 +10394,14 @@
minimumVersion = 6.5.0;
};
};
1938951929959D6400FF1D16 /* XCRemoteSwiftPackageReference "appboy-segment-ios" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/Appboy/appboy-segment-ios";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 4.0.0;
};
};
194520C12888542100CA9B88 /* XCRemoteSwiftPackageReference "stripe-ios" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/stripe/stripe-ios";
Expand Down Expand Up @@ -10495,22 +10490,6 @@
minimumVersion = 4.0.0;
};
};
70CEC162298B2A290009D67A /* XCRemoteSwiftPackageReference "braze-ios-sdk" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/braze-inc/braze-ios-sdk.git";
requirement = {
kind = exactVersion;
version = 4.5.1;
};
};
70CEC16B298B2AC90009D67A /* XCRemoteSwiftPackageReference "appboy-segment-ios" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/Appboy/appboy-segment-ios.git";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 4.0.0;
};
};
/* End XCRemoteSwiftPackageReference section */

/* Begin XCSwiftPackageProductDependency section */
Expand Down Expand Up @@ -10589,6 +10568,16 @@
package = 602C97D628DB787900919CA8 /* XCRemoteSwiftPackageReference "px-iOS-Framework" */;
productName = PerimeterX;
};
1938951A29959D6400FF1D16 /* AppboySegment */ = {
isa = XCSwiftPackageProductDependency;
package = 1938951929959D6400FF1D16 /* XCRemoteSwiftPackageReference "appboy-segment-ios" */;
productName = AppboySegment;
};
1938951C29959D9800FF1D16 /* AppboySegment */ = {
isa = XCSwiftPackageProductDependency;
package = 1938951929959D6400FF1D16 /* XCRemoteSwiftPackageReference "appboy-segment-ios" */;
productName = AppboySegment;
};
1981AC8F289075D900BB4897 /* Stripe */ = {
isa = XCSwiftPackageProductDependency;
package = 194520C12888542100CA9B88 /* XCRemoteSwiftPackageReference "stripe-ios" */;
Expand Down Expand Up @@ -10684,36 +10673,6 @@
package = 60EAD1C528D25A36009F9474 /* XCRemoteSwiftPackageReference "appcenter-sdk-apple" */;
productName = AppCenterDistribute;
};
70CEC163298B2A2A0009D67A /* AppboyKit */ = {
isa = XCSwiftPackageProductDependency;
package = 70CEC162298B2A290009D67A /* XCRemoteSwiftPackageReference "braze-ios-sdk" */;
productName = AppboyKit;
};
70CEC165298B2A2A0009D67A /* AppboyUI */ = {
isa = XCSwiftPackageProductDependency;
package = 70CEC162298B2A290009D67A /* XCRemoteSwiftPackageReference "braze-ios-sdk" */;
productName = AppboyUI;
};
70CEC167298B2A770009D67A /* AppboyKit */ = {
isa = XCSwiftPackageProductDependency;
package = 70CEC162298B2A290009D67A /* XCRemoteSwiftPackageReference "braze-ios-sdk" */;
productName = AppboyKit;
};
70CEC169298B2A810009D67A /* AppboyUI */ = {
isa = XCSwiftPackageProductDependency;
package = 70CEC162298B2A290009D67A /* XCRemoteSwiftPackageReference "braze-ios-sdk" */;
productName = AppboyUI;
};
70CEC16C298B2ACA0009D67A /* AppboySegment */ = {
isa = XCSwiftPackageProductDependency;
package = 70CEC16B298B2AC90009D67A /* XCRemoteSwiftPackageReference "appboy-segment-ios" */;
productName = AppboySegment;
};
70CEC16E298B2B010009D67A /* AppboySegment */ = {
isa = XCSwiftPackageProductDependency;
package = 70CEC16B298B2AC90009D67A /* XCRemoteSwiftPackageReference "appboy-segment-ios" */;
productName = AppboySegment;
};
/* End XCSwiftPackageProductDependency section */
};
rootObject = A7E06C711C5A6EB300EBDCC2 /* Project object */;
Expand Down
Expand Up @@ -48,7 +48,7 @@
{
"identity" : "appboy-segment-ios",
"kind" : "remoteSourceControl",
"location" : "https://github.com/Appboy/appboy-segment-ios.git",
"location" : "https://github.com/Appboy/appboy-segment-ios",
"state" : {
"revision" : "08a061113e8a7e835e6bc9c0e1629d94e63aa29e",
"version" : "4.6.0"
Expand Down
17 changes: 10 additions & 7 deletions Library/Tracking/Segment.swift
Expand Up @@ -4,22 +4,25 @@ import KsApi

public extension Analytics {
/**
Returns an `Analytics` instance, with Segment, using an `AnalyticsConfiguration`.
Returns an `Analytics` and `SEGAppboyIntegrationFactory` instance, with Segment, using an `AnalyticsConfiguration`.
*/
static func configuredClient(withWriteKey writeKey: String,
braze: SEGAppboyIntegrationFactory?) -> AnalyticsConfiguration {
static func configuredClient(withWriteKey writeKey: String)
-> (AnalyticsConfiguration, SEGAppboyIntegrationFactory?) {
let configuration = AnalyticsConfiguration(writeKey: writeKey)
configuration
.trackApplicationLifecycleEvents = true

configuration.sourceMiddleware = [BrazeDebounceMiddleware()]
// Braze is always configured but feature-flagged elsewhere.
// Data sent to Braze is feature-flagged by the enabling/disabling Segment.
if let availableBrazeInstance = braze {
configuration.use(availableBrazeInstance)
configuration.sourceMiddleware = [BrazeDebounceMiddleware()]
// FIXME: For some reason this instance of SEGAppyboyIntegrationFactory is not the same as one passed in. It's supposed to be the same singleton.
guard let factoryInstance = SEGAppboyIntegrationFactory.instance() else {
return (configuration, nil)
}

return configuration
configuration.use(factoryInstance)

return (configuration, factoryInstance)
}
}

Expand Down

0 comments on commit 7586740

Please sign in to comment.