Englisch version   English version


Version Anpassungen
1.0 (2021-05-05) Initiale Version


Download

Verwendung

Über Benachrichtigungskanäle

Konfiguration

Foreground-Service / Doze-Mode

Schaltflächen in der Media-Notification

Ereignisse aktivieren

Meta-Daten und Erscheinungsbild

Fortschrittsbalken (ProgressBar, ab Android 10, API Level 29)

Handhabung

Fehlerbehandlung

Referenz

Eigenschaften

Funktionen

Ereignisse

Beispiel

Die Benutzeroberfläche

Steuerelemente

Optionen

Zum Verständnis der Implementierung

Erstellen der Extension

Bereitstellen der Bibliotheken

Kopieren der Bibliotheken

Deklaration in den Quellen

Pachten der .aix-Dateien für Kodular

Portieren eines Projekts vom App Inventor nach Kodular

Werkzeuge

 

Achtung !!!

Leider sind die Extensions für App Inventor und Kodular nicht identisch! Das ZIP-Archiv enthält zwei Versionen Abschnitt (s.Erstellen der Extension):

Im Abschnitt Erstellen der Extension wird auch erklärt, wie man ein App-Inventor-Projekt in ein Kodular-Projekt überführen kann. Umgekehrt ist das leider nicht möglich.

Wenn man nicht sicher ist, welche der Versionen eingebunden ist, so kann man dies anhand der Versionsbezeichnung herausfinden. Die Kodular-Version beginnt mit einem "K".

 
App Inventor Version   Kodular Version

Download

Das ZIP-Archiv UrsAI2MediaNotification zum Download. Das Archiv enthält den Quellcode, das kompilierte Binary zum Upload in den App Inventor und eine Beispiel-Anwendung.

Verwendung

Seit dem API-Level 21 (LolliPop 5.0) gibt es die Media Controls, eine besondere Form der Benachrichtigung (Notification), die eigens zur Steuerung von Mediaplayern  entwickelt wurde. Der Clou ist, dass auch Steuerimpulse externer Wiedergabegeräte ausgewertet werden.

Diese Extension ist ausschließlich zu Verwaltung von Media-Notifications gedacht. Wer reguläre Benachrichtigungen erstellen will, sollte die Extension UrsAI2Notifier benutzen.

Über Benachrichtigungskanäle

Mit dem API-Level 26 (Version Oreo 8.0) hat Android das Konzept der Benachrichtigungskanäle eingeführt (NotificationChannel, bei manchen Geräten auch Benachrichtigungskategorien genannt). Sämtliche Benachrichtigungen müssen ab API Level 26 einem solchen Kanal zugeordnet werden. Bis einschließlich API Level 25 sind alle den Benachrichtigungskanal betreffende Angaben und Funktionen wirkungslos.

Das Benachrichtigungskonzept ist relativ komplex. Android erlaubt es, Einstellungen sowohl auf der Geräteebene, als auch auf der Kanalebene und bei den Benachrichtigungen selbst vorzunehmen.

Viele Eigenschaften der Benachrichtigungen, z.B. die Wichtigkeit (Importance), werden auf der Kanal-Ebene festgelegt. Diese Eigenschaften werden von der App bei der Anlage des Kanals festgelegt. Der Benutzer hat mit Hilfe die App Eigenschaften vollen Zugriff auf die meisten der Kanalattribute und kann sie nach belieben modifizieren. Die Modifikationen des Benutzers sollen nicht überschrieben werden. Deshalb können die Kanaleigenschaften nachträglich nicht mehr per Programm geändert werden.  Das geht sogar soweit, dass, wenn eine Kanal gelöscht und anschließend wieder angelegt wird, er mit den zuletzt vorhandenen Einstellungen erzeugt wird. Das "Löschen" ist praktisch nur ein "Verstecken". Lediglich die Eigenschaften Name und Description eines Kanals lassen sich nachträglich ändern. Die Beseitigung von Schreibfehler wäre ansonsten unmöglich.

Man sollte sich also sehr gut überlegen, welche Eigenschaften einem Kanal zugewiesen werden.

Die Extension bietet die Eigenschaften ChannelID, ChannelName, ChannelDescription und ChannelImportance zur Festlegung der Kanaleigenschaften. Der Kanal wird direkt nach Start der App angelegt (im Companion erst dann, wenn das erste Mal ShowNotification aufgerufen wird).

