Zum Inhalt springen
Kontakt
Case Study · Android · Native

Auto-Dialer: Anruflisten automatisiert abarbeiten (Android)

Native Android-App, die ganze Anruflisten automatisch abwählt – direkt an die Telefonie des Betriebssystems angebunden. Für den betrieblichen Einsatz eines Kunden entwickelt.

Android NativeMethod ChannelsCSV-ImportFlutter
Auto-Dialer-App von SB-Techworks: Warteschlange, automatisches Wählen und CSV-Import
500.000+App-Downloads
24 hAntwort-Zeit (Mo–Fr)
100 %Code-Eigentum bei dir
1Ansprechpartner von Anfrage bis Launch

Die Herausforderung

Wer beruflich Listen abtelefoniert – Rückrufe, Terminabstimmungen, wiederkehrende Kontaktrunden –, verbringt Zeit nicht mit dem Gespräch, sondern mit dem Drumherum: Nummer heraussuchen, abtippen, wählen, nach dem Auflegen zurück in die Liste finden, Position merken. Die Aufgabe klingt nach einem simplen Automatisierungsfall. Technisch ist sie es nicht, weil Android nicht dafür gebaut ist, dass eine App von außen die Telefonie steuert.

Der Kern des Problems liegt im Lebenszyklus der App. Sobald ein Anruf ausgelöst wird, übernimmt das Betriebssystem: Die System-Telefonie kommt in den Vordergrund, die auslösende App wandert in den Hintergrund und kann dort – je nach Android-Version, Hersteller und Energiespar-Einstellung – pausiert oder beendet werden. Genau in diesem Moment muss aber die eigentliche Automatik stattfinden: erkennen, dass das Gespräch beendet ist, den Eintrag als abgearbeitet markieren und die nächste Nummer wählen. Eine Warteschlange, die im Zustand der Oberfläche lebt, ist damit unbrauchbar.

Dazu kommen zwei praktische Hürden. Erstens die Berechtigungen: Direktes Wählen ohne Bestätigungsschritt setzt eine ausdrücklich erteilte Laufzeit-Berechtigung voraus – ohne sie gibt es keine Automatik, sondern nur einen vorausgefüllten Wählbildschirm. Zweitens die Datenqualität: Nummern kommen entweder aus der Kontaktdatenbank des Geräts oder aus CSV-Dateien, die aus ganz anderen Vorsystemen stammen, mit unterschiedlichen Trennzeichen, Zeichenkodierungen und Schreibweisen für ein und dieselbe Rufnummer.

Der Ansatz

Die App ist bewusst zweigeteilt. Alles, was Oberfläche ist – Listenverwaltung, Import, Fortschritt der Warteschlange, Einstellungen –, läuft in Flutter. Alles, was die Telefonie berührt, liegt nativ in Android. Die Naht zwischen beiden Welten sind Method Channels, und sie ist asymmetrisch gedacht: Kommandos wandern von Dart in den nativen Teil, Zustandsänderungen kommen als Ereignisstrom zurück. Das hält die Schnittstelle klein und macht sie zum einzigen Ort, an dem beide Seiten sich abstimmen müssen.

Der Zuschnitt ist kein Zufall. Der Oberflächen-Anteil einer solchen App ist der größere und der, an dem am meisten iteriert wird – dafür spielt Flutter seine Stärken aus. Der Telefonie-Anteil ist klein, aber empfindlich: Die zuständigen Android-Schnittstellen haben sich über die Versionen mehrfach verändert, etwa die Ablösung des klassischen PhoneStateListener durch TelephonyCallback ab Android 12, und die Regeln rund um Telefonie-Berechtigungen werden regelmäßig nachgeschärft. Solche Änderungen fängt man besser in einer kleinen, isolierten Kotlin-Schicht ab als verteilt über die ganze App.

Die Abarbeitung selbst ist ein Zustandsautomat auf der nativen Seite: bereit, wählt, im Gespräch, nach dem Gespräch, nächster Eintrag oder Pause. Weitergeschaltet wird nicht über Timer, sondern über die Anrufzustände, die das System meldet. Das ist der entscheidende Unterschied in der Praxis: Ein zeitgesteuerter Dialer läuft aus dem Tritt, sobald ein Gespräch länger dauert, spät angenommen wird oder in der Mailbox landet. Ein ereignisgesteuerter wartet schlicht, bis der Anrufzustand wieder auf frei wechselt.

