ParkWhiz Android SDK
Introduction
The ParkWhiz Android SDK enables developers to find and book parking using the ParkWhiz platform. Contained within are network requests and responses that can be used to access the ParkWhiz 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 an integration from the ground up.
You will need an API key to use with the SDK. If you do not already have one, send an email to partner-support@parkwhiz.com to request credentials. There will be different API keys that correspond to production and sandbox environments respectively. In order to use each environment, the proper key will need to match.
Setup
In order to import the SDK, add the parkwhiz-android-sdk.appspot.com endpoint to the repositories in your top level build.gradle file. Set the required credentials.
allprojects {
repositories {
...
maven {
credentials {
username parkwhizUser
password parkwhizPassword
}
url "https://parkwhiz-android-sdk.appspot.com"
}
}
}In your app build.gradle module, include the following dependency:
dependencies {
...
implementation 'com.parkwhiz.android:sdk:$parkwhiz_version'
}
Initialize the ParkWhiz instance from within your Application.onCreate() method:
override fun onCreate() {
super.onCreate()
val config = ArriveConfig.Builder(this,"API_KEY")
.setEnvironment(Environment.SANDBOX || Environment.PRODUCTION)
.setPaymentAuthorizationToken(...)
.build()
Arrive.initialize(config)
}Token Management
Public Token
The public token is managed by the SDK so there should be no need to manually retrieve it. If you need to access the public token for any reason you can use the PublicTokenManager.
Authenticated Token
The authentication token is automatically stored and refreshed after a successful login api call is made. You can check the users logged in state:
val authenticatedTokenManager = Arrive.configuration.authenticatedTokenManager
val isLoggedIn = authenticatedTokenManager.isLoggedInLogout user:
val authenticatedTokenManager = Arrive.configuration.authenticatedTokenManager
authenticatedTokenManager.clear()Observe logged in state via a couroutines Flow:
Arrive.configuration.authenticatedTokenManager.isLoggedInFlow.collect { isLoggedIn ->
if (isLoggedIn) {
...
} else {
...
}
}Payments
Make sure you have set the PaymentAuthorizationToken when initializing the Arrive SDK.
PayPal & Google Pay Setup
AndroidManifest.xml
<activity
android:name="com.arrive.android.sdk.payments.PaymentActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="${applicationId}.braintree" />
</intent-filter>
</activity> If you plan on using Google Pay in app you will need to add Google Play Services Wallet to your build.gradle.
dependencies {
...
implementation 'com.google.android.gms:play-services-wallet:18.1.3'
}Requesting Google Pay Nonce
CoroutineScope().launch {
Arrive.paymentMethodService.requestGooglePayNonce(FragmentActivity, "USD", "5.00").collect { nonce ->
when (nonce) {
is GooglePayNonce.Loading -> {...}
is GooglePayNonce.Created -> {...}
is GooglePayNonce.Canceled -> {...}
is GooglePayNonce.Error -> {...}
}
}
}
If successful, GooglePayNonce.Created is returned which includes the nonce (The payment token) and the users Google Pay Email (Needed for guest checkout). GooglePayNonce.Canceled is returned if the user cancels during the Google Pay flow and GooglePayNonce.Error is returned if there is an error with getting the payment nonce.
Requesting PayPay Nonce
CoroutineScope().launch {
Arrive.paymentMethodService.requestPayPalForPayment(FragmentActivity, "USD", "5.00", locationName).collect { nonce ->
when (nonce) {
is PayPalNonce.Loading -> {...}
is PayPalNonce.Created -> {...}
is PayPalNonce.Canceled -> {...}
is PayPalNonce.Error -> {...}
}
}
}
If successful, PayPalNonce.Created is returned which includes the nonce (The payment token). PayPalNonce.Canceled is returned if the user cancels during the PayPay flow and PayPalNonce.Error is returned if there is an error with getting the payment nonce.
Credit Card Payment
CoroutineScope().launch {
val response = Arrive.paymentMethodService.createPaymentMethod(
cardNumber = ...,
cvv = ...,
expirationDate = ..., // Should be formatted using “MM/YY”
postalCode = ...,
label = ... // User can give a name to this card
)
withContext(Dispatchers.Main) {
when (response) {
is NetworkResponse.Success -> {
val paymentMethod = response.body
}
is NetworkResponse.ServerError -> {...}
is NetworkResponse.NetworkError -> {...}
}
}
}Rate Tiers
The SDK lets you retrieve multiple quotes for a single location, representing different rate tiers that are available to the user. Three rate tiers are retrieved at most, and the maximum duration of each rate tier is 24 hours.
In order to get different rate tiers, you should first get the initial quote using any of the relevant methods in QuoteService, and then call QuoteService.getAssociatedRateBuckets(quote: Quote) where quote is the initial quote. This method returns a list of 1-3 rate buckets, which are essentially a quote and a pricing object associated with it, with the initial quote always being the first item in that list.
Get rate tiers with Coroutines
CoroutineScope(Dispatchers.IO).launch {
val initialQuote = ... //See 'Get Quotes' section for details on how to retrieve the initial quote
val response = Arrive.quoteService.getAssociatedRateBuckets(initialQuote)
withContext(Dispatchers.Main) {
when (response) {
is NetworkResponse.Success -> {
val rateBuckets: List<RateBucket> = response.body
}
is NetworkResponse.ServerError -> {...}
is NetworkResponse.NetworkError -> {...}
}
}
}Samples
Get Locations
val latitude = ...
val longitude = ...
val query = QueryParam.Builder()
.setCoordinates(latitude, longitude)
.build()
CoroutineScope(Dispatchers.IO).launch {
val response = Arrive.locationsService.getLocations(query)
withContext(Dispatchers.Main) {
when (response) {
is NetworkResponse.Success -> {
val locations = response.body
}
is NetworkResponse.ServerError -> {...}
is NetworkResponse.NetworkError -> {...}
}
}
}Add a Vehicle
CoroutineScope(Dispatchers.IO).launch {
val response = Arrive.vehicleService.addVehicle(
licensePlateNumber = "1B5 2R9",
label = "The pickup truck",
isDefault = true,
licensePlateState ="CA")
withContext(Dispatchers.Main) {
when (response) {
is NetworkResponse.Success -> {
val addedVehicle = response.body
}
is NetworkResponse.ServerError -> {...}
is NetworkResponse.NetworkError -> {...}
}
}
}Get Quotes
val latitude = ...
val longitude = ...
val query = QueryParam.Builder()
.setCoordinates(latitude, longitude)
.build()
CoroutineScope(Dispatchers.IO).launch {
val response = Arrive.quoteService.getQuotes(
query = query,
startTime = startTime,
endTime = endTime
)
withContext(Dispatchers.Main) {
when (response) {
is NetworkResponse.Success -> {
val quotes = response.body
}
is NetworkResponse.ServerError -> {...}
is NetworkResponse.NetworkError -> {...}
}
}
}Book Parking
BookingRequestBody
| Parameter | Type | Description |
|---|---|---|
| quoteId | String | Selected PurchaseOption id |
| finalPrice | String | Purchase price that comes from Bookings.getPreview api call |
| paymentMethodNonce | String? | One-time use payment method ex. Google Pay nonce |
| savedPaymentToken | String? | PaymentMethod id from previously saved payment method |
| addOnIds | List<String>? | List of AddOn ids to purchase with quote |
| couponCode | String? | Valid Coupon Code from user |
| autoApplyCoupon | Boolean | Whether to automatically apply coupons attached to the customer |
| plateNumber | String? | Adds a license plate to the booking |
| vehicleId | Long? | Adds license plate of the vehicle that corresponds to the Vehicle id |
| String? | Required if user is not logged in |
val body = BookingRequestBody(...)
CoroutineScope(Dispatchers.IO).launch {
val response = Arrive.bookingService.bookParking(body)
withContext(Dispatchers.Main) {
when (response) {
is NetworkResponse.Success -> {
val booking = response.body
}
is NetworkResponse.ServerError -> {...}
is NetworkResponse.NetworkError -> {...}
}
}
}BLE Reservations
The BLE extension allows you to open BLE gates for reservations.
Setup
To add this extension add the gradle dependency to your build.gradle. (If you are adding both the base sdk and this extension, make sure you are using matching versions of both.)
dependencies {
...
implementation 'com.arrive.android:sdk-ext-ble:2.1.1'
}When configuring the SDK, you will need to add the BLE extension to the builder.
.addExtension(ArriveBleExtension(context, IntegrationType.BLE_FLASH))Accessing the ReservationBleManager
The ReservationBleManager is contained within the ArriveBleExtension class. In order to open gates with a Booking you will need to access the ReservationBleManager.
You can save your instance of the ArriveBleExtension or retreive it via Arrive.getExtension<ArriveBleExtension>(). Then, you can call ArriveBleExtension.reservationBleManager to get the ReservationBleManager
Opening an entry gate with a reservation
reservationBleManager.openEntranceGate( `Booking)Opening an exit gate with a reservation
reservationBleManager.openExitGate( `Booking)Flash SDK
Introduction
The Flash SDK enables developers to register and check users Flash Monthly accounts. You will need user credentials in order to access the SDK. If you do not already have them, send an email to partner-support@arrive.com to request credentials.
Setup
In your app build.gradle module, include the following dependency:
dependencies {
...
implementation ''com.flashparking:flash-access:1.0.1''
}
Register Monthly User
This will start the device registration process for Flash Monthly using FlashParkingManager. The user can only register the phone number associated with their monthly account.
FlashParkingMananger.registerDevice(context: Context)Returns Monthly Customer Status
Checks to see if the user is associated with a Flash Monthly account using FlashParkingManager
FlashParkingManager.getMonthlyCustomer(UUID loginToken, final UUID locationId, FlashAsyncEvents eventHandler)If the customer is registered in the system and has at least one monthly parking location associated with their account it will return true. If the user has no monthly account or it fails it will throw an exception.
Returns Customer Information
Asynchronously returns a FlashMobileCustomer
FlashParkingMananger.getCustomerAsync(UUID loginToken, final UUID locationId, final FlashAsyncEvents eventHandler)Sample code
FlashParkingManager.getCustomerAsync(loginToken, locationId, new FlashAsyncEvents() {
@Override
public void FlashAsyncStartedRequest() {
}
@Override
public void FlashAsyncFinished(String methodName, Object Data) {
FlashMobileCustomer customer =(FlashMobileCustomer) Data;
}
@Override
public void FlashAsyncFinishedWithException(Exception ex) {
}
@Override
public void FlashAsyncEndedRequest() {
}
});Open Gate
First the device and customer must be registered with a flash monthly account. To open a gate within bluetooth range use class FlashGateMananger and call checkInOutMonthly() passing in the customer id. Make sure both the device location permission and bluetooth are enabled.
FlashGateMananger.checkInOutMonthly(UUID customerId)This call Validates the provided customer ID and vends the entry/exit gate. Below is a sample.
mFlashGateManager = new FlashGateManager();
mFlashGateManager.initialize(this, 1, 1, true, true, true);
SharedPreferences sharedPref = mContext.getSharedPreferences("com.flashparking.example.customerId", Context.MODE_PRIVATE);
String customerId = sharedPref.getString("customerId", null);
if(customerId != null)
mFlashGateManager.checkInOutMonthly(UUID.fromString(customerId));
Creating QR code
Koisks allow for flash monthly customers to scan QR codes. You can use glide or an image libary of your choice in order to create monthly qr codes. Here is a sample of how to create a monthly QR code using the flash customer id.
scanCodeImageView.loadScanCode(BarcodeFormat.QR_CODE, "FVUN${customerId.replace("-", "")}")fun loadScanCode(format: ScanCodeFormat, data: String, qrErrorCorrectionLevel: String? = null) {
val barcode = createBarcode(data, format, qrErrorCorrectionLevel)
if (!hasSetPadding()) setPadding(scanCodePadding)
layoutParams.height = barcode.height + paddingTop + paddingBottom
layoutParams.width = barcode.width + paddingStart + paddingEnd
layoutParams = layoutParams
GlideAppWrapper(context)
.load(barcode)
.into(view)
}private fun createGlideBarcode(data: String, format: BarcodeFormat, qrErrorCorrectionLevel: String? = null): GlideBarcode {
val scanCodeHeight: Int
val scanCodeWidth: Int
when (format) {
BarcodeFormat.QR_CODE -> {
scanCodeWidth = 128dp
scanCodeHeight = 128dp
}
else -> throw IllegalStateException("No sizes available for format: $format")
}
return GlideBarcode(data, format, scanCodeWidth, scanCodeHeight, qrErrorCorrectionLevel)
}Changelog
V2.5.15
- Updated sdk to target android 31
- Added
operatingHourstoLocation - Removed BleVendIngeration support
- Added
VenueAndEventService.getVenueEvents(...)to support pagination
V2.5.14
- Added support for retrieving
Ticketsfrom the BookingService - Added additional parameters to TicketEndpoints
V2.5.13
- Added fees and coupons to
TicketPreviewEndpoint
V2.5.12
- Added support for
RecommendationsAndQuotes
V2.5.11
- Added nullable parameters to
TicketPreview
V2.5.10
- Added additonal paramters to
TicketService.getSpgPreview(..)
V2.5.9
- Added TapToPayService to SDK
- Added additonal paramters to
TicketRequestBody
V2.5.8
- Added additonal parameters to
TicketService
V2.5.7
- Added additonal parameters to
TicketPreview
V2.5.6
- Added
externalTicketIdtoTicketPreviewin order to support DTC
V2.5.4
- Resolved issue with
Seller.logo
V2.5.3
- Added
LocationEmbeddedtoTapToInfoto retrieveSeller
V2.5.2
- Added
BookingService.bookingShare(...)to get shared bookings - Changed
CreditCardTokenizer.tokenize(...)to public to allow purchases - Fixed flash java 8 issue
- Relocated Flash SDK code
- Updated Flash SDK to support checking for
customers.monthlyLocations
V2.3.3
- Resolved issue with
InternalGooglePayClient - Resolved issue with
Location.state
V2.3.2
- Resolved crash with
InternalGooglePayClient
V2.3.1
- Added adjustable rate bucket end times to
QuoteService.getAssociatedRateBuckets - Updated to gradle 7.0.2
- Updated to kotlin version 1.5.31
- Fixed 24 hour case for
endTimeinQuoteService - Added
Feeto bookingsPreview
V2.1.1
- Updated to Braintree v4
V2.1.0
- Updated to Braintree 4.6.0
- Moved all payment handling to the
PaymentMethodService
V2.0.0
- Updated to Kotlin 1.5.20
- Refactored and simplfied data models
- Added the ability to extend the base SDK.
- Added support for BLE Reservations via the BLE extension
- Removed support for RxJava - If RxJava support is required, you may utilize the wrapper library maintained by the Kotlin team.
v1.1.0
- Added
QuoteService.getOnStreetQuotesto query for on street parking information - Updated to Kotlin 1.4.30
- Added
Availabilityto theEventmodel
v1.0.14
QuoteService.getAssociatedRateBuckets(quote: Quote)now includes the original quote in the returned list.
v1.0.13
- Added
QuoteService.getAssociatedRateBuckets(Quote)
v1.0.12
- Added
GooglePayPayment.isReadyToPay
v1.0.11
- Guest user is now auto logged in if they are purchasing a booking through guest checkout with a new account email
v1.0.10
- Changed
Fee.typeto useFeeTypeenum - Added
ValidationtoPurchaseOptionto check if license plate is required - Added
CreatePaymentMethodRequestBody.isDefaultto allow setting payment method as default duringPaymentMethodService.createPaymentMethod(...) - Updated
AccountService.resetPasswordto auto log user in if password is successfully reset - Updated Retrofit to
2.9.0and OkHttp to4.7.2
v1.0.9
- Fixed proguard issue when using minify in builds
- Updated
SpaceAvailability.statusto an EnumAvailabilityStatus - Updated
Availability.statusto an EnumAvailabilityStatus - Updated
Displayproperties to EnumDisplayStatus - Added
GooglePayPaymentto handle getting nonce for Google Pay payment - Added
PayPalPaymentto handle getting nonce for PayPal payment
v1.0.8
- Added
isTimeTBDtoBookingmodel - Added
sellerIdtoQueryParamoption to allow searching quotes by seller id - Added
reviewtoBooking.embeddedwhich will only be present when user has created a review for that booking - Changed
addOnIdsfrom aStringtype toList<String>inBookingPreviewRequestBody,BookingRequestBodyandOslTicketRequestBody
v1.0.7
- Added
Eventmodel toParkingPass.embedded - Created
TicketChangeVehicleRequestBodymodel forTicketsService.changeVehicle - Created
BookingChangeVehicleRequestBodymodel forBookingsService.changeVehicle - Renamed
Eventreturned in autocomplete toAutocompleteEvent - Switched to use single
Eventmodel besides for autocomplete - Added
BookingSharetoBooking.embeddedto check whether a booking has been shared - Added
isShareManageabletoBookingto check if a booking can be shared
v1.0.6
- Added
LocationService.createReview(...)to create review for a location - Added
LocationService.getReviews(...)to get all reviews for a specified location - Added
CancellableStatusModel which replacesisCancellablewithinPurchaseOption - Added
CancellableStatusproperty toPurchaseOptionandBookingModels
v1.0.5
- Updated Retrofit and Moshi libraries
- Added new class
CreditCardTokenizationto handle tokenizing user payment methods - Updated
PaymentMethodService.createPaymentMethodto handle card tokenization and creating payment method through the arrive api
v1.0.4
- Added
AccountService.getIntegrationTokens()to load tokens for ble - Added
AccountService.openInugoGate(...)which is used to open ble gates via api call - Added
onDemandDisclaimersto theLocationmodel - Added
isLogged(): Flow<Boolean>to theAuthenticatedTokenManagerwhich allows listening to the logged in state - Renamed
TicketService.validateTicket(...)toTicketService.updateTicket(...)which still allows validation but also now allows updating the payment method of an active ticket - Replaced
Location.onDemandOptionswithLocation.onDemandIntegrationssinceonDemandOptionsare deprecated from the arrive api - Updated to use JDK 8 version of the Kotlin plugin dependency
v1.0.3
- Replaced
passValuewithfullPriceinBooking
v1.0.2
- Added
passValuetoParkingPass.validation.displayobject to determine if passes price should be displayed on the parking pass
v1.0.1
- Added Token validation check during initialization (Will auto refresh public tokens or will clear authenticated token if no longer valid)
- Added new optional parameters
BookingsQueryParam,SorttoBookingService.getBookings - Replaced usages of
Proximityclass withLatLng - Changed
QueryParamclass variables visibility to public - Changed
PublicTokenandTokenModels to match api directly using Unix Timestamp (seconds) rather than using milliseconds - Changed
expirationvariable inPublicTokenManagerandAuthenticatedTokenManagertoexpirationInSecondsfor clarity - Added
webUrlvariable toParkingPassmodel
v1.0.0
- Initial Release