Will man andere Eigenschaften ändern, muss ein neuer Kanal (neue ChannelID) verwendet werden. Den bestehenden Kanal versteckt man sinnvollerweise beim Start der App mit HideChannel.

Konfiguration

Sämtliche Änderungen haben keine sofortige Wirkung. Erst beim nächsten Aufruf von ShowNotification werden sie übernommen.

Foreground-Service / Doze-Mode

FFür manche Projekte ist es notwendig zu verhindern, dass die zugehörige App vom Betriebssystem deaktiviert wird. Mit der Version 6.0 (Marshmallow) hat Android den Doze-Modus zur Optimierung der Akku-Laufzeiten eingeführt. Diese Funktion schaltet, wenn keine App aktiv bedient wird, nach und nach alles herunter (Display, CPU, WiFi, etc.). Um den Doze Mode wirkungsvoll zu umgehen, ist es notwendig, einen Foreground-Service anzulegen. Viele nützliche Hintergrundinformationen findet man im ZEBRA Developer Portal: Keeping your Android application running when the device wants to sleep.

Die meisten Android-Installationen erkennen, wenn ein Mediaplayer aktiv ist und schalten das Gerät nicht ab. Für den Fall, dass dies doch geschieht, kann über die Eigenschaft ForegroundService festgelegt werden, dass bei der Anzeige der Notification ein Foreground-Service gestartet wird. Hat die installierte Android-Version einen API Level von unter 26, ist die Angabe wirkungslos.

Schaltflächen in der Media-Notification

Die Schaltfläche mit dem Play()- bzw. dem Pause()-Symbol wird immer angezeigt. Welches der beiden angezeigt wird, kann über die Funktionen SetStatePaused (zeigt an) und SetStatePlaying (zeigt ) an) eingestellt werden.

Die anderen Schaltflächen lassen sich über die Support...-Funktionen an- und abstellen, je nachdem welche Funktionen die App unterstützt.

Ereignisse aktivieren

Ist ClickAble gesetzt, wird beim Anklicken des Benachrichtigungskörpers die App in den Vordergrund gebracht und das Ereignis OnClick ausgelöst. Ist ClickAble auf false gesetzt, passiert beim Anklicken der Benachrichtigung nichts.

Wird DeleteAble gesetzt, kann der Anwender die Benachrichtigung, z.B. durch Wischen, löschen. Wenn die Notification vom Anwender gelöscht wird, wird das Ereignis UserCanceled ausgelöst.

Meta-Daten und Erscheinungsbild

Die Hintergrundfarbe ist nicht einstellbar, sondern wird von Android automatisch aus dem Album-Image ermittelt.

Über die Funktion SetMetaData und SetMetaDataEx können Titel, Interpret und und ein Bild (AlbumImage) angegeben werden, die in der Benachrichtigung angezeigt werden.

AlbumImage

Für AlbumImage sind folgende Angaben möglich:

Typ Prefix Beispiel
URL http oder https https://ullisroboterseite.de/android-AI2-MediaNotification/MediaNotification.png
Asset // oder nichts //MediaNotification.png oder einfach nur MediaNotification.png
Datei, relativer Pfad / /data/user/0/appinventor.ai_bienonline.UrsMediaNotificationAI2/MediaNotification.png
Datei, absoluter Pfad file:///  file:///Android/data/appinventor.ai_bienonline.UrsMediaNotificationAI2/MediaNotification.png

Bei der Angabe einer URL ist zu beachten, dass das Bild synchron geladen wird. Dies kann bei großen Dateien oder langsamen Verbindungen einige Zeit in Anspruch nehmen. Eine andere Möglichkeit ist es, eine Extension zu verwenden, die einen asynchronen (nebenläufigen) Download der Datei ermöglicht (z.B. die Extension ImageLoader).

Um den Zugriff auf die Dateien zu erleichtern, gibt es die Funktionen

Small Icon

Die Möglichkeit, eigene Grafiken für das SmallIcon einzubinden (Eigenschaft SmallIconImage), besteht erst ab API Level 23. Deshalb gibt es zusätzlich die Möglichkeit über die Eigenschaft SmallSystemIcon ein System-Icon auszuwählen (für mögliche Angaben siehe: System Notification Icons). Die Auswahlregel ist wie folgt:

Bedingung Auswahl
API Level SmallIconImage SmallSystemIcon
≥ 23 gefüllt X SmallIconImage
leer gefüllt SmallSystemIcon
leer leer kein Icon
< 23 X gefüllt SmallSystemIcon
X leer kein Icon

