Aktualisiert am 12 Min. LesezeitVon Docutain SDK Team

Fotoüberweisung mit Kotlin Multiplatform integrieren

Starten Sie die Docutain Fotoüberweisung aus gemeinsamem Kotlin-Code und übernehmen Sie die erkannten Zahlungsdaten in Ihre Android- oder iOS-App.

Das KMP-Paket stellt eine gemeinsame API in commonMain bereit. Für Erfassung und Erkennung verwendet Docutain die nativen Implementierungen beider Plattformen. Ihre App kann darum plattformspezifische Oberflächen oder Compose Multiplatform einsetzen. Das SDK liest Rechnungsdaten oder einen GiroCode lokal aus und liefert Zahlungsdaten zurück; die Prüfung und Freigabe der Überweisung erfolgen in Ihrem eigenen Ablauf.

Zielplattformen
Android und iOS
Gemeinsame API
Kotlin commonMain
Mindestversion
Android API 24; iOS 13
Ergebnis
JSON-String oder null

Projektstruktur und Plattformvoraussetzungen

Planen Sie drei Schichten: In commonMain liegen SDK-Aufrufe, Ergebniszustände und die gemeinsame Fachlogik. Die Android- und iOS-Apps übernehmen Plattformintegration, Ressourcen und Dateifreigabe. Die native Docutain-Oberfläche führt durch Aufnahme und Bearbeitung; Ihre Oberfläche zeigt anschließend das Ergebnis an. Eine gemeinsame API bedeutet daher nicht, dass jede Plattformkonfiguration entfällt.

Für Android nennt die aktuelle Einrichtung JDK 17, compileSdk 37 und ein dazu passendes Android Gradle Plugin, beispielsweise 9.1.1 oder neuer. Für iOS benötigen Sie eine macOS-Buildumgebung mit Xcode und CocoaPods. Prüfen Sie die Kombination mit Ihrem bestehenden Projekt im KMP-Einrichtungsleitfaden. Ergänzen Sie auf iOS eine verständliche NSCameraUsageDescription und prüfen Sie die Kamerafreigabe auf beiden Geräten vor dem ersten produktiven Test.

Beide Plattformen vorbereiten

Fügen Sie das KMP-Artefakt dem gemeinsamen Modul hinzu. Die iOS-App benötigt außerdem den nativen Docutain-CocoaPod:

kotlin {
    sourceSets {
        commonMain.dependencies {
            implementation("de.docutain:Docutain-SDK-KMP:1.0.0")
        }
    }
}
platform :ios, '13.0'
target 'YourApp' do
  use_frameworks!
  pod 'DocutainSdk', '1.9.0'
end

Führen Sie nach der Podfile-Änderung pod install aus und ergänzen Sie NSCameraUsageDescription in der Info.plist der iOS-App. Der KMP-Einrichtungsleitfaden nennt derzeit SDK 1.0.0 und iOS 13+. Das Compose-Sample verwendet noch 1.0.0-beta.1 und setzt für seine App iOS 15 voraus. Wenn Sie das Sample unverändert bauen, verwenden Sie dessen zusammenpassende Abhängigkeiten.

SDK vor dem Start des Ablaufs initialisieren

import de.docutain.sdk.kmp.DocutainException
import de.docutain.sdk.kmp.DocutainSdk

try {
    DocutainSdk.initSdk("<YOUR-LICENSE-KEY>")
} catch (exception: DocutainException) {
    // Zahlungsfunktion deaktivieren und passenden Fehler anzeigen.
}

Initialisieren Sie das SDK beim App-Start, bevor die Fotoüberweisung geöffnet werden kann. Sie können eine Testlizenz für Ihre App-Kennungen anfordern. Laut Einrichtungsanleitung des Samples kann ein KMP-Lizenzschlüssel Android und iOS abdecken.

Fotoüberweisung in einer Coroutine starten

startPhotoPayment ist eine Suspend-Funktion. Das Beispiel läuft in einem Compose-Screen. Bei einer KMP-App mit nativer Oberfläche rufen Sie dieselbe API aus einem geeigneten Coroutine-Scope Ihrer gemeinsamen Anwendungsschicht auf.

import androidx.compose.runtime.rememberCoroutineScope
import de.docutain.sdk.kmp.DocutainException
import de.docutain.sdk.kmp.DocutainSdk
import de.docutain.sdk.kmp.PhotoPaymentConfiguration
import kotlinx.coroutines.launch