Die Eingangsseite bleibt bewusst einfach: Nummern kommen aus den Gerätekontakten oder aus einer CSV-Datei. Die Normalisierung auf ein einheitliches Wählformat – führende Null, Ländervorwahl, Leer- und Sonderzeichen in der Schreibweise – gehört in den Import und nicht in die laufende Anrufserie. Was einmal in der Warteschlange steht, soll wählbar sein. Und weil eine Automatik, die sich nicht anhalten lässt, im Betrieb unbrauchbar ist, bleibt der aktuelle Eintrag jederzeit sichtbar und die Abarbeitung jederzeit unterbrechbar.

Was entstanden ist

  • Automatisches Wählen ganzer Listen
  • CSV- & Kontakt-Import
  • Warteschlangen-Abarbeitung
  • Native Android-Telefonie via Method Channels

Technische Entscheidungen

Flutter-Oberfläche, Telefonie nativ in Kotlin

Die Alternativen waren eine vollständig native Android-App oder der Versuch, alles über fertige Plugins aus dem Flutter-Ökosystem abzudecken. Gewählt wurde der Mittelweg, weil der Oberflächen-Anteil groß und der Telefonie-Anteil klein, aber tief ist. Der Preis ist eine zusätzliche Grenze im System: Zustand existiert auf beiden Seiten, Stacktraces enden an der Kanalgrenze, und Debugging spannt sich über zwei Laufzeitumgebungen. Das rechnet sich nur, solange die native Fläche bewusst klein gehalten wird.

System-Telefonie anstoßen statt Standard-Telefon-App werden

Wer unter Android volle Kontrolle über ein Gespräch will – eigene Gesprächsoberfläche, programmgesteuertes Auflegen –, muss die Rolle der Standard-Telefon-App übernehmen. Das heißt, die komplette Telefonie-Oberfläche des Geräts zu ersetzen, zusätzliche Store-Anforderungen zu erfüllen und Nutzer aktiv umstellen zu lassen: für ein Werkzeug, das Listen abarbeiten soll, ein unverhältnismäßiger Umbau. Stattdessen stößt die App Anrufe über die System-Telefonie an und beobachtet den Anrufzustand. Der Preis dafür: Während des Gesprächs ist die System-Oberfläche zu sehen, und das Auflegen bleibt beim Menschen.

Warteschlange nativ und ereignisgesteuert statt im UI-Zustand

Naheliegend wäre gewesen, die Warteschlange dort zu halten, wo sie angezeigt wird – in Dart. Das scheitert daran, dass die App während jedes Gesprächs im Hintergrund ist und dort nicht garantiert weiterläuft. Die Abarbeitung liegt deshalb nativ, gekoppelt an Anrufzustands-Ereignisse. Der Preis sind Zustand an zwei Stellen, der synchron gehalten werden muss, zusätzlicher Aufwand dafür, die Abarbeitung unter Androids Hintergrund-Beschränkungen zuverlässig am Leben zu halten, und ein Verhalten, das sich nur auf echten Geräten seriös testen lässt – Emulatoren bilden Telefonie und herstellerspezifische Energiesparlogik nicht ab.

CSV-Import statt Backend-Anbindung

Die Alternative wäre ein Server gewesen, der Listen zentral verwaltet und synchronisiert – mit Konten, Rechten und laufendem Betriebsaufwand. Für diesen Einsatzzweck genügt der kleinste gemeinsame Nenner: Praktisch jedes Vorsystem, aus dem Nummern kommen, kann CSV exportieren, und die Daten bleiben auf dem Gerät. Der Preis ist die fehlende zentrale Verwaltung – keine geräteübergreifende Dublettenprüfung, kein Abgleich – und ein Import, der reale Dateien aushalten muss: Semikolon statt Komma, Kodierungen jenseits von UTF-8 und Tabellenprogramme, die aus einer Rufnummer eine Zahl machen und dabei die führende Null verlieren.

Tech-Stack

Android NativeMethod ChannelsCSV-ImportFlutter

Ergebnis

Für den betrieblichen Einsatz eines Kunden entwickelt und dort in der Praxis genutzt: Die App steuert die native Android-Telefonie und arbeitet Anruflisten selbstständig ab. Einsatzdetails des Kunden behandeln wir vertraulich.

Was das für ähnliche Projekte bedeutet

Verallgemeinerbar ist vor allem eines: Bei Apps, die Funktionen des Betriebssystems automatisieren, steckt der Aufwand selten im sichtbaren Feature, sondern im Prozess-Lebenszyklus und im Berechtigungsmodell. Die Frage, ob eine App etwas technisch kann, ist meist schnell beantwortet. Die eigentlichen Fragen lauten, was passiert, wenn das System die App in den Hintergrund schiebt, welche Berechtigung aktiv erteilt werden muss und was davon in der nächsten Betriebssystem-Version anders geregelt ist. Solche Apps haben – anders als reine Oberflächen-Anwendungen – einen dauerhaften Wartungsanteil, der von Anfang an in die Planung gehört.

