Getting started

Network SDK

  1. Prerequisites
  2. Authentication & Configuration
  3. Plan a Trip
  4. Get Quotes
  5. Book a Trip
  6. Track a Trip
  7. Testing

Before we start we need to go through a couple of preparation steps in order to initialise the SDK. We also provide a quick Intro on to how to make our network calls work. This will help you to understand the differences in the relevant use-cases.

Setup

In order to use the Karhoo Network SDK you need to add it to your project as a dependency and configure it. This will be done in your build.gradle in the root directory if you are on Android or using Swift Package Manager or Cocoapods if on iOS. You can find instructions on how to do this below.

Android

Add the Network SDK to your project

allprojects {
    repositories {
        google()
        maven { url 'https://jitpack.io' }
    }
}

In your build.gradle located in the App directory for dependencies:

//In your app dependancies add the latest SDK verison
implementation 'com.github.karhoo:karhoo-android-sdk:1.4.5'

iOS

Swift Package Manager

Create a new project using either SwiftUI or UIKit. Then to get the KarhooSDK, go to:

File > Swift Packages > Add package dependency

In the window which opens up, simply copy and paste this link: karhoo/karhoo-ios-sdk

Press finish and select the versioning you want, it will then handle all of the package dependencies.

Cocoapods

Add the following to your Podfile

pod 'KarhooSDK', '1.6.1'

Using Network SDK Services

Every call to SDK services returns either a Call or PollCall dependent upon the nature of the endpoint.

Call

Call has one function available, called execute. Calling execute will open up a completion handler, which will contain a Result type enum. What’s going on behind the scenes is a single network request to the KarhooAPI and the result being returned asynchronously to the completion handler.

interface Call<T> {
    fun execute(subscriber: (Resource<T>) -> Unit)
}

PollCall

PollCall has two functions available, called execute and observable. Calling execute will simply do the same as a Call. observable however will return an Observable, which can be used for endpoints that require polling, such as tracking a moving vehicle or the state of a trip in progress. See the Driver Tracking Service as an example of a PollCall return type

interface PollCall<T> : Call<T> {
    fun observable(): Observable<T>
}

Observable

The PollCall observable function will return an Observable, which can be used for endpoints that require polling, such as tracking a moving vehicle or the state of a trip in progress. An Observable has a subscribe and unsubscribe function.

interface Observable<T> {
    ...
    fun subscribe(observer: Observer<Resource<T>>, repeatInterval: Long = BASE_POLL_TIME)
    fun unsubscribe(observer: Observer<Resource<T>>)
    ...
}

Observer

These functions take an Observer. The Observer can be subscribed or unsubscribed on an observable.

interface Observer<T> {
    fun onValueChanged(value: T)
}

In the code example, the Observer is constructed with a result type of DriverTrackingInfo.

let driverTrackingObserver = Observer<DriverTrackingInfo> { [weak self] result in
    switch result {
        case .success(let driverTrackingInfo):
            print("Driver position: \(driverTrackingInfo.position)")
        case .failure(let error):
            // handle error (KarhooError)
    }
}
val driverPositionObserver = object : Observer<Resource<DriverTrackingInfo>> {
    override fun onValueChanged(value: Resource<DriverTrackingInfo>) {
        when (value) {
            is Resource.Success -> print(value.data)
            is Resource.Failure -> print(value.error.internalMessage)
        }
    }
}

Result/Resource Type

All calls to the KarhooSDK are returned; as a success or as a typed Error. These two result types are encapsulated inside an enum.

public enum Result<T> {
    case success(result: T)
    case failure(error: KarhooError?)

    // was the result successful?
    public func isSuccess() -> Bool

    // get the success value (returns optional expected result type as the result may have failed)
    public func successValue() -> T? 

   // get the error value (returns optional KarhooError as the result may have succeeded)
   public func errorValue() -> KarhooError? 
}

// recommended unwrap approach

let result = Result<String>.success(result: "Hello World")

switch result {
  case .success(let result):
    print(result)
  case .failure(let error):
    print(error)
}

// OR

if let value = result.successValue() {
    print(result)
} else if let error = result.errorValue() {
    print(error)
}

Subscribe / Unsubscribe observers

The Observer can now be subscribed or unsubscribed on an observable. In this case, the observable returned from the PollCall of the Driver Tracking Service endpoint.

🚧

Remember to unsubscribe Observers when you no longer need them, such as in the unloading of a view.

// create observable
let driverTrackingObservable = driverTracking.trackDriver(tripId: "1234").observable(pollTime: 5)

// subscribe observer to observable
driverTrackingObservable.subscribe(observer: driverTrackingObserver)

// unsubscribe observer from observable
driverTrackingObservable.unsubscribe(observer: driverTrackingObserver)
Changelog
// Subscribe to observable with repeatable poll time
val REPEAT_INTERVAL = 50000
val driverTrackingInfoObservable = driverTrackingService.trackDriver("1234").observable().apply {
    driverPositionObserver?.let {
        subscribe(it, REPEAT_INTERVAL)
    }
}

// Unsubscribe from observable
driverPositionObserver?.let {
    driverTrackingInfoObservable?.unsubscribe(it)
}

Naming Conventions

For this guide, we will mainly be using Android/Kotlin naming conventions for our descriptions. However, in our examples, you can find both Swift and Kotlin.