Implementierung Android - Consentfreie Messung
1 Vorgaben zum Aufruf der consentfreien Messung (IOMb Library)
Die Erfassung der App-Nutzung durch den Benutzer erfolgt, indem die App die IOMb-Library bei definierten Ereignissen, welche eine Nutzer-Interaktion kennzeichnen, aufruft.
Die Nutzer-Interaktion wird als Event bezeichnet.
Die IOMb-Library muss von der App bei Eintreten des Events explizit aufgerufen werden.
Weiterhin misst die IOMb-Library bestimmte System- oder App-spezifische Werte automatisch. Zu diesem Zweck muss die Integration der IOMb-Library Android wie im Kapitel „Integration der IOMb-Library Android“ beschrieben erfolgen.
1.1 Interpretation von Events als mobile PI
Die nachfolgend aufgeführten Vorgaben definieren, wie die ÖWA- Library im Kontext der IOMb Mobile Applications Messung zu verwenden ist.
Aus technischer Sicht wird zwischen 2 Typen von Events unterschieden:
PI-Events
Bei den PI-Events wird der Event dazu benutzt, analog zur Web-Messung, eine PageImpression zu erzeugen. Diesem Event muss ein Contentpath (in der Folge einfach als „CP“ bezeichnet) zugeordnet werden. Dieser CP kann anschließend den unterschiedlichen Kategorien zugeordnet werden und dient als Grundlage für die Bildung von Belegungseinheiten. Bei den PI-Events sind die Vorgaben zur Page Impression der ÖWA zu beachten.
Eine PageImpression ist eine Nutzeraktion innerhalb eines mobilen Angebots, die zu einem Aufruf eines Werbemittels führt oder führen könnte. Jede Nutzeraktion darf nur einmal gezählt werden. Nutzeraktionen, die zu keiner potenziellen Werbeauslieferung führen, dürfen nicht gezählt werden.
Voraussetzungen für die Zuweisung einer PI zu einem Angebot:
Der ausgelieferte Inhalt muss (bei mobile enabled Websites) den FQDN bzw. (bei Apps) den App-Namen des Angebots (oder Alias/Redirect) oder den zugewiesenen MEW- oder App-Namen des Angebots tragen.
Nutzeraktion:
Eine PI wird ausgelöst durch eine vom Nutzer durchgeführte Aktion. Darunter fallen ebenfalls: Reload, Öffnen einer App, Öffnen eines Browsers.
Keine Nutzeraktion:
Aufruf eines Inhalts durch eine automatische Weiterleitung (außer Redirects und Alias)., automatischer Reload, das Aufrufen eines Inhaltes beim Schließen (auch: Background) eines Browserfensters oder einer App, das Aufrufen von Inhalten über Robots/Spider und Ähnliches.
Keine PageImpression:
Das Scrollen innerhalb eines bereits geladenen Inhalts.
Non-PI-Events
Non-PI-Events sind Nutzeraktionen, die als Event im consentfreien System erfasst werden, jedoch nicht zur Zählung einer Mobile Impression führen. Diesem Event darf kein Contentpath zugeordnet werden. Beispiele für Non-PI-Events sind
- automatisch von der IOMb-Library erfasste Events
- vom Anbieter festgelegte Events, welche keine mobile PI darstellen und dennoch als Events gemessen werden sollen, um z.B. die Nutzung der App durch die Nutzer besser nachvollziehen zu können.
Richtlinien zur Vergabe der Codes
Bei den PI-Events ist der CP als eindeutige Kennzeichnung des angezeigten Inhalts mitzugeben. Der CP wird vom App-Anbieter spezifiziert.
Bei der Spezifikation des Contentpaths sind die CP-Richtlinien der ÖWA zu beachten:
- Länge: Ein CP darf maximal 255 Zeichen enthalten
- Anzahl: Es dürfen maximal 15.000 CPs verwendet werden
- Erlaubte Zeichen: a-z, A-Z, 0-9; Komma „,“; Bindestrich „-“; Unterstrich „_“; Slash „/“
Eine ausführliche Liste gültiger ÖWA-Kategorien (Contentpath) finden Sie unter:
1.2 Events
In den nachfolgenden Tabellen sind Events aufgeführt, welche in der Messung erhoben werden bzw. erhoben werden können. Unter welchen Umständen ein Event zu einer Page Impression führen kann, wird im Folgenden ebenfalls erläutert.
PI-Events
Im Folgenden sind Events aufgeführt, welche typischerweise zur Auslösung einer PI führen. Die Übernahme des Schemas wird empfohlen. Die Events müssen manuell ausgelöst werden. Das Vorgehen ist im Kapitel „Logging eines Events“ beschrieben. Eine automatische Erhebung erfolgt nicht. PI-Events muss ein Contentpath zugeordnet werden. Dieser Contentpath kann anschließend den unterschiedlichen Kategorien zugeordnet werden und dient als Grundlage für die Bildung von Belegungseinheiten.
Bei den PI-Events sind die Vorgaben zur PageImpression der ÖWA zu beachten.
- Event Klasse: IOLViewEvent
- Event Type: Appeared
- Event: Ein View (aka „Page“) wurde angezeigt oder mit neuen Daten aktualisiert
- Bemerkung: Beispiele:
Appeared: initialer Aufruf einer Seite
Sobald in der App ein unter „manuell auszulösende Events“ beschriebenes Ereignis ausgelöst wird, ist die IOMb-Library Android per logEvent aufzurufen. Hierbei ist eine Instanz der entsprechenden IOLEvent-Subklasse als Parameter zu übergeben (siehe dazu auch „IOMb-Library Android Funktionen“).
2 Bereitstellung/Anforderungen
Im Folgenden wird die technische Integration der consentfreien ÖWA-Library (IOMb-Library) in eine Android Projekt-Struktur beschrieben.
2.1 Bereitstellung
Die IOMb-Library Android wird als Maven Package bereitgestellt und lässt sich über eine Gradle Build Configuration in ein Android App Projekt integrieren.
2.2 Anforderungen
Die IOMb-Library für Android unterstützt die Integration über die Entwicklungsumgebung „Android Studio“ unter Windows/macOS bzw. Linux.
Entwicklungsumgebung
- Android Studio 2021.3.1 (und höher)
- Gradle Plugin Version 7.4 (und höher)
- Target SDK Version 31 (oder höher)
- Min SDK Version 21 (oder höher)
Betriebssystem/Plattform
Die IOMb-Library Android setzt für den Betrieb Android v5.0 (API Level 21) oder höher voraus.
Kompatibilität
Eine neue Version des Android Betriebssystems macht evtl. ein Update der IOMb-Library notwendig. Eine vollständige Aufwärtskompatibilität kann u.U. nicht gewährleistet werden.
3 Integration der IOMb-Library Android
Die Integration der IOMb-Library Android erfolgt in wenigen Schritten über Maven:
Android Studio: Gradle Build Configuration der Application öffnen, dort unter „repositories“ die folgenden Anweisungen eintragen
repositories {
maven {
url "https://repo.infonline.de/api/v4/projects/5/packages/maven"
name "INFOnline"
}
}
Android Studio: Unter „dependencies“ die IOMb-Library referenzieren
dependencies {
implementation 'de.infonline:iomb-library:1.1.2' // Versionsnummer bei Updates anpassen
...
}
4 Java8+ / Android API Level < 26 Support
Wenn Ihre App Geräte mit einem API Level unter 26 unterstützt, müssen neuere Java 8 Funktionen im Buildprozess inkludiert werden („Desugaring“).
Dazu muss die Gradle Build Configuration der Application wie folgt angepasst werden:
android {
defaultConfig {
// Required when setting minSdkVersion to 20 or lower
multiDexEnabled true
}
compileOptions {
// Flag to enable support for the new language APIs
coreLibraryDesugaringEnabled true
// Sets Java compatibility to Java 8
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
}
Weitere Informationen und die aktuellste Version der Desugaring Library können der offiziellen Android Developer Dokumentation entnommen werden: https://developer.android.com/studio/write/java8-support
4.1 AGP8 / R8 Fullmode Support
Mit Einführung des Advanced Gradle Plugin v8.0.0 (AGP8) wurde der R8 full mode per default aktiviert (Details).
Ab Version v1.1.1 liefert die IOMbLib Android alle erforderlichen Regeln zur Unterstützung des R8 Fullmode aus.
Für ältere Versionen bis v1.1.2 müssen die folgenden Regeln manuell integriert werden:
Alternativ kann der R8 full mode auch deaktiviert werden:
android.enableR8.fullMode = false
5 Initialisierung der consentfreien ÖWA-Library (IOMb-Library Android)
Zur Nutzung der consentfreien ÖWA-Messung muss das Mess-System IOMb AT genutzt werden.
Die dafür notwendigen Parameter wie Angebotskennung und Base URL werden durch INFOnline für jedes Angebot individuell vergeben bzw. im Folgenden erläutert und sind in der nachfolgenden Darstellung nur beispielhaft.
Initialisierung einer IOMb ÖWA Session
Erstellung eines IOMBATSetup Objekts (inkl. Angebotskennung und Basis-URL) sowie Initialisierung der IOMb ÖWA Session in einem Objekt „IOMB_AT_Session“ vom Typ Measurement
import de.infonline.lib.iomb.IOMB
import de.infonline.lib.iomb.measurements.Measurement
import de.infonline.lib.iomb.measurements.iomb.IOMBATSetup
val setup = IOMBATSetup(
baseUrl = "https://data-ef4e2c0163.example.com",
offerIdentifier = "Angebotskennung")
IOMB.create(setup).subscribe { it ->
IOMB_AT_SESSION = it
}
companion object {
lateinit var IOMB_AT_SESSION: Measurement
}
Angebotskennung und https://data-ef4e2c0163.example.com sind Beispiele. Ihre angebotsindividuellen Werte erhalten Sie von der INFOnline. Falls Sie die Serviceplattform als Self-hosting betreiben, wird im folgenden Kapitel beschrieben, wie die baseURL aufgebaut ist.
Im o.g. Beispiel wird die IOMb ÖWA Session asynchron erzeugt.
Alternativ kann dies auch synchron („blocking“) geschehen:
IOMB_AT_SESSION = IOMB.createBlocking(setup)
Event Logging
Events werden über die IOMBSession geloggt. Sie können in den Activities der App geloggt werden, z.B. den Aufruf eines Views:
val event = IOLViewEvent(type = IOLViewEvent.IOLViewEventType.Appeared, category = "MainScreen")
IOMB_SESSION.logEvent(event)
IOMB_AT_SESSION.logEvent(event)
6 IOMb-Library Android API
Die IOMb-Library Android bietet zur Nutzung der IOMb Messung die im Folgenden beschriebenen Funktionen:
6.1 Aufruf der IOMb Session
Alle im Folgenden beschriebenen Funktionen der IOMb-Library Android müssen auf dem Measurement Objekt aufgerufen werden, auf dem die Session erzeugt wurde.
var IOMBATSession : Measurement
IOMBATSession = IOMB.createBlocking(setup)
IOMBATSession.logEvent(...)
6.2 Konfiguration einer Session
Vor der Initialisierung einer IOMb ÖWA Session muss ein gültiges IOMBATSetup Objekt erstellt werden
Parameter:
- Angebotskennung – „offeridentifier“ (mandatory)
Eine eindeutige Kennung des Angebots der jeweiligen App. Die Angebotskennung wird von INFOnline pro App und pro Betriebssystem eindeutig vergeben. - BaseURL – „baseURL“ (mandatory)
Die BaseURL der Serviceplattform ist der eingetragene Domain-Dienstname als CNAME bei Hosting der Serviceplattform der INFOnline. Sollten Sie die Serviceplattform im Self-hosting betreiben, setzen Sie hier Ihren AAA(A) DNS-Eintrag. - Hybrid Identifier – „hybrididentifier“ (optional, nicht mehr benötigt)
Hierbei handelt es sich um ein historisches Feld, welches keine Relevanz mehr für die Messung hat und daher nicht mehr verwendet wird bzw. nicht mehr befüllt werden muss (s. untenstehendes Beispiel).
Eine optionale Kennung zur Verknüpfung der Messströme aus dem nativen Teil und Webinhalten in einem WebView innerhalb einer App. - Customer Data – „customerData“ (optional, nicht mehr benötigt)
Hierbei handelt es sich um ein historisches Feld, welches keine Relevanz mehr für die Messung hat und daher nicht mehr verwendet wird bzw. nicht mehr befüllt werden muss (s. untenstehendes Beispiel).
Ein Freifeld für interne Zwecke des Anbieters.
Beispiel:
val setup = IOMBATSetup(
offerIdentifier = "Angebotskennung",
baseUrl = "https://data-ef4e2c0163.example.com")
6.3 Initialisierung einer Session
Die IOMb Library Android muss vor der Erfassung der Events gestartet werden. Dabei müssen die Angebotskennung der App sowie eine gültige BaseURL im jeweiligen IOMb Setup Objekt (s.o.) korrekt gesetzt sein.
Eine Session kann synchron (blocking) oder asynchron (auf einem anderen Thread) erstellt werden
Parameter:
- IOMBATSetup (mandatory)
Für die consentfreie ÖWA-Messung muss ein IOMBATSetup Objekt verwendet werden.
Beispiel Init Synchron:
IOMBATSession = IOMB.createBlocking(IOMBATSetup)
Beispiel Init Asynchron:
IOMB.create(IOMBATSetup).subscribe { it ->
IOMBATSession = it
}
6.4 Logging eines Events
Die Messdaten werden mittels des Aufrufs logEvent erfasst. Dabei muss ein zuvor initialisiertes Event übergeben werden.
fun logEvent(event: IOLEvent)
Um ein Event zu erzeugen, muss ein Initializer der entsprechenden IOLEvent-Subklasse aufgerufen werden. Dabei können bis zu vier Parameter übergeben werden, drei davon sind optional.
IOLEvent(identifier: String,
category: String?,
state: String?,
comment: String?
Die fehlenden Werte werden dann um nil bzw. Default-Werte ergänzt. Einige der Events werden durch die IOMb-Library automatisch erfasst.
Parameter:
- EventType (mandatory)
Das zu erfassende Event. Die einzelnen Events können verschiedene Zustände einnehmen. So kann ein Download z.B. gestartet, durch den User abgebrochen, erfolgreich durchgeführt oder fehlerhaft beendet worden sein. Bei einigen Events entfällt der type Parameter, da für diese Events nur ein gültiger Type definiert ist. Beim IOLCustomEvent wird statt eines type der frei definierbare String Parameter name benötigt. - Category (mandatory)
Der Contentpath wird im Parameter “category“ übermittelt. Dieser Contentpath wird vom Anbieter selbst festgelegt. Der Contentpath dient zur inhaltlichen Kennzeichnung des angezeigten Contents. Der Anbieter entscheidet anhand der im Kapitel 1 (Richtlinien zur Vergabe der Codes) beschriebenen Richtlinien, ob ein Event eine mobile PI im Sinne der ÖWA Richtlinien darstellt. Wenn ein Event unter die Definition einer mobilen PI fällt, ist zwingend ein Contentpath mitzugeben. Stellt ein Event keine mobile PI dar, soll nil übergeben werden. Die Länge dieses Feldes ist auf 255 Zeichen beschränkt. - Kommentar (optional)
Kommentarfeld. Die Länge dieses Feldes ist nicht beschränkt. Übergabe dieses Wertes ist optional, ist er nicht definiert, soll er nicht übergeben werden. - Parameter (optional)
Eine Hash Map mit frei bestimmbaren Zusatzinformationen zu dem Event. Key und Value müssen vom Typ String sein, die maximale Länge ist jeweils auf 255 Zeichen beschränkt. Übergabe dieses Wertes ist optional.
6.5 Verfügbare Events
Die IOMb-Library stellt folgende von „IOLEvent“ abgeleitete Event-Klassen mit den zugehörigen Types zur Verfügung:
- IOLViewEvent
- IOLViewEventType.Appeared
Beispiele:
IOLViewEvent / IOLViewEventType.Appeared
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val event = IOLViewEvent(type = IOLViewEvent.IOLViewEventType.Appeared,
category = "MainScreen")
App.IOMB_SESSION.logEvent(event)
}
6.6 Session beenden
Die aktive Session der IOMb-Library kann explizit beendet werden. Dies ermöglicht z.B. die Realisierung eines Opt-out während der App-Laufzeit. Etwaige bis dahin erfasste Daten werden nicht mehr versendet.
Nur bei Opt-out durch den Nutzer verwenden!
IOMB.delete(Measurement.Type.IOMB_AT)
Soll die Messung fortgeführt werden, muss die IOMb Session neu gestartet werden! Das Vorgehen ist unter „Initialisierung einer Session“ beschrieben.
6.7 Einbindung Opt-out-Funktion
Den Nutzern einer App muss eine Opt-out Funktion zur Verfügung gestellt werden. Die Implementierung obliegt dem Entwickler der jeweiligen App und sollte bei Aktivierung durch den Benutzer dazu führen, dass die IOMbLibrary entweder gar nicht initialisiert wird oder die laufende Session explizit beendet wird. Das Vorgehen ist unter „Session beenden“ beschrieben.
Nach Einbindung der Funktion können die Nutzer der App das Opt-out aktivieren und deaktivieren. Sofern ein Opt-out aktiviert wird, werden keine Messdaten erfasst.
Wird eine laufende Session explizit beendet, dann werden alle bis dahin erfassten, aber noch nicht versandten Messdaten verworfen.
Wird das Opt-out revidiert, dann sollte die IOMb-Library wieder gestartet werden. Das Vorgehen ist unter „Initialisierung einer Session“ beschrieben.
7 IOMb-Library Android - Debug Informationen
Zum Zweck der allgemeinen Fehleranalyse und insb. des Versands der Messdaten kann die IOMb Lib Android in einen Debug-Modus versetzt werden.
In diesem Debug-Modus erzeugt die IOMb Lib Android Ausgaben im Logstrom (Konsole): Fehler, Warnungen, Infos, Events und Requests.
Diese Ausgaben können dann in der Konsole komfortabel gefiltert werden.
Um den Debug-Modus zu aktivieren, wird das Flag debugMode_ des Singleton Objekts IOLDebug auf true gesetzt:
class App : Application() {
override fun onCreate() {
super.onCreate()
IOLDebug.debugMode = true
Per default ist der Debug-Modus deaktiviert.
Bitte deaktivieren Sie den Debug-Modus vor der Veröffentlichung der App.
Logs können mittels eines auf IOLDebug zu setzenden Callbacks abgefangen und in beliebige Kanäle geleitet werden.
IOLDebug.logListener = object : LogListener {
override fun onLog(
priority: Int,
tag: String,
message: String?,
throwable: Throwable?
) {
if(priority >= Log.DEBUG) {
// e.g. push to external log system
}
}
}