On-Demand-Auslieferung konfigurieren

Mit Funktionsmodulen kannst du bestimmte Funktionen und Ressourcen vom Basismodul deiner App trennen und in dein App-Bundle aufnehmen. Mit Play Feature Delivery können Nutzer diese Komponenten beispielsweise später bei Bedarf herunterladen und installieren, nachdem sie bereits das Basis-APK Ihrer App installiert haben.

Nehmen wir zum Beispiel eine Messaging-App, die Funktionen zum Aufnehmen und Senden von Bildern enthält, aber nur ein kleiner Prozentsatz der Nutzer sendet Bilder. Es kann sinnvoll sein, den Bildversand als herunterladbares Funktionsmodul einzubinden. So ist der erste App-Download für alle Nutzer kleiner und nur diejenigen, die Bildnachrichten senden, müssen diese zusätzliche Komponente herunterladen.

Diese Art der Modularisierung erfordert mehr Aufwand und möglicherweise eine Refaktorierung des vorhandenen Codes deiner App. Überlege dir daher genau, welche Funktionen deiner App am meisten davon profitieren würden, wenn sie Nutzern on demand zur Verfügung stehen. Weitere Informationen zu optimalen Anwendungsfällen und Richtlinien für On-Demand-Funktionen findest du unter UX-Best Practices für die On-Demand-Bereitstellung.

Wenn Sie App-Funktionen im Laufe der Zeit schrittweise modularisieren möchten, ohne erweiterte Bereitstellungsoptionen wie die On-Demand-Bereitstellung zu aktivieren, konfigurieren Sie stattdessen die Bereitstellung bei der Installation.

Auf dieser Seite wird beschrieben, wie Sie Ihrem App-Projekt ein Funktionsmodul hinzufügen und es für die On-Demand-Bereitstellung konfigurieren. Bevor Sie beginnen, müssen Sie Android Studio 3.5 oder höher und das Android-Gradle-Plug-in 3.5.0 oder höher verwenden.

Neues Modul für die On-Demand-Auslieferung konfigurieren

Am einfachsten lässt sich ein neues Funktionsmodul mit Android Studio 3.5 oder höher erstellen. Da Funktionsmodule eine inhärente Abhängigkeit vom Basis-App-Modul haben, können Sie sie nur vorhandenen App-Projekten hinzufügen.

So fügen Sie Ihrem App-Projekt mit Android Studio ein Funktionsmodul hinzu:

  1. Öffnen Sie Ihr App-Projekt in der IDE, falls noch nicht geschehen.
  2. Wählen Sie in der Menüleiste Datei > Neu > Neues Modul aus.
  3. Wähle im Dialogfeld Neues Modul erstellen die Option Dynamisches Funktionsmodul aus und klicke auf Weiter.
  4. Führen Sie im Abschnitt Neues Modul konfigurieren die folgenden Schritte aus:
    1. Wählen Sie im Drop-down-Menü das Basis-Anwendungsmodul für Ihr App-Projekt aus.
    2. Geben Sie einen Modulnamen an. Die IDE verwendet diesen Namen, um das Modul in Ihrer Gradle-Einstellungsdatei als Gradle-Unterprojekt zu identifizieren. Wenn Sie Ihr App-Bundle erstellen, verwendet Gradle das letzte Element des Unterprojektnamens, um das Attribut <manifest split> in das Manifest des Funktionsmoduls einzufügen.
    3. Geben Sie den Paketnamen des Moduls an. Standardmäßig schlägt Android Studio einen Paketnamen vor, der den Namen des Stammverzeichnispakets des Basismoduls und den im vorherigen Schritt angegebenen Modulnamen kombiniert.
    4. Wählen Sie das Mindest-API-Level aus, das das Modul unterstützen soll. Dieser Wert sollte mit dem des Basismoduls übereinstimmen.
  5. Klicken Sie auf Weiter.
  6. Führen Sie im Abschnitt Module Download Options (Downloadoptionen für Module) die folgenden Schritte aus:

    1. Geben Sie den Modultitel mit bis zu 50 Zeichen an. Die Plattform verwendet diesen Titel, um das Modul für Nutzer zu identifizieren, z. B. wenn sie bestätigen, ob sie das Modul herunterladen möchten. Aus diesem Grund muss das Basismodul Ihrer App den Modultitel als String-Ressource enthalten, die Sie übersetzen können. Wenn Sie das Modul mit Android Studio erstellen, fügt die IDE die String-Ressource für Sie dem Basismodul hinzu und fügt den folgenden Eintrag in das Manifest des Funktionsmoduls ein:

      <dist:module
          ...
          dist:title="@string/feature_title">
      </dist:module>
      
    2. Wählen Sie im Drop-down-Menü unter Einbeziehung bei der Installation die Option Modul nicht bei der Installation einbeziehen aus. Android Studio fügt Folgendes in das Manifest des Moduls ein, um Ihre Auswahl widerzuspiegeln:

      <dist:module ... >
        <dist:delivery>
            <dist:on-demand/>
        </dist:delivery>
      </dist:module>
      
    3. Klicke das Kästchen neben Fusing an, wenn dieses Modul für Geräte mit Android 4.4 (API-Level 20) und niedriger verfügbar sein und in Multi-APKs enthalten sein soll. Das bedeutet, dass Sie das On-Demand-Verhalten für dieses Modul aktivieren und die Zusammenführung deaktivieren können, um es auf Geräten, die das Herunterladen und Installieren von unterteilten APKs nicht unterstützen, wegzulassen. Android Studio fügt Folgendes in das Manifest des Moduls ein, um Ihre Auswahl widerzuspiegeln:

      <dist:module ...>
          <dist:fusing dist:include="true | false" />
      </dist:module>
      
  7. Klicken Sie auf Fertig.

Nachdem Android Studio das Modul erstellt hat, können Sie sich den Inhalt im Bereich Project ansehen. Wählen Sie dazu in der Menüleiste View > Toolfenster > Project aus. Der Standardcode, die Ressourcen und die Organisation sollten denen des Standard-App-Moduls ähneln.

Als Nächstes müssen Sie die Funktion für die Installation auf Abruf mithilfe der Play Feature Delivery-Bibliothek implementieren.

Play Feature Delivery-Bibliothek in Ihr Projekt einbinden

Bevor du beginnen kannst, musst du deinem Projekt die Play Feature Delivery-Bibliothek hinzufügen.

On-Demand-Modul anfordern

Wenn Ihre App ein Funktionsmodul benötigt, kann sie es über die Klasse SplitInstallManager anfordern, während sie im Vordergrund ausgeführt wird. Wenn Ihre App eine Anfrage stellt, muss sie den Namen des Moduls angeben, der durch das split-Element im Manifest des Zielmoduls definiert ist. Wenn Sie mit Android Studio ein Funktionsmodul erstellen, verwendet das Build-System den von Ihnen angegebenen Modulnamen, um diese Property zur Kompilierungszeit in das Manifest des Moduls einzufügen. Weitere Informationen finden Sie unter Funktionsmodul-Manifeste.

Angenommen, eine App hat ein On-Demand-Modul, mit dem Bildnachrichten über die Kamera des Geräts aufgenommen und gesendet werden können. In diesem On-Demand-Modul ist split="pictureMessages" im Manifest angegeben. Im folgenden Beispiel wird SplitInstallManager verwendet, um das Modul pictureMessages anzufordern (zusammen mit einem zusätzlichen Modul für einige Werbefilter):