Fortschrittsbalken (ProgressBar, ab Android 10, API Level 29)

Ab Android 10 kann die Media-Notification einen Fortschrittsbalken (ProgressBar) und eine Suchleiste (SeekBar) anzeigen. Dazu muss die Spieldauer (Duration) des Media-Objekts und die aktuelle Abspielposition (CurrentPosition) bekannt sein.

SetMetaDataEx erlaubt die Angabe der Spieldauer, die für die Anzeige eines Fortschrittsbalkens (ProgressBar) benötigt wird. Einige Media-Player, wie der im Beispiel benutzte TaifunPlayer, liefern diese Information. Dazu muss der Player aber entsprechend initialisiert sein. Die Funktion GetDuration ermittelt die Spieldauer aus einer Datei, unabhängig von einem Player.

Für den Parameter Source sind folgende Angaben möglich:

Typ Prefix Beispiel
Asset // oder nichts //JazzInParis.mp3 oder einfach nur JazzInParis.mp3
Datei, relativer Pfad / /data/user/0/appinventor.ai_bienonline.UrsMediaNotificationAI2/JazzInParis.mp3
Datei, absoluter Pfad file:///  file:///Android/data/appinventor.ai_bienonline.UrsMediaNotificationAI2/JazzInParis.mp3

Der Funktion ShowWithProgressBar zeigt einen Fortschrittsbalken an. Er startet an mit der Position, die im Parameter CurrentPosition übergeben wird. Danach läuft er selbständig weiter. Wenn man die Abspielposition per Programm ändert, muss man den Fortschrittsbalken wieder mit ShowWithProgressBar synchronisieren.

Bei Versionen älter als Android 10, funktionieren SetMetaDataEx und ShowWithProgressBar ebenfalls, allerdings wird kein Fortschrittsbalken angezeigt.

Handhabung

Man stellt die initialen Eigenschaften der Komponente passend ein, übergibt die Media-Metadaten (SetMetaData oder SetMetaDataEx) und ruft anschließend ShowNotification bzw. ShowWithProgressBar auf. Von nun an braucht man eigentlich nur noch auf die Ereignisse reagieren. Je nach Ereignis stellt man den Mediaplayer passend ein, passt Eigenschaften der Komponente an und ruft wieder ShowNotification auf.

In der Regel soll der Mediaplayer nicht nur von der Media-Notification gesteuert werden. Meist enthält die App ebenfalls Steuerelemente, die den Player kontrollieren sollen. Um die Blöcke im Projekt einfach zu gestalten, gibt es die Funktionen Play, Pause, Rewind, etc., die die gleichen Ereignisse auslösen, wie die Notification. Es ist also keine doppelte Programmierung für die Steuerelemente auf der Benutzeroberfläche notwendig. Es muss lediglich die passende Funktion aufgerufen werden.

Fehlerbehandlung

 Fehler werden über das Ereignisse Screen.ErrorOccurred  gemeldet.

Code Text Bedeutung Anmerkung
17500 Album image not found. Das angegebene Album-Image konnte nicht geladen werden. Betroffene Funktionen sind SetMetaData und SetMetaDataEx
17501 No meta data set. Die Benachrichtigung soll angezeigt werden, ohne dass vorher SetMetaData oder SetMetaDataEx aufgerufen wurde. Betroffene Funktion ist ShowNotification.
17502 SmallIconImage invalid. Die Grafik-Datei beim Parameter SmallIconImage kann nicht geladen werden. Betroffene Funktion ist ShowNotification. Die Benachrichtigung wird ohne ein Icon angezeigt.
17503 SmallSystemIcon invalid. Die Angabe beim Parameter SmallSystemIcon kann nicht aufgelöst werden. Betroffene Funktion ist ShowNotification. Die Benachrichtigung wird ohne ein Icon angezeigt.
17504 Cannot start foreGround service. Der angeforderte Foreground-Service kann nicht gestartet werden. Betroffene Funktion ist ShowNotification.
17505 Not a valid media file. Die angegebene Datei kann nicht gefunden werden oder ist keine Media-Datei. Betroffene Funktion ist GetDuration.

Referenz

Eigenschaften