val scope = rememberCoroutineScope()
scope.launch {
    try {
        val result = DocutainSdk.startPhotoPayment(PhotoPaymentConfiguration())
        when {
            result == null -> { /* Abbruch: vorhandenen Entwurf behalten. */ }
            result.isEmpty() -> { /* Manuelle Eingabe oder neuen Versuch anbieten. */ }
            else -> { /* JSON in ein App-Modell lesen; Parsefehler behandeln. */ }
        }
    } catch (exception: DocutainException) {
        // SDK-Fehler anzeigen, ohne eine Zahlung auszulösen.
    }
}

Das gekürzte Beispiel zeigt den SDK-Aufruf und die Ergebnisfälle; JSON-Parser und Zahlungsentwurf gehören zum Anwendungscode. Ein nichtleeres Ergebnis enthält die Zahlungsdaten als JSON. null steht für einen Abbruch. Ein leerer String kann zurückkommen, wenn keine Daten gefunden wurden und der Bildschirm für leere Ergebnisse deaktiviert ist. Unterbinden Sie einen zweiten Start, solange die Coroutine auf den nativen Ablauf wartet.

JSON in einen Zahlungsentwurf übernehmen

Der Empfänger steht in SEPACreditor, der Betrag in Amount, der Verwendungszweck in Reference und die Bankverbindung in Address.Bank. Behandeln Sie Felder als optional: Rechnungen unterscheiden sich und erkannte Werte können eine Korrektur benötigen. Wenn die BIC-Erkennung deaktiviert wird, ändert sich die Struktur der Bankdaten zu einer IBAN-Liste; passen Sie dann auch die Zuordnung an.

Zeigen Sie die Werte in Ihrer Zahlungsmaske zur Prüfung an und wenden Sie vor dem Absenden die Validierungs- und Freigaberegeln Ihrer App an. Docutain erkennt Zahlungsinformationen, führt aber keine Überweisung aus. Die GiroCode-Erkennung ist im selben Fotoüberweisungsablauf standardmäßig aktiviert.

Mit PhotoPaymentConfiguration steuern Sie Erfassungsoberfläche und optionale Analysefunktionen. Im Sample aktiviert PhotoPayment.kt die Erkennung des Zahlungsstatus und bietet Optionen für GiroCode, BIC und Seitenbearbeitung. PaymentData.kt liest die JSON-Daten in Zahlungsfelder ein. Das aktuelle Ergebnisschema und die Optionen stehen in der KMP-Dokumentation zur Fotoüberweisung.

Konkretes Kotlin-Modell für den Zahlungsentwurf

Das folgende Modell bildet die Standardausgabe mit aktivierter BIC-Erkennung ab. Verwenden Sie in commonMain die JSON-Bibliothek kotlinx-serialization-json in einer zu Ihrem Projekt passenden Version. Da hier der JSON-Baum gelesen wird, ist für dieses Beispiel kein generierter Serializer erforderlich. Das Modell gehört zur App und ist kein SDK-Typ.

import kotlinx.serialization.json.*

data class BankCandidate(val iban: String?, val bic: String?)
data class PaymentDraft(
    val recipient: String?,
    val amountText: String?,
    val reference: String?,
    val banks: List<BankCandidate>
)

private fun JsonObject.optionalText(key: String): String? {
    val value = this[key] ?: return null
    if (value is JsonNull) return null
    require(value is JsonPrimitive) { "Unexpected field: $key" }
    return value.contentOrNull?.takeIf { it.isNotBlank() }
}

// For the default readBIC = true schema.
fun parsePaymentDraft(raw: String): PaymentDraft {
    val root = Json.parseToJsonElement(raw).jsonObject
    val address = root["Address"]?.takeUnless { it is JsonNull }?.jsonObject
    val banks = address?.get("Bank")
        ?.takeUnless { it is JsonNull }?.jsonArray.orEmpty()
        .map { entry ->
            val bank = entry.jsonObject
            BankCandidate(bank.optionalText("IBAN"), bank.optionalText("BIC"))
        }
    return PaymentDraft(
        recipient = root.optionalText("SEPACreditor"),
        amountText = root.optionalText("Amount"),
        reference = root.optionalText("Reference"),
        banks = banks
    )
}

Rufen Sie parsePaymentDraft(result) nur im Zweig für ein nichtleeres Ergebnis auf. Fangen Sie SerializationException und IllegalArgumentException an dieser Grenze ab und behalten Sie bei einem Fehler den bisherigen Entwurf. Erst nach erfolgreichem Parsing wird der neue Entwurf angezeigt. Bei mehreren Bankverbindungen muss eine bewusste Auswahl möglich sein; übernehmen Sie nicht ungeprüft den ersten Eintrag.

