Skip to content

Commit

Permalink
Merge StripeApplePay (stripe#717)
Browse files Browse the repository at this point in the history
  • Loading branch information
davidme-stripe authored Feb 7, 2022
1 parent 6422e4c commit fb4d3cc
Show file tree
Hide file tree
Showing 133 changed files with 4,775 additions and 502 deletions.
1 change: 1 addition & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ jobs:
stripecore_tests \
stripeidentity_tests \
stripecardscan_tests \
stripeapplepay_tests \
stripeuicore_tests \
ui_tests \
installation_cocoapods_without_frameworks_objc \
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
* [Changed] The "save this card" checkbox in PaymentSheet is now unchecked by default.
* [Fixed] Fixes issue that could cause symbol name collisions when using Objective-C
* [Fixed] Fixes potential crash when using PaymentSheet with SwiftUI
* `Stripe` now requires `StripeApplePay`. See `MIGRATING.md` for more info.
### Identity
### Card scanning
### API
Expand Down
10 changes: 10 additions & 0 deletions Example/AppClipExample/AppClipExample (iOS).entitlements
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-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>com.apple.developer.in-app-payments</key>
<array>
<string>merchant.com.stripetest.appclipexample</string>
</array>
</dict>
</plist>
979 changes: 979 additions & 0 deletions Example/AppClipExample/AppClipExample.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-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>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-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>com.apple.developer.in-app-payments</key>
<array>
<string>merchant.com.stripetest.appclipexample</string>
</array>
<key>com.apple.developer.parent-application-identifiers</key>
<array>
<string>$(AppIdentifierPrefix)com.stripe.AppClipExample</string>
</array>
</dict>
</plist>
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"colors" : [
{
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
{
"images" : [
{
"idiom" : "iphone",
"scale" : "2x",
"size" : "20x20"
},
{
"idiom" : "iphone",
"scale" : "3x",
"size" : "20x20"
},
{
"idiom" : "iphone",
"scale" : "2x",
"size" : "29x29"
},
{
"idiom" : "iphone",
"scale" : "3x",
"size" : "29x29"
},
{
"idiom" : "iphone",
"scale" : "2x",
"size" : "40x40"
},
{
"idiom" : "iphone",
"scale" : "3x",
"size" : "40x40"
},
{
"idiom" : "iphone",
"scale" : "2x",
"size" : "60x60"
},
{
"idiom" : "iphone",
"scale" : "3x",
"size" : "60x60"
},
{
"idiom" : "ipad",
"scale" : "1x",
"size" : "20x20"
},
{
"idiom" : "ipad",
"scale" : "2x",
"size" : "20x20"
},
{
"idiom" : "ipad",
"scale" : "1x",
"size" : "29x29"
},
{
"idiom" : "ipad",
"scale" : "2x",
"size" : "29x29"
},
{
"idiom" : "ipad",
"scale" : "1x",
"size" : "40x40"
},
{
"idiom" : "ipad",
"scale" : "2x",
"size" : "40x40"
},
{
"idiom" : "ipad",
"scale" : "1x",
"size" : "76x76"
},
{
"idiom" : "ipad",
"scale" : "2x",
"size" : "76x76"
},
{
"idiom" : "ipad",
"scale" : "2x",
"size" : "83.5x83.5"
},
{
"idiom" : "ios-marketing",
"scale" : "1x",
"size" : "1024x1024"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}
13 changes: 13 additions & 0 deletions Example/AppClipExample/AppClipExampleClip/Info.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-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>NSAppClip</key>
<dict>
<key>NSAppClipRequestEphemeralUserNotification</key>
<false/>
<key>NSAppClipRequestLocationConfirmation</key>
<false/>
</dict>
</dict>
</plist>
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
//
// AppClipExampleClipTests.swift
// AppClipExampleClipTests
//
// Created by David Estes on 1/20/22.
//

import XCTest
@testable import AppClipExampleClip

class AppClipExampleClipTests: XCTestCase {

override func setUpWithError() throws {
// Put setup code here. This method is called before the invocation of each test method in the class.
}

override func tearDownWithError() throws {
// Put teardown code here. This method is called after the invocation of each test method in the class.
}

func testExample() throws {
// This is an example of a functional test case.
// Use XCTAssert and related functions to verify your tests produce the correct results.
// Any test you write for XCTest can be annotated as throws and async.
// Mark your test throws to produce an unexpected failure when your test encounters an uncaught error.
// Mark your test async to allow awaiting for asynchronous code to complete. Check the results with assertions afterwards.
}

func testPerformanceExample() throws {
// This is an example of a performance test case.
self.measure {
// Put the code you want to measure the time of here.
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
//
// AppClipExampleClipUITests.swift
// AppClipExampleClipUITests
//
// Created by David Estes on 1/20/22.
//

import XCTest

class AppClipExampleClipUITests: XCTestCase {

override func setUpWithError() throws {
// Put setup code here. This method is called before the invocation of each test method in the class.

// In UI tests it is usually best to stop immediately when a failure occurs.
continueAfterFailure = false

// In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
}

override func tearDownWithError() throws {
// Put teardown code here. This method is called after the invocation of each test method in the class.
}

func testExample() throws {
// UI tests must launch the application that they test.
let app = XCUIApplication()
app.launch()

// Use recording to get started writing UI tests.
// Use XCTAssert and related functions to verify your tests produce the correct results.
}

func testLaunchPerformance() throws {
if #available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 7.0, *) {
// This measures how long it takes to launch your application.
measure(metrics: [XCTApplicationLaunchMetric()]) {
XCUIApplication().launch()
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//
// AppClipExampleClipUITestsLaunchTests.swift
// AppClipExampleClipUITests
//
// Created by David Estes on 1/20/22.
//

import XCTest

class AppClipExampleClipUITestsLaunchTests: XCTestCase {

override class var runsForEachTargetApplicationUIConfiguration: Bool {
true
}

override func setUpWithError() throws {
continueAfterFailure = false
}

func testLaunch() throws {
let app = XCUIApplication()
app.launch()

// Insert steps here to perform after app launch but before taking a screenshot,
// such as logging into a test account or navigating somewhere in the app

let attachment = XCTAttachment(screenshot: app.screenshot())
attachment.name = "Launch Screen"
attachment.lifetime = .keepAlways
add(attachment)
}
}
17 changes: 17 additions & 0 deletions Example/AppClipExample/Shared/AppClipExampleApp.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//
// AppClipExampleApp.swift
// Shared
//
// Created by David Estes on 1/7/22.
//

import SwiftUI

@main
struct AppClipExampleApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
68 changes: 68 additions & 0 deletions Example/AppClipExample/Shared/ApplePayModel.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
//
// ApplePayModel.swift
// IntegrationTester
//
// Created by David Estes on 2/18/21.
//

import Foundation
import StripeApplePay
import PassKit

class MyApplePayBackendModel : NSObject, ObservableObject, ApplePayContextDelegate {
@Published var paymentStatus: STPApplePayContext.PaymentStatus?
@Published var lastPaymentError: Error?

func pay() {
// Configure a payment request
let pr = StripeAPI.paymentRequest(withMerchantIdentifier: "merchant.com.stripetest.appclipexample", country: "US", currency: "USD")

// You'd generally want to configure at least `.postalAddress` here.
// We don't require anything here, as we don't want to enter an address
// in CI.
pr.requiredShippingContactFields = []
pr.requiredBillingContactFields = []

// Configure shipping methods
let firstClassShipping = PKShippingMethod(label: "First Class Mail", amount: NSDecimalNumber(string: "10.99"))
firstClassShipping.detail = "Arrives in 3-5 days"
firstClassShipping.identifier = "firstclass"
let rocketRidesShipping = PKShippingMethod(label: "Rocket Rides courier", amount: NSDecimalNumber(string: "10.99"))
rocketRidesShipping.detail = "Arrives in 1-2 hours"
rocketRidesShipping.identifier = "rocketrides"
pr.shippingMethods = [
firstClassShipping,
rocketRidesShipping
]

// Build payment summary items
// (You'll generally want to configure these based on the selected address and shipping method.
pr.paymentSummaryItems = [
PKPaymentSummaryItem(label: "A very nice computer", amount: NSDecimalNumber(string: "19.99")),
PKPaymentSummaryItem(label: "Shipping", amount: NSDecimalNumber(string: "10.99")),
PKPaymentSummaryItem(label: "Stripe Computer Shop", amount: NSDecimalNumber(string: "29.99"))
]

// Present the Apple Pay Context:
let applePayContext = STPApplePayContext(paymentRequest: pr, delegate: self)
applePayContext?.presentApplePay()
}

func applePayContext(_ context: STPApplePayContext, didCreatePaymentMethod paymentMethod: StripeAPI.PaymentMethod, paymentInformation: PKPayment, completion: @escaping IntentClientSecretCompletionBlock) {
// When the Apple Pay sheet is confirmed, create a PaymentIntent on your backend from the provided PKPayment information.
BackendModel.shared.fetchPaymentIntent() { secret in
if let clientSecret = secret {
// Call the completion block with the PaymentIntent's client secret.
completion(clientSecret, nil)
} else {
completion(nil, NSError())
}
}
}

func applePayContext(_ context: STPApplePayContext, didCompleteWith status: STPApplePayContext.PaymentStatus, error: Error?) {
// When the payment is complete, display the status.
self.paymentStatus = status
self.lastPaymentError = error
}
}
Loading

0 comments on commit fb4d3cc

Please sign in to comment.