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

App installed check #1233

Merged
merged 17 commits into from
Apr 4, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
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
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
# Braintree iOS SDK Release Notes

## unreleased
* BraintreeCore
jaxdesmarais marked this conversation as resolved.
Show resolved Hide resolved
* Add property `BTAppContextSwitcher.sharedInstance.universalLink` for the PayPal app switch flow
* BraintreePayPal
* Add `BTPayPalVault.enablePayPalAppSwitch`
* If set to `true` we will attempt to use the PayPal App Switch flow
* Require Xcode 15.0+ (per [App Store requirements](https://developer.apple.com/news/?id=khzvxn8a))
* BraintreePayPal
* Add `BTPayPalVaultRequest(userAuthenticationEmail:enablePayPalAppSwitch:universalLink:offerCredit:)`
Expand Down
22 changes: 18 additions & 4 deletions Sources/BraintreePayPal/BTPayPalClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ import BraintreeDataCollector

/// Exposed for testing to get the instance of BTAPIClient
var apiClient: BTAPIClient

/// Defaults to `UIApplication.shared`, but exposed for unit tests to inject test doubles
/// to prevent calls to openURL. Subclassing UIApplication is not possible, since it enforces that only one instance can ever exist.
var application: URLOpener = UIApplication.shared

/// Exposed for testing the approvalURL construction
var approvalURL: URL? = nil

Expand Down Expand Up @@ -49,6 +49,9 @@ import BraintreeDataCollector
/// In the PayPal flow this will be either an EC token or a Billing Agreement token
private var payPalContextID: String? = nil

/// URL Scheme for PayPal In-App Checkout
private let payPalInAppScheme: String = "paypal-in-app-checkout://"

// MARK: - Initializer

/// Initialize a new PayPal client instance.
Expand Down Expand Up @@ -154,9 +157,16 @@ import BraintreeDataCollector
}
}
}


@objc public func isPayPalAppInstalled() -> Bool {
stechiu marked this conversation as resolved.
Show resolved Hide resolved
guard let paypalURL = URL(string: payPalInAppScheme) else {
return false
}
return application.canOpenURL(paypalURL)
}

// MARK: - Internal Methods

func handleBrowserSwitchReturn(
_ url: URL?,
paymentType: BTPayPalPaymentType,
Expand Down Expand Up @@ -262,6 +272,10 @@ import BraintreeDataCollector
return
}

if !self.isPayPalAppInstalled() {
(request as? BTPayPalVaultRequest)?.enablePayPalAppSwitch = false
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!

}

self.payPalRequest = request
self.apiClient.post(request.hermesPath, parameters: request.parameters(with: configuration)) { body, response, error in
if let error = error as? NSError {
Expand Down
21 changes: 21 additions & 0 deletions UnitTests/BraintreePayPalTests/BTPayPalClient_Tests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -728,6 +728,27 @@ class BTPayPalClient_Tests: XCTestCase {
}


func testIsiOSAppSwitchAvailable_whenApplicationCanOpenPayPalInAppURL_returnsTrue() {
Copy link
Contributor

@scannillo scannillo Apr 1, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of asserting that the function isPayPalAppInstalled returns some boolean, we rather want our unit tests to assert on the component's public API (in this case BTPayPalClient). Implementation details (such as if the app installed check lives in a method or not) should be able to change without breaking our unit tests.

So this test should assert on the end result behavior, which is that the API POST request to /v1/paypal_hermes/create_payment_resource does include the app switch params if the app is installed, and does not include the app switch params if the app is not installed.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the feedback! I've made changes to test the endpoints

let payPalClient = BTPayPalClient(apiClient: mockAPIClient)
BTAppContextSwitcher.sharedInstance.returnURLScheme = "scheme"
let fakeApplication = FakeApplication()
fakeApplication.cannedCanOpenURL = false
fakeApplication.canOpenURLWhitelist.append(URL(string: "paypal-in-app-checkout://")!)
payPalClient.application = fakeApplication

XCTAssertTrue(payPalClient.isPayPalAppInstalled())
}

func testIsiOSAppSwitchAvailable_whenApplicationCantOpenPayPalInAppURL_returnsFalse() {
let payPalClient = BTPayPalClient(apiClient: mockAPIClient)
BTAppContextSwitcher.sharedInstance.returnURLScheme = "scheme"
let fakeApplication = FakeApplication()
fakeApplication.cannedCanOpenURL = false
payPalClient.application = fakeApplication

XCTAssertFalse(payPalClient.isPayPalAppInstalled())
}

// MARK: - Analytics

func testAPIClientMetadata_hasIntegrationSetToCustom() {
Expand Down
Loading