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

Create Example App #16

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
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
20 changes: 20 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name: iOS Build

on:
push:
branches:
- main
pull_request:
branches:
- main

jobs:
build:
runs-on: macos-latest
steps:
- name: Checkout Code
uses: actions/checkout@v2

- name: Build SwiftUI project
run: |
xcodebuild -project Example/SwiftUIExample/MobilePaymentsSwiftUIExample.xcodeproj -scheme MobilePaymentsSwiftUIExample -sdk iphoneos -configuration Release SKIP_SETUP_SCRIPT=YES CODE_SIGNING_ALLOWED=NO CODE_SIGNING_REQUIRED=NO CODE_SIGN_IDENTITY=NO
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
## User settings
xcuserdata/
.build
17 changes: 17 additions & 0 deletions Example/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Square Mobile Payments SDK Example App


### Assumptions and prerequisites

The example app make the following assumptions:

* You have read the [Mobile Payments SDK "Build on iOS"](https://developer.squareup.com/docs/mobile-payments-sdk/ios) documentation. The example app focuses on demonstrating how the Square Mobile Payments SDK works by using all of the provided user interfaces of the SDK.
* You have a Square account enabled for payment processing. If you have not
enabled payment processing on your account (or you are not sure), visit
[squareup.com/activate](https://squareup.com/activate).


### Install the required tools
* Confirm your environment meets the Square Mobile Payments SDK build requirements listed in the [root README] for this repo.
* Clone this repo (if you have not already):
`git clone https://github.com/square/mobile-payments-sdk-ios`
8 changes: 8 additions & 0 deletions Example/Shared/Config.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
public enum Config {
static let squareApplicationID: String = "your_square_application_id"
tamerbader marked this conversation as resolved.
Show resolved Hide resolved

// In a production application you should use your server to obtain an access token and locationID.
// For this sample app, we can just authorize Reader SDK using hardcoded values.
static let accessToken: String = "your_access_token"
static let locationID: String = "your_location_id"
}
224 changes: 224 additions & 0 deletions Example/Shared/Preview Content/MockMobilePaymentsSDK.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,224 @@
import SquareMobilePaymentsSDK

class MockMobilePaymentsSDK: NSObject, SDKManager {
let authorizationManager: AuthorizationManager
let paymentManager: PaymentManager
let readCardInfoManager: ReadCardInfoManager
let readerManager: ReaderManager
let settingsManager: SettingsManager

init(
authorizationManager: AuthorizationManager = MockAuthorizationManager(),
paymentManager: PaymentManager = MockPaymentManager(),
readCardInfoManager: ReadCardInfoManager = MockReadCardInfoManager(),
readerManager: ReaderManager = MockReaderManager(),
settingsManager: SettingsManager = MockSettingsManager()
) {
self.authorizationManager = authorizationManager
self.paymentManager = paymentManager
self.readCardInfoManager = readCardInfoManager
self.readerManager = readerManager
self.settingsManager = settingsManager
}
}

class MockAuthorizationManager: NSObject, AuthorizationManager {
let location: Location?
var state: AuthorizationState

init(
location: Location? = MockLocation(),
state: AuthorizationState = .authorized
) {
self.location = location
self.state = state
}

func authorize(withAccessToken accessToken: String, locationID: String, completion: @escaping (Error?) -> Void) { }
func deauthorize(completion: @escaping () -> Void) { }
func add(_ authorizationStateObserver: AuthorizationStateObserver) { }
func remove(_ authorizationStateObserver: AuthorizationStateObserver) { }
}

class MockLocation: NSObject, Location {
let id: String
let name: String
let mcc: String
let currency: Currency

init(
id: String = "1",
name: String = "My Location",
mcc: String = "mcc",
currency: Currency = .USD
) {
self.id = id
self.name = name
self.mcc = mcc
self.currency = currency
}
}

class MockPaymentManager: NSObject, PaymentManager {
var availableCardInputMethods: CardInputMethods
let offlinePaymentQueue: OfflinePaymentQueue

init(
availableCardInputMethods: CardInputMethods = .init([.chip, .contactless, .swipe]),
offlinePaymentQueue: OfflinePaymentQueue = MockOfflinePaymentQueue()
) {
self.availableCardInputMethods = availableCardInputMethods
self.offlinePaymentQueue = offlinePaymentQueue
}

func startPayment(
_ paymentParameters: PaymentParameters,
promptParameters: PromptParameters,
from viewController: UIViewController,
delegate: PaymentManagerDelegate
) -> PaymentHandle? { nil }
func add(_ availableCardInputMethodsObserver: AvailableCardInputMethodsObserver) { }
func remove(_ availableCardInputMethodsObserver: AvailableCardInputMethodsObserver) { }
}

class MockOfflinePaymentQueue: NSObject, OfflinePaymentQueue {
func getTotalStoredPaymentsAmount(completion: @escaping (MoneyAmount?, Error?) -> Void) { }
func getPayments(_ completion: @escaping ([OfflinePayment], Error?) -> Void) { }
}

class MockReadCardInfoManager: NSObject, ReadCardInfoManager {
func prepareToReadCardInfoOnce(withStoreSwipedCard storeSwipedCard: Bool, shouldReadPreInsertedCard: Bool) { }
func cancelReadingCardInfo() { }
func add(_ readCardInfoObserver: ReadCardInfoObserver) { }
func remove(_ readCardInfoObserver: ReadCardInfoObserver) { }
}

class MockReaderManager: NSObject, ReaderManager {
var readers: [ReaderInfo]
var isPairingInProgress: Bool

init(
readers: [ReaderInfo] = [MockReaderInfo()],
isPairingInProgress: Bool = false
) {
self.readers = readers
self.isPairingInProgress = isPairingInProgress
}

func startPairing(with delegate: ReaderPairingDelegate) -> PairingHandle? { nil }
func linkTapToPayReader(completion: @escaping (Error?) -> Void) { }
func relinkTapToPayReader(completion: @escaping (Error?) -> Void) { }
func isTapToPayReaderLinked(completion: @escaping (Bool, Error?) -> Void) { }
func isTapToPayReaderSupported() -> Bool { true }
func forget(_ readerInfo: ReaderInfo) { }
func blink(_ readerInfo: ReaderInfo) { }
func retryConnection(_ readerInfo: ReaderInfo) { }
func add(_ readerObserver: ReaderObserver) { }
func remove(_ readerObserver: ReaderObserver) { }
}

class MockReaderInfo: NSObject, ReaderInfo {
var id: UInt
var name: String
var serialNumber: String?
var model: ReaderModel
var supportedInputMethods: CardInputMethods
var connectionInfo: ReaderConnectionInfo
var firmwareInfo: ReaderFirmwareInfo?
var state: ReaderState
var batteryStatus: ReaderBatteryStatus?
var isBlinkable: Bool
var isForgettable: Bool
var isConnectionRetryable: Bool
var cardInsertionStatus: CardInsertionStatus

init(
id: UInt = 1,
name: String = "My Reader",
serialNumber: String? = nil,
model: ReaderModel = .contactlessAndChip,
supportedInputMethods: CardInputMethods = .init([.contactless, .chip]),
connectionInfo: ReaderConnectionInfo = MockReaderConnectionInfo(),
firmwareInfo: ReaderFirmwareInfo? = nil,
state: ReaderState = .ready,
batteryStatus: ReaderBatteryStatus? = nil,
isBlinkable: Bool = true,
isForgettable: Bool = true,
isConnectionRetryable: Bool = false,
cardInsertionStatus: CardInsertionStatus = .notInserted
) {
self.id = id
self.name = name
self.serialNumber = serialNumber
self.model = model
self.supportedInputMethods = supportedInputMethods
self.connectionInfo = connectionInfo
self.firmwareInfo = firmwareInfo
self.state = state
self.batteryStatus = batteryStatus
self.isBlinkable = isBlinkable
self.isForgettable = isForgettable
self.isConnectionRetryable = isConnectionRetryable
self.cardInsertionStatus = cardInsertionStatus
}
}

class MockReaderConnectionInfo: NSObject, ReaderConnectionInfo {
var state: ReaderConnectionState
var failureInfo: ReaderConnectionFailureInfo?

init(
state: ReaderConnectionState = .connected,
failureInfo: ReaderConnectionFailureInfo? = nil
) {
self.state = state
self.failureInfo = failureInfo
}
}

class MockSettingsManager: NSObject, SettingsManager {
let sdkSettings: SDKSettings
let paymentSettings: PaymentSettings

init(
sdkSettings: SDKSettings = MockSDKSettings(),
paymentSettings: PaymentSettings = MockPaymentSettings()
) {
self.sdkSettings = sdkSettings
self.paymentSettings = paymentSettings
}

func presentSettings(
with viewController: UIViewController,
completion: @escaping (Error?) -> Void
) { }
}

class MockSDKSettings: NSObject, SDKSettings {
let environment: Environment
let version: String

init(
environment: Environment = .sandbox,
version: String = "1"
) {
self.environment = environment
self.version = version
}
}

class MockPaymentSettings: NSObject, PaymentSettings {
let isOfflineProcessingAllowed: Bool
let offlineTransactionAmountLimit: MoneyAmount?
let offlineTotalStoredAmountLimit: MoneyAmount?

init(
isOfflineProcessingAllowed: Bool = true,
offlineTransactionAmountLimit: MoneyAmount? = nil,
offlineTotalStoredAmountLimit: MoneyAmount? = nil
) {
self.isOfflineProcessingAllowed = isOfflineProcessingAllowed
self.offlineTransactionAmountLimit = offlineTransactionAmountLimit
self.offlineTotalStoredAmountLimit = offlineTotalStoredAmountLimit
}
}
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,14 @@
{
"images" : [
{
"filename" : "appIcon.png",
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions Example/Shared/Resources/Assets.xcassets/Contents.json
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,21 @@
{
"images" : [
{
"filename" : "donut.svg",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
42 changes: 42 additions & 0 deletions Example/Shared/Resources/Launch Screen.storyboard
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="32700.99.1234" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<device id="retina6_12" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22685"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="donut" translatesAutoresizingMaskIntoConstraints="NO" id="jm1-Cu-PKf">
<rect key="frame" x="96.666666666666686" y="314.66666666666669" width="200" height="248.00000000000006"/>
<constraints>
<constraint firstAttribute="width" constant="200" id="2LC-bF-tvo"/>
</constraints>
</imageView>
</subviews>
<viewLayoutGuide key="safeArea" id="Bcu-3y-fUS"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="jm1-Cu-PKf" firstAttribute="centerY" secondItem="Bcu-3y-fUS" secondAttribute="centerY" id="Pkc-ec-dua"/>
<constraint firstItem="jm1-Cu-PKf" firstAttribute="centerX" secondItem="Bcu-3y-fUS" secondAttribute="centerX" id="ibB-mm-Vyv"/>
</constraints>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="53" y="375"/>
</scene>
</scenes>
<resources>
<image name="donut" width="248" height="248"/>
</resources>
</document>
Loading
Loading