Kotlin

// Creates an instance of SplitInstallManager.
val splitInstallManager = SplitInstallManagerFactory.create(context)

// Creates a request to install a module.
val request =
    SplitInstallRequest
        .newBuilder()
        // You can download multiple on demand modules per
        // request by invoking the following method for each
        // module you want to install.
        .addModule("pictureMessages")
        .addModule("promotionalFilters")
        .build()

splitInstallManager
    // Submits the request to install the module through the
    // asynchronous startInstall() task. Your app needs to be
    // in the foreground to submit the request.
    .startInstall(request)
    // You should also be able to gracefully handle
    // request state changes and errors. To learn more, go to
    // the section about how to Monitor the request state.
    .addOnSuccessListener { sessionId -> ... }
    .addOnFailureListener { exception ->  ... }

Java

// Creates an instance of SplitInstallManager.
SplitInstallManager splitInstallManager =
    SplitInstallManagerFactory.create(context);

// Creates a request to install a module.
SplitInstallRequest request =
    SplitInstallRequest
        .newBuilder()
        // You can download multiple on demand modules per
        // request by invoking the following method for each
        // module you want to install.
        .addModule("pictureMessages")
        .addModule("promotionalFilters")
        .build();

splitInstallManager
    // Submits the request to install the module through the
    // asynchronous startInstall() task. Your app needs to be
    // in the foreground to submit the request.
    .startInstall(request)
    // You should also be able to gracefully handle
    // request state changes and errors. To learn more, go to
    // the section about how to Monitor the request state.
    .addOnSuccessListener(sessionId -> { ... })
    .addOnFailureListener(exception -> { ... });

Wenn Ihre App ein On-Demand-Modul anfordert, verwendet die Play Feature Delivery-Bibliothek eine „Fire-and-Forget“-Strategie. Das heißt, die Anfrage zum Herunterladen des Moduls wird an die Plattform gesendet, aber es wird nicht überwacht, ob die Installation erfolgreich war. Damit die User Journey nach der Installation fortgesetzt wird oder Fehler ordnungsgemäß behandelt werden, müssen Sie den Anfragestatus überwachen.

Hinweis:Es ist kein Problem, ein Funktionsmodul anzufordern, das bereits auf dem Gerät installiert ist. Die API betrachtet die Anfrage sofort als abgeschlossen, wenn sie feststellt, dass das Modul bereits installiert ist. Außerdem wird ein Modul nach der Installation von Google Play automatisch aktualisiert. Wenn Sie also eine neue Version Ihres App-Bundles hochladen, werden alle installierten APKs, die zu Ihrer App gehören, von der Plattform aktualisiert. Weitere Informationen finden Sie unter App-Updates verwalten.

Damit Ihre App auf den Code und die Ressourcen des Moduls zugreifen kann, muss SplitCompat aktiviert sein. SplitCompat ist für Android Instant Apps nicht erforderlich.

Installation von On-Demand-Modulen zurückstellen

Wenn deine App ein On-Demand-Modul nicht sofort herunterladen und installieren muss, kannst du die Installation auf einen Zeitpunkt verschieben, an dem die App im Hintergrund ausgeführt wird. Beispielsweise, wenn du Werbematerial für eine spätere Veröffentlichung deiner App vorab laden möchtest.

Sie können ein Modul angeben, das später mit der Methode deferredInstall() heruntergeladen werden soll, wie unten gezeigt. Im Gegensatz zu SplitInstallManager.startInstall() muss Ihre App nicht im Vordergrund sein, um eine Anfrage für eine verzögerte Installation zu initiieren.

Kotlin

// Requests an on demand module to be downloaded when the app enters
// the background. You can specify more than one module at a time.
splitInstallManager.deferredInstall(listOf("promotionalFilters"))

Java

// Requests an on demand module to be downloaded when the app enters
// the background. You can specify more than one module at a time.
splitInstallManager.deferredInstall(Arrays.asList("promotionalFilters"));

Anfragen für verzögerte Installationen werden nach dem Best-Effort-Prinzip bearbeitet und ihr Fortschritt kann nicht verfolgt werden. Bevor du also versuchst, auf ein Modul zuzugreifen, das du für die verzögerte Installation angegeben hast, solltest du prüfen, ob das Modul installiert wurde. Wenn Sie das Modul sofort benötigen, verwenden Sie stattdessen SplitInstallManager.startInstall(), um es anzufordern, wie im vorherigen Abschnitt gezeigt.

Anfragestatus überwachen

Wenn du eine Fortschrittsanzeige aktualisieren, nach der Installation einen Intent auslösen oder einen Anfragefehler ordnungsgemäß verarbeiten möchtest, musst du auf Statusaktualisierungen der asynchronen SplitInstallManager.startInstall()-Aufgabe warten. Bevor Sie Updates für Ihre Installationsanfrage erhalten können, müssen Sie einen Listener registrieren und die Sitzungs-ID für die Anfrage abrufen, wie unten gezeigt.

Kotlin

// Initializes a variable to later track the session ID for a given request.
var mySessionId = 0

// Creates a listener for request status updates.
val listener = SplitInstallStateUpdatedListener { state ->
    if (state.sessionId() == mySessionId) {
      // Read the status of the request to handle the state update.
    }
}

// Registers the listener.
splitInstallManager.registerListener(listener)

...

splitInstallManager
    .startInstall(request)
    // When the platform accepts your request to download
    // an on demand module, it binds it to the following session ID.
    // You use this ID to track further status updates for the request.
    .addOnSuccessListener { sessionId -> mySessionId = sessionId }
    // You should also add the following listener to handle any errors
    // processing the request.
    .addOnFailureListener { exception ->
        // Handle request errors.
    }

// When your app no longer requires further updates, unregister the listener.
splitInstallManager.unregisterListener(listener)

Java

// Initializes a variable to later track the session ID for a given request.
int mySessionId = 0;

// Creates a listener for request status updates.
SplitInstallStateUpdatedListener listener = state -> {
    if (state.sessionId() == mySessionId) {
      // Read the status of the request to handle the state update.
    }
};

// Registers the listener.
splitInstallManager.registerListener(listener);

...

splitInstallManager
    .startInstall(request)
    // When the platform accepts your request to download
    // an on demand module, it binds it to the following session ID.
    // You use this ID to track further status updates for the request.
    .addOnSuccessListener(sessionId -> { mySessionId = sessionId; })
    // You should also add the following listener to handle any errors
    // processing the request.
    .addOnFailureListener(exception -> {
        // Handle request errors.
    });

// When your app no longer requires further updates, unregister the listener.
splitInstallManager.unregisterListener(listener);

Anfragefehler verarbeiten

Beachten Sie, dass die On-Demand-Installation von Funktionsmodulen manchmal fehlschlagen kann, genau wie die App-Installation nicht immer erfolgreich ist. Eine fehlgeschlagene Installation kann auf Probleme wie geringen Gerätespeicher, fehlende Netzwerkverbindung oder darauf zurückzuführen sein, dass der Nutzer nicht im Google Play Store angemeldet ist. Vorschläge, wie Sie diese Situationen aus Nutzersicht elegant handhaben können, finden Sie in unseren UX-Richtlinien für On-Demand-Lieferungen.

Im Code sollten Sie Fehler beim Herunterladen oder Installieren eines Moduls mit addOnFailureListener() behandeln, wie unten gezeigt:

