Version | Anpassungen |
---|---|
1.0 (2020-04-16) | Initiale Version |
2.0 (2020-04-29) | - Ermöglicht die Auswertung von Start- und Rückgabe-Werten - Start als eigenständiger oder abhängiger Prozess |
2.1 (2020-06-03) | MyAppName, MyPackageName hinzugefügt |
2.2 (2021-04-21 |
Bei Geräten ab Android 10 und Geräten von Xiaomi gab es Probleme (siehe Hinweise). Folgende Eigenschaften wurden hinzugefügt: CanDrawOverlays, CanLaunchFromBackground,CurrentLanguage, IsXiaomi, Manufacturer, PermissionDelay, VersionName, VersionSDK Folgende Methoden wurden hinzugefügt: CheckBackgroundLaunchPermission, LaunchAppFromIntent, LaunchForResultFromIntent, OpenMiuiPermissionEditor Das Ereignis AfterBackgroundPermssion wurde hinzugefügt. Folgende Permission werden im Manifest zusätzlich angefordert: SYSTEM_ALERT_WINDOW & ACTION_MANAGE_OVERLAY_PERMISSION Der zusätzliche Block LauncherIntent bietet weitere Möglichkeiten, wie die zu startende App ausgeführt werden soll. |
2.3 (2021-05-12) | Das Starten einer AI2-App (Intent-Typ Screen) hat bei Kodular nicht funktioniert, wenn der Package Name geändert wurde. |
2.4 (2021-05-15) | Das Starten einer AI2-App (Intent-Typ Screen) hat bei Kodular nicht funktioniert, wenn der Package Name geändert wurde. Weitere Änderungen waren notwendig. |
2.5 (2021-05-13) | Eigenschaft FlagNewTask wurde beim Intent nicht korrekt
ausgewertet, wird für Android 10 aber benötigt. Voreinstellung für Eigenschaft FlagNewTask ist nun true. |
2.6 (2023-09-10) | Ab Android 11 ist die Permission QUERY_ALL_PACKAGES notwendig, wenn man alle Dateien in der Funktion getNameList oder getPackageList aufgeführt werden sollen. |
App Inventor ermöglicht es, andere Activities mit der ActivityStarter-Komponente zu starten. Leider ist das Starten von installierten Apps sehr umständlich. Gemäß Anleitung muss die .apk der zu startenden App herunter geladen und darin der Paket-Name heraus gefunden werden. Beides ist weder einfach, noch immer möglich.
Diese Extension vereinfacht das Starten von Apps.
Hinweis für Benutzer von Geräten mit Android 10 und aufwärts:
Seit Android 10 benötigt eine App zusätzliche Berechtigungen (SYSTEM_ALERT_WINDOW), wenn sie eine andere App starten will, während sie selbst im Hintergrund ausgeführt wird (siehe Restrictions on starting activities from the background, letzter Punkt). Diese Berechtigung kann nicht per Programm gesetzt werden, sondern muss von Anwender über einen Dialog bestätigt werden (s. Zusätzliche Berechtigungen ab Android 10 und bei Xiaomi-Geräten). Eine mögliche Lösung für das Problem wird im Beispiel vorgestellt.
Hinweis für Benutzer von Geräten des Herstellers Xiaomi:
Bei Xiaomi-Geräten wird, unabhängig von der installierten Android-Version, eine weitere Berechtigung benötigt, wenn eine App eine andere App starten will, während sie selbst im Hintergrund ausgeführt wird. Diese Berechtigung nicht per Programm gesetzt werden, sondern muss von Anwender über einen Dialog bestätigt werden (s. Zusätzliche Berechtigungen ab Android 10 und bei Xiaomi-Geräten). Es kann auch nicht per Programm abgefragt werden, ob diese Berechtigung bereits erteilt wurde. Eine mögliche Lösung für das Problem wird im Beispiel vorgestellt.
Benutzer von Xiaomi-Geräten mit der Android Version 10 und aufwärts müssen beide Berechtigungen erteilen.
Inhaltsverzeichnis
Zusätzliche Berechtigungen ab Android 10 und bei Xiaomi-Geräten
Datenaustausch zwischen zwei AI2-Apps
Das ZIP-Archiv UrsAI2AppLauncher zum Download. Das Archiv enthält den Quellcode, das kompilierte Binary zum Upload in den App Inventor und eine Beispiel-Anwendung.
Apps müssen über ihren Paketnamen (package name, z.B. "de.ullisroboterseite.ursai2applauncher") gestartet werden. Die Methode getNameList liefert eine Liste der Bezeichnungen aller Apps, die gestartet werden können. Um hier eine Vorauswahl zu treffen, kann ein Text zum Filtern der Liste angegeben werden. Es werden nur die Apps gelistet, deren Bezeichnung den angegeben Filtertext enthalten. Die Liste kann z.B. in einer ListPicker-Komponente präsentiert werden.
Die Methode PackageFromName liefert den zur App zugehörigen Paketnamen. Dieser kann dann dazu benutzt werden, die bezeichnete App zu starten.
Die zu startende App kann auf zwei Arten gestartet werden:
In beiden Fällen können der gestarteten App Startwerte mitgegeben werden.
Nach dem Start einer App wird das Ereignis AfterAppLaunched ausgelöst. Es gibt Auskunft darüber, ob der Start der App erfolgreich war.
Der Start einer App erfolgt in der Android-Welt über Intents. Ein Intent ist eine abstrakte Beschreibung einer auszuführenden Operation. Er dient u.a. zum starten von Apps. Der Intent enthält alle Informationen, die zum starten einer App benötigt werden und enthält auch die auszutauschenden Daten.
Austauschdaten zwischen Apps können dem Intent als sogenannte Extras übergeben werden. Extras sind eine Liste von Schlüssel-Werte-Paare. Die gestartete App kann diese Werte abrufen und auswerten.
Über die verschiedenen Varianten der Launch...-Methoden kann die zu startende App mit Startwerten versorgt werden.
Der folgende Abschnitt ist nur relevant bei als abhängig gestartete Apps. Nur diese können Werte zurück liefern.
Immer kann die aufgerufene App abgebrochen werden, ohne Ergebnisse zurück zu liefern. In diesem Fall wird nach Abbruch der aufgerufenen App das Ereignis ActivityCanceled ausgelöst.
Wurde die aufgerufene App regulär beendet, wird das Ereignis AfterActivity ausgelöst und es können Rückgabewerte übergeben werden. Diese werden, wie bei den Startwerten, intern als Schlüssel-Werte-Paare in einem Intent abgelegt. AI2 Apps können Rückgabewerte über die Blöcke close screen with value und close screen with plain text zur Verfügung stellen. AI2 stellt diesen Wert als Schlüssel-Werte-Paar mit dem Schlüssel "APP_INVENTOR_RESULT" in den Intent ein.
Die aufrufende App kann den zurückgelieferten Intent auswerten. Die Extension stellt die hierzu notwendigen Methoden bereit.
Android benutzt Intent-Objekte, um dem System Aufträge zu erteilen. Ein Intent enthält alle Angaben, die notwendig sind, den Auftrag auszuführen. Der AI2 ActivityStarter z.B. benutzt intern Intents um andere Apps zu starten.
Über ein LauncherIntent-Objekt (Referenz), dass den LaunchAppFromIntent- und LaunchForResultFromIntent-Funktionen übergeben wird, wird festgelegt, welche Aktion ausgeführt werden soll, wenn die Benachrichtigung angetippt wird.
Diese Komponente ist eine Sammlung von Eigenschaften. Sie besitzt weder Funktionen noch Ereignisse.
Der Aktionstyp (ActionType) bestimmt, welche Aktion mit dem Intent ausgelöst wird:
Hinweis: Benutzer von Xiaomi-Geräten mit der Android Version 10 und aufwärts müssen beide Berechtigungen erteilen!
Seit Android 10 benötigt eine App zusätzliche Berechtigungen (SYSTEM_ALERT_WINDOW), wenn sie eine andere App starten will, während sie selbst im Hintergrund ausgeführt wird (siehe Restrictions on starting activities from the background, letzter Punkt). Diese Berechtigung kann nicht per Programm gesetzt werden, sondern muss von Anwender über einen Dialog bestätigt werden.
Die Extension stellt die Funktion CheckBackgroundLaunchPermission bereit. Die Funktion prüft, ob die installierte Android Version einen API-Level von 29 (Android 10) oder höher hat und ob dann die Berechtigung SYSTEM_ALERT_WINDOW erteilt wurde. Falls es notwendig ist, dass diese Berechtigung noch erteilt wird, wird ein Dialog zum Erteilen der Berechtigung geöffnet:
Deutsche Variante | Englische Variante |
Das Ergebnis der Berechtigungsabfrage wird über das Ereignis AfterBackgroundPermssion zurück geliefert. Der neue Zustand der Berechtigung ist nicht sofort nach dem Schließen des Berechtigungsdialogs verfügbar. Das Ereignis wird deshalb erst nach einer kurzen Verzögerung (Eigenschaft PermissionDelay, Vorreinstellung 500 ms) nach dem Schließen des Dialogs ausgelöst. Während dieser Zeit ist der Zustand der Berechtigung undefiniert. Es empfiehlt sich, darauf zu achten, dass währenddessen keine unsinnigen Daten angezeigt werden oder problematische Eingabe gemacht werden können. Am besten stellt man alle betroffenen Bildschirmelemente in ein VerticalArrangement. Dieses kann man zeitweise unsichtbar schalten oder z.B. über die Funktion EnableArrangement der UrsAI2ComponentGroup Extension deaktivieren (s.u. Beispiel).
Zur detaillierten Behandlung dieser Berechtigung stehen zur weiterhin Verfügung:
Bei Xiaomi-Geräten wird, unabhängig von der installierten Android-Version, eine weitere Berechtigung benötigt, wenn eine App eine andere App starten will, während sie selbst im Hintergrund ausgeführt wird. Diese Berechtigung nicht per Programm gesetzt werden, sondern muss von Anwender über einen Dialog bestätigt werden (s. Zusätzliche Berechtigungen ab Android 10 und bei Xiaomi-Geräten). Erschwerend kommt hinzu, dass nicht per Programm abgefragt werden kann, ob diese Berechtigung bereits erteilt wurde.
Für die Behandlung dieser Problematik stehen folgende Elemente zur Verfügung:
Der Xiaomi-Berechtigungseditor:
Deutsche Variante | Englische Variante |
Das Beispielprojekt zeigt eine Möglichkeit, wie diese Berechtigungen behandelt werden können.
Man kann die Berechtigungen auch über die Settings-App vergeben. Dieser Blog-Eintrag zeigt wie es geht: Enable “display pop-up windows” on new Xiaomi phones. Eine andere Zugangsmöglichkeit: Lange auf das Symbol der App drücken, dann "App-Info" auswählen.
Block | Funktion | Anmerkung |
---|---|---|
App- und Package-Namen | ||
Liefert die Bezeichnungen der installierten und startfähigen Apps als alphabetisch sortierte
Liste von Texten. Über den Parameter Filter kann eine Vorauswahl getroffen werden. Es werden nur die Apps ausgeliefert, deren Namen den angegeben Text enthält. Wird eine leerer Text ("") angegeben, wird nicht gefiltert. Groß-/Kleinschreibung wird ignoriert. |
Der Filter wird mit der Java-Methode String.contains() ausgewertet. Vor der Auswertung werden Filterwert und App-Bezeichnung in per String.toLowerCase() in Kleinbuchstaben umgewandelt. | |
Liefert die Paketnamen der installierten und startfähigen Apps als alphabetisch sortierte
Liste von Texten. Über den Parameter Filter kann eine Vorauswahl getroffen werden. Es werden nur die Apps ausgeliefert, deren Namen den angegeben Text enthält. Wird eine leerer Text ("") angegeben, wird nicht gefiltert. Groß-/Kleinschreibung wird ignoriert. |
Der Filter wird mit der Java-Methode String.contains() ausgewertet. Vor der Auswertung werden Filterwert und App-Bezeichnung in per String.toLowerCase() in Kleinbuchstaben umgewandelt. | |
Liefert den Paketnamen (package name) der App deren Bezeichnung im Parameter AppName übergeben wurde. | Es wird einen leerer Text ("") zurück geliefert, wenn kein Paketname ermittelt werden konnte. | |
Liefern den Namen der eigenen App bzw. deren Paketnamen. | ||
App starten | ||
Startet die App mit dem angegebenen Paketnamen entweder als eigenständiger oder als abhängiger Prozess (s.o.). | Der Erfolg dieser Aktion wird über den Event AfterAppLaunched (s.u.) mitgeteilt. | |
Startet die App mit dem angegebenen Paketnamen entweder als eigenständiger oder als abhängiger
Prozess (s.o.). StartValue: Der an die zu startende App zu übergebene Startwert. |
AI2 wertet den Schlüssel "APP_INVENTOR_START" aus und stellt den zugehörigen Wert
über die Methode
getStartValue
bzw.
getPlainStartText
zur Verfügung. getStartValue erlaubt die Übergabe beliebiger Objekte, auch Listen. |
|
Startet die App mit dem angegebenen Paketnamen entweder als eigenständiger oder als abhängiger
Prozess (s.o.). Über das Parameterpaar Key/Value können der gestartet App Informationen übermittelt werden. Key und Value erwarten Texte als Argumente. |
Werden andere Parameter-Typen als Texte (Strings) übergeben, wandelt AI2 diese in Strings um. | |
Startet die App mit dem angegebenen Paketnamen entweder als eigenständiger oder als abhängiger
Prozess (s.o.). Der Parameter Pairs ist eine Liste von Listen mit jeweils zwei Werten. Der erste Wert wird als Schlüssel, der zweite als zugehöriger Wert interpretiert. |
Weiter Information hierzu findet man bei http://ai2.appinventor.mit.edu/reference/other/activitystarter.html oder https://appinventor.mit.edu/explore/ai2/activity-starter.html |
|
Das LauncherIntentObject legt fest, welche Activity gestartet wird, und deren Start-Optionen. |
Siehe Reference UrsIntent | |
Liefert das Ergebnis des Startversuchs: 0: erfolgreich 1: Paket nicht gefunden 2: Pairs nicht korrekt konstruiert |
||
Daten-Rückgabe | ||
Legt die Rückgabewerte fest. | AI2 übergibt die angegebenen Werte als Schlüssel-Wert-Paar mit dem Schlüssel "APP_INVENTOR_RESULT". | |
Die aufgerufene App wurde abgebrochen. | Rückgabewerte stehen nicht zur Verfügung. | |
Die aufgerufene App wurde regulär beendet. Result: Rückgabewert einer AI2-App. |
Wenn die aufgerufene App einen Wert mit dem Schlüssel "APP_INVENTOR_RESULT" zurück gibt, wird dieser in einen String konvertiert und im Parameter Result zur Verfügung gestellt. | |
Liefert eine Liste aller Schlüssel der im Rückgabe-Intent enthaltenen Schlüssel-Werte-Paare. | Der Rückgabewert der Funktion ist eine Liste mit Strings. | |
Liefert den zum Schlüssel Key gehörenden Wert als String. | Der Wert wird über die Java-Funktion toString konvertiert. | |
Liefert den zum Schlüssel Key gehörenden Wert als Object. | Es findet keine Konvertierung statt. AI2 übergibt Werte als JSON-String. | |
Sonstige Elemente |
Hinweis:
Bei den meisten Flags ist mir nicht wirklich klar, was sie genau
bewirken. Ich habe mich zwar um eine passende Übersetzung bemüht, bin mir aber nicht sicher on das
überall gelungen ist. Im Zweifelsfall bitte die verlinkte Originalreferenz benutzen.
Ab Android
10 muss die Eigenschaft FlagNewTask auf
true gesetzt sein.
Der Aktionstyp (ActionType) bestimmt, welche Aktion mit dem Intent ausgelöst wird:
Die Spalte S markiert Felder die für den ActionType Screen relevant sind, die Spalte L die für den ActionType Launcher.
Bezeichnung | Typ | S | L | Funktion | Voreinstellung |
---|---|---|---|---|---|
ActionType | choice (nur im Designer) |
X | X | Legt den Aktionstyp fest. Mögliche Werte sind None, Screen, Launcher, Event oder GoBack. Je nach Aktionstyp werden verschiedene Felder ausgewertet. | None |
ActivityAction | text | - | X | Die auszuführende allgemeine Aktion. | -none- |
ActivityClass | text | - | X |
Gibt den Klassenteil der spezifischen Komponente an, die gestartet werden soll.
ActivityPackage und ActivityClass definieren die Activity, die beim Antippen der Benachrichtigung gestartet werden soll. |
-none- |
ActivityPackage | text | - | X | Gibt den Paketnamen der spezifischen Komponente an, die gestartet werden soll. ActivityPackage und ActivityClass definieren die Activity, die beim Antippen der Benachrichtigung gestartet werden soll. |
-none- |
DataType | text | - | X | Gibt den MIME-Typ an, der an die Activity übergeben werden soll | -none- |
DataUri | text | - | X | Gibt den Daten-URI an, der zum Starten der Activity verwendet wird. | -none- |
FlagClearTask | boolean | X | X | Die gestartete Aktivität wird ein neuer Task im Verlaufsstapel. | false |
FlagClearTop | boolean | X | X | Wenn die zu startende Activity bereits in dem aktuellen Task ausgeführt wird, wird keine neue Instanz dieser Activity gestartet. Stattdessen werden alle anderen darüber liegenden Activitys geschlossen und dieser Intent an die alte Aktivität, jetzt an der Spitze des Activity-Stacks, als neuer Intent übergeben. | false |
FlagExcludeFromRecent | boolean | X | X | Die neue Activity wird nicht in der Liste der kürzlich gestarteten Activitys gespeichert. | false |
FlagNewTask | boolean | X | X | Diese
Activity
wird zum Beginn eines neuen
Task in diesem Verlaufsstapel. Ab Android 10, muss dieses Flag auf true gesetzt sein. |
true |
FlagNoAnimation | boolean | X | X | Dieses Flag verhindert, dass das System eine Aktivitätsübergangsanimation erzeugt, um zum nächsten Aktivitätsstatus zu gelangen. | false |
FlagNoHistory | boolean | X | X | Die neue Activity wird nicht im Verlaufsstapel gespeichert. Sobald der Benutzer sie verlässt, ist die Activity beendet. | false |
FlagPreviousIsTop | boolean | X | X | Wenn dieser Intent dazu verwendet wird, um eine neue Activity zu starten, wird die aktuelle Activity nicht als oberste Activity gewertet. Die vorherige Activity wird als oberste Activity verwendet, wobei davon ausgegangen wird, dass die aktuelle Activity sofort beendet wird. | false |
FlagReorderToFront | boolean | X | X | Dieses Flag bewirkt, dass die gestartete Activity an die Spitze des Verlaufsstapels verschoben wird, wenn sie bereits ausgeführt wird. | false |
FlagResetTaskIfNeeded | boolean | X | X | Wird diese Activity entweder in einem neuen Task gestartet oder an die Spitze eines vorhandenen Task gebracht, wird sie als Einstieg für den Task gestartet. Dies führt dazu, dass alle Zugehörigkeiten erstellt werden, die erforderlich sind, um diesen Task in den richtigen Zustand zu versetzen (Activity hineinverschieben oder entfernen) oder diesen Task bei Bedarf einfach in seinen Ausgangszustand zurückzusetzen. | false |
FlagSingleTop | boolean | X | X | Wenn gesetzt, wird die Activity nicht gestartet, wenn sie bereits oben im Verlaufsstapel ausgeführt wird. | false |
FlagTaskOnHome | boolean | X | X | Dieses Flag bewirkt, dass ein neu startender Task über der aktuellen Home Activity (falls vorhanden) platziert wird. Das heißt, wenn der Benutzer die Back-Taste drückt, wird er immer wieder zum Home Screen zurückkehren, auch wenn dies nicht die letzte Activity war, die er ausgeführt hat. Dies kann nur in Verbindung mit FLAG_ACTIVITY_NEW_TASK verwendet werden. | false |
ScreenStartValue | text | X | - | Der Startwert, der dem zu öffnenden Screen übergeben werden soll. Abrufbar per Control.getStartValue . | -none- |
ScreenToOpen | text | X | - | Der Name des Screens, der beim Antippen der Benachrichtigung geöffnet werden soll. | "Screen1" |
Die Download-Archiv enthält zwei Beispiel-Apps:
Das erste Beispiel zeigt den Datenaustausch zwischen zwei AI2-Apps.
Das folgende Beispiel zeigt, wie die Methoden getNameList und PackageFromName dazu verwandt werden können, eine App zu starten. Der Aufruf über LaunchForResult sorgt dafür, dass die startenden App so lange pausiert, bis die aufgerufene App beendet wurde.
Aufruf der Liste der verfügbaren Apps | Auswahl der App "Kamera" | Start der App | Anzeige des Abbruchs der aufgerufenen App |
Gleich beim Start der App (Screen.Initialize) wird geprüft, ob andere Apps aus dem Hintergrund heraus gestartet werden können. Damit in der Zeit zwischen der Anforderung der notwendigen Berechtigung und der Rückmeldung keine Eingaben gemacht werden können, sind alle relevanten Screen-Elemente in das VerticalArrangement HiddenPart eingebettet. Dieses Arrangement wird gleich zum App-Start mit der Methode EnableArrangement meiner Extension UrsAI2ComponentGroup gesperrt.
Am oberen befindet sich ein unsichtbarer Warnhinweis. Alle wesentlichen Elemente sind in HiddenPart eingebettet. | Alle wesentlichen Elemente sind in HiddenPart eingebettet. | Bei Start der App wird HiddenPart gesperrt und die Berechtigung überprüft. |
Wenn die Rückmeldung zur Berechtigungsabfrage erfolgt, wird HiddenPart freigeschaltet. Wenn die Berechtigung zum Start von Apps aus dem Hintergrund heraus nicht erteilt wurde, wird der Warnhinweis sichtbar geschaltet.
Beim Start der App wird geprüft, ob es sich im ein Xiaomi-Gerät handelt. Ist dies der Fall, wird zunächst die Schaltfläche freigeschaltet, mit der der Miui-Permission-Editor geöffnet werden kann. Beim erstmaligen Starten der App wird ein Hinweis-Screen geöffnet, der den Anwender auffordert, die entsprechenden Berechtigungen freizugeben. Damit dies nicht bei jedem Start der App geschieht, wird in einer Datenbank (TinyDB) gespeichert, ob der Hinweis bereits einmal angezeigt wurde. Der Hinweis wird ist in zwei Sprachen hinterlegt, in Deutsch und in Englisch.
Die Hinweisanzeigen:
Deutsche Variante | Englische Variante |
Für die Erstellung eigener Extensions habe ich einige Tipps zusammengestellt: AI2 FAQ: Extensions entwickeln.