Arrive iOS SDK
Introduction
The Arrive iOS SDK enables developers to find and book parking using the Arrive platform. Contained within the SDK are network requests and responses that can be used to access the Arrive API via native implementations as well as fully fleshed-out model objects. Each SDK function provides access to the API without the overhead of building integration from the ground up.
You will need an API key to use with the SDK. If you do not already have one, email partner-support@arrive.com to request credentials. Different API keys will correspond to production
and sandbox
environments. To use each environment, the proper key will need to match.
Setup
We provide two consumer options (dSYMs are included for all libraries).
- Manually download the SDK and use it as a fat library -
https://s3.us-west-2.amazonaws.com/cdn.ios.parkwhiz.com/ios-sdk/{build_number}/Arrive.zip
- Import files to the project.
- Include library/all libraries at Target → General → Frameworks, Libraries, and Embedded Content.
- In some cases, the library should be Embed & Sign.
- By CocoaPods -
Our latest build's
podspec
is stored at - https://s3.us-west-2.amazonaws.com/cdn.ios.parkwhiz.com/ios-sdk/ArriveSDK.podspec However, if, for any reason, a specific build is needed, it could be found at - https://s3.us-west-2.amazonaws.com/cdn.ios.parkwhiz.com/ios-sdk/{build_number}/ArriveSDK.podspec
@podspec_path = 'https://s3.us-west-2.amazonaws.com/cdn.ios.parkwhiz.com/ios-sdk/ArriveSDK.podspec'
For All Libraries (Core+BLE) -
pod 'ArriveSDK', :podspec => @podspec_path
For Arrive Core API -
pod 'ArriveSDK/Core', :podspec => @podspec_path
Initialize an Arrive instance
import Arrive
let apiKey = "<#yourApiKey#>"
let configuration = ApiConfiguration(clientId: apiKey, environment: .sandbox)
self.arriveApi = ArriveApi(with: configuration)
Token Management
Before making any API calls, you need to get a public token.
Public Token
arriveApi.authenticationService.getPublicToken {
response in
print(response)
}
Authenticated Token
Most API calls require user authentication. To get a user authentication, use the SDK's AuthenticationService
to authenticate a user.
arriveApi.authenticationService.authenticateUser(email: "<#username#>", password: "<#password#>") {
response in
switch response {
case .success(let authorization):
print(authorization)
case .failure(let error):
print(error)
}
}
The authentication token is automatically stored and refreshed after a successful login API call. You can check the user's logged-in state:
arriveApi.authenticationService.isUserAuthenticated
Sample Calls
Get Locations
let coordinates = Coordinates(lat: 41.879072, lng: -87.6448557)
arriveApi.locationService.getLocations(near: coordinates, within: 0.5) {
locations in
...
//work with the returned array of locations
...
}
Add a Vehicle
arriveApi.vehicleService.addVehicle(plateNumber: "1B5 2R9",
state: "CA",
nickname: "The pickup truck",
isDefault: true
) {
vehicle in
...
//work with the returned vehicle
...
}
Get Quotes
To search for parking around a geographic location, create a search (ParkingSearch
) and use an instance of the ParkingSearchService
from the SDK to execute the search.
Note: Parking searches only require a public token
let search = ParkingSearch.center(Coordinates(lat: 41.879072, lng: -87.6448557))
arriveApi.parkingSearchService.getQuotes(search: search) { (quotes) in
...
//work with the returned array of quotes
...
}
Get a Ticket associated with a Booking
Note: You must pass in the booking's original authorization code. The authorization code can be found on the
Booking
model.
arriveApi.bookingService.getTicket(bookingId: 123, authorizationCode: "abc123") { result in
switch result {
case .success(let ticket):
//work with the returned ticket
case .failure(let error):
//error
}
}
ArriveBLE Docs
ArriveBLE
allows interaction with Flash gates through the device's CoreBluetooth. It is a standalone framework, but parts of its logic depend on Arrive/Core SDK.
Every file that needs to use ArriveBLE logic must import it.
import ArriveBLE
Transient
Initialize a BLEGateManager instance
Create a BLEGateManager
and conform to its delegate - BLEGateDelegate
.
A BLEGateManager
requires a BLEGateConfigurations
object to configure the manager.
lazy var configurations = BLEGateConfigurations(
passType: .transient(appId: ##APP_ID##, authKey: ##Auth_Key##),
transactionId: ##TRANSACTION_ID##,
log: true // (default is false)
)
- appId - FlashParking provides your 20-character application ID.
- authKey - FlashParking provides your 20-character authorization key.
- transactionId - Transaction Id (or voucher code) that includes your prefix provided by FlashParking.
- log: Enables logging recommended to disable on production.
BLEGateDelegate
should conform to -
// Gate is ready for interaction with an iOS device.
// At this point, we start scanning.
func gateIsReady() {
manager.startScan()
}
func gateSuccess(_: BLEGateMessage) {
}
func gateFailure(_ error: BLEGateResponse) {
// see BLEGateResponse
}
Valid Gate Responses
public enum BLEGateResponse: Int {
case success = 1
/// TransactionID been used
case alreadyUsed
/// TransactionID / MonthlyCustomerID / TicketID / KeyTag - NotFound
case notFound
case facilityFull
case corruptedTicket
case unknown
/// TransactionID been expired
case expired
/// TransactionID isn't valid yet
case tooEarly
case unRecognizedAccountType
/// Invalid AppKey and/or AuthKey
case authentication
case paymentError
/// AppKey and/or AuthKey weren't injected
case missingCredentials
/// Bluetooth isn't enabled
case bluetoothDisabled = 100
/// Monthly - Device isn't registered
case monthlyAccountNotFound
/// No response from gate
case timedOut
case gateNotFound
/// TransactionID wasn't injected
case noAvailableToken
}
Transient Sample Code:
import UIKit
import CoreLocation
import ArriveBLE
class TransientViewController: UIViewController, BLEGateDelegate {
// MARK: - Members
var manager: BLEGateManager!
lazy var configurations = BLEGateConfigurations(
passType: .transient(appId: ##APP_ID##, authKey: ##Auth_Key##),
transactionId: ##TRANSACTION_ID##,
log: true
)
// MARK: - Methods
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
manager = BLEGateManager(
configurations: configurations,
delegate: self
)
}
func gateIsReady() {
manager.startScan()
}
func gateSuccess(_: BLEGateMessage) {
// do any success logic
}
func gateFailure(_ error: BLEGateResponse) {
// handle error
}
@IBAction func openTheGate() {
manager.openGate()
}
}
Enable Monthly
Initialize a BLEGateManager instance
Create a BLEGateManager
and conform to its delegate - BLEGateDelegate
. A BLEGateManager
requires a BLEGateConfigurations
object to configure the manager. Use passType: .monthly
.
import ArriveBLE
class SomeClass: BLEGateDelegate {
// ...
lazy var bleConfig = BLEGateConfigurations(passType: .monthly)
lazy var manager = BLEGateManager(with: bleConfig, delegate: self)
// ...
}
Start by registering the device associated with the user's Flash monthly account. The user can only register the phone number of whatever is tied to the SIM card in the phone. Follow the code below to bootstrap the onboarding process.
Start the registration process by calling register
:
// ...
manager.register(self)
// ...
Note that register
takes a UIViewController
. This is required to present the MFMessageComposeViewController
to the user to send a text message to associate the phone number with the current device.
- If the customer is registered in the system and has at least one monthly parking location,
gateSuccess
will be invoked withBLEGateMessage
equaling.authentication
. - If no monthly locations are associated with the phone number, or the account does not exist,
gateFailure
will be invoked with an.authentication
error. Use this to determine if the user has monthly parking enabled or not. - If the user cancels the registration process by dismissing the
MFMessageComposeViewController
,gateFailure
will also be invoked with an.authentication
error.
Open Gate
First, the device and customer must be registered - see Enable Monthly.
To open a gate within BLE range, ensure that the gate is ready, then call openGate()
:
if isReady {
manager.openGate()
}
- If the gate successfully opens, the
gateSuccess
function ofBLEGateDelegate
will be invoked. - If the gate fails to open or another error occurs, the
gateFailure
function ofBLEGateDelegate
will be invoked.
Start/Stop Scan
Initializing a BLEGateManager
will automatically start scanning for gates, but it is possible to start scanning manually:
manager.startScan()
To stop scanning for gates, call:
manager.stopScan()
Get a QR Code
Kiosks allow for the scanning of a QR code to vend monthly customers. To generate the QR code string, ensure your passType
for BLEGateManager
is .monthly
. After the device is registered (see Enable Monthly), the QR code is stored permanently and accessible as a property on the manager from there on out:
gateManager.qrCode
- If the current
passType
is not.monthly
,qrCode
will benil
. - If the device has not been registered,
qrCode
will benil
.
Get Monthly Parking Status
Although a customer can't register for monthly parking without having at least one monthly location, it may be useful to check the monthly parking status before/after registration:
gateManager.isMonthlyRegistered
Monthly Pass Sample Code:
import UIKit
import ArriveBLE
class ViewController: UIViewController, BLEGateDelegate {
lazy var bleConfig = BLEGateConfigurations(passType: .monthly)
var manager: BLEGateManager!
private var isReady = false
// MARK: - Proposed Methods
override func viewDidLoad() {
super.viewDidLoad()
manager = BLEGateManager(with: bleConfig, delegate: self)
}
@IBAction func register(_ sender: UIButton) {
if !manager.isMonthlyRegistered {
manager.register(self)
}
}
@IBAction func openGate(_ sender: UIButton) {
if isReady {
manager.openGate()
}
}
// MARK: - BLEGateDelegate
func gateIsReady() {
// Gate is discovered and ready.
isReady = true
}
func gateSuccess(_ status: BLEGateMessage) {
// Authenticated successfully, or gate opened.
switch status {
case .authentication:
print("Authenticated successfully!")
case .opened:
print("Opened gate successfully!")
default:
break
}
}
func gateFailure(_ error: BLEGateError) {
// Issue with gate or authentication.
switch error {
case .authentication:
print("User has no monthly locations!")
default:
print("Other error occurred.")
}
}
}