From 17df6b7c8f802ec5bf5cd012a270ff9fcbb50927 Mon Sep 17 00:00:00 2001 From: Mark Mroz Date: Thu, 9 Mar 2023 10:12:02 -0500 Subject: [PATCH] Release 0.3.0 --- CashAppPayKit.podspec | 2 +- CashAppPayKitUI.podspec | 2 +- Demo/PayKitDemo/PayKitViewController.swift | 10 +++---- Demo/PayKitDemo/SceneDelegate.swift | 2 +- README.md | 26 +++++++++---------- RELEASE-NOTES.md | 10 +++++++ .../PayKit/{PayKit.swift => CashAppPay.swift} | 19 +++++++------- Sources/PayKit/NetworkManager.swift | 6 ++--- .../Services/Analytics/AnalyticsService.swift | 3 ++- .../Services/Networking/UserAgent.swift | 2 +- Sources/PayKit/StateMachine.swift | 14 +++++----- ...st.swift => CashAppPay+EndpointTest.swift} | 6 ++--- ...ayKitTests.swift => CashAppPayTests.swift} | 12 ++++----- .../StateMachineAnalyticsTests.swift | 4 +-- Tests/PayKitTests/StateMachineTests.swift | 8 +++--- Tests/PayKitTests/UserAgentTests.swift | 2 +- 16 files changed, 70 insertions(+), 58 deletions(-) rename Sources/PayKit/{PayKit.swift => CashAppPay.swift} (90%) rename Tests/PayKitTests/{PayKit+EndpointTest.swift => CashAppPay+EndpointTest.swift} (72%) rename Tests/PayKitTests/{PayKitTests.swift => CashAppPayTests.swift} (95%) diff --git a/CashAppPayKit.podspec b/CashAppPayKit.podspec index d89da40..62d4776 100644 --- a/CashAppPayKit.podspec +++ b/CashAppPayKit.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'CashAppPayKit' - s.version = '0.2.0' + s.version = '0.3.0' s.summary = 'PayKit iOS SDK' s.homepage = 'https://github.com/cashapp/cash-app-pay-ios-sdk' s.license = 'Apache License, Version 2.0' diff --git a/CashAppPayKitUI.podspec b/CashAppPayKitUI.podspec index 7a3fdf3..830d383 100644 --- a/CashAppPayKitUI.podspec +++ b/CashAppPayKitUI.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'CashAppPayKitUI' - s.version = "0.2.0" + s.version = "0.3.0" s.summary = 'UI components for the PayKit iOS SDK' s.homepage = 'https://github.com/cashapp/cash-app-pay-ios-sdk' s.license = 'Apache License, Version 2.0' diff --git a/Demo/PayKitDemo/PayKitViewController.swift b/Demo/PayKitDemo/PayKitViewController.swift index 571a29e..7e102d0 100644 --- a/Demo/PayKitDemo/PayKitViewController.swift +++ b/Demo/PayKitDemo/PayKitViewController.swift @@ -45,8 +45,8 @@ class PayKitViewController: UIViewController { } } - private lazy var sdk: PayKit = { - let sdk = PayKit(clientID: sandboxClientID, endpoint: .sandbox) + private lazy var sdk: CashAppPay = { + let sdk = CashAppPay(clientID: sandboxClientID, endpoint: .sandbox) sdk.addObserver(self) return sdk }() @@ -307,11 +307,11 @@ extension PayKitViewController { } } -// MARK: - PayKitObserver +// MARK: - CashAppPayObserver -extension PayKitViewController: PayKitObserver { +extension PayKitViewController: CashAppPayObserver { // swiftlint:disable:next cyclomatic_complexity - func stateDidChange(to state: PayKitState) { + func stateDidChange(to state: CashAppPayState) { switch state { case .notStarted: statusTextView.text = "Hit that button!" diff --git a/Demo/PayKitDemo/SceneDelegate.swift b/Demo/PayKitDemo/SceneDelegate.swift index e4bb047..d7ab5b6 100644 --- a/Demo/PayKitDemo/SceneDelegate.swift +++ b/Demo/PayKitDemo/SceneDelegate.swift @@ -32,7 +32,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { func scene(_ scene: UIScene, openURLContexts URLContexts: Set) { if let url = URLContexts.first?.url { NotificationCenter.default.post( - name: PayKit.RedirectNotification, + name: CashAppPay.RedirectNotification, object: nil, userInfo: [UIApplication.LaunchOptionsKey.url: url] ) diff --git a/README.md b/README.md index bc244cb..d2a6df9 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ # PayKit for iOS -[![License](https://img.shields.io/badge/license-Apache2-green.svg?style=flat)](LICENSE) ![Swift](https://img.shields.io/badge/swift-5.0-brightgreen.svg) ![Xcode 11.0+](https://img.shields.io/badge/Xcode-11.0%2B-blue.svg) ![iOS 13.0+](https://img.shields.io/badge/iOS-13.0%2B-blue.svg) [![SPM](https://img.shields.io/badge/Swift%20Package%20Manager-compatible-brightgreen.svg)](https://github.com/apple/swift-package-manager) +[![License](https://img.shields.io/badge/license-Apache2-green.svg?style=flat)](LICENSE) ![Swift](https://img.shields.io/badge/swift-5.0-brightgreen.svg) ![Xcode 11.0+](https://img.shields.io/badge/Xcode-11.0%2B-blue.svg) ![iOS 11.0+](https://img.shields.io/badge/iOS-13.0%2B-blue.svg) [![SPM](https://img.shields.io/badge/Swift%20Package%20Manager-compatible-brightgreen.svg)](https://github.com/apple/swift-package-manager) Pay Kit is an open source software framework that allows you to accept Cash App Pay in your App. The framework provides a modules that can be used out of the box where the customer will be redirected from your checkout experience to Cash App to approve the payment before being redirected back to your App. It is composed of two SPM packages which can each be imported separately. -* **`PayKit`:** This is the best place to start building your app. `PayKit` provides a protocol called `PayKitObserver` that receives updates from Pay Kit. Your checkout view controller can conform to this protocol, or you can create a dedicated observer class. +* **`PayKit`:** This is the best place to start building your app. `PayKit` provides a protocol called `CashAppPayObserver` that receives updates from Pay Kit. Your checkout view controller can conform to this protocol, or you can create a dedicated observer class. * **`PayKitUI`:** Provides the views used across the framework. The views are provided to the user to launch a Pay Kit payment and to present the Cashtag but do not prescribe how they must be used. @@ -14,9 +14,9 @@ Pay Kit is an open source software framework that allows you to accept Cash App * [SPM](#spm) * [Cocoapods](#cocoapods) * [`PayKit`](#paykit) - * [`PayKitObserver`](#pay-kit-observer) + * [`CashAppPayObserver`](#cash-app-pay-observer) * [Implement URL handling](#implement-url-handling) - * [Instantiate PayKit](#instantiate-paykit) + * [Instantiate CashAppPay](#instantiate-CashAppPay) * [Create a Customer Request](#create-a-customer-request) * [Authorize the Customer Request](#authorize-the-customer-request) * [Pass Grants to the Backend and Create Payment](#grants) @@ -45,12 +45,12 @@ Add Cocoapods to your to your project. Open the `Podfile` and add `pod 'CashAppP # PayKit -### `PayKitObserver` +### `CashAppPayObserver` -The `PayKitObserver` protocol contains only one method: +The `CashAppPayObserver` protocol contains only one method: ```swift -func stateDidChange(to state: CashAppPaySDKState) { +func stateDidChange(to state: CashAppPayState) { // handle state changes } ``` @@ -76,7 +76,7 @@ Choose a unique scheme for your application and register it in Xcode from the In You will pass a URL that uses this scheme (or a Universal Link your app handles) into the `createCustomerRequest()` method that starts the authorization process. -When your app is called back by Cash App, simply post the `PayKit.RedirectNotification` from your `AppDelegate` or `SceneDelegate`, and the SDK will handle the rest: +When your app is called back by Cash App, simply post the `CashAppPay.RedirectNotification` from your `AppDelegate` or `SceneDelegate`, and the SDK will handle the rest: ```swift import UIKit @@ -86,7 +86,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { func scene(_ scene: UIScene, openURLContexts URLContexts: Set) { if let url = URLContexts.first?.url { NotificationCenter.default.post( - name: PayKit.RedirectNotification, + name: CashAppPay.RedirectNotification, object: nil, userInfo: [UIApplication.LaunchOptionsKey.url : url] ) @@ -96,7 +96,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { } ``` -### Instantiate `PayKit` +### Instantiate `CashAppPay` When you are ready to authorize a payment using Cash App Pay, @@ -104,12 +104,12 @@ When you are ready to authorize a payment using Cash App Pay, 2. The SDK defaults to point to the `production` endpoint; for development, set the endpoint to `sandbox` 3. Add your observer to the SDK -For example, from your checkout view controller that implements the `PayKitObserver` protocol, you can instantiate the SDK to be: +For example, from your checkout view controller that implements the `CashAppPayObserver` protocol, you can instantiate the SDK to be: ```swift private let sandboxClientID = "YOUR_CLIENT_ID" -private lazy var sdk: PayKit = { - let sdk = PayKit(clientID: sandboxClientID, endpoint: .sandbox) +private lazy var sdk: CashAppPay = { + let sdk = CashAppPay(clientID: sandboxClientID, endpoint: .sandbox) sdk.addObserver(self) return sdk }() diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md index 8268cbc..0d179ce 100644 --- a/RELEASE-NOTES.md +++ b/RELEASE-NOTES.md @@ -1,3 +1,13 @@ +## PayKit 0.3.0 Release Notes + +*PayKit 0.3.0* supports *iOS* and requires *Xcode 9* or later. The minimum supported *Base SDK* is *11.0*. + +*PayKit 0.3.0* includes the following new features and enhancements. + +- **Name changes** + + *PayKit* class has been renamed to *CashAppPay*. + ## PayKit 0.2.0 Release Notes *PayKit 0.2.0* supports *iOS* and requires *Xcode 9* or later. The minimum supported *Base SDK* is *11.0*. diff --git a/Sources/PayKit/PayKit.swift b/Sources/PayKit/CashAppPay.swift similarity index 90% rename from Sources/PayKit/PayKit.swift rename to Sources/PayKit/CashAppPay.swift index 9a23510..2c095a0 100644 --- a/Sources/PayKit/PayKit.swift +++ b/Sources/PayKit/CashAppPay.swift @@ -17,9 +17,9 @@ import Foundation import UIKit -public class PayKit { +public class CashAppPay { - public static let version = "0.2.0" + public static let version = "0.3.0" public static let RedirectNotification: Notification.Name = Notification.Name("CashAppPayRedirect") @@ -32,8 +32,9 @@ public class PayKit { commonParameters: [ EventStream2.CommonFields.clientID.rawValue: clientID, EventStream2.CommonFields.platform.rawValue: "iOS", - EventStream2.CommonFields.sdkVersion.rawValue: PayKit.version, + EventStream2.CommonFields.sdkVersion.rawValue: CashAppPay.version, EventStream2.CommonFields.clientUA.rawValue: UserAgent.userAgent, + EventStream2.CommonFields.isSandbox.rawValue: (endpoint == .sandbox), ], store: AnalyticsDataSource(), client: AnalyticsClient(restService: ResilientRESTService()) @@ -96,7 +97,7 @@ public class PayKit { } } -public enum PayKitState: Equatable { +public enum CashAppPayState: Equatable { /// Ready for a Create Customer Request to be initiated. case notStarted /// CustomerRequest is being created. For information only. @@ -126,16 +127,16 @@ public enum PayKitState: Equatable { case unexpectedError(UnexpectedError) } -public protocol PayKitObserver: AnyObject { - func stateDidChange(to state: PayKitState) +public protocol CashAppPayObserver: AnyObject { + func stateDidChange(to state: CashAppPayState) } -public extension PayKit { - func addObserver(_ observer: PayKitObserver) { +public extension CashAppPay { + func addObserver(_ observer: CashAppPayObserver) { stateMachine.addObserver(observer) } - func removeObserver(_ observer: PayKitObserver) { + func removeObserver(_ observer: CashAppPayObserver) { stateMachine.removeObserver(observer) } } diff --git a/Sources/PayKit/NetworkManager.swift b/Sources/PayKit/NetworkManager.swift index 6aa005e..9417ef7 100644 --- a/Sources/PayKit/NetworkManager.swift +++ b/Sources/PayKit/NetworkManager.swift @@ -41,13 +41,13 @@ class NetworkManager { // MARK: - Visible API - init(clientID: String, endpoint: PayKit.Endpoint) { + init(clientID: String, endpoint: CashAppPay.Endpoint) { self.clientID = clientID self.endpoint = endpoint self.restService = ResilientRESTService() } - let endpoint: PayKit.Endpoint + let endpoint: CashAppPay.Endpoint func createCustomerRequest( params: CreateCustomerRequestParams, @@ -152,7 +152,7 @@ enum DebugError: Error { case noRedirectURL(CustomerRequest) } -extension PayKit.Endpoint { +extension CashAppPay.Endpoint { var baseURL: URL { switch self { case .production: diff --git a/Sources/PayKit/Services/Analytics/AnalyticsService.swift b/Sources/PayKit/Services/Analytics/AnalyticsService.swift index e4b84ab..38ef600 100644 --- a/Sources/PayKit/Services/Analytics/AnalyticsService.swift +++ b/Sources/PayKit/Services/Analytics/AnalyticsService.swift @@ -90,7 +90,7 @@ class EventStream2: AnalyticsService { self?.enqueueUpload() } - RunLoop.current.add(timer, forMode: .common) + RunLoop.main.add(timer, forMode: .common) } // MARK: - Public @@ -137,5 +137,6 @@ extension EventStream2 { case platform = "platform" case sdkVersion = "sdk_version" case clientUA = "client_ua" + case isSandbox = "is_sandbox" } } diff --git a/Sources/PayKit/Services/Networking/UserAgent.swift b/Sources/PayKit/Services/Networking/UserAgent.swift index 124be69..ae04fbf 100644 --- a/Sources/PayKit/Services/Networking/UserAgent.swift +++ b/Sources/PayKit/Services/Networking/UserAgent.swift @@ -33,7 +33,7 @@ enum UserAgent { } let appIdentifier = infoDictionaryString(forKey: kCFBundleIdentifierKey as String) let appVersion = infoDictionaryString(forKey: kCFBundleVersionKey as String) - var payKitVersion = PayKit.version + var payKitVersion = CashAppPay.version let model = UIDevice.current.deviceModel ?? unknownValue let language = Locale.current.languageCode?.lowercased() ?? unknownValue diff --git a/Sources/PayKit/StateMachine.swift b/Sources/PayKit/StateMachine.swift index f1a71e2..b514328 100644 --- a/Sources/PayKit/StateMachine.swift +++ b/Sources/PayKit/StateMachine.swift @@ -27,7 +27,7 @@ class StateMachine { var notificationObserver: NSObjectProtocol? var pollingTimer: Timer? - var state: PayKitState = .notStarted { + var state: CashAppPayState = .notStarted { didSet { stateDidChange(to: state, from: oldValue) } @@ -37,7 +37,7 @@ class StateMachine { self.networkManager = networkManager self.analyticsService = analyticsService NotificationCenter.default.addObserver( - forName: PayKit.RedirectNotification, + forName: CashAppPay.RedirectNotification, object: nil, queue: nil ) { [weak self] _ in @@ -59,7 +59,7 @@ class StateMachine { } // swiftlint:disable:next cyclomatic_complexity function_body_length - func stateDidChange(to state: PayKitState, from oldState: PayKitState) { + func stateDidChange(to state: CashAppPayState, from oldState: CashAppPayState) { // Clear polling timer and observer if necessary. cleanUpSideEffectsFor(state: state) @@ -174,7 +174,7 @@ class StateMachine { } } - func cleanUpSideEffectsFor(state: PayKitState) { + func cleanUpSideEffectsFor(state: CashAppPayState) { // If we're in any state other than .polling, invalidate the timer. if case .polling = state { // do nothing @@ -198,16 +198,16 @@ class StateMachine { extension StateMachine { struct Observation { - weak var observer: PayKitObserver? + weak var observer: CashAppPayObserver? } - func addObserver(_ observer: PayKitObserver) { + func addObserver(_ observer: CashAppPayObserver) { let id = ObjectIdentifier(observer) observations[id] = Observation(observer: observer) analyticsService.track(ListenerEvent(listenerUID: id.debugDescription, isAdded: true)) } - func removeObserver(_ observer: PayKitObserver) { + func removeObserver(_ observer: CashAppPayObserver) { let id = ObjectIdentifier(observer) observations.removeValue(forKey: id) analyticsService.track(ListenerEvent(listenerUID: id.debugDescription, isAdded: false)) diff --git a/Tests/PayKitTests/PayKit+EndpointTest.swift b/Tests/PayKitTests/CashAppPay+EndpointTest.swift similarity index 72% rename from Tests/PayKitTests/PayKit+EndpointTest.swift rename to Tests/PayKitTests/CashAppPay+EndpointTest.swift index 872f4ef..2de8938 100644 --- a/Tests/PayKitTests/PayKit+EndpointTest.swift +++ b/Tests/PayKitTests/CashAppPay+EndpointTest.swift @@ -17,9 +17,9 @@ @testable import PayKit import XCTest -class PayKit_EndpointTest: XCTestCase { +class CashAppPay_EndpointTest: XCTestCase { func test_endpoint_url() { - XCTAssertEqual(PayKit.Endpoint.sandbox.baseURL.absoluteString, "https://sandbox.api.cash.app/") - XCTAssertEqual(PayKit.Endpoint.production.baseURL.absoluteString, "https://api.cash.app/") + XCTAssertEqual(CashAppPay.Endpoint.sandbox.baseURL.absoluteString, "https://sandbox.api.cash.app/") + XCTAssertEqual(CashAppPay.Endpoint.production.baseURL.absoluteString, "https://api.cash.app/") } } diff --git a/Tests/PayKitTests/PayKitTests.swift b/Tests/PayKitTests/CashAppPayTests.swift similarity index 95% rename from Tests/PayKitTests/PayKitTests.swift rename to Tests/PayKitTests/CashAppPayTests.swift index bb3f773..39f1c45 100644 --- a/Tests/PayKitTests/PayKitTests.swift +++ b/Tests/PayKitTests/CashAppPayTests.swift @@ -19,12 +19,12 @@ import XCTest class PayKitTests: XCTestCase { - private var payKit: PayKit! + private var payKit: CashAppPay! override func setUp() { super.setUp() let stateMachine = StateMachine(networkManager: MockNetworkManager(), analyticsService: MockAnalytics()) - self.payKit = PayKit(stateMachine: stateMachine, endpoint: .production) + self.payKit = CashAppPay(stateMachine: stateMachine, endpoint: .production) } override func tearDown() { @@ -165,14 +165,14 @@ class PayKitTests: XCTestCase { } } -private class TestObserver: PayKitObserver { - var stateDidChangeStub: (PayKitState) -> Void +private class TestObserver: CashAppPayObserver { + var stateDidChangeStub: (CashAppPayState) -> Void - init(stateDidChangeStub: @escaping (PayKitState) -> Void) { + init(stateDidChangeStub: @escaping (CashAppPayState) -> Void) { self.stateDidChangeStub = stateDidChangeStub } - func stateDidChange(to state: PayKitState) { + func stateDidChange(to state: CashAppPayState) { stateDidChangeStub(state) } } diff --git a/Tests/PayKitTests/StateMachineAnalyticsTests.swift b/Tests/PayKitTests/StateMachineAnalyticsTests.swift index b7fbe98..8cba9ad 100644 --- a/Tests/PayKitTests/StateMachineAnalyticsTests.swift +++ b/Tests/PayKitTests/StateMachineAnalyticsTests.swift @@ -248,6 +248,6 @@ class StateMachineAnalyticsTests: XCTestCase { } } -private class TestObserver: PayKitObserver { - func stateDidChange(to state: PayKitState) {} +private class TestObserver: CashAppPayObserver { + func stateDidChange(to state: CashAppPayState) {} } diff --git a/Tests/PayKitTests/StateMachineTests.swift b/Tests/PayKitTests/StateMachineTests.swift index f241585..e7ef58d 100644 --- a/Tests/PayKitTests/StateMachineTests.swift +++ b/Tests/PayKitTests/StateMachineTests.swift @@ -79,22 +79,22 @@ class StateMachineTests: XCTestCase { // The state machine should advance to .polling if we're in .redirecting. stateMachine.state = .redirecting(customerRequest) - NotificationCenter.default.post(name: PayKit.RedirectNotification, object: nil) + NotificationCenter.default.post(name: CashAppPay.RedirectNotification, object: nil) XCTAssertEqual(stateMachine.state, .polling(customerRequest)) // The state machine should also advance to .polling if we're in .readyToAuthorize; // it's unexpected, but we can continue. stateMachine.state = .readyToAuthorize(customerRequest) - NotificationCenter.default.post(name: PayKit.RedirectNotification, object: nil) + NotificationCenter.default.post(name: CashAppPay.RedirectNotification, object: nil) XCTAssertEqual(stateMachine.state, .polling(customerRequest)) // If we're in any other state, we shouldn't advance. stateMachine.state = .notStarted - NotificationCenter.default.post(name: PayKit.RedirectNotification, object: nil) + NotificationCenter.default.post(name: CashAppPay.RedirectNotification, object: nil) XCTAssertEqual(stateMachine.state, .notStarted) stateMachine.state = .creatingCustomerRequest(TestValues.createCustomerRequestParams) - NotificationCenter.default.post(name: PayKit.RedirectNotification, object: nil) + NotificationCenter.default.post(name: CashAppPay.RedirectNotification, object: nil) XCTAssertEqual(stateMachine.state, .creatingCustomerRequest(TestValues.createCustomerRequestParams)) } diff --git a/Tests/PayKitTests/UserAgentTests.swift b/Tests/PayKitTests/UserAgentTests.swift index cdb4d45..c8c2da7 100644 --- a/Tests/PayKitTests/UserAgentTests.swift +++ b/Tests/PayKitTests/UserAgentTests.swift @@ -21,7 +21,7 @@ class UserAgentTests: XCTestCase { func test_user_agent() { let appIdentifier = infoDictionaryString(forKey: kCFBundleIdentifierKey as String) let appVersion = infoDictionaryString(forKey: kCFBundleVersionKey as String) - let payKitVersion = PayKit.version + let payKitVersion = CashAppPay.version let model = UIDevice.current.deviceModel ?? UserAgent.unknownValue let language = Locale.current.languageCode?.lowercased() ?? UserAgent.unknownValue