Android Platform Guide
Complete guide for integrating the MOSA SDK into Android applications.
Requirements
- Minimum Android API Level: 24 (Android 7.0 Nougat)
- Kotlin: 1.8.0 or higher
- Device: Android device with NFC and BLE support
- Gradle: 7.0 or higher
Installation
Gradle (Kotlin DSL)
Add to your build.gradle.kts:
dependencies {
implementation("com.mosadock:sdk:1.0.0") // Replace with actual version
}
Gradle (Groovy)
Add to your build.gradle:
dependencies {
implementation 'com.mosadock:sdk:1.0.0'
}
Maven
Add to your pom.xml:
<dependency>
<groupId>com.mosadock</groupId>
<artifactId>sdk</artifactId>
<version>1.0.0</version>
</dependency>
Configuration
AndroidManifest.xml
Add required permissions and features:
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Bluetooth permissions -->
<!-- Android 12+ (API 31+) -->
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<!-- Legacy Bluetooth (Android 11 and below) -->
<uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" />
<!-- Location permissions (required for BLE scanning) -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!-- NFC permissions -->
<uses-permission android:name="android.permission.NFC" />
<!-- Foreground service permissions -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> <!-- Android 13+ -->
<!-- Network permissions -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- Hardware features -->
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true" />
<uses-feature android:name="android.hardware.nfc" android:required="true" />
</manifest>
Initialization
Builder Pattern (Recommended)
import to.mosa.lib.dock.MOSADockSDK
val sdk = MOSADockSDK.builder()
.setActivity(this)
.setApiKey("your-api-key")
.setUserId("user-123")
.setAutoRequestPermissions(true)
.setAdvancedLogging(false)
.build()
Direct Initialization
val sdk = MOSADockSDK.create(
activity = this,
apiKey = "your-api-key",
userId = "user-123",
autoRequestPermissions = true,
enableAdvancedLogging = false
)
Singleton Pattern (Legacy)
val sdk = MOSADockSDK.getInstance(
activity = this,
apiKey = "your-api-key",
userId = "user-123"
)
Permissions
Required Permissions
The SDK requires the following permissions:
Android 12+ (API 31+):
BLUETOOTH_CONNECT- Connect to BLE devicesBLUETOOTH_SCAN- Scan for BLE devicesACCESS_FINE_LOCATION- Required for BLE scanningNFC- NFC tag readingPOST_NOTIFICATIONS- Foreground service notifications (Android 13+)
Android 11 and below:
BLUETOOTH- Legacy Bluetooth permissionBLUETOOTH_ADMIN- Legacy Bluetooth admin permissionACCESS_FINE_LOCATION- Required for BLE scanningACCESS_COARSE_LOCATION- Required for Android 9 and belowNFC- NFC tag reading
Requesting Permissions
The SDK can automatically request permissions if setAutoRequestPermissions(true) is set. Alternatively, request manually:
lifecycleScope.launch {
val hasPermissions = sdk.checkAndRequestPermissions()
if (!hasPermissions) {
// Handle permission denial
val missingPermissions = sdk.getMissingPermissions()
showPermissionDialog(missingPermissions)
}
}
Check Permission Status
if (sdk.hasRequiredPermissions()) {
// All permissions granted
} else {
val missing = sdk.getMissingPermissions()
// Handle missing permissions
}
Device Capabilities
Check BLE Support
if (!sdk.isBLESupported()) {
// Device doesn't support BLE
showError("Bluetooth LE is not supported on this device")
return
}
Check NFC Support
if (!sdk.isNFCSupported()) {
// Device doesn't support NFC
showError("NFC is not supported on this device")
return
}
Check BLE Enabled
if (!sdk.isBLEEnabled()) {
// Prompt user to enable Bluetooth
val intent = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)
startActivityForResult(intent, REQUEST_ENABLE_BLE)
}
Check NFC Enabled
if (!sdk.isNFCEnabled()) {
// Prompt user to enable NFC
val intent = Intent(Settings.ACTION_NFC_SETTINGS)
startActivity(intent)
}
Basic Usage
Request Unlock Key
lifecycleScope.launch {
val unlockKey = sdk.requestUnlockKey(
type = MOSADockUnlockKeyType.BikeLock,
areaId = "area-123"
)
if (unlockKey != null) {
// Use key for dock operation
performDockOperation(unlockKey)
} else {
// Handle key request failure
showError("Failed to request unlock key")
}
}
Perform Dock Operation
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
}
override fun onDockChainInserted() {
// Chain inserted
}
override fun onDockSecured() {
// Dock secured
}
override fun onBleDisConnected() {
// BLE disconnected
}
override fun onRequestKey() {
// Key request initiated (Android only)
}
override fun onError(error: MosaError) {
// Handle error
}
}
)
}
ProGuard/R8 Rules
If you're using ProGuard or R8, add these rules to your proguard-rules.pro:
# MOSA SDK
-keep class to.mosa.lib.** { *; }
-keepclassmembers class to.mosa.lib.** { *; }
-dontwarn to.mosa.lib.**
# Keep callback interfaces
-keep interface to.mosa.lib.dock.models.MOSADockSDKCallback { *; }
# Keep data classes
-keep class to.mosa.lib.**.models.** { *; }
-keepclassmembers class to.mosa.lib.**.models.** {
<fields>;
<methods>;
}
BLE Foreground Service
The SDK uses a Foreground Service for stable BLE connections. This is automatically managed and displays a persistent notification during operations. The notification can be customized by providing a notification channel ID in your app's resources.
Threading
- SDK methods are
suspendfunctions and should be called from coroutines - Callbacks are invoked on the main thread
- BLE operations run in a background foreground service
Lifecycle Management
The SDK handles app lifecycle automatically:
- Foreground: Full functionality available
- Background: BLE operations continue via foreground service
- Terminated: Sessions and events are persisted for sync when app restarts
Error Handling
Errors are reported via the onError callback with structured MosaError objects:
override fun onError(error: MosaError) {
when (error.errorType) {
MosaErrorType.NFC_DISABLED -> {
// Handle NFC disabled
}
MosaErrorType.BLE_DISABLED -> {
// Handle BLE disabled
}
MosaErrorType.DOCK_TIMEOUT -> {
// Handle timeout
}
else -> {
// Handle other errors
}
}
}
Best Practices
- Initialize SDK Early: Initialize in
onCreate()of your main Activity - Check Capabilities: Always check device capabilities before operations
- Handle Permissions: Request permissions before dock operations
- Implement Callbacks: Implement all callback methods for complete UI updates
- Error Handling: Always implement
onErrorcallback - Lifecycle: Use
lifecycleScopefor coroutine-based SDK calls
Next Steps
- SDK Callbacks - Complete callback documentation
- Use Case Guides - Bike parking and sharing examples
- API Reference - Complete API documentation
For iOS integration, see the iOS Platform Guide.