Platform comparison - iOS and Android

Dragon Copilot web app for mobile provides APIs for iOS and Android. To maintain consistency in implementation approaches between platforms, both platforms share:

  • Common naming conventions: ApplicationConfig, ApplicationConfigProvider, UserInfo, PatientInfo, VisitInfo.
  • Common data classes: ClientTokenProvider, ClientToken, ClientEntraToken, ClientSoFToken.
  • Session lifecycle methods: getInstance(), openSession(), closeSession(), clearInstance().
  • Multi-patient workflows: Switch patients without re-initialization.
  • Token architecture: Offline caching, EIS exchange for partner tokens, validation.
  • Theme and language support: Both platforms support appearance and locale changes.
  • Ambient recording and dictation events: Available on both platforms.

The two platforms have the following key architectural difference:

  • Event handling: iOS uses delegate protocols, Android uses Kotlin flows for event streams.

Architectural differences

1. Event handling

The primary difference between platforms is how they handle events:

iOS Android
Delegate protocols with optional methods. Kotlin Flow with sealed class hierarchies.
AppUiDelegate, AppRecordingDelegate, AppDictationDelegate, AppSettingsDelegate event, uiEvent, recordingEvent, dictationEvent flows
Callback-based: func recordingStarted() Flow-based: Flow<AppRecordingUiEvent.RecordingStarted>

iOS Example:

class MyDelegate: AppRecordingDelegate {
    func recordingStarted() {
        // Handle recording start
    }
}

Android Example:

lifecycleScope.launch {
    applicationConfig.recordingEvent.collect { event ->
        when (event) {
            is AppRecordingUiEvent.RecordingStarted -> { /* Handle */ }
        }
    }
}

2. Configuration provider structure

iOS Android
Two protocols: ConfigurationProvider + SessionDataProvider Single data class: ApplicationConfigProvider
Configuration and user info separate from patient/visit All data in one configuration object

iOS:

protocol ConfigurationProvider {
    func getConfiguration() -> ApplicationConfigProvider
    func getAccessTokenProvider() -> AppAccessTokenProvider
    func getUser() -> UserInfo
}

protocol SessionDataProvider {
    func getPatient() -> PatientInfo
    func getVisit() -> VisitInfo
}

Android:

data class ApplicationConfigProvider(
    val userInfo: UserInfo?,
    val customerId: String?,
    val partnerId: String?,
    val serverInfo: ServerInfo,
    val clientAppInfo: ClientAppInfo,
    // ...
)

// Patient and visit provided to openSession()
applicationConfig.openSession(
    patientInfo: PatientInfo?,
    visitInfo: VisitInfo?
)

3. Token provider callbacks

iOS Android
Protocol with success and failure callbacks Listener interface with callbacks
AppAccessTokenProvider protocol AcquireNewTokenListener interface

iOS:

@objc public protocol AppAccessTokenProvider {
    func accessToken(
        scopes: [String]?, 
        forceRefresh: Bool,
        onSuccess: @escaping (ClientTokenProvider) -> Void,
        onFailure: @escaping (Error) -> Void
    )
}

Android:

fun interface AcquireNewTokenListener {
    fun acquireNewToken(
        scopes: List<String>?,
        forceRefresh: Boolean,
        onSuccess: (ClientTokenProvider) -> Unit,
        onFailure: (Exception) -> Unit
    )
}

Platform-specific features

Android-only features

Feature Description
OnLoadingBackPress Event when back button is pressed during loading.
RecordingStopReason Detailed stop reasons: USER, SYSTEM_ERROR, MAX_LIMIT_REACHED, AUDIO_INTERRUPTED, INCOMPATIBLE_AUDIO_DEVICE_DETECTED, AUDIO_DEVICE_CHANGED.
RecordingProgressNotification Granular recording progress events: WARN_LIMIT_REACHED, AUDIO_SILENCE_DETECTED, EXTERNAL_AUDIO_DEVICE_DETECTED.
Separate flow streams. Different flows for event, uiEvent, recordingEvent, dictationEvent, internalClientEvent.
Required permissions callback. CheckPermissionCallback for runtime permission requests.

iOS-only features

Feature Description
UIViewController support. openSessionController() for UIKit integration.
SwiftUI View support. openSession() returns SwiftUI View.
Protocol-based architecture. More flexible delegate implementation with optional methods.
RecordingInterruptionReason iOS-specific: systemError, audioInterruption, reachedMaxDuration, incompatibleInputDevice, audioRouteChanged.
RecordingNotification iOS-specific: reachedWarnDuration, audioLoss, externalMicDetected.

Event mapping reference

Common events across platforms:

Event type iOS delegate method Android flow event
WebView loaded webViewLoaded(_ isLoadingDone: Bool) AppUiEvent.WebViewLoaded
Recording started recordingStarted() AppRecordingUiEvent.RecordingStarted(correlationId)
Recording stopped recordingStopped() AppRecordingUiEvent.RecordingStopped(correlationId, reason)
Recording failed recordingFailed() AppRecordingUiEvent.RecordingFailed(correlationId, error)
Recording interrupted recordingInterrupted(reason:) Captured in RecordingStopped with reason
Recording notification recordingNotification(notification:) AppRecordingUiEvent.RecordingProgress(correlationId, notification)
Recording uploading N/A AppRecordingUiEvent.RecordingUploading(correlationId)
Recording uploaded N/A AppRecordingUiEvent.RecordingUploaded(correlationId)
Dictation started dictationStarted() AppDictationUiEvent.DictationStarted(correlationId)
Dictation stopped dictationStopped() AppDictationUiEvent.DictationStopped(correlationId)
Theme changed appearanceThemeChanged(to: String) AppSettingsUiEvent.AppearanceChanged(theme: String)
Language changed changeApplicationLanguage(to: String) AppSettingsUiEvent.ApplicationLanguageChanged(locale: String)
Keep screen on isIdleTimerDisabled(isOn: Bool) AppSettingsUiEvent.KeepScreenOnChanged(isScreenOn: Boolean)
Error occurred N/A AppUiEvent.ErrorOccurred(error: Exception)

Migration between platforms

If you're porting an integration from one platform to another, pay attention to the following design considerations:

  • Event handling: Convert delegate methods to flow collection or vice versa.
  • Configuration: Combine or split configuration and session data providers as needed.
  • Platform features: Check for platform-specific events and handle them accordingly.
  • UI integration: iOS offers both UIKit (openSessionController) and SwiftUI (openSession); Android uses Jetpack Compose or traditional Views.

Tip

Both platforms provide optional delegate methods and events. Implement only what your integration needs.