Der Betrag bleibt zunächst Text. Überführen Sie ihn mit den Dezimal- und Währungsregeln Ihrer Zahlungsanwendung in deren Geldmodell; verwenden Sie dafür keine unkontrollierte Gleitkomma-Konvertierung. Fehlende Empfänger, Beträge oder IBANs bleiben sichtbar unvollständig. Eine erfolgreiche JSON-Verarbeitung ersetzt weder die Prüfung durch den Nutzer noch die Zahlungsfreigabe.

Der hier beschriebene Zahlungsablauf bezieht sich auf IBAN, SEPA und GiroCode. Leiten Sie daraus keine Unterstützung beliebiger nationaler Zahlungssysteme ab. Prüfen Sie Rechnungslayouts, Sprache, Betragsformat und Währung Ihrer Zielmärkte mit einem eigenen Testbestand.

Analyse, Wiederholung und Dateiimport konfigurieren

val config = PhotoPaymentConfiguration().apply {
    allowGiroCode = true
    analyzeConfig.readBIC = true
    analyzeConfig.readSEPACreditor = true
    analyzeConfig.readPaymentState = true
}
// Inside your coroutine:
val result = DocutainSdk.startPhotoPayment(config)

Behalten Sie readSEPACreditor bei: Der tatsächliche Zahlungsempfänger kann vom Rechnungsabsender abweichen. readPaymentState ergänzt einen erkannten Zahlungsstatus; dieser ist ein Hinweis aus dem Dokument und kein Abgleich mit dem Bankkonto. Details stehen in der Photo Payment Dokumentation.

Lassen Sie während der Evaluation den voreingestellten Empty Result Screen aktiv. Er bietet Wiederholen oder Abbrechen, wenn keine Zahlungsdaten erkannt wurden. Mit emptyResultScreen = null übernimmt Ihre App diesen Ablauf und muss ein leeres Ergebnis behandeln. Einen Abbruch sollten Sie nicht als Erkennungsfehler anzeigen.

Für geteilte PDFs und Bilder registrieren Sie die App auf jeder Plattform als Ziel. Android liefert lesbare content://-URIs; auf iOS kopieren Sie eine extern geöffnete Datei während des gültigen Zugriffs in einen eigenen App-Speicher und übergeben genau eine file://-URL. Starten Sie startPhotoPaymentWithExternalFiles erst nach der Initialisierung und verbrauchen Sie jeden ausstehenden Import nur einmal. Die Dokumentation und das verlinkte Compose-Sample zeigen die Plattform-Handler.

Auf beiden Plattformen testen

  • Testen Sie auf echten Android- und iOS-Geräten mit typischen Rechnungen und GiroCodes.
  • Prüfen Sie null, leere Ergebnisse, SDK-Fehler und ungültiges JSON vor dem Befüllen eines Entwurfs.
  • Vergleichen Sie Empfänger, IBAN, Betrag und Verwendungszweck mit der Vorlage und ermöglichen Sie Korrekturen.
  • Prüfen Sie App-Wechsel und wiederholtes Tippen, während die SDK-Oberfläche geöffnet ist.
  • Für in die App geteilte Dokumente können Sie startPhotoPaymentWithExternalFiles anhand der offiziellen Dokumentation evaluieren.

Das offizielle KMP-Compose-Beispiel zeigt eine vollständige Integration für Android und iOS.

Typische Integrationsfehler eingrenzen

Wenn die Oberfläche mehrfach startet, prüfen Sie den Auslöser: Starten Sie aus einer Nutzeraktion und sperren Sie diese bis zum Abschluss. Ein direkter Start im Composable-Funktionskörper kann bei einer Recomposition erneut ausgelöst werden. Trennen Sie „bereit“, „läuft“, „abgebrochen“, „erfolgreich“ und „fehlgeschlagen“ in Ihrem UI-Zustand. Setzen Sie die Laufsperre auch bei Fehlern zurück.

Bei Initialisierungsproblemen prüfen Sie Lizenz und App-Kennungen, bei iOS-Linkerfehlern zuerst Pod-Installation und die abgestimmten Abhängigkeiten. Verwechseln Sie den Abbruch durch Nutzer nicht mit einer Coroutine-Cancellation. Letztere sollte an den übergeordneten Scope weitergegeben werden. Die KMP-Doku erklärt Coroutines and suspend functions sowie Error Handling.

In Ihrer App testen

Fotoüberweisung mit KMP evaluieren

Prüfen Sie die lokale Erkennung und die Übergabe an Ihren Zahlungsentwurf auf beiden Plattformen.

Kontaktieren Sie uns und erhalten Sie Ihr Angebot


Lassen Sie unseren Kollegen Harry Beck wissen, wie wir Ihnen helfen können und erhalten Sie ein unverbindliches Angebot.



Informationen zur Verarbeitung Ihrer Angaben finden Sie in unseren Datenschutzhinweisen.