Ebenso übertragbar ist die Architekturfrage: Cross-Platform oder nativ entscheidet sich sinnvoll pro Funktion, nicht pro Projekt. Eine plattformübergreifende Oberfläche mit einer schmalen nativen Schicht genau dort, wo Systemzugriff nötig ist, ist häufig die günstigere Antwort als beide Extreme – vorausgesetzt, die native Fläche wird bewusst begrenzt und dokumentiert. Und für interne Werkzeuge gilt: Der Zuschnitt entscheidet über die Machbarkeit. Ein Dialer, der eine Liste abarbeitet, ist ein überschaubares Vorhaben; ein System, das zusätzlich Kampagnen, Gesprächsergebnisse und Fremdsysteme verwaltet, ist ein anderes Projekt.

Häufige Fragen

Was unterscheidet einen Auto-Dialer von einem Predictive Dialer?

Ein Auto- oder Power-Dialer wählt die Nummern einer Liste nacheinander auf einem Gerät – die telefonierende Person ist bereits da, bevor die Verbindung steht. Ein Predictive Dialer wählt dagegen mehrere Leitungen parallel und verteilt zustande gekommene Verbindungen statistisch auf einen Pool von Agenten, was eine eigene Telefonie-Infrastruktur voraussetzt. Dieses Projekt ist bewusst der erste Fall: ein Werkzeug für ein Gerät und eine Person, keine Callcenter-Plattform.

Kann eine Android-App Anrufe automatisch auslösen?

Ja – über die System-Telefonie, sofern die Laufzeit-Berechtigung für direktes Wählen ausdrücklich erteilt wurde. Ohne diese Berechtigung lässt sich nur der Wählbildschirm vorausgefüllt öffnen, was eine automatische Abarbeitung ausschließt. Nicht frei verfügbar sind dagegen die Gesprächsoberfläche und das programmgesteuerte Auflegen: Beides ist auf aktuellen Android-Versionen im Wesentlichen der Standard-Telefon-App vorbehalten. Automatik heißt hier also: wählen, den Anrufzustand beobachten und nach Gesprächsende weiterschalten.

Warum Flutter mit nativem Anteil und nicht komplett nativ?

Weil sich die beiden Anteile unterschiedlich verhalten. Die Oberfläche ist der größere Teil, ändert sich häufiger und profitiert von schnellen Iterationen – dafür ist Flutter gut geeignet. Der Zugriff auf die System-Telefonie ist klein, aber plattformspezifisch und versionsabhängig und gehört deshalb nativ. Method Channels verbinden beides, kosten aber eine zusätzliche Schnittstelle, die gepflegt und getestet werden muss.

Wie kommen die Nummern in eine solche App?

Über die Kontakte des Geräts oder per CSV-Import. Für Listen, die aus anderen Systemen stammen, ist CSV in der Praxis der robustere Weg, weil nahezu jedes Vorsystem dieses Format exportieren kann. Die typischen Stolperstellen liegen dabei nicht im Parsen, sondern in den Daten: Semikolon statt Komma als Trennzeichen, Kodierungen jenseits von UTF-8 und Rufnummern, die von Tabellenprogrammen als Zahl interpretiert und um die führende Null gekürzt wurden. Deshalb gehört die Normalisierung auf ein einheitliches Wählformat in den Import.

Läuft die Abarbeitung weiter, während telefoniert wird?

Während eines Gesprächs ist die App zwangsläufig im Hintergrund, weil die System-Telefonie den Vordergrund einnimmt. Die Abarbeitung muss deshalb so gebaut sein, dass sie das übersteht: nativ und über Anrufzustands-Ereignisse weitergeschaltet statt über Timer. Android schränkt Hintergrundarbeit bewusst ein – dieser Teil entscheidet deshalb über die Zuverlässigkeit. Herstellerspezifische Energiesparmechanismen sind hier die häufigste Fehlerquelle und lassen sich nur auf echten Geräten prüfen.

Wofür ist ein solcher Dialer nicht gedacht?

Dafür ist er nicht gebaut. Der Anwendungsfall ist das Abarbeiten bestehender, eigener Nummernlisten auf einem einzelnen Gerät. Wer wann angerufen werden darf, entscheidet kein Dialer; diese Verantwortung liegt beim Betrieb, der ihn einsetzt.

Ähnliches Projekt geplant?

SB-Techworks entwickelt individuelle Apps für iOS und Android – vom MVP bis zur skalierbaren Business-App, direkt aus der Entwicklung. Du bekommst innerhalb von 24 Stunden (Mo–Fr) eine ehrliche Einschätzung zu Machbarkeit und Kosten.

Kostenlose Einschätzung anfordern  App entwickeln lassen →