ChannelDescription
Für den Benutzer sichtbare Beschreibung des Benachrichtigungskanals (NotificationChanel). Diese Eigenschaft kann nachträglich geändert werden.
ChannelID
Die ID des Benachrichtigungskanals (NotificationChanel) (nicht nachträglich änderbar).
ChannelImportance
Legt die Bedeutsamkeit (Importance) des Kanals fest. Die Voreinstellung ist NotificationManager.IMPORTANCE_LOW.
ChannelName
Für den Benutzer sichtbarer Name des Benachrichtigungskanals (NotificationChanel). Diese Eigenschaft kann nachträglich geändert werden.
ClickAble
true: Das Anklicken der Benachrichtigung stellt die App in den Vordergrund und löst dort das Ereignis OnClick aus. false: Das Anklicken der Benachrichtigung hat keine Wirkung.
Hinweis: Das Ändern dieser Eigenschaft wirkt sich erst nach dem nächsten Aufruf von ShowNotification aus.
DeleteAble
Die Benachrichtigung kann vom Anwender, z.B. durch Wischen, gelöscht werden. Diese Option hat bei aktivem Foreground-Service keine Wirkung. Der Foreground-Service verbietet das Löschen der Benachrichtigung.
Hinweis: Das Ändern dieser Eigenschaft wirkt sich erst nach dem nächsten Aufruf von ShowNotification aus.
ForegroundService
Bei der Anzeige der Benachrichtigung wird ein Foreground-Service gestartet. Der Foreground-Service verhindert, dass der Doze-Modus zuschlägt. Die Funktion ist im Companion wirkungslos, da hier keine Foreground-Services unterstützt werden. Je nach Android-Version und Hersteller des Geräts sind weitere Maßnahmen notwendig (s. Beispiel).
IsRunningInCompanion
Gibt an, ob die Anwendung aktuell im Companion läuft.
SmallIconImage
Erst ab API Level 23! Asset-Name (Rubrik Media im App Inventor) der Datei für das Icon in der Status-Leiste (siehe auch Notification.Builder.setSamallIcon). Bei Versionen bis API Level 22 wird diese Angabe ignoriert. Siehe auch Meta-Daten und Erscheinungsbild.
Ob das Icon angezeigt wird, ist abhängig von der Android-Version, vom Gerätehersteller und der Bedeutsamkeitsstufe des Benachrichtigungskanals.
Hinweis: Das Ändern dieser Eigenschaft wirkt sich erst nach dem nächsten Aufruf von ShowNotification aus.
SmallSystemIcon
Icon für Android-Versionen bis API-Level 22. Für mögliche Angaben siehe: System Notification Icons. Siehe auch Meta-Daten und Erscheinungsbild.
Ob das Icon angezeigt wird, ist abhängig von der Android-Version, vom Gerätehersteller und der Bedeutsamkeitsstufe des Benachrichtigungskanals.
Hinweis: Das Ändern dieser Eigenschaft wirkt sich erst nach dem nächsten Aufruf von ShowNotification aus.
StateIsPlaying
Liefert den Zustand der Benachrichtigung. true: Das Pause-Symbol () wird angezeigt. false: das Play-Symbol () wird angezeigt.
SupportFastForward
In der Benachrichtigung wird das Symbol für Fast Forward (>>) angezeigt.
Hinweis: Das Ändern dieser Eigenschaft wirkt sich erst nach dem nächsten Aufruf von ShowNotification aus.
SupportRewind
In der Benachrichtigung wird das Symbol für Rewind (<<) angezeigt.
Hinweis: Das Ändern dieser Eigenschaft wirkt sich erst nach dem nächsten Aufruf von ShowNotification aus.
SupportSkipToNext
In der Benachrichtigung wird das Symbol für Skip to next (>|) angezeigt.
Hinweis: Das Ändern dieser Eigenschaft wirkt sich erst nach dem nächsten Aufruf von ShowNotification aus.
SupportSkipToPrevious
In der Benachrichtigung wird das Symbol für Skip to previous (|<) angezeigt.
Hinweis: Das Ändern dieser Eigenschaft wirkt sich erst nach dem nächsten Aufruf von ShowNotification aus.
Version
Versionsname der Extension. Version für Kodular beginnen mit einem "K", z.B. "K1.0.0".
VersionSDK
Der API-Level der aktuell laufenden Android-Instanz.

Funktionen

FastForward ()
Löst das Ereignis OnFastForward aus. Schaltflächen auf der Benutzeroberfläche können über diese Funktion das gleiche Ereignis (und so auch den gleichen Code) wie das Antippen der Media-Schaltfläche Fast Forward auslösen.
GetAppDataDir ()
Liefert den Pfad für das app-spezifische Verzeichnis. Der Aufruf von GetAppDataDir() auf meinem Testgerät für das Beispiel-Programm liefert folgendes Ergebnis:
     /data/user/0/appinventor.ai_bienonline.UrsMediaNotificationAI2
