Danny Kukic
    • EasyPointmentOnline-Buchung für Praxen.
    • PillRemindEin Medikamenten-Wecker für Android.
    • Toivoa TassuilleHundemassage & Lasertherapie.
    • Kennel UnlockSpringer-Spaniel-Züchter.
← Projekte

PillRemind

Ein nativer Medikamenten-Wecker für Android. Der Wecker klingelt jedes Mal, und genau das macht Android am schwersten.

Was es ist

Ein Medikamenten-Wecker für Android. Er verwaltet mehrere Medikamente mit jeweils eigenen Einnahmezeiten, und wenn eine ansteht, klingelt ein echter Wecker. Er liegt über dem Sperrbildschirm, läuft auf dem Wecker-Kanal und ist laut genug, um jemanden zu wecken. Ausschalten kannst du ihn über die Knöpfe am Bildschirm oder mit den Lautstärke- und Power-Tasten, so wie jeden anderen Wecker auf dem Handy. Design und Code sind beide von mir, von der Einnahmelogik bis zum Weckbildschirm.

Warum es nativ sein musste

Die erste Version war Expo und React Native, und das meiste lief. Verlässlich klingeln konnte sie nicht. Alle vier Probleme unten liegen an der Grenze zwischen App und Betriebssystem, wo eine JavaScript-Brücke nicht hinreicht, also habe ich das Ganze in Kotlin neu gebaut.

Android 14 hat den Full-Screen-Intent beschnitten

Ein Full-Screen-Intent lässt einen Wecker den Bildschirm übernehmen, statt nur als Benachrichtigung hereinzurutschen. In Android 14 wurde diese Berechtigung auf Wecker- und Telefon-Apps beschränkt, und eine per Sideload installierte App wie meine fiel raus. Aus dem Wecker wurde still und leise eine Benachrichtigung.

→Jetzt übernimmt ein Foreground Service das Klingeln und schickt den Full-Screen-Intent. Das ist der Weg, den die Hersteller am zuverlässigsten zulassen.

Die Hersteller haben showWhenLocked ignoriert

OxygenOS, MIUI und One UI blockieren jeweils, dass Apps im Hintergrund eine Activity starten oder über dem Sperrbildschirm zeichnen. Das Flag, das einen Bildschirm vor ein gesperrtes Handy setzen soll, hat auf meinen Geräten schlicht nichts getan.

→Der Weckbildschirm setzt die Window-Flags im Code und im Manifest und wird aus einem Foreground Service gestartet, nicht aus einem Broadcast Receiver.

Der Vollbild-Wecker: Uhrzeit, Name des Medikaments und die Knöpfe „Genommen“ und „Snooze“

Die Benachrichtigung wollte die PIN

Ein Tipp auf „Genommen“ verlangte erst das Entsperren. Für einen sicheren Sperrbildschirm ist das richtig, und um drei Uhr nachts mit dem Handy in einer Hand völlig falsch.

→„Genommen“ und „Snooze“ sitzen im eigenen Weckbildschirm der App, der ohnehin schon über dem Sperrbildschirm liegt. Nach einer PIN fragt da nichts mehr.

Die Hardware-Tasten konnten ihn nicht stoppen

Jeder andere Wecker auf dem Handy hört auf, wenn du Lautstärke oder Power drückst. React Native bot mir keinen sauberen Weg, diese Tasten abzufangen, also war meiner der eine Wecker, für den du auf den Bildschirm schauen musstest.

→Natives Kotlin steuert die Key-Events und die Audio-Pipeline direkt, also verstummt er über Lautstärke und Power wie alles andere.

Der Heute-Bildschirm: eine Wochenleiste aus Tageskreisen über der Liste der heutigen Einnahmen

Wie er auslöst

AlarmScheduler registriert jeden Alarm über setAlarmClock, den einzigen Scheduling-Aufruf, den Hersteller selten verschieben, und setzt ihn rund drei Tage im Voraus. Wird einer fällig, startet ein Broadcast Receiver einen Foreground Service, der den Ton in der Schleife auf dem Wecker-Kanal hält, sich Wake Lock und Audio-Fokus nimmt und die Full-Screen-Intent-Benachrichtigung schickt. Die öffnet den Weckbildschirm, der über dem Sperrbildschirm liegt und die Hardware-Tasten abfängt.

Eine Einnahme, bis zu sechs Auslöser

  1. T−30 Vorwarnung
  2. T−5 Vorwarnung
  3. T der Wecker
  4. T+10 Wiederholung
  5. T+20 Wiederholung
  6. T+30 Wiederholung

Zwei Vorwarnungen, der Wecker selbst, dann drei Wiederholungen, falls niemand reagiert. Snooze verbraucht die nächste Wiederholung, statt eine draufzulegen. Mehr als viermal kann eine Einnahme also nie klingeln.

Ein Monatskalender, in dem jeder Tag danach eingefärbt ist, ob die Einnahmen erfolgt sind

Auf Testbarkeit gebaut

Die Einnahmelogik liegt in einer Schicht ganz ohne Android-Importe. Reines Kotlin. Auslösezeitpunkte, Zeitzonen-Verankerung, was die Zeitumstellung mit einer Einnahme zur falschen Stunde anstellt, wie ein Snooze einen der eigenen Wiederholungs-Slots aufbraucht. Das alles läuft und wird getestet, ohne dass ein Gerät beteiligt ist, und alles, was das Betriebssystem berührt, sitzt als dünner Adapter obendrauf. Die Trennung kommt aus dem Prototyp, in dem die reine Einnahmelogik als einziger Teil durchgehend funktioniert hat, während alles auf der Native-Bridge das nicht tat.

Stack

KotlinJetpack ComposeMaterial 3RoomDataStoreWorkManagerAlarmManagerNavigation ComposeJUnit
Der Medikamenten-Editor mit Namensfeld und einer Zeile pro täglicher Einnahmezeit

Rolle

Design & Umsetzung

Status

Privates Projekt, per Sideload

Jahr

2026

PillRemind
Nächstes Projekt: Toivoa Tassuille →

© 2026 Danny Kukic

ImpressumDatenschutz