Skip to content

Commit

Permalink
Release 0.3.0
Browse files Browse the repository at this point in the history
  • Loading branch information
mmroz committed Mar 9, 2023
1 parent f188618 commit 17df6b7
Show file tree
Hide file tree
Showing 16 changed files with 70 additions and 58 deletions.
2 changes: 1 addition & 1 deletion CashAppPayKit.podspec
Original file line number Diff line number Diff line change
@@ -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'
Expand Down
2 changes: 1 addition & 1 deletion CashAppPayKitUI.podspec
Original file line number Diff line number Diff line change
@@ -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'
Expand Down
10 changes: 5 additions & 5 deletions Demo/PayKitDemo/PayKitViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
}()
Expand Down Expand Up @@ -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!"
Expand Down
2 changes: 1 addition & 1 deletion Demo/PayKitDemo/SceneDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
if let url = URLContexts.first?.url {
NotificationCenter.default.post(
name: PayKit.RedirectNotification,
name: CashAppPay.RedirectNotification,
object: nil,
userInfo: [UIApplication.LaunchOptionsKey.url: url]
)
Expand Down
26 changes: 13 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
@@ -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.

Expand All @@ -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)
Expand Down Expand Up @@ -45,12 +45,12 @@ Add Cocoapods to your to your project. Open the `Podfile` and add `pod 'CashAppP

# PayKit <a name="paykit"></a>

### `PayKitObserver` <a name="pay-kit-observer"></a>
### `CashAppPayObserver` <a name="cash-app-pay-observer"></a>

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
}
```
Expand All @@ -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
Expand All @@ -86,7 +86,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
if let url = URLContexts.first?.url {
NotificationCenter.default.post(
name: PayKit.RedirectNotification,
name: CashAppPay.RedirectNotification,
object: nil,
userInfo: [UIApplication.LaunchOptionsKey.url : url]
)
Expand All @@ -96,20 +96,20 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
}
```

### Instantiate `PayKit` <a name="instantiate-paykit"></a>
### Instantiate `CashAppPay` <a name="instantiate-CashAppPay"></a>

When you are ready to authorize a payment using Cash App Pay,

1. Instantiate the SDK with your Client ID
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
}()
Expand Down
10 changes: 10 additions & 0 deletions RELEASE-NOTES.md
Original file line number Diff line number Diff line change
@@ -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*.
Expand Down
19 changes: 10 additions & 9 deletions Sources/PayKit/PayKit.swift → Sources/PayKit/CashAppPay.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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")

Expand All @@ -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())
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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)
}
}
6 changes: 3 additions & 3 deletions Sources/PayKit/NetworkManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -152,7 +152,7 @@ enum DebugError: Error {
case noRedirectURL(CustomerRequest)
}

extension PayKit.Endpoint {
extension CashAppPay.Endpoint {
var baseURL: URL {
switch self {
case .production:
Expand Down
3 changes: 2 additions & 1 deletion Sources/PayKit/Services/Analytics/AnalyticsService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ class EventStream2: AnalyticsService {
self?.enqueueUpload()
}

RunLoop.current.add(timer, forMode: .common)
RunLoop.main.add(timer, forMode: .common)
}

// MARK: - Public
Expand Down Expand Up @@ -137,5 +137,6 @@ extension EventStream2 {
case platform = "platform"
case sdkVersion = "sdk_version"
case clientUA = "client_ua"
case isSandbox = "is_sandbox"
}
}
2 changes: 1 addition & 1 deletion Sources/PayKit/Services/Networking/UserAgent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
14 changes: 7 additions & 7 deletions Sources/PayKit/StateMachine.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand All @@ -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
Expand All @@ -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)

Expand Down Expand Up @@ -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
Expand All @@ -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))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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/")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down Expand Up @@ -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)
}
}
4 changes: 2 additions & 2 deletions Tests/PayKitTests/StateMachineAnalyticsTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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) {}
}
8 changes: 4 additions & 4 deletions Tests/PayKitTests/StateMachineTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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))
}

Expand Down
Loading

0 comments on commit 17df6b7

Please sign in to comment.