GetDownloadDir (Prefix)
Liefert den Pfad für das Download-Verzeichnis. Der bei Prefix angegebene wird den Namen vorangestellt. Der Aufruf von GetDownloadDir("file://") auf meinem Testgerät für das Beispiel-Programm liefert folgendes Ergebnis:
     file:///storage/emulated/0/Download
GetDuration (Source)
Liefert die Spieldauer der angegeben Media-Datei in Millisekunden. Wie der Parameter Source beschickt werden kann, wird im Abschnitt Meta-Daten und Erscheinungsbild näher erläutert.
Wenn die Media-Datei nicht analysiert werden kann, wird das Ereignis Screen.ErrorOccurred mit der Fehlernummer 17505 ausgelöst.
GetDurationString (Source)
Liefert die Spieldauer der angegeben Media-Datei im Format H:MM:SS. Wie der Parameter Source beschickt werden kann, wird im Abschnitt Meta-Daten und Erscheinungsbild näher erläutert.
Wenn die Media-Datei nicht analysiert werden kann, wird das Ereignis Screen.ErrorOccurred mit der Fehlernummer 17505 ausgelöst.
GetVolumes (Prefix)
Liefert eine Liste der installierten Speicher (Volumes). Unter Index 1 findest man meist den internen Speicher, unter Index 2 die externe SD-Karte. Der bei Prefix angegebene wird den Namen vorangestellt. Der Aufruf von getVolumes("file://) gibt auf meinem Testgerät folgende Elemente:
     file:///storage/emulated/
     file:///storage/F277-0260/
HideChannel ()
Versteckt den Channel. Erst ab API Level 26!
Wenn ein neuer Kanal mit derselben ID erstellt wird, wird der gelöschte Kanal mit allen Einstellungen wieder hergestellt, die er vor dem Löschen hatte.
Pause ()
Löst das Ereignis OnPause aus. Schaltflächen auf der Benutzeroberfläche können über diese Funktion das gleiche Ereignis (und so auch den gleichen Code) wie das Antippen der Media-Schaltfläche Pause auslösen.
Play ()
LLöst das Ereignis OnPlay aus. Schaltflächen auf der Benutzeroberfläche können über diese Funktion das gleiche Ereignis (und so auch den gleichen Code) wie das Antippen der Media-Schaltfläche Play auslösen.
Rewind ()
Löst das Ereignis OnRewind aus. Schaltflächen auf der Benutzeroberfläche können über diese Funktion das gleiche Ereignis (und so auch den gleichen Code) wie das Antippen der Media-Schaltfläche Rewind auslösen.
SetMetaData (Title, Artist, AlbumImage)
Die Meta-Daten werden an die Benachrichtigung übergeben. Wie der Parameter AlbumImage beschickt werden kann, wird im Abschnitt Meta-Daten und Erscheinungsbild näher erläutert.
Wenn das Album-Image nicht geladen werden kann, wird das Ereignis Screen.ErrorOccurred mit der Fehlernummer 17500 ausgelöst. Die Meta-Daten werden ohne ein Album-Image angelegt.
Hinweis: Das Ändern dieser Daten wirkt sich erst nach dem nächsten Aufruf von ShowNotification aus.
SetMetaDataEx (Title, Artist, AlbumImage, Duration)
Die Meta-Daten werden an die Benachrichtigung übergeben. Wie der Parameter AlbumImage beschickt werden kann, wird im Abschnitt Meta-Daten und Erscheinungsbild näher erläutert.
Wenn das Album-Image nicht geladen werden kann, wird das Ereignis Screen.ErrorOccurred mit der Fehlernummer 17500 ausgelöst. Die Meta-Daten werden ohne ein Album-Image angelegt.
Hinweis: Das Ändern dieser Daten wirkt sich erst nach dem nächsten Aufruf von ShowNotification aus.
SetStatePaused ()
Die Benachrichtigung erhält den Status Pause. Das Play-Symbol () wird angezeigt.
Hinweis: Das Ändern dieser Daten wirkt sich erst nach dem nächsten Aufruf von ShowNotification aus.
SetStatePlaying ()
Die Benachrichtigung erhält den Status Play. Das Play-Symbol () wird angezeigt.
Hinweis: Das Ändern dieser Daten wirkt sich erst nach dem nächsten Aufruf von ShowNotification aus.
ShowNotification ()
Die Benachrichtigung wird angezeigt. Wenn die ForegroundService eingeschaltet ist, wird in der kompilierten App ein Foreground-Service gestartet (nicht im Companion). Für mögliche Fehler siehe Abschnitt Fehlerbehandlung.
ShowWithProgressBar (CurrentPosition)
Die Benachrichtigung wird angezeigt. Unter Android 10 und folgende wird, wenn über SetMetaDataEx die Spieldauer (Duration) übermittelt wurde, ein Fortschrittsbalken angezeigt. Die Position der Fortschrittsmarkierung von aus den Angabe zu CurrentPosition in Relation zu Duration ermittelt.
Wenn die ForegroundService eingeschaltet ist, wird in der kompilierten App ein Foreground-Service gestartet (nicht im Companion). Für mögliche Fehler siehe Abschnitt Fehlerbehandlung.
SkipToNext ()
Löst das Ereignis OnSkipToNext aus. Schaltflächen auf der Benutzeroberfläche können über diese Funktion das gleiche Ereignis (und so auch den gleichen Code) wie das Antippen der Media-Schaltfläche Skip to next auslösen.
SkipToPrevious ()
Löst das Ereignis SkipToPrevious aus. Schaltflächen auf der Benutzeroberfläche können über diese Funktion das gleiche Ereignis (und so auch den gleichen Code) wie das Antippen der Media-Schaltfläche Skip to previous auslösen.
Stop ()
Löscht die Benachrichtigung. Ein ggf. aktivierter Foreground-Service wird gestoppt.

Ereignisse

OnClick ()
Die Benachrichtigung wurde angeklickt. Nur aktiv, wenn Eigenschaft ClickAble eingestellt ist
OnFastForward (FromNotification)
Das Symbol Fast Forward (>>) in der Benachrichtigung wurde angeklickt (FromNotification = true) oder die Funktion FastForward wurde aufgerufen (FromNotification = false).
OnPause (FromNotification)
Das Symbol Pause () in der Benachrichtigung wurde angeklickt (FromNotification = true) oder die Funktion Pause wurde aufgerufen (FromNotification = false).
OnPlay (FromNotification)
Das Symbol Play () in der Benachrichtigung wurde angeklickt (FromNotification = true) oder die Funktion Play wurde aufgerufen (FromNotification = false).
OnRewind (FromNotification)
Das Symbol Rewind (<<) in der Benachrichtigung wurde angeklickt (FromNotification = true) oder die Funktion Rewind wurde aufgerufen (FromNotification = false).
OnSkipToNext (FromNotification)
Das Symbol Skip to next (>|) in der Benachrichtigung wurde angeklickt (FromNotification = true) oder die Funktion SkipToNext wurde aufgerufen (FromNotification = false).
OnSkipToPrevious (FromNotification)
Das Symbol Skip to previous (|<) in der Benachrichtigung wurde angeklickt (FromNotification = true) oder die Funktion SkipToPrevious wurde aufgerufen (FromNotification = false).
OnStop (FromNotification)
Die Funktion Stop wurde aufgerufen (FromNotification = false). Ein evtl. aktiver Foreground-Service wurde gestoppt.
UserCanceled ()
Der Anwender hat die Benachrichtigung gelöscht. Nur aktiv, wenn Eigenschaft DeleteAble eingestellt und kein Foreground-Service aktiv ist. Ein aktiver Foreground-Service verbietet das Löschen der zugehörigen Benachrichtigung.

Beispiel

Das Download-Archiv enthält ein Beispiel-Projekt in zwei Versionen, je eine für App Inventor und Kodular:

 UrsMediaNotification

Das Download-ZIP-Archiv enthält im Verzeichnis example je eine Beispielprojektdatei für App Inventor (UrsMediaNotification.aia) und für Kodular (UrsMediaNotificationK.aia).

Das Beispiel demonstriert, wie ein Mediaplayer mit der Extension gesteuert werden kann. Als Player wird der TaifunPlayer verwendet. Es können vier verschiedene Musikstücke abgespielt werden.

In Kodular können die Fonts der Schaltflächen individuell eingestellt werden. U.a. steht dort der Material Icons Font mit vielen nützlichen Symbolen von Google zur Verfügung. Für den App Inventor wird die Extension MyFonts von Anke benutzt.

Die Benutzeroberfläche

Steuerelemente

Die Steuerelemente werden je nach aktuellen Zustand der App freigegeben oder gesperrt. Sie bewirken

Die zugehörige MediaNotification dupliziert diese Steuerelemente. Es werden nur die freigegeben Elemente angezeigt (Off Broadway ist das letzte Stück in der Playlist, SkipToNext ist deshalb gesperrt und wird nicht angezeigt):

  (Screenshot Xiaomi Redmi 5 Plus, Android Oreo 8.1)

Die Anzeige eines Stoppsymbols steht in der Android Media-Notification leider nicht zur Verfügung.

In Android 10 wird die Hintergrundfarbe automatisch an die Farbe des Album-Bildes angepasst.

(Screenshot Google Pixel 2 XL API 30 Emulator)

Ein Fortschrittsbalken (ab Android 10) wird eingeblendet, wenn man die Notification aufzieht:

Optionen

Zum Verständnis der Implementierung

Die Prozedur SetMusic füllt die Extension mit den Metadaten (Titel, Interpret, Album-Bild).

Bei der Initialisierung wird dafür gesorgt, dass die App gleich zu Beginn korrekt arbeitet. SetMusic stellt die Metadaten und die Musikquelle für den TainfunPlayer auf das erste Musikstück ein. Mit der Kombination MediaPlayer.Start und MediaPlayer.Pause wird erreicht, dass die Eigenschaften Duration und CurrentPosition des Mediaplayers abgerufen werden können, ohne dass er anfängt zu spielen. MediaNotification.SetStatePaused und MediaNotification.ShowNotification zeigen die Notification im Zustand Pause (Symbol ) an. WakeLock.RequestBatteryOptimization setzt die App auf die WhiteList. Beim ersten Start der App erhält der Anwender eine Anfrage, die Erlaubnis hierzu anfordert.

Bei der Änderung der Option WithForegroundService muss ein ggf. bereits gestarteter Foreground-Service mit der Anweisung MediaNotifiaction.Stop gestoppt werden. Diese Anweisung löst das Ereignis OnStop aus. Im Normalfall wird in diesem Ereignis der MediaPlayer gestoppt. Damit dies jedoch nicht beim Umschalten der Option geschieht, wird dies mit Hilfe der Variablen DontStopPlayer verhindert.

Beim Weiterschalten zum nächsten Musikstück (SkipToNext) und beim Zurückschalten (SkipToPrevious) wird zunächst der der aktuelle Zustand des Mediaplayers in einer lokalen Variablen zwischengespeichert. Dieser soll nach dem Umschalten wieder hergestellt werden. Danach wird der Player gestoppt. Das nächste (das vorhergehende) Musikstück wird ermittelt und dabei dem Zustand der Playlist entsprechenden Schaltflächen freigegeben bzw. gesperrt. Die Blöcke werden über die Prozedur SetMusic mit den Daten des neu ausgewählten Musikstücks gefüttert. Zum Schluss werden entsprechend des gespeicherten Player-Zustands die Ereignisse OnPlay bzw. OnPause ausgelöst. In den Ereignissen wird dafür gesorgt, dass der Mediaplayer und die MediaNotification passen eingestellt werden.

Erstellen der Extension

Die Extension verwendet viele Android-Klassen aus der Androidx-Bibliothek. Die Bibliothek steht unter App Inventor nur Teilweise und unter Kodular gar nicht zur Verfügung. Für die beiden Versionen müssen deshalb unterschiedliche Bibliotheken zusätzlich eingebunden werden.

Die Extension kann zusammen mit der UrsAI2WakeLock-Entension verhindern, dass der Doze-Modus zuschlägt und das Smartphone abschaltet. Dazu wird ein ForegroundService gestartet. Dieser Service muss in der Manifest-Datei der App deklariert werden. Im App Inventor geht dies, Kodular hat noch nicht nachgezogen. Hier muss die erstellte .aix-Datei nachträglich gepacht werden.

Die folgende Beschreibung setzt voraus, dass die Entwicklungsumgebung nach dem in AI2 FAQ: Extensions entwickeln beschriebenen Schema eingerichtet wurde.

Bei Verzeichnisangaben in den folgenden Abschnitten muss <user> stets durch den entsprechenden Namen ersetzt werden!

Bereitstellen der Bibliotheken

Das ZIP-Archiv enthält im Verzeichnis de.ullisroboterseite neben den Verzeichnissen für den Source-Code der Extension auch zwei Androidx-Bibliotheksdateien: androidx.core-1.3.2-runtime.jar und androidx.media-1.3.1-runtime. Kodular benötigt beide Dateien, App Inventor nur androidx.media-1.3.1-runtime. androidx.core ist dort vorhanden (leider veraltet oder nicht vollständig).

Kopieren der Bibliotheken

Damit die Bibliotheken in die Extension eingebunden werden, müssen sie in das vorgesehene Verzeichnis kopiert und im Source-Code deklariert werden.

Beim Kopieren wird nicht zwischen den beiden Versionen unterschieden. Es werden beide Bibliotheken in das Zielverzeichnis kopiert. Das Kopieren geschieht über das Build-Script. Dazu muss in der Datei

C:/Users/<user>/appinventor-sources/appinventor/components/build.xml

folgende Einträge in der Rubrik CopyComponentLibraries

<copy toFile="${public.deps.dir}/androidx.media.jar"      file="C:/Users/<user>/appinventor-sources/appinventor/components/src/de/ullisroboterseite/androidx.media-1.3.1-runtime.jar"/>

und

<copy toFile="${public.deps.dir}/androidx.core.jar"     file="C:/Users/<user>/appinventor-sources/appinventor/components/src/de/ullisroboterseite/androidx.core-1.3.2-runtime.jar"/>

Deklaration in den Quellen

In der App-Inventor-Version wird die Media-Bibliothek über die Annotation @UsesLibraries deklariert und der Foreground-Service über Annotation @UsesServices:

@UsesServices(services = {
        @ServiceElement(name = "de.ullisroboterseite.ursai2medianotification.ForegroundService", enabled = "true", exported = "false") })
@UsesLibraries(libraries = "androidx.media.jar")

In der Kodular-Version müssen beide Bibliotheken deklariert werden. Die Deklaration des Foreground-Services ist wirkungslos, erleichtert aber das Patchen der kompilierten Extension.

Die Umgebung ist nun so weit vorbereitet, dass die Extension kompiliert werden können.

Pachten der .aix-Dateien für Kodular

Der Build-Vorgang erstellt die Datei de.ullisroboterseite.ursai2medianotificationK.aix (man achte auf das "K" am Ende des Namens). Diese Datei hat das Format einer ZIP-Datei, kann also mit einem entsprechenden Programm geöffnet und bearbeitet werden. Gegebenenfalls hilft es die Datei in ...zip umzubenennen.

Die .aix-Datei enthält den Ordner de.ullisroboterseite.ursai2medianotificationK und darunter den Ordner files. Im Ordner files befinden sich die beiden Dateien component_build_info.json und component_build_infos.json. Beide können mit einem einfachen Texteditor geöffnet und bearbeitet werden. In beiden Dateien befindet sich der Eintrag

"services":["<service android:name=\"de.ullisroboterseite.ursai2medianotificationK.ForegroundService\" android:enabled=\"true\" android:exported=\"false\">\n <\/service>\n"]

und der Eintrag

"broadcastReceivers":[]

Der Text zwischen den eckigen Klammern bei services muss in die eckigen Klammern bei broadcastReceivers kopiert werden:

"broadcastReceivers":["<service android:name=\"de.ullisroboterseite.ursai2medianotificationK.ForegroundService\" android:enabled=\"true\" android:exported=\"false\">\n <\/service>\n"]

Falls die Dateien zum Bearbeiten aus dem ZIP-Archiv extrahiert wurden, müssen sie nun wieder in das Archiv (die .aix-Datei) einkopiert werden.

Portieren eines Projekts vom App Inventor nach Kodular

Dazu wird zunächst im App Inventor das Projekt als .aia-Datei exportiert. Diese Datei hat das Format einer ZIP-Datei, kann also mit einem entsprechenden Programm geöffnet und bearbeitet werden. Gegebenenfalls hilft es die Datei in ...zip umzubenennen.

Im Zip-Archiv befindet sich der Ordner assets/external_comps. In diesem Order sind die ins Projekt eingebunden Extensions enthalten.

Der Ordner de.ullisroboterseite.ursai2medianotification wird gelöscht. Stattdessen wird der Inhalt der Extension de.ullisroboterseite.ursai2medianotificationk.aix an diese Stelle kopiert (gleichnamiger Ordner). Anschließend kann die .aia-Datei nach Kodular importeiert werden. Die Bezeichnung in beiden Extension sind gleich, so dass dies keine Probleme macht.

Werkzeuge

Für die Erstellung eigener Extensions habe ich einige Tipps zusammengestellt: AI2 FAQ: Extensions entwickeln.