Version | Anpassungen |
---|---|
1.0 (2025-09-12) | Initiale Version |
Bei App-Inventor-Projekten liefern die Sensoren keine Werte, wenn sich die App nicht mehr im Vordergrund befindet. Mithilfe dieser Erweiterung wird ein ForegroundService installiert, über den Sensordaten generiert werden können – selbst dann, wenn die App vollständig in den Hintergrund gelangt oder, in Kombination mit einem WakeLock, der Bildschirm ausgeschaltet wird.
Inhaltsverzeichnis
Berechtigung für Benachrichtigungen
Beschleunigungssensor (Accelerometer)
Hinweis: Die Extension ist wegen des notwendigen ForegroundService ggf. nicht für eine Mehrfachinstanziierung geeignet. Deshalb sollte man nur eine Instanz der Extension in der gesamten App verwenden.
Das ZIP-Archiv UrsAI2Sensor zum Download. Das Archiv enthält den Quellcode, das kompilierte Binary zum Upload in den App Inventor und eine Beispiel-Anwendung.
Die Extension kapselt in der aktuellen Version den Beschleunigungssensor (Accelerometer) und eine Schütteldetektor (Shakingsensor). Weitere Sensoren werden nach und nach eingebunden werden.
Um Sensordaten zu erhalten, wenn die App im Hintergrund ausgeführt wird oder wenn der Bildschirm ausgeschaltet wird, ist es notwendig einen WakeLock anzufordern, in Kombination mit der Einrichtung eines ForegroundService.
Der App-Inventor-Companion besitzt leider nicht die Berechtigungen, einen WakeLock anzufordern oder einen ForegroundService einzurichten. Dazu muss die App kompiliert werden. Das ist sehr umständlich, wenn man i.W. die Sensorfunktionen testen will. Der ForegroundService wird deshalb nur auf Anforderung durch die Funktion StartForegroundService angelegt.
Wenn der ForegroundService nicht eingerichtet wird, werden die Sensordaten direkt über die Extension geliefert. Damit funktionieren die Sensorfunktionen auch mit dem Companion. Das erleichtert den Test erheblich. Allerdings setzt die Datenerzeugung aus, wenn sich die App (d.h. der Companion) nicht mehr im Vordergrund befindet.
Wenn der ForegroundService eingerichtet ist, werden die Sensordaten dort angeliefert und an die Extension weiter gegeben. Man erhält Sensordaten auch dann, wenn sich die App nicht mehr im Vordergrund befindet. Ist ein WakeLock aktiviert, werden auch dann Daten generiert, wenn der Bildschirm ausgeschaltet ist. Dazu muss die App jedoch kompiliert werden.
Der ForegroundService kann über die Funktion StopForegroundService wieder gestoppt werden.
Bereits gestartete Sensoren werden beim Aufruf der Funktionen StartForegroundService oder StopForegroundService gestoppt. Wenn der ForegroundService gestartet wurde, wird dies über das Ereignis AfterServiceStarted angezeigt.
Ob die App im Companion läuft, also kein ForegroundService möglich ist, kann über die Eigenschaft IsRunningInCompanion abgefragt werden.
Hinweis: Im Zuge der Android-Weiterentwicklung hat sich die Implementierung von Benachrichtigungen mehrfach erheblich geändert. Außerdem gibt es Abhängigkeiten vom Gerätemodell.
Der ForegroundService muss zwingend (und auch sinnvollerweise) mit einer Benachrichtigung (Notification) versehen sein. Diese wird bei der Einrichtung des ForegroundService angelegt.
In neueren Android-Versionen (ab Android 14?) sind Benachrichtigungen nicht automatisch aktiviert, bzw. können vom Benutzer deaktiviert werden. Dies gilt auch für die Benachrichtigungen, die an einen ForegroundService gebunden sind. Der ForegroundService zur Sensordatenermittlung ist i.d.R. mit einem WakeLock verbunden, der verhindert, dass die CPU ausgeschaltet wird. Somit werden auch dann Sensordaten geliefert, wenn der Bildschirm des Smartphones ausgeschaltet wird. Das ist m.E. ein unglückliche Entwicklung, da fortlaufend der Akku belastet wird, ohne das der Anwender davon etwas erfährt.
Ob der Anwender die Berechtigung zur Anzeige von Benachrichtigung für die App erteilt hat, kann über die Eigenschaft HasPostPermission abgefragt werden. Diese fragt aber nur die generelle Berechtigung ab, ob die App Benachrichtigungen anzeigen darf. Der Anwender kann immer noch die Berechtigung für einen speziellen Kanal entziehen. Hier habe ich leider nicht herausgefunden, wie man das Anfragen kann.
Die Extension kann die Berechtigung, Benachrichtigungen zu senden, über die Funktion RequestNotificationPermission anfordern. Das Ergebnis wird über das Ereignis OnPermissionResponse zurück geliefert. In der Anleitung zu der App sollte unbedingt auf den Grund der Abfrage hingewiesen werden. Das Beispielprojekt zeigt, wie so etwas funktionieren könnte.
Kanalspezifische Berechtigungsvergabe für die Beispiel-App bei einem Motorola g15, deutsche Version.
Ab Android 15 (?) kann der Anwender auch dann Benachrichtigungen löschen, wenn sie mit einem ForegroundService verbunden sind. Dies hat keinen Einfluss auf die Funktion der Services. Die App läuft auch im Hintergrund weiter. Wenn die Eigenschaft NotificationDeletable auf false gesetzt ist, generiert die Extension eine neue Benachrichtigung, wenn sie gelöscht wurde.
Eine Benachrichtigung muss einem Benachrichtigungskanal (NotificationChannel) zugeordnet werden. Dieser wird bereits bei der ersten Instanziierung der Extension angelegt, d.h. beim ersten Start der kompilierten App mit dieser Extension. Beim Betrieb im Companion werden kein Benachrichtigungskanal und demzufolge auch keine Benachrichtigung angelegt.
Jeder Benachrichtigungskanal besitzt eine eindeutige Kennung, die zur Android-internen Identifizierung des Kanals dient. Diese Kennung (Eigenschaft ChannelID) wird durch die Extension festgelegt und kann nicht nachträglich geändert werden.
Ebenfalls wird die Bedeutsamkeit der Kanals (Eigenschaft ChannelImportance) bei der ersten Instanziierung der Extension festgelegt und kann nicht nachträglich geändert werden.
Die Bezeichnung des Kanals (Eigenschaft ChannelName) und die Kanalbeschreibung (Eigenschaft ChannelDescription) können nachträglich geändert werden.
Der Benachrichtigungston wird explizit abgeschaltet.
Ob die App im Companion läuft, also keine Benachrichtigung vorgesehen ist, kann über die Eigenschaft IsRunningInCompanion abgefragt werden.
Die Benachrichtigung (Notification) wird angezeigt, wenn der ForegroundService gestartet wird und wieder gelöscht, wenn der Service gestoppt wird. Ob im konkreten Fall eine Benachrichtigung angezeigt wird, hängt davon ab, ob die App die dazu notwendigen Berechtigungen besitzt (siehe auch Abschnitt Berechtigung für Benachrichtigungen).
Jede Benachrichtigung besitzt eine eindeutige ID-Nummer. Diese wird von der Extension festgelegt und kann über die Eigenschaft NotificationID abgefragt werden.
Die Gestaltung der Benachrichtigung geschieht über die Eigenschaften NotificationTitle, NotificationText, NotificationIcon bzw. NotificationIconAsset, NotificationLargeIcon. Hinzu kommen evtl. bis zu drei Aktionsschaltflächen, die über die Eigenschaften Action1Title, Action2Title und Action3Title definiert werden. Es werden nur die Schaltflächen angezeigt, zu denen ein Wert angegeben wurde.
Mit NotificationDeletable kann man steuern, ob der Anwender die Benachrichtigung löschen darf. Das Verhalten der Benachrichtigungen halt im Laufe der verschiedenen Android-Versionen deutlich verändert. Außerdem besteht eine Abhängigkeit von der konkreten Implementierung von Android durch die Hersteller (siehe auch Abschnitt Berechtigung für Benachrichtigungen). Je nach Android-Version ist das Löschen einer Benachrichtigung, die mit einem ForegroundService verbunden ist, nicht möglich, kann über NotificationDeletable verboten werden oder bewirkt, dass die Benachrichtigung nach dem Löschen neu erzeugt wird. Voraussetzung ist, dass der Anwender in den neueren Android-Versionen die Berechtigung zum Senden von Benachrichtigungen erteilt hat. In den neueren Versionen wird je nach Stellung von NotificationDeletable die Benachrichtigung neu erzeugt oder das Ereignis OnDeleteNotification ausgelöst.
Mit der Eigenschaft ScreenToOpen wird festgelegt, was beim Antippen der Benachrichtigung geschehen soll. Wenn der Wert leer bleibt, passiert nichts, wenn die Benachrichtigung angetippt wird. Ansonsten wird der angegebene Screen geöffnet. Wenn der Screen neu geöffnet wird, kann über die Eigenschaft StartValue ein Startwert mitgegeben wird, der über die Methode Control.get start value abgefragt werden kann.
Jede Benachrichtigung kann mit bis zu drei Aktionsschaltflächen versehen werden. Diese werden durch die Eigenschaften Action1Title, Action2Title und Action3Title angefordert und definiert. Wird eine dieser Schaltflächen angetippt, wird das Ereignis OnActionClick ausgelöst. Die dabei übergebene Aktionsnummer bezieht sich auf die Nummer in Action?Title.
Unter Umständen ist es wichtig zu wissen, in welchem (Lebenszyklus-) Zustand sich die App befindet. Deshalb sind einige Ereignisse herausgeführt, die Änderungen des Zustands anzeigen. Diese sind:
Diese Extension hat wegen des notwendigen und gemeinsam genutzten ForegroundService ein allgemeines Interface, dass von allen Sensoren genutzt wird. Dies entspricht im Wesentlichen der Konzeption des Android-Sensor-API. Einzelne Parameter der zum Sensor-API gehörenden Methoden und Ereignissen haben bei den verschiedenen Sensortypen unterschiedliche Bedeutungen. Diese werden in den nachfolgen Kapiteln im Detail erläutert.
Die verfügbaren Sensortypen sind als Auswahlliste implementiert. Diese und weitere Auswahlparameter stehen im App Inventor als einzelne Elemente zur Verfügung und können in den Funktionen und Ereignissen verwendet werden:
Ob ein bestimmter Sensor auf dem Gerät verfügbar ist, kann über die Funktion GetAvailable abgefragt werden. Die mögliche Rate, mit der Sensordaten geleifert werden können, kann über die Funktionen GetMinDelay und GetMaxDelay abgerufen werden. Die konkrete Rate wird beim Start des Sensors in der Funktion StartSensor festgelegt.
Ein Sensor wird mit der Funktion StartSensor gestartet. Der erste Parameter SensorType gibt an, welcher der möglichen Sensoren gestartet werden soll. Der zweite Parameter Delay gibt den Zeitraum zwischen zwei SensorChanged-Ereignissen in μs an und sollte einen Wert zwischen GetMinDelay und GetMaxDelay haben. Werte außerhalb dieses Bereichs werden durch die Werte von GetMinDelay bzw GetMaxDelay ersetzt. Control ist eine Liste mit weiteren Steuerungsdaten für den spezifizierten Sensor. Diese werden in den Kapiteln zu den einzelnen Sensoren im Detail beschrieben.
Ein bestimmter Sensor wird mit der Funktion StopSensor wieder gestoppt. StopAllSensors stoppt alle laufenden Sensoren.
Wenn ein Sensor gestartet ist, wird in den den festgelegten Abständen das Ereignis SensorChanged ausgelöst. Dieses Ereignis übermittelt welcher Sensor das Ereignis (Parameter SensorType) getriggert hat, eine Liste mit den Sensordaten (Parameter Data) und eine Angabe über die Präzision der Werte (Parameter Accuracy). Data und Accuracy sind abhängig vom Sensortyp und werden in den folgenden Kapiteln im Detail beschrieben.
Die Sensordaten können auch asynchron, d.h. unabhängig vom Ereignis SensorChanged, abgerufen werden. Die Funktion HasValidReadings gibt an, ob bereits gültige Werte vorliegen. GetValues liefert dann eine Liste der zuletzt ermittelten Messwerte.
Der Beschleunigungssensor (Accelerometer) misst Beschleunigung in drei Dimensionen unter Verwendung von SI-Einheiten (m/s²).
Parameter SensorType: Accelerometer
Parameter Control: Keine weiteren Angaben erforderlich (leere Liste).
Parameter Accuracy: Angaben zur Präzision der Werte: Low (1), Medium (2), High (3)
Parameter Data, Rückgabe von GetValues: Eine Liste mit folgenden Angaben
Der Erschütterungssensor (Shaking Sensor) erkennt das Schütteln des Telefons. Das Schütteln löst das Ereignis SensorChanged aus. Messwerte werden nicht übergeben. Die Funktion GetValues liefert eine leere Liste.
Parameter SensorType: ShakingSensor
Parameter Control: Eine Liste mit einem Element, das Angaben zur Empfindlichkeit (Sensivity) macht. Mögliche Angaben sind:
Parameter Accuracy: Angaben zur Präzision der Werte: Meaningless (0)
Parameter Data, Rückgabe von GetValues: Eine leere Liste.
![]() |
Beispielprojekt |
Das Beispielprojekt versucht alle wesentlichen Features der Extension darzustellen. Es sind drei Screens implementiert:
Screen1 besteht aus mehreren Bereichen. Zum besseren Überblick sind diese farblich hinterlegt.
Angezeigt werden: ein evtl. Startwert, die Version der Extension und der Wert der Eigenschaft HasPostPermission. Die Werte werden im Ereignis Screen1.Initialize ermittelt. HasPostPermission wird im Ereignis OnPermissionResponse angepasst.
Dieser Bereich wird im nicht im Companion angezeigt, da dort kein ForegroundService angelegt werden kann. In der kompilierten App wird er angezeigt, wenn die Berechtigung zum Senden von Benachrichtigungen nicht erteilt sind. Der angezeigte Text lautet vollständig "You must grant permission to post notifications for the app to work correctly.".
Über die Schaltfläche cmdRequestPermission (Request Permission) wird über die Funktion RequestNotificationPermission ein Dialog zur Erteilung der Berechtigung geöffnet.
Dieser Bereich steht im Companion nicht zur Verfügung, da dort kein ForegroundService angefordert werden kann. In der kompilierten App erscheint er nur, wenn die Berechtigung zum Senden von Benachrichtigungen erteilt wurde.
Man kann den ForegroundService starten, inkl. der oben gezeigten Benachrichtigung und einem WakeLock, und auch wieder stoppen. Die Sensoren müssen danach neu gestartet werden. Bei laufendem ForegroundService werden die Sensoren über diesen abgefragt und liefern auch dann Ergebnisse, wenn die App in den Hintergrund gelangt oder der Bildschirm ausgeschaltet wird. Um das zu verifizieren, werden über den Timer tmSend bei gestartetem Beschleunigungssensor dessen Daten per UDP an die Broadcast-Adresse 255.255.255.255, Port 2222 gesendet.
Das Verhalten der Benachrichtigung kann angepasst werden. Wenn die Benachrichtigung angezeigt wird, kann über die Schaltfläche cmdAlterNotification (Alter Notification Title) die Überschrift der Benachrichtigung in "Altered Title" abgeändert. Über die Schaltfläche cmdAlterChannel kann gezeigt werden, dass man den Namen des Benachrichtigungskanals nachträglich ändern kann. Der neue Name ist dann "New Channel".
Wird eine der Aktionsschaltflächen in der Benachrichtigung angetippt, wird dessen Nummer kurz im Label lblActionButton angezeigt. Über den Timer tmClearActionMsg wird die Anzeige nach drei Sekunden wieder gelöscht.
In diesem Bereich werden die Daten des Beschleunigungssensors angezeigt. Wenn der Sensor gestartet wurde, die Messdaten des Ereignisses SensorChanged in der eingestellten Rate im Label lblFromEventAcc angezeigt. Außerdem wird, gesteuert über den Timer tmSend, die aktuellen Messwerte im Sekundentakt über die Funktion GetValues abgerufen und im Label lblFromReadingAcc angezeigt. Zusätzlich werden die Daten per UDP an die Broadcast-Adresse 255.255.255.255, Port 2222 gesendet.
Wenn der Schüttelsensor gestartet wurde und das Gerät geschüttelt wird, wird der Bildschirmhintergrund für kurze Zeit farbig geschaltet. Über den Timer tmResetBgColor erhält er nach ca. einer Sekunde wieder sein ursprüngliche Farbe.
Für die Erstellung einer eigenen Extension habe ich einige Tipps zusammengestellt: AI2 FAQ: Extensions entwickeln.