Mobile SDKs
The following section describes how to integrate the mobile SDKs and the main methods that are required to operate with Harbor Lockers.
Integrate iOS SDK
The iOS SDK is available through Cocoapods. Add the following line to your Podfile:
pod "HarborLockersSDK"
You can also specify the version of the SDK, for example:
pod "HarborLockersSDK", '1.0.10'
Then run pod install
to install the pods.
To start using the HarborSDK, you must import it into your files
@import HarborLockersSDK
#import <HarborLockersSDK/HarborLockersSDK.h>
#import <HarborLockersSDK/HarborLockersSDK-Swift.h>
The iOS SDK requires Bluetooth access, in your info.plist
add the following entries:
NSBluetoothAlwaysUsageDescription
-> A description of why your app needs access to Bluetooth.NSBluetoothPeripheralUsageDescription
-> Same description as before. This is needed only if your app targets iOS 12 or earlier.
Integrate Android SDK
The Android SDK is distributed through Jitpack. It can be integrated through gradle
, maven
, sbt
, and leiningen
as following:
In your root build.gradle
, at the end of repositories, add the following
allprojects {
repositories {
...
maven { url 'https://jitpack.io' }
}
}
Then add the dependency
dependencies {
implementation 'com.github.Harbor-Lockers:harbor-android-sdk:<version>'
}
Add the JitPack repository to your build file
<repositories>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
</repositories>
Then add the dependency
<dependency>
<groupId>com.github.Harbor-Lockers</groupId>
<artifactId>harbor-android-sdk</artifactId>
<version>version_number</version>
</dependency>
Add it in your build.sbt at the end of resolvers:
resolvers += "jitpack" at "https://jitpack.io"
Then add the dependency
libraryDependencies += "com.github.Harbor-Lockers" % "harbor-android-sdk" % "Tag"
Add it in your project.clj at the end of repositories:
:repositories [["jitpack" "https://jitpack.io"]]
Then add the dependency
:dependencies [[com.github.Harbor-Lockers/harbor-android-sdk "Tag"]]
Add the following entries to your AndroidManifest.xml
:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>
The android:required
value in the last line depends on wether you want your app to be listed to users that doesn’t have BLE support on their devices. This might be the case if all your app does is control lockers with Harbor SDK and can’t do anything useful without BLE support.
Using the SDK
Once you have the SDK integrated there are a series of steps you need to follow to connect to a tower and open a locker.
Most of the data required by the SDK are provided by your server. Your Backend is responsible for the following:
Define the location ID, tower ID, and locker ID you’ll interact with.
Provide you with an SDK authentication token.
Provide you with the session token information so you can connect to the tower.
Provide you with the payload and payload auth to control your assigned locker.
In addition to that, your backend will be responsible for managing the lockers assigned to your account.
Note
You might need to integrate other API calls to release lockers, change assigned locker, or mark a locker as used. Check the API integration sections for details.
Initialize the SDK
The SDK is a singleton class, so you can access it as follows:
[HarborSDK shared]
HarborSDK.shared
HarborSDK
HarborSDK.INSTANCE
Before connecting to a tower, you’ll need to initialize the SDK, set the Environment you want to use, set the Harbor Access Token, and start looking for nearby towers.
The first thing you need to do is to set the HarborSDKDelegate
and, if needed, configure a HarborSDKConsole
to get the logs (you might want to do this only in debug mode)
The HarborSDKDelegate
will notify you about nearby towers found through BLE, while the HarborSDKConsole
delegate might be helpful for debugging.
@objc
public protocol HarborSDKConsole {
func printToConsole(_ string: String)
}
@objc
public protocol HarborSDKDelegate {
func harborDidDiscoverTowers(_ towers: [Tower])
}
interface HarborSDKConsole {
fun printToConsole(string: String)
}
interface HarborSDKDelegate {
fun harborDidDiscoverTowers(towers: List<Tower>)
}
Now set the environment you want to use with the setEnvironment
function. This will allow you to use either DEVELOPMENT
or PRODUCTION
envs (defined in an enum) or a custom URL if you get a dedicated environment set for you.
The last step to initialize the SDK is to set the SDK Access Token
. For this, you’ll need the SDK Access Token provided by your server. A boilerplate initialization code looks like this:
[[HarborSDK shared] setDelegate:self];
[[HarborSDK shared] setOutputConsole:self];
[[HarborSDK shared] setEnvironment:EnvironmentDevelopment];
[[HarborSDK shared] setAccessToken:token];
HarborSDK.shared.setDelegate(self)
HarborSDK.shared.setOutputConsole(self)
HarborSDK.shared.setEnvironment(Environment.Development)
HarborSDK.shared.setAccessToken(token)
HarborSDK.setDelegate(this)
HarborSDK.setOutputConsole(this)
HarborSDK.setEnvironment(Environment.DEVELOPMENT)
HarborSDK.setAccessToken(token)
HarborSDK.INSTANCE.setDelegate(this)
HarborSDK.INSTANCE.setOutputConsole(this)
HarborSDK.INSTANCE.setEnvironment(Environment.DEVELOPMENT)
HarborSDK.INSTANCE.setAccessToken(token)
Connect to a Tower and Establish a Session
Now that the SDK is configured, you can search for nearby towers and try to connect to them.
When you get notified about discovered towers, you might either show a list of the towers to connect to or if you already know which tower to connect, you can automatically connect to it.
To search for nearby towers, call the startTowersDiscovery
function. Note that you’ll need to set up the HarborSDKDelegate
before getting notified about the discovered towers.
To connect to a tower, use the connectToTower
function. This function receives a Tower
object, which you receive in the HarborSDKDelegate
methods
The connectToTower
function has a completion callback that notifies you if you got connected to the tower correctly.
Here’s an example that automatically connects to a tower assuming you are looking for tower with ID 0000000000000010
. This example is written in Objective-C, but it should be easy to translate to other languages.
#define TIMER_LIMIT_IN_SECONDS 15
int count = 0;
NSTimer *timer;
- (void)waitForSyncCompletion
{
count++;
BOOL isSyncing = [[HarborSDK shared] isSyncing];
if (!isSyncing) {
// tower is in sync with Harbor's backend, can start interaction
} else if (count == TIMER_LIMIT_IN_SECONDS)
{
// sync not completed within time limit, return error
[timer invalidate];
timer = nil;
return;
} else {
// wait for sync to finish
}
}
- (void)harborDidDiscoverTowers:(NSArray<Tower *> *)towers {
for(Tower * tower in towers) {
if ([tower.towerId.hexString isEqualToString:@"0000000000000010"]) {
[[HarborSDK shared] connectToTower:tower completion:^(NSString * _Nullable name, NSError * _Nullable error) {
if([name length] > 0) {
// Tower connected successfully
[[HarborSDK shared] establishSessionWithTowerId:nil
duration:600
sessionPermissions:role.integerValue
completionHandler:^(BOOL success,
NSError * _Nullable error) {
if(success) {
timer = [NSTimer scheduledTimerWithTimeInterval:1.0
target:self
selector:@selector(waitForSyncCompletion)
userInfo:nil
repeats:YES];
} else {
// An error occurred
}
}];
} else if(error != nil) {
// An error occurred
}
}];
}
}
}
Once you’re connected to a tower, you need to establish a session to start interacting with it. To establish a session, use the establishSession
function to create a pickup or drop off session in the tower.
The establishSession
function receives the following parameters:
towerId
: 8 bytes containing the towerID.duration
: How long you expect the session to last (in seconds). Note that if you don’t interact with the tower in more than a minute, your session will be closed by the tower.sessionPermissions
: Indicates the permission level for your session. Most of the third party developers will only be able to establish pickup and drop off sessions.completionHandler
: Callback to handle the results.
Wait for the Tower to Sync
Once you’re connected to a tower and have a session established, the tower will start syncing with Harbor’s backend. Here, you need to wait for the tower to sync with Harbor’s backend and then you can start interacting with the tower. The isSyncing
method will return the status flag of the syncing operation which value will be false
when completed. Given the different possible scenarios regarding network speed and connectivity we are using a timer in the example above to keep it simple.
Interacting with the Tower
Once you have a session established and the tower is in sync, you can start interacting with it to open the lockers.
Open a locker
Your server must be integrated with the Harbor API to do this. Your server will request a payload and a payload auth to Harbor that will contain the encrypted data required to open your locker. The details on how to do this are covered in Make a delivery, so we assume you already have the payload and payload auth to be sent to the tower.
Use the sendOpenLockerWithToken
function to open a locker. This function receives the following parameters:
payload
: encrypted payload containing the data about the locker to be opened.payloadAuth
: authentication packet to validate the authenticity of the payload.completionHandler
: callback indicating if a locker was opened (providing locker ID), or if some error happened (for example the locker wasn’t found).
After a locker was opened, the tower remembers the last opened locker, which is the one considered for other commands such as reopenLocker
, checkLockerDoor
, or revertLockerState
.
Check Locker Door
After a locker was opened, you can check the state of the door using the sendCheckLockerDoor
function.
The completion handler will notify you if the door you just tried to open is open or close. If no door was opened during your session, the completion handler will return an error.
You can use this method for 2 things:
To confirm the door was opened (as it might fail to pop open).
To get notified when your user closed the locker door, and move the app to the next screen/state.
Reopen Locker Door
Another thing you might want to do is to reopen the lastly opened locker. This might be useful if your user forgot to add something inside, or if the door was accidentally closed before the user completed the drop off.
Call the sendReopenLocker
function to reopen the same locker that was lastly opened in your session. If no door was opened during your session, the completion handler will return an error.
Terminate a session
After you’re done interacting with the tower, you must terminate your session. This will trigger some processes both in the SDK and the tower, that are important to keep consistency in the system.
Since the tower doesn’t have an internet connection, your application (through the SDK) is a key piece to keep it updated and synchronized with Harbor’s backend.
Call the sendTerminateSession
function to terminate a session. This function allows you to specify an error code and message, in case the session is being terminated prematurely for some reason. This code and message will be helpful for us in case we need to debug your issue.
The sendTerminateSession
function receives the following parameters:
errorCode
: A code to log to the terminate session event on the device side. Maybe 0 if no error occurred.errorMessage
: An optional message to store in the error event log, in case there was an error.completionHandler
: A callback containing a boolean indicating if the session was terminated successfully, and an optional error in case something unexpected happened.
Terminating the session triggers a sync process on the SDK, which is important to notify Harbor that the locker was used and to update the state of the tower.
This covers the basic use of a Harbor Tower through the SDK.
Debug Logging
When the debug logging feature is enabled, each step of the process in Harbor SDK is recorded in a log callback. This log callback provides a detailed record that can be utilized for analyzing and addressing any failures that may occur during the connection and drop-off/pick-up process. By reviewing the log, you can gain insights into the specific actions and events that took place, allowing you to troubleshoot and resolve any issues effectively.
After you initialize the SDK, set the Logging capabilities up using the log level you need:
- HarborLockersSDK.setLogLevel('debug'); // can be: debug, verbose, info, warning, error
Then, using an Event Emitter add a listener for HarborLogged:
- subscriptionLog = eventEmitter.addListener('HarborLogged', result => {
console.log("Harbor Log: ", result);
Finally, remember to remove the subscription when you are no longer going to use it, subscriptionLog.remove();
Important to note, the logging capability for our React Native SDK works as of version 1.0.33