Bike Parking Guide
Simple guide for implementing bike parking functionality using the MOSA SDK. This guide focuses on SDK method calls from the mobile app's perspective.
Overview
Bike parking allows users to lock their bikes at parking locations and unlock them later. The flow involves:
- Locking: User parks bike at a dock
- Unlocking: User retrieves bike from dock
Locking a Bike
Step 1: Request Lock Key
Request a bikeLock key for the parking area:
- Android
- iOS
- Flutter
lifecycleScope.launch {
val unlockKey = sdk.requestUnlockKey(
type = MOSADockUnlockKeyType.BikeLock,
areaId = "area-123"
)
if (unlockKey != null) {
lockBike(unlockKey)
}
}
Task {
do {
let unlockKey = try await sdk.requestUnlockKey(
type: .bikeLock,
areaId: "area-123",
userId: "user-123"
)
await lockBike(unlockKey)
} catch {
showError("Failed to request lock key: \(error)")
}
}
try {
final unlockKey = await mosaDockSdk.requestUnlockKey(
type: MosaDockUnlockKeyType.bikeLock,
areaId: 'area-123',
userId: 'user-123',
);
await lockBike(unlockKey);
} catch (e) {
showError('Failed to request lock key: $e');
}
Step 2: Execute Lock Operation
Call unlockSmartLock() with the lock key and parking location type:
- Android
- iOS
- Flutter
private fun lockBike(unlockKey: MOSADockKey) {
lifecycleScope.launch {
sdk.unlockSmartLock(
unlockKey = unlockKey,
gfaLocationType = MOSADockLocationType.PARKING,
callback = object : MOSADockSDKCallback {
override fun onNFCScanCompleted(mosaTag: MosaTag) {
// NFC scan completed
}
override fun onBleConnecting() {
// BLE connecting
}
override fun onBleConnected() {
// BLE connected
}
override fun onKeySent() {
// Key sent to dock
}
override fun onDockUnlocked() {
// Dock unlocked
}
override fun onDockChainInserted() {
// Chain inserted - bike is locked
}
override fun onDockSecured() {
// Dock secured - operation complete
}
override fun onError(error: MosaError) {
// Handle error
}
// Implement other callbacks...
}
)
}
}
func lockBike(_ unlockKey: UnlockKey) async {
do {
try await sdk.unlockSmartLock(
with: unlockKey,
location: .parking,
delegate: self
)
} catch {
showError("Lock operation failed: \(error)")
}
}
// Delegate callbacks
func onNFCScanCompleted(_ tag: MosaTag) {
// NFC scan completed
}
func onBleConnecting() {
// BLE connecting
}
func onBleConnected() {
// BLE connected
}
func onKeySent() {
// Key sent to dock
}
func onDockUnlocked() {
// Dock unlocked
}
func onDockChainInserted() {
// Chain inserted - bike is locked
}
func onDockSecured() {
// Dock secured - operation complete
}
func onError(_ error: MosaError) {
// Handle error
}
Future<void> lockBike(MosaDockKey unlockKey) async {
try {
await mosaDockSdk.handleClientUnlock(
unlockKey: unlockKey,
locationType: MosaDockLocationType.parking.value,
);
} catch (e) {
showError('Lock operation failed: $e');
}
}
// Callback handling (set up before calling handleClientUnlock)
mosaDockSdk.dockCallbackEvents.listen((event) {
switch (event.type) {
case DockCallbackType.nfcScanCompleted:
// NFC scan completed
break;
case DockCallbackType.bleConnecting:
// BLE connecting
break;
case DockCallbackType.bleConnected:
// BLE connected
break;
case DockCallbackType.keySent:
// Key sent to dock
break;
case DockCallbackType.dockUnlocked:
// Dock unlocked
break;
case DockCallbackType.dockChainInserted:
// Chain inserted - bike is locked
break;
case DockCallbackType.dockSecured:
// Dock secured - operation complete
break;
case DockCallbackType.error:
// Handle error
break;
default:
break;
}
});
Callback Sequence for Locking
The expected callback sequence:
onNFCScanCompleted- NFC tag readonBleConnecting- BLE connection startedonBleConnected- BLE connectedonKeySent- Lock key sent to dockonDockUnlocked- Dock unlockedonDockChainInserted- Chain inserted (bike locked)onDockSecured- Dock secured (operation complete)
Unlocking a Bike
Step 1: Request Unlock Key
Request a bikeUnlock key. The SDK uses the existing session from the previous lock operation:
- Android
- iOS
- Flutter
lifecycleScope.launch {
val unlockKey = sdk.requestUnlockKey(
type = MOSADockUnlockKeyType.BikeUnlock,
areaId = "area-123" // areaId from session
)
if (unlockKey != null) {
unlockBike(unlockKey)
}
}
Task {
do {
let unlockKey = try await sdk.requestUnlockKey(
type: .bikeUnlock,
areaId: "area-123", // areaId from session
userId: "user-123"
)
await unlockBike(unlockKey)
} catch {
showError("Failed to request unlock key: \(error)")
}
}
try {
final unlockKey = await mosaDockSdk.requestUnlockKey(
type: MosaDockUnlockKeyType.bikeUnlock,
areaId: 'area-123', // areaId from session
userId: 'user-123',
);
await unlockBike(unlockKey);
} catch (e) {
showError('Failed to request unlock key: $e');
}
Step 2: Execute Unlock Operation
Call unlockSmartLock() with the unlock key and parking location type:
- Android
- iOS
- Flutter
private fun unlockBike(unlockKey: MOSADockKey) {
lifecycleScope.launch {
sdk.unlockSmartLock(
unlockKey = unlockKey,
gfaLocationType = MOSADockLocationType.PARKING,
callback = object : MOSADockSDKCallback {
override fun onNFCScanCompleted(mosaTag: MosaTag) {
// NFC scan completed
}
override fun onBleConnecting() {
// BLE connecting
}
override fun onBleConnected() {
// BLE connected
}
override fun onKeySent() {
// Key sent to dock
}
override fun onDockUnlocked() {
// Dock unlocked
}
override fun onDockChainRemoved() {
// Chain removed - bike ready to take
}
override fun onError(error: MosaError) {
// Handle error
}
// Implement other callbacks...
}
)
}
}
func unlockBike(_ unlockKey: UnlockKey) async {
do {
try await sdk.unlockSmartLock(
with: unlockKey,
location: .parking,
delegate: self
)
} catch {
showError("Unlock operation failed: \(error)")
}
}
// Delegate callbacks
func onNFCScanCompleted(_ tag: MosaTag) {
// NFC scan completed
}
func onBleConnecting() {
// BLE connecting
}
func onBleConnected() {
// BLE connected
}
func onKeySent() {
// Key sent to dock
}
func onDockUnlocked() {
// Dock unlocked
}
func onDockChainRemoved() {
// Chain removed - bike ready to take
}
func onError(_ error: MosaError) {
// Handle error
}
Future<void> unlockBike(MosaDockKey unlockKey) async {
try {
await mosaDockSdk.handleClientUnlock(
unlockKey: unlockKey,
locationType: MosaDockLocationType.parking.value,
);
} catch (e) {
showError('Unlock operation failed: $e');
}
}
// Callback handling
mosaDockSdk.dockCallbackEvents.listen((event) {
switch (event.type) {
case DockCallbackType.nfcScanCompleted:
// NFC scan completed
break;
case DockCallbackType.bleConnecting:
// BLE connecting
break;
case DockCallbackType.bleConnected:
// BLE connected
break;
case DockCallbackType.keySent:
// Key sent to dock
break;
case DockCallbackType.dockUnlocked:
// Dock unlocked
break;
case DockCallbackType.dockChainRemoved:
// Chain removed - bike ready to take
break;
case DockCallbackType.error:
// Handle error
break;
default:
break;
}
});
Callback Sequence for Unlocking
The expected callback sequence:
onNFCScanCompleted- NFC tag readonBleConnecting- BLE connection startedonBleConnected- BLE connectedonKeySent- Unlock key sent to dockonDockUnlocked- Dock unlockedonDockChainRemoved- Chain removed (bike ready to take)
Complete Example
Here's a complete example combining both operations:
- Android
- iOS
- Flutter
class BikeParkingActivity : AppCompatActivity(), MOSADockSDKCallback {
private lateinit var sdk: MOSADockSDK
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
sdk = MOSADockSDK.builder()
.setActivity(this)
.setApiKey("your-api-key")
.setUserId("user-123")
.build()
}
fun parkBike() {
lifecycleScope.launch {
val unlockKey = sdk.requestUnlockKey(
type = MOSADockUnlockKeyType.BikeLock,
areaId = "area-123"
)
if (unlockKey != null) {
sdk.unlockSmartLock(
unlockKey = unlockKey,
gfaLocationType = MOSADockLocationType.PARKING,
callback = this@BikeParkingActivity
)
}
}
}
fun retrieveBike() {
lifecycleScope.launch {
val unlockKey = sdk.requestUnlockKey(
type = MOSADockUnlockKeyType.BikeUnlock,
areaId = "area-123"
)
if (unlockKey != null) {
sdk.unlockSmartLock(
unlockKey = unlockKey,
gfaLocationType = MOSADockLocationType.PARKING,
callback = this@BikeParkingActivity
)
}
}
}
// Implement callbacks...
}
class BikeParkingViewController: UIViewController, MosaDockDelegate {
var sdk: MosaDockSDK!
override func viewDidLoad() {
super.viewDidLoad()
MosaDockSDK.initialize(
with: self,
apiKey: "your-api-key",
userId: "user-123"
)
sdk = MosaDockSDK.shared
sdk.setDelegate(self)
}
func parkBike() {
Task {
do {
let unlockKey = try await sdk.requestUnlockKey(
type: .bikeLock,
areaId: "area-123",
userId: "user-123"
)
try await sdk.unlockSmartLock(
with: unlockKey,
location: .parking,
delegate: self
)
} catch {
showError("Failed: \(error)")
}
}
}
func retrieveBike() {
Task {
do {
let unlockKey = try await sdk.requestUnlockKey(
type: .bikeUnlock,
areaId: "area-123",
userId: "user-123"
)
try await sdk.unlockSmartLock(
with: unlockKey,
location: .parking,
delegate: self
)
} catch {
showError("Failed: \(error)")
}
}
}
// Implement delegate methods...
}
class BikeParkingScreen extends StatefulWidget {
@override
_BikeParkingScreenState createState() => _BikeParkingScreenState();
}
class _BikeParkingScreenState extends State<BikeParkingScreen> {
final mosaDockSdk = MosaDockSdk();
@override
void initState() {
super.initState();
_setupCallbacks();
mosaDockSdk.initialize(
apiKey: 'your-api-key',
userId: 'user-123',
);
}
void _setupCallbacks() {
mosaDockSdk.dockCallbackEvents.listen((event) {
// Handle callbacks
});
}
Future<void> parkBike() async {
try {
final unlockKey = await mosaDockSdk.requestUnlockKey(
type: MosaDockUnlockKeyType.bikeLock,
areaId: 'area-123',
userId: 'user-123',
);
await mosaDockSdk.handleClientUnlock(
unlockKey: unlockKey,
locationType: MosaDockLocationType.parking.value,
);
} catch (e) {
showError('Failed: $e');
}
}
Future<void> retrieveBike() async {
try {
final unlockKey = await mosaDockSdk.requestUnlockKey(
type: MosaDockUnlockKeyType.bikeUnlock,
areaId: 'area-123',
userId: 'user-123',
);
await mosaDockSdk.handleClientUnlock(
unlockKey: unlockKey,
locationType: MosaDockLocationType.parking.value,
);
} catch (e) {
showError('Failed: $e');
}
}
}
Required Parameters
Lock Operation
- Key Type:
bikeLock - Area ID: ID of the parking area
- Location Type:
PARKING/.parking/parking
Unlock Operation
- Key Type:
bikeUnlock - Area ID: ID of the parking area (from session)
- Factory Dock ID: Obtained from NFC scan (handled internally)
- Location Type:
PARKING/.parking/parking
Next Steps
- Bike Sharing Guide - Guide for bike sharing operations
- SDK Callbacks - Understanding callback lifecycle
- API Reference - Complete UnlockKey documentation