Kotlin

splitInstallManager
    .startInstall(request)
    .addOnFailureListener { exception ->
        when ((exception as SplitInstallException).errorCode) {
            SplitInstallErrorCode.NETWORK_ERROR -> {
                // Display a message that requests the user to establish a
                // network connection.
            }
            SplitInstallErrorCode.ACTIVE_SESSIONS_LIMIT_EXCEEDED -> checkForActiveDownloads()
            ...
        }
    }

fun checkForActiveDownloads() {
    splitInstallManager
        // Returns a SplitInstallSessionState object for each active session as a List.
        .sessionStates
        .addOnCompleteListener { task ->
            if (task.isSuccessful) {
                // Check for active sessions.
                for (state in task.result) {
                    if (state.status() == SplitInstallSessionStatus.DOWNLOADING) {
                        // Cancel the request, or request a deferred installation.
                    }
                }
            }
        }
}

Java

splitInstallManager
    .startInstall(request)
    .addOnFailureListener(exception -> {
        switch (((SplitInstallException) exception).getErrorCode()) {
            case SplitInstallErrorCode.NETWORK_ERROR:
                // Display a message that requests the user to establish a
                // network connection.
                break;
            case SplitInstallErrorCode.ACTIVE_SESSIONS_LIMIT_EXCEEDED:
                checkForActiveDownloads();
            ...
    });

void checkForActiveDownloads() {
    splitInstallManager
        // Returns a SplitInstallSessionState object for each active session as a List.
        .getSessionStates()
        .addOnCompleteListener( task -> {
            if (task.isSuccessful()) {
                // Check for active sessions.
                for (SplitInstallSessionState state : task.getResult()) {
                    if (state.status() == SplitInstallSessionStatus.DOWNLOADING) {
                        // Cancel the request, or request a deferred installation.
                    }
                }
            }
        });
}

In der folgenden Tabelle werden die Fehlerstatus beschrieben, die in Ihrer App auftreten können:

Fehlercode Beschreibung Empfohlene Maßnahme
ACTIVE_SESSIONS_LIMIT_EXCEEDED Die Anfrage wird abgelehnt, weil mindestens eine vorhandene Anfrage gerade heruntergeladen wird. Prüfen Sie, ob es Anfragen gibt, die noch heruntergeladen werden, wie im Beispiel oben gezeigt.
MODULE_UNAVAILABLE Google Play kann das angeforderte Modul anhand der aktuell installierten Version der App, des Geräts und des Google Play-Kontos des Nutzers nicht finden. Wenn der Nutzer keinen Zugriff auf das Modul hat, benachrichtigen Sie ihn.
INVALID_REQUEST Google Play hat die Anfrage erhalten, aber sie ist ungültig. Prüfen Sie, ob die in der Anfrage enthaltenen Informationen vollständig und korrekt sind.
SESSION_NOT_FOUND Für die angegebene Sitzungs-ID wurde keine Sitzung gefunden. Wenn Sie den Status einer Anfrage anhand ihrer Sitzungs-ID überwachen möchten, achten Sie darauf, dass die Sitzungs-ID korrekt ist.
API_NOT_AVAILABLE Die Play Feature Delivery-Bibliothek wird auf dem aktuellen Gerät nicht unterstützt. Das bedeutet, dass das Gerät keine On-Demand-Funktionen herunterladen und installieren kann. Bei Geräten mit Android 4.4 (API-Level 20) oder niedriger sollten Sie Funktionsmodule bei der Installation mit dem Manifestattribut dist:fusing einbinden. Weitere Informationen findest du im Manifest für Funktionsmodule.
NETWORK_ERROR Die Anfrage ist aufgrund eines Netzwerkfehlers fehlgeschlagen. Fordere den Nutzer auf, entweder eine Netzwerkverbindung herzustellen oder zu einem anderen Netzwerk zu wechseln.
ACCESS_DENIED Die App kann die Anfrage aufgrund unzureichender Berechtigungen nicht registrieren. Dies geschieht in der Regel, wenn die App im Hintergrund ausgeführt wird. Wiederholen Sie die Anfrage, wenn die App wieder im Vordergrund ist.
INCOMPATIBLE_WITH_EXISTING_SESSION Die Anfrage enthält mindestens ein Modul, das bereits angefordert, aber noch nicht installiert wurde. Erstelle entweder eine neue Anfrage, die keine Module enthält, die deine App bereits angefordert hat, oder warte, bis alle aktuell angeforderten Module installiert sind, bevor du die Anfrage noch einmal sendest.

Beachten Sie, dass das Anfordern eines bereits installierten Moduls nicht zu einem Fehler führt.

SERVICE_DIED Der Dienst, der für die Verarbeitung der Anfrage verantwortlich ist, ist ausgefallen. Wiederholen Sie die Anfrage.

Deine SplitInstallStateUpdatedListener erhält eine SplitInstallSessionState mit diesem Fehlercode, dem Status FAILED und der Sitzungs-ID -1.

INSUFFICIENT_STORAGE Auf dem Gerät ist nicht genügend freier Speicherplatz vorhanden, um das Funktionsmodul zu installieren. Benachrichtige den Nutzer, dass er nicht genügend Speicherplatz hat, um diese Funktion zu installieren.
SPLITCOMPAT_VERIFICATION_ERROR, SPLITCOMPAT_EMULATION_ERROR, SPLITCOMPAT_COPY_ERROR SplitCompat konnte das Funktionsmodul nicht laden. Diese Fehler sollten nach dem nächsten Neustart der App automatisch behoben werden.
PLAY_STORE_NOT_FOUND Die Google Play Store App ist nicht auf dem Gerät installiert. Informiere den Nutzer, dass die Google Play Store App erforderlich ist, um diese Funktion herunterzuladen.
APP_NOT_OWNED Die App wurde nicht über Google Play installiert und die Funktion kann nicht heruntergeladen werden. Dieser Fehler kann nur bei verzögerten Installationen auftreten. Wenn du möchtest, dass der Nutzer die App bei Google Play erwirbt, verwende startInstall(), um die erforderliche Nutzerbestätigung einzuholen.
INTERNAL_ERROR Im Google Play Store ist ein interner Fehler aufgetreten. Wiederholen Sie die Anfrage.

Wenn ein Nutzer das Herunterladen eines On-Demand-Moduls anfordert und ein Fehler auftritt, kannst du ein Dialogfeld mit zwei Optionen anzeigen lassen: Noch einmal versuchen (die Anfrage wird noch einmal versucht) und Abbrechen (die Anfrage wird abgebrochen). Für zusätzliche Unterstützung solltest du auch einen Hilfe-Link angeben, der Nutzer zur Google Play-Hilfe weiterleitet.

Statusaktualisierungen verarbeiten

Nachdem Sie einen Listener registriert und die Sitzungs-ID für Ihre Anfrage aufgezeichnet haben, verwenden Sie StateUpdatedListener.onStateUpdate(), um Statusänderungen zu verarbeiten, wie unten gezeigt.

Kotlin

override fun onStateUpdate(state : SplitInstallSessionState) {
    if (state.status() == SplitInstallSessionStatus.FAILED
        && state.errorCode() == SplitInstallErrorCode.SERVICE_DIED) {
       // Retry the request.
       return
    }
    if (state.sessionId() == mySessionId) {
        when (state.status()) {
            SplitInstallSessionStatus.DOWNLOADING -> {
              val totalBytes = state.totalBytesToDownload()
              val progress = state.bytesDownloaded()
              // Update progress bar.
            }
            SplitInstallSessionStatus.INSTALLED -> {

              // After a module is installed, you can start accessing its content or
              // fire an intent to start an activity in the installed module.
              // For other use cases, see access code and resources from installed modules.

              // If the request is an on demand module for an Android Instant App
              // running on Android 8.0 (API level 26) or higher, you need to
              // update the app context using the SplitInstallHelper API.
            }
        }
    }
}

Java

@Override
public void onStateUpdate(SplitInstallSessionState state) {
    if (state.status() == SplitInstallSessionStatus.FAILED
        && state.errorCode() == SplitInstallErrorCode.SERVICE_DIES) {
       // Retry the request.
       return;
    }
    if (state.sessionId() == mySessionId) {
        switch (state.status()) {
            case SplitInstallSessionStatus.DOWNLOADING:
              int totalBytes = state.totalBytesToDownload();
              int progress = state.bytesDownloaded();
              // Update progress bar.
              break;

            case SplitInstallSessionStatus.INSTALLED:

              // After a module is installed, you can start accessing its content or
              // fire an intent to start an activity in the installed module.
              // For other use cases, see access code and resources from installed modules.

              // If the request is an on demand module for an Android Instant App
              // running on Android 8.0 (API level 26) or higher, you need to
              // update the app context using the SplitInstallHelper API.
        }
    }
}

Die möglichen Status für Ihre Installationsanfrage sind in der folgenden Tabelle beschrieben.

Anfragestatus Beschreibung Empfohlene Maßnahme
AUSSTEHEND Die Anfrage wurde akzeptiert und der Download sollte bald beginnen. Initialisieren Sie UI-Komponenten wie eine Fortschrittsanzeige, um dem Nutzer Feedback zum Download zu geben.
REQUIRES_USER_CONFIRMATION Der Download muss vom Nutzer bestätigt werden. Dieser Status tritt am häufigsten auf, wenn die App nicht über Google Play installiert wurde. Fordern Sie den Nutzer auf, den Download der Funktion über Google Play zu bestätigen. Weitere Informationen finden Sie im Abschnitt Nutzerbestätigung einholen.
Downloads Download läuft. Wenn du eine Fortschrittsanzeige für den Download bereitstellst, verwende die Methoden SplitInstallSessionState.bytesDownloaded() und SplitInstallSessionState.totalBytesToDownload(), um die Benutzeroberfläche zu aktualisieren (siehe Codebeispiel über dieser Tabelle).
HERUNTERGELADEN Das Gerät hat das Modul heruntergeladen, die Installation hat aber noch nicht begonnen. Apps sollten SplitCompat aktivieren, um Zugriff auf heruntergeladene Module zu haben und diesen Status zu vermeiden. Dies ist erforderlich, um auf den Code und die Ressourcen des Funktionsmoduls zuzugreifen.
Installation... Das Gerät installiert gerade das Modul. Aktualisieren Sie die Fortschrittsanzeige. Dieser Zustand ist in der Regel nur von kurzer Dauer.
INSTALLIERT Das Modul ist auf dem Gerät installiert. Zugriffscode und Ressource im Modul, um die User Journey fortzusetzen.

Wenn das Modul für eine Android Instant App bestimmt ist, die unter Android 8.0 (API-Level 26) oder höher ausgeführt wird, müssen Sie splitInstallHelper verwenden, um App-Komponenten mit dem neuen Modul zu aktualisieren.

FEHLGESCHLAGEN Die Anfrage ist fehlgeschlagen, bevor das Modul auf dem Gerät installiert wurde. Fordern Sie den Nutzer auf, die Anfrage entweder noch einmal zu senden oder abzubrechen.
WIRD ABGEBROCHEN Das Gerät bricht die Anfrage gerade ab. Weitere Informationen finden Sie im Abschnitt Installationsanfrage abbrechen.
GESTRICHEN Die Anfrage wurde abgebrochen.

Nutzerbestätigung einholen

In einigen Fällen kann Google Play eine Bestätigung des Nutzers verlangen, bevor eine Downloadanfrage erfüllt wird. Das ist beispielsweise der Fall, wenn Ihre App nicht über Google Play installiert wurde oder wenn Sie versuchen, einen großen Download über mobile Daten durchzuführen. In solchen Fällen lautet der Status der Anfrage REQUIRES_USER_CONFIRMATION und deine App muss die Bestätigung des Nutzers einholen, bevor das Gerät die Module in der Anfrage herunterladen und installieren kann. Um eine Bestätigung zu erhalten, sollte Ihre App den Nutzer wie folgt auffordern:

Kotlin

override fun onSessionStateUpdate(state: SplitInstallSessionState) {
    if (state.status() == SplitInstallSessionStatus.REQUIRES_USER_CONFIRMATION) {
        // Displays a confirmation for the user to confirm the request.
        splitInstallManager.startConfirmationDialogForResult(
          state,
          // an activity result launcher registered via registerForActivityResult
          activityResultLauncher)
    }
    ...
 }

Java

@Override void onSessionStateUpdate(SplitInstallSessionState state) {
    if (state.status() == SplitInstallSessionStatus.REQUIRES_USER_CONFIRMATION) {
        // Displays a confirmation for the user to confirm the request.
        splitInstallManager.startConfirmationDialogForResult(
          state,
          // an activity result launcher registered via registerForActivityResult
          activityResultLauncher);
    }
    ...
 }

Sie können einen Activity Result Launcher mit dem integrierten ActivityResultContracts.StartIntentSenderForResult-Contract registrieren. Weitere Informationen findest du unter Activity Result APIs.

Der Status der Anfrage wird je nach Antwort des Nutzers aktualisiert:

  • Wenn der Nutzer die Bestätigung akzeptiert, ändert sich der Status der Anfrage in PENDING und der Download wird fortgesetzt.
  • Wenn der Nutzer die Bestätigung ablehnt, ändert sich der Status der Anfrage in CANCELED.
  • Wenn der Nutzer keine Auswahl trifft, bevor das Dialogfeld geschlossen wird, bleibt der Anfragestatus REQUIRES_USER_CONFIRMATION. Ihre App kann den Nutzer noch einmal auffordern, die Anfrage abzuschließen.

Wenn Sie einen Callback mit der Antwort des Nutzers erhalten möchten, können Sie den ActivityResultCallback wie unten gezeigt überschreiben.

Kotlin

registerForActivityResult(StartIntentSenderForResult()) { result: ActivityResult -> {
        // Handle the user's decision. For example, if the user selects "Cancel",
        // you may want to disable certain functionality that depends on the module.
    }
}

Java

registerForActivityResult(
    new ActivityResultContracts.StartIntentSenderForResult(),
    new ActivityResultCallback<ActivityResult>() {
        @Override
        public void onActivityResult(ActivityResult result) {
            // Handle the user's decision. For example, if the user selects "Cancel",
            // you may want to disable certain functionality that depends on the module.
        }
    });

Installationsanfrage abbrechen

Wenn Ihre App eine Anfrage vor der Installation abbrechen muss, kann sie die Methode cancelInstall() mit der Sitzungs-ID der Anfrage aufrufen, wie unten gezeigt.

Kotlin

splitInstallManager
    // Cancels the request for the given session ID.
    .cancelInstall(mySessionId)

Java

splitInstallManager
    // Cancels the request for the given session ID.
    .cancelInstall(mySessionId);

Zugriffsmodule

Damit Ihre App nach dem Herunterladen eines Moduls auf dessen Code und Ressourcen zugreifen kann, muss sie die SplitCompat-Bibliothek sowohl für die App als auch für jede Aktivität in den Funktionsmodulen aktivieren, die von der App heruntergeladen werden.

Beachten Sie jedoch, dass die Plattform für einige Zeit (in einigen Fällen Tage) nach dem Herunterladen des Moduls die folgenden Einschränkungen beim Zugriff auf den Inhalt eines Moduls hat:

  • Die Plattform kann keine neuen Manifesteinträge anwenden, die vom Modul eingeführt wurden.
  • Die Plattform kann nicht auf die Ressourcen des Moduls für System-UI-Komponenten wie Benachrichtigungen zugreifen. Wenn Sie solche Ressourcen sofort verwenden müssen, sollten Sie sie in das Basismodul Ihrer App aufnehmen.

SplitCompat aktivieren

Damit Ihre App auf Code und Ressourcen aus einem heruntergeladenen Modul zugreifen kann, müssen Sie SplitCompat mit einer der in den folgenden Abschnitten beschriebenen Methoden aktivieren.

Nachdem Sie SplitCompat für Ihre App aktiviert haben, müssen Sie SplitCompat auch für jede Aktivität in den Funktionsmodulen aktivieren, auf die Ihre App Zugriff haben soll.

SplitCompatApplication im Manifest deklarieren

Am einfachsten aktivieren Sie SplitCompat, indem Sie SplitCompatApplication im Manifest Ihrer App als Unterklasse von Application deklarieren, wie unten gezeigt:

<application
    ...
    android:name="com.google.android.play.core.splitcompat.SplitCompatApplication">
</application>

Nachdem die App auf einem Gerät installiert wurde, kannst du automatisch auf Code und Ressourcen aus heruntergeladenen Funktionsmodulen zugreifen.

SplitCompat zur Laufzeit aufrufen

Du kannst SplitCompat auch zur Laufzeit in bestimmten Aktivitäten oder Diensten aktivieren. Die Aktivierung von SplitCompat auf diese Weise ist erforderlich, um Aktivitäten zu starten, die in Funktionsmodulen enthalten sind. Überschreiben Sie dazu attachBaseContext wie unten gezeigt.

Wenn Sie eine benutzerdefinierte Application-Klasse haben, lassen Sie sie stattdessen SplitCompatApplication erweitern, um SplitCompat für Ihre App zu aktivieren, wie unten gezeigt:

Kotlin

class MyApplication : SplitCompatApplication() {
    ...
}

Java

public class MyApplication extends SplitCompatApplication {
    ...
}

SplitCompatApplication überschreibt einfach ContextWrapper.attachBaseContext(), um SplitCompat.install(Context applicationContext) einzuschließen. Wenn Sie nicht möchten, dass Ihre Application-Klasse SplitCompatApplication erweitert, können Sie die attachBaseContext()-Methode manuell so überschreiben:

Kotlin

override fun attachBaseContext(base: Context) {
    super.attachBaseContext(base)
    // Emulates installation of future on demand modules using SplitCompat.
    SplitCompat.install(this)
}

Java

@Override
protected void attachBaseContext(Context base) {
    super.attachBaseContext(base);
    // Emulates installation of future on demand modules using SplitCompat.
    SplitCompat.install(this);
}

Wenn Ihr On-Demand-Modul sowohl mit Instant-Apps als auch mit installierten Apps kompatibel ist, können Sie SplitCompat bedingt aufrufen:

Kotlin

override fun attachBaseContext(base: Context) {
    super.attachBaseContext(base)
    if (!InstantApps.isInstantApp(this)) {
        SplitCompat.install(this)
    }
}

Java

@Override
protected void attachBaseContext(Context base) {
    super.attachBaseContext(base);
    if (!InstantApps.isInstantApp(this)) {
        SplitCompat.install(this);
    }
}

SplitCompat für Modulaktivitäten aktivieren

Nachdem Sie SplitCompat für Ihre Basis-App aktiviert haben, müssen Sie SplitCompat für jede Aktivität aktivieren, die Ihre App in einem Funktionsmodul herunterlädt. Verwenden Sie dazu die Methode SplitCompat.installActivity():

Kotlin

override fun attachBaseContext(base: Context) {
    super.attachBaseContext(base)
    // Emulates installation of on demand modules using SplitCompat.
    SplitCompat.installActivity(this)
}

Java

@Override
protected void attachBaseContext(Context base) {
    super.attachBaseContext(base);
    // Emulates installation of on demand modules using SplitCompat.
    SplitCompat.installActivity(this);
}

Auf in Funktionsmodulen definierte Komponenten zugreifen

In einem Funktionsmodul definierte Aktivität starten

Nachdem Sie SplitCompat aktiviert haben, können Sie in Funktionsmodulen definierte Aktivitäten mit startActivity() starten.

Kotlin

startActivity(Intent()
  .setClassName("com.package", "com.package.module.MyActivity")
  .setFlags(...))

Java

startActivity(new Intent()
  .setClassName("com.package", "com.package.module.MyActivity")
  .setFlags(...));

Der erste Parameter für setClassName ist der Paketname der App und der zweite Parameter ist der vollständige Klassenname der Aktivität.

Wenn Sie eine Aktivität in einem Funktionsmodul haben, das Sie on demand heruntergeladen haben, müssen Sie SplitCompat in der Aktivität aktivieren.

In einem Funktionsmodul definierten Dienst starten

Nachdem Sie SplitCompat aktiviert haben, können Sie in Funktionsmodulen definierte Dienste mit startService() starten.

Kotlin

startService(Intent()
  .setClassName("com.package", "com.package.module.MyService")
  .setFlags(...))

Java

startService(new Intent()
  .setClassName("com.package", "com.package.module.MyService")
  .setFlags(...));

In einem Funktionsmodul definierte Komponente exportieren

Exportierte Android-Komponenten sollten nicht in optionalen Modulen enthalten sein.

Das Build-System führt Manifesteinträge für alle Module im Basismodul zusammen. Wenn ein optionales Modul eine exportierte Komponente enthält, ist diese auch vor der Installation des Moduls zugänglich und kann beim Aufruf aus einer anderen App aufgrund von fehlendem Code zu einem Absturz führen.

Bei internen Komponenten ist das kein Problem. Auf sie wird nur von der App zugegriffen, sodass die App prüfen kann, ob das Modul installiert ist, bevor sie auf die Komponente zugreift.

Wenn Sie eine exportierte Komponente benötigen und deren Inhalt in einem optionalen Modul enthalten sein soll, sollten Sie ein Proxymuster implementieren. Dazu können Sie der Basis eine exportierte Proxy-Komponente hinzufügen. Wenn auf die Proxy-Komponente zugegriffen wird, kann sie prüfen, ob das Modul mit dem Inhalt vorhanden ist. Wenn das Modul vorhanden ist, kann die Proxy-Komponente die interne Komponente aus dem Modul über einen Intent starten und den Intent von der Aufrufer-App weiterleiten. Wenn das Modul nicht vorhanden ist, kann die Komponente das Modul herunterladen oder eine entsprechende Fehlermeldung an die Aufrufer-App zurückgeben.

Auf Code und Ressourcen aus installierten Modulen zugreifen

Wenn Sie SplitCompat für Ihren Basisanwendungskontext und die Aktivitäten in Ihrem Funktionsmodul aktivieren, können Sie den Code und die Ressourcen aus einem Funktionsmodul so verwenden, als wären sie Teil des Basis-APK, sobald das optionale Modul installiert ist.

Zugriffscode aus einem anderen Modul

Auf Basiscode aus einem Modul zugreifen

Code, der sich in Ihrem Basismodul befindet, kann direkt von anderen Modulen verwendet werden. Sie müssen nichts Besonderes tun. Importieren und verwenden Sie einfach die benötigten Klassen.

Auf Modulcode aus einem anderen Modul zugreifen

Auf ein Objekt oder eine Klasse innerhalb eines Moduls kann nicht direkt von einem anderen Modul aus statisch zugegriffen werden, aber indirekt über Reflexion.

Aufgrund der Leistungskosten der Reflexion sollten Sie darauf achten, wie oft dies geschieht. Verwenden Sie für komplexe Anwendungsfälle Frameworks für die Abhängigkeitsinjektion wie Dagger 2, um einen einzelnen Reflexionsaufruf pro Anwendungslebensdauer zu gewährleisten.

Um die Interaktionen mit dem Objekt nach der Instanziierung zu vereinfachen, wird empfohlen, eine Schnittstelle im Basismodul und ihre Implementierung im Funktionsmodul zu definieren. Beispiel:

Kotlin

// In the base module
interface MyInterface {
  fun hello(): String
}

// In the feature module
object MyInterfaceImpl : MyInterface {
  override fun hello() = "Hello"
}

// In the base module, where we want to access the feature module code
val stringFromModule = (Class.forName("com.package.module.MyInterfaceImpl")
    .kotlin.objectInstance as MyInterface).hello();

Java

// In the base module
public interface MyInterface {
  String hello();
}

// In the feature module
public class MyInterfaceImpl implements MyInterface {
  @Override
  public String hello() {
    return "Hello";
  }
}

// In the base module, where we want to access the feature module code
String stringFromModule =
   ((MyInterface) Class.forName("com.package.module.MyInterfaceImpl").getConstructor().newInstance()).hello();

Auf Ressourcen und Assets aus einem anderen Modul zugreifen

Nachdem ein Modul installiert wurde, können Sie auf die Ressourcen und Assets im Modul auf die übliche Weise zugreifen, wobei zwei Einschränkungen gelten:

  • Wenn Sie von einem anderen Modul aus auf eine Ressource zugreifen, hat das Modul keinen Zugriff auf die Ressourcen-ID. Auf die Ressource kann jedoch weiterhin über den Namen zugegriffen werden. Das Paket, das zum Verweisen auf die Ressource verwendet werden soll, ist das Paket des Moduls, in dem die Ressource definiert ist.
  • Wenn Sie von einem anderen installierten Modul Ihrer App auf Assets oder Ressourcen zugreifen möchten, die in einem neu installierten Modul vorhanden sind, müssen Sie dazu den Anwendungskontext verwenden. Der Kontext der Komponente, die versucht, auf die Ressourcen zuzugreifen, wird noch nicht aktualisiert. Alternativ können Sie diese Komponente neu erstellen (z. B. durch Aufrufen von Activity.recreate()) oder SplitCompat nach der Installation des Funktionsmoduls neu installieren.

Nativer Code in einer App mit On-Demand-Bereitstellung laden

Wir empfehlen, ReLinker zu verwenden, um alle nativen Bibliotheken zu laden, wenn Sie die On-Demand-Bereitstellung von Funktionsmodulen nutzen. ReLinker behebt ein Problem beim Laden nativer Bibliotheken nach der Installation eines Funktionsmoduls. Weitere Informationen zu ReLinker findest du in den Android JNI-Tipps.

Nativen Code aus einem optionalen Modul laden

Nachdem ein Split installiert wurde, empfehlen wir, den nativen Code über ReLinker zu laden. Für Instant-Apps sollten Sie diese spezielle Methode verwenden.

Wenn du System.loadLibrary() verwendest, um deinen nativen Code zu laden, und deine native Bibliothek von einer anderen Bibliothek im Modul abhängt, musst du diese andere Bibliothek zuerst manuell laden. Wenn Sie ReLinker verwenden, ist der entsprechende Vorgang Relinker.recursively().loadLibrary().

Wenn Sie dlopen() in nativem Code verwenden, um eine in einem optionalen Modul definierte Bibliothek zu laden, funktioniert dies nicht mit relativen Bibliothekspfaden. Die beste Lösung besteht darin, den absoluten Pfad der Bibliothek über ClassLoader.findLibrary() aus dem Java-Code abzurufen und dann in Ihrem dlopen()-Aufruf zu verwenden. Tun Sie dies, bevor Sie den nativen Code eingeben, oder verwenden Sie einen JNI-Aufruf von Ihrem nativen Code in Java.

Auf installierte Android Instant Apps zugreifen

Nachdem ein Android Instant App-Modul als INSTALLED gemeldet wurde, können Sie über einen aktualisierten App-Kontext auf den Code und die Ressourcen zugreifen. Ein Kontext, den Ihre App vor der Installation eines Moduls erstellt, z. B. ein Kontext, der bereits in einer Variablen gespeichert ist, enthält nicht den Inhalt des neuen Moduls. Ein neuer Kontext hingegen schon. Diesen können Sie beispielsweise mit createPackageContext abrufen.

Kotlin

// Generate a new context as soon as a request for a new module
// reports as INSTALLED.
override fun onStateUpdate(state: SplitInstallSessionState ) {
    if (state.sessionId() == mySessionId) {
        when (state.status()) {
            ...
            SplitInstallSessionStatus.INSTALLED -> {
                val newContext = context.createPackageContext(context.packageName, 0)
                // If you use AssetManager to access your app’s raw asset files, you’ll need
                // to generate a new AssetManager instance from the updated context.
                val am = newContext.assets
            }
        }
    }
}

Java

// Generate a new context as soon as a request for a new module
// reports as INSTALLED.
@Override
public void onStateUpdate(SplitInstallSessionState state) {
    if (state.sessionId() == mySessionId) {
        switch (state.status()) {
            ...
            case SplitInstallSessionStatus.INSTALLED:
                Context newContext = context.createPackageContext(context.getPackageName(), 0);
                // If you use AssetManager to access your app’s raw asset files, you’ll need
                // to generate a new AssetManager instance from the updated context.
                AssetManager am = newContext.getAssets();
        }
    }
}

Android Instant Apps unter Android 8.0 und höher

Wenn Sie ein On-Demand-Modul für eine Android Instant App unter Android 8.0 (API-Level 26) und höher anfordern, müssen Sie die App nach einer Installationsanfrage, die als INSTALLED gemeldet wird, mit dem Kontext des neuen Moduls aktualisieren. Rufen Sie dazu SplitInstallHelper.updateAppInfo(Context context) auf. Andernfalls sind der Code und die Ressourcen des Moduls in der App noch nicht bekannt. Nachdem Sie die Metadaten der App aktualisiert haben, sollten Sie den Inhalt des Moduls während des nächsten Hauptthread-Ereignisses laden, indem Sie einen neuen Handler aufrufen, wie unten gezeigt:

Kotlin

override fun onStateUpdate(state: SplitInstallSessionState ) {
    if (state.sessionId() == mySessionId) {
        when (state.status()) {
            ...
            SplitInstallSessionStatus.INSTALLED -> {
                // You need to perform the following only for Android Instant Apps
                // running on Android 8.0 (API level 26) and higher.
                if (BuildCompat.isAtLeastO()) {
                    // Updates the app’s context with the code and resources of the
                    // installed module.
                    SplitInstallHelper.updateAppInfo(context)
                    Handler().post {
                        // Loads contents from the module using AssetManager
                        val am = context.assets
                        ...
                    }
                }
            }
        }
    }
}

Java

@Override
public void onStateUpdate(SplitInstallSessionState state) {
    if (state.sessionId() == mySessionId) {
        switch (state.status()) {
            ...
            case SplitInstallSessionStatus.INSTALLED:
            // You need to perform the following only for Android Instant Apps
            // running on Android 8.0 (API level 26) and higher.
            if (BuildCompat.isAtLeastO()) {
                // Updates the app’s context with the code and resources of the
                // installed module.
                SplitInstallHelper.updateAppInfo(context);
                new Handler().post(new Runnable() {
                    @Override public void run() {
                        // Loads contents from the module using AssetManager
                        AssetManager am = context.getAssets();
                        ...
                    }
                });
            }
        }
    }
}

C/C++-Bibliotheken laden

Wenn du C/C++-Bibliotheken aus einem Modul laden möchtest, das das Gerät bereits in einer Instant App heruntergeladen hat, verwende SplitInstallHelper.loadLibrary(Context context, String libName), wie unten gezeigt:

Kotlin

override fun onStateUpdate(state: SplitInstallSessionState) {
    if (state.sessionId() == mySessionId) {
        when (state.status()) {
            SplitInstallSessionStatus.INSTALLED -> {
                // Updates the app’s context as soon as a module is installed.
                val newContext = context.createPackageContext(context.packageName, 0)
                // To load C/C++ libraries from an installed module, use the following API
                // instead of System.load().
                SplitInstallHelper.loadLibrary(newContext, “my-cpp-lib”)
                ...
            }
        }
    }
}

Java

public void onStateUpdate(SplitInstallSessionState state) {
    if (state.sessionId() == mySessionId) {
        switch (state.status()) {
            case SplitInstallSessionStatus.INSTALLED:
                // Updates the app’s context as soon as a module is installed.
                Context newContext = context.createPackageContext(context.getPackageName(), 0);
                // To load C/C++ libraries from an installed module, use the following API
                // instead of System.load().
                SplitInstallHelper.loadLibrary(newContext, “my-cpp-lib”);
                ...
        }
    }
}

Bekannte Einschränkungen

  • Es ist nicht möglich, Android WebView in einer Aktivität zu verwenden, die auf Ressourcen oder Assets aus einem optionalen Modul zugreift. Dies liegt an einer Inkompatibilität zwischen WebView und SplitCompat auf Android API-Level 28 und niedriger.
  • Android-ApplicationInfo-Objekte, deren Inhalte oder Objekte, die sie enthalten, können nicht in Ihrer App im Cache gespeichert werden. Sie sollten diese Objekte immer nach Bedarf aus einem App-Kontext abrufen. Das Caching solcher Objekte kann dazu führen, dass die App bei der Installation eines Funktionsmoduls abstürzt.

Installierte Module verwalten

Wenn Sie prüfen möchten, welche Funktionsmodule derzeit auf dem Gerät installiert sind, können Sie SplitInstallManager.getInstalledModules() aufrufen. Dadurch wird ein Set<String> mit den Namen der installierten Module zurückgegeben, wie unten dargestellt.

Kotlin

val installedModules: Set<String> = splitInstallManager.installedModules

Java

Set<String> installedModules = splitInstallManager.getInstalledModules();

Module deinstallieren

Sie können das Gerät auffordern, Module zu deinstallieren, indem Sie SplitInstallManager.deferredUninstall(List<String> moduleNames) aufrufen, wie unten gezeigt.

Kotlin

// Specifies two feature modules for deferred uninstall.
splitInstallManager.deferredUninstall(listOf("pictureMessages", "promotionalFilters"))

Java

// Specifies two feature modules for deferred uninstall.
splitInstallManager.deferredUninstall(Arrays.asList("pictureMessages", "promotionalFilters"));

Module werden nicht sofort deinstalliert. Das bedeutet, dass das Gerät sie im Hintergrund deinstalliert, um Speicherplatz freizugeben. Sie können prüfen, ob das Gerät ein Modul gelöscht hat, indem Sie SplitInstallManager.getInstalledModules() aufrufen und das Ergebnis prüfen, wie im vorherigen Abschnitt beschrieben.

Zusätzliche Sprachressourcen herunterladen

Bei App-Bundles werden auf Geräten nur der Code und die Ressourcen heruntergeladen, die für die Ausführung Ihrer App erforderlich sind. Bei Sprachressourcen werden also nur die Sprachressourcen Ihrer App heruntergeladen, die den Sprachen entsprechen, die derzeit in den Einstellungen des Geräts ausgewählt sind.

Wenn Sie möchten, dass Ihre App Zugriff auf zusätzliche Sprachressourcen hat, z. B. um eine Sprachauswahl in der App zu implementieren, können Sie die Play Feature Delivery-Bibliothek verwenden, um sie bei Bedarf herunterzuladen. Der Vorgang ähnelt dem Herunterladen eines Funktionsmoduls, wie unten dargestellt.

Kotlin

// Captures the user’s preferred language and persists it
// through the app’s SharedPreferences.
sharedPrefs.edit().putString(LANGUAGE_SELECTION, "fr").apply()
...

// Creates a request to download and install additional language resources.
val request = SplitInstallRequest.newBuilder()
        // Uses the addLanguage() method to include French language resources in the request.
        // Note that country codes are ignored. That is, if your app
        // includes resources for “fr-FR” and “fr-CA”, resources for both
        // country codes are downloaded when requesting resources for "fr".
        .addLanguage(Locale.forLanguageTag(sharedPrefs.getString(LANGUAGE_SELECTION)))
        .build()

// Submits the request to install the additional language resources.
splitInstallManager.startInstall(request)

Java

// Captures the user’s preferred language and persists it
// through the app’s SharedPreferences.
sharedPrefs.edit().putString(LANGUAGE_SELECTION, "fr").apply();
...

// Creates a request to download and install additional language resources.
SplitInstallRequest request =
    SplitInstallRequest.newBuilder()
        // Uses the addLanguage() method to include French language resources in the request.
        // Note that country codes are ignored. That is, if your app
        // includes resources for “fr-FR” and “fr-CA”, resources for both
        // country codes are downloaded when requesting resources for "fr".
        .addLanguage(Locale.forLanguageTag(sharedPrefs.getString(LANGUAGE_SELECTION)))
        .build();

// Submits the request to install the additional language resources.
splitInstallManager.startInstall(request);

Die Anfrage wird so verarbeitet, als wäre es eine Anfrage für ein Funktionsmodul. Sie können den Anfragestatus also wie gewohnt überwachen.

Wenn Ihre App die zusätzlichen Sprachressourcen nicht sofort benötigt, können Sie die Installation auf einen Zeitpunkt verschieben, an dem die App im Hintergrund ausgeführt wird, wie unten gezeigt.

Kotlin

splitInstallManager.deferredLanguageInstall(
    Locale.forLanguageTag(sharedPrefs.getString(LANGUAGE_SELECTION)))

Java

splitInstallManager.deferredLanguageInstall(
    Locale.forLanguageTag(sharedPrefs.getString(LANGUAGE_SELECTION)));

Auf heruntergeladene Sprachressourcen zugreifen

Damit Ihre App auf heruntergeladene Sprachressourcen zugreifen kann, muss sie die Methode SplitCompat.installActivity() innerhalb der Methode attachBaseContext() jeder Aktivität ausführen, die Zugriff auf diese Ressourcen benötigt, wie unten gezeigt.

Kotlin

override fun attachBaseContext(base: Context) {
  super.attachBaseContext(base)
  SplitCompat.installActivity(this)
}

Java

@Override
protected void attachBaseContext(Context base) {
  super.attachBaseContext(base);
  SplitCompat.installActivity(this);
}

Aktualisieren Sie für jede Aktivität, für die Sie Sprachressourcen verwenden möchten, die von Ihrer App heruntergeladen wurden, den Basiskontext und legen Sie über Configuration ein neues Gebietsschema fest:

Kotlin

override fun attachBaseContext(base: Context) {
  val configuration = Configuration()
  configuration.setLocale(Locale.forLanguageTag(sharedPrefs.getString(LANGUAGE_SELECTION)))
  val context = base.createConfigurationContext(configuration)
  super.attachBaseContext(context)
  SplitCompat.install(this)
}

Java

@Override
protected void attachBaseContext(Context base) {
  Configuration configuration = new Configuration();
  configuration.setLocale(Locale.forLanguageTag(sharedPrefs.getString(LANGUAGE_SELECTION)));
  Context context = base.createConfigurationContext(configuration);
  super.attachBaseContext(context);
  SplitCompat.install(this);
}

Damit diese Änderungen wirksam werden, müssen Sie Ihre Aktivität neu erstellen, nachdem die neue Sprache installiert und einsatzbereit ist. Sie können die Methode Activity#recreate() verwenden.

Kotlin

when (state.status()) {
  SplitInstallSessionStatus.INSTALLED -> {
      // Recreates the activity to load resources for the new language
      // preference.
      activity.recreate()
  }
  ...
}

Java

switch (state.status()) {
  case SplitInstallSessionStatus.INSTALLED:
      // Recreates the activity to load resources for the new language
      // preference.
      activity.recreate();
  ...
}

Zusätzliche Sprachressourcen deinstallieren

Ähnlich wie Funktionsmodule können Sie zusätzliche Ressourcen jederzeit deinstallieren. Bevor Sie eine Deinstallation anfordern, sollten Sie zuerst feststellen, welche Sprachen derzeit installiert sind.

Kotlin

val installedLanguages: Set<String> = splitInstallManager.installedLanguages

Java

Set<String> installedLanguages = splitInstallManager.getInstalledLanguages();

Anschließend können Sie mit der Methode deferredLanguageUninstall() entscheiden, welche Sprachen deinstalliert werden sollen, wie unten gezeigt.

Kotlin

splitInstallManager.deferredLanguageUninstall(
    Locale.forLanguageTag(sharedPrefs.getString(LANGUAGE_SELECTION)))

Java

splitInstallManager.deferredLanguageUninstall(
    Locale.forLanguageTag(sharedPrefs.getString(LANGUAGE_SELECTION)));

Modulinstallationen lokal testen

Mit der Play Feature Delivery-Bibliothek können Sie die folgenden Funktionen Ihrer App lokal testen, ohne eine Verbindung zum Google Play Store herstellen zu müssen:

Auf dieser Seite wird beschrieben, wie Sie die unterteilten APKs Ihrer App auf Ihrem Testgerät bereitstellen, damit Play Feature Delivery diese APKs automatisch verwendet, um das Anfordern, Herunterladen und Installieren von Modulen aus dem Google Play Store zu simulieren.

Sie müssen zwar keine Änderungen an der Logik Ihrer App vornehmen, aber die folgenden Anforderungen erfüllen:

  • Laden Sie die aktuelle Version von bundletool herunter und installieren Sie sie. Sie benötigen bundletool, um aus dem Bundle Ihrer App neue installierbare APKs zu erstellen.

APK-Set erstellen

Wenn Sie dies noch nicht getan haben, erstellen Sie die unterteilten APKs Ihrer App so:

  1. Erstellen Sie mit einer der folgenden Methoden ein App-Bundle für Ihre App:
  2. Verwenden Sie bundletool, um mit dem folgenden Befehl eine Reihe von APKs für alle Gerätekonfigurationen zu generieren:

    bundletool build-apks --local-testing
      --bundle my_app.aab
      --output my_app.apks
    

Das Flag --local-testing fügt den Manifesten Ihrer APKs Metadaten hinzu, die der Play Feature Delivery-Bibliothek mitteilen, dass die lokalen unterteilten APKs zum Testen der Installation von Funktionsmodulen verwendet werden sollen, ohne eine Verbindung zum Google Play Store herzustellen.

App auf dem Gerät bereitstellen

Nachdem Sie mit dem Flag --local-testing eine Reihe von APKs erstellt haben, verwenden Sie bundletool, um die Basisversion Ihrer App zu installieren und zusätzliche APKs in den lokalen Speicher Ihres Geräts zu übertragen. Sie können beide Aktionen mit dem folgenden Befehl ausführen:

bundletool install-apks --apks my_app.apks

Wenn du jetzt deine App startest und die Aufrufabfolge zum Herunterladen und Installieren eines Funktionsmoduls abschließt, verwendet die Play Feature Delivery-Bibliothek die APKs, die bundletool in den lokalen Speicher des Geräts übertragen hat.

Netzwerkfehler simulieren

Um Modulinstallationen aus dem Google Play Store zu simulieren, verwendet die Play Feature Delivery-Bibliothek eine Alternative zu SplitInstallManager, die FakeSplitInstallManager, um das Modul anzufordern. Wenn Sie bundletool mit dem Flag --local-testing verwenden, um eine Reihe von APKs zu erstellen und auf Ihrem Testgerät bereitzustellen, enthält es Metadaten, die die Play Feature Delivery-Bibliothek anweisen, die API-Aufrufe Ihrer App automatisch so umzustellen, dass FakeSplitInstallManager anstelle von SplitInstallManager aufgerufen wird.

FakeSplitInstallManager enthält ein boolesches Flag, das Sie aktivieren können, um einen Netzwerkfehler zu simulieren, wenn Ihre App das nächste Mal die Installation eines Moduls anfordert. Wenn Sie in Ihren Tests auf FakeSplitInstallManager zugreifen möchten, können Sie mit FakeSplitInstallManagerFactory eine Instanz davon abrufen, wie unten gezeigt:

Kotlin

// Creates an instance of FakeSplitInstallManager with the app's context.
val fakeSplitInstallManager = FakeSplitInstallManagerFactory.create(context)
// Tells Play Feature Delivery Library to force the next module request to
// result in a network error.
fakeSplitInstallManager.setShouldNetworkError(true)

Java

// Creates an instance of FakeSplitInstallManager with the app's context.
FakeSplitInstallManager fakeSplitInstallManager =
    FakeSplitInstallManagerFactory.create(context);
// Tells Play Feature Delivery Library to force the next module request to
// result in a network error.
fakeSplitInstallManager.setShouldNetworkError(true);