On-Demand-Auslieferung konfigurieren

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

Stellen Sie sich beispielsweise eine SMS-App vor, die Funktionen zum Erfassen und Senden von Bildnachrichten enthält, aber nur ein kleiner Prozentsatz der Nutzer Bildnachrichten sendet. Es kann sinnvoll sein, Bildnachrichten als herunterladbares Funktionsmodul hinzuzufügen. Auf diese Weise ist der erste App-Download für alle Nutzer kleiner und nur die Nutzer, die Bildnachrichten senden, müssen diese zusätzliche Komponente herunterladen.

Beachten Sie, dass diese Art der Modularisierung mehr Aufwand erfordert und möglicherweise eine Refaktorierung des vorhandenen Codes Ihrer App erfordert. Überlegen Sie sich also gut, welche Funktionen Ihrer App am meisten von einer On-Demand-Verfügbarkeit für Nutzer profitieren würden. Weitere Informationen zu optimalen Anwendungsfällen und Richtlinien für On-Demand-Funktionen finden Sie in den UX-Best Practices für die On-Demand-Bereitstellung.

Wenn Sie Anwendungsfeatures 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 erfahren Sie, wie Sie Ihrem Anwendungsprojekt ein Featuremodul hinzufügen und für die On-Demand-Bereitstellung konfigurieren. Sie müssen Android Studio 3.5 oder höher und das Android-Gradle-Plug-in 3.5.0 oder höher verwenden.

Neues Modul für On-Demand-Lieferung konfigurieren

Am einfachsten erstellen Sie ein neues Funktionsmodul mit Android Studio 3.5 oder höher. 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 mithilfe von Android Studio ein Funktionsmodul hinzu:

  1. Öffnen Sie Ihr App-Projekt in der IDE, falls Sie dies noch nicht getan haben.
  2. Wählen Sie in der Menüleiste File > New > New Module aus.
  3. Wählen Sie im Dialogfeld Neues Modul erstellen die Option Modul für dynamische Funktionen aus und klicken Sie auf Weiter.
  4. Führen Sie im Abschnitt Configure your new module (Neues Modul konfigurieren) die folgenden Schritte aus:
    1. Wählen Sie im Drop-down-Menü das Basisanwendungsmodul für Ihr App-Projekt aus.
    2. Geben Sie einen Modulnamen an. Die IDE verwendet diesen Namen, um das Modul in der Gradle-Einstellungsdatei als Gradle-Unterprojekt zu identifizieren. Beim Erstellen des App Bundles verwendet Gradle das letzte Element des Unterprojektnamens, um das Attribut <manifest split> in das Manifest des Feature-Moduls einzufügen.
    3. Geben Sie den Paketnamen des Moduls an. Standardmäßig schlägt Android Studio einen Paketnamen vor, der den Namen des Stammpakets des Basismoduls mit dem Modulnamen kombiniert, den Sie im vorherigen Schritt angegeben haben.
    4. Wählen Sie das Mindest-API-Level aus, das das Modul unterstützen soll. Dieser Wert sollte mit dem Wert des Basismoduls übereinstimmen.
  5. Klicken Sie auf Weiter.
  6. Führen Sie im Abschnitt Module Download Options (Optionen für den Moduldownload) folgende Schritte aus:

    1. Geben Sie den Modultitel mit bis zu 50 Zeichen an. Die Plattform verwendet diesen Titel, um Nutzern das Modul zu identifizieren, z. B. um zu bestätigen, ob der Nutzer das Modul herunterladen möchte. Aus diesem Grund muss das Basismodul Ihrer Anwendung den Modultitel als Stringressource enthalten, die Sie übersetzen können. Beim Erstellen des Moduls mit Android Studio fügt die IDE dem Basismodul die String-Ressource für Sie 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 Aufnahme bei Installation die Option Modul bei der Installation nicht einschließen aus. Android Studio fügt dem Manifest des Moduls Folgendes hinzu, um Ihre Auswahl widerzuspiegeln:

      <dist:module ... >
        <dist:delivery>
            <dist:on-demand/>
        </dist:delivery>
      </dist:module>
      
    3. Klicke auf das Kästchen neben Fusing, wenn dieses Modul für Geräte mit Android 4.4 (API-Level 20) und niedriger verfügbar und in Multi-APKs enthalten sein soll. Das bedeutet, dass Sie das On-Demand-Verhalten für dieses Modul aktivieren und das Zusammenführen deaktivieren können, um es auf Geräten auszulassen, die das Herunterladen und Installieren geteilter APKs nicht unterstützen. Android Studio fügt dem Manifest des Moduls Folgendes hinzu, 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, überprüfen Sie seinen Inhalt selbst im Bereich Project (Projekt). Wählen Sie dazu in der Menüleiste View > Tool Windows > Project (Ansicht > Toolfenster > Projekt) aus. Der Standardcode, die Standardressourcen und die Standardorganisation sollten denen des Standard-App-Moduls ähnlich sein.

Als Nächstes müssen Sie die On-Demand-Installation mithilfe der Play Feature Delivery-Bibliothek implementieren.

Google Play Feature Delivery Library in Ihr Projekt einbinden

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

On-Demand-Modul anfordern

Wenn Ihre App ein Featuremodul benötigt, kann sie über die Klasse SplitInstallManager eines anfordern, während sie im Vordergrund ausgeführt wird. Bei einer Anfrage muss in Ihrer App der Name des Moduls angegeben werden, wie durch das Element split im Manifest des Zielmoduls definiert. Wenn Sie mithilfe von Android Studio ein Funktionsmodul erstellen, verwendet das Build-System den von Ihnen angegebenen Modulnamen, um dieses Attribut bei der Kompilierung in das Manifest des Moduls einzufügen. Weitere Informationen finden Sie unter Manifeste für Feature-Module.

Stellen Sie sich beispielsweise eine App mit einem On-Demand-Modul zum Erfassen und Senden von Bildnachrichten über die Kamera des Geräts vor. Dieses On-Demand-Modul gibt in seinem Manifest split="pictureMessages" an. 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 deine App ein On-Demand-Modul anfordert, wendet die Play Feature Delivery Library eine Fire-and-Forget-Strategie an. Das heißt, es sendet die Anfrage zum Herunterladen des Moduls an die Plattform, überwacht aber nicht, ob die Installation erfolgreich war. Damit du die Nutzer nach der Installation weiter voranbringen kannst oder Fehler problemlos behoben werden können, solltest du den Anfragestatus beobachten.

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

Damit Sie auf den Code und die Ressourcen des Moduls zugreifen können, muss SplitCompat für Ihre Anwendung aktiviert sein. Beachten Sie, dass SplitCompat für Android Instant Apps nicht erforderlich ist.

Installation von On-Demand-Modulen aufschieben

Wenn Ihre App nicht sofort ein On-Demand-Modul herunterladen und installieren soll, können Sie die Installation auf einen Zeitpunkt verschieben, zu dem die App im Hintergrund ausgeführt wird. Das ist beispielsweise sinnvoll, wenn du Werbematerial für einen späteren Start deiner App laden möchtest.

Mit der Methode deferredInstall() können Sie ein Modul angeben, das später heruntergeladen werden soll, wie unten gezeigt. Außerdem muss sich Ihre App im Gegensatz zu SplitInstallManager.startInstall() nicht im Vordergrund befinden, 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 erfolgen auf Best-Effort-Basis und Sie können den Fortschritt nicht verfolgen. Bevor Sie also auf ein Modul zugreifen, das Sie für die verzögerte Installation angegeben haben, sollten Sie überprüfen, ob das Modul installiert wurde. Wenn das Modul sofort verfügbar sein soll, fordern Sie es stattdessen mit SplitInstallManager.startInstall() an, wie im vorherigen Abschnitt gezeigt.

Anfragestatus überwachen

Damit eine Fortschrittsanzeige aktualisiert, ein Intent nach der Installation ausgelöst oder ein Anfragefehler ordnungsgemäß verarbeitet werden kann, müssen Sie auf Statusaktualisierungen durch die asynchrone SplitInstallManager.startInstall()-Aufgabe warten. Bevor Sie Updates für Ihre Installationsanfrage erhalten, registrieren Sie einen Listener und rufen Sie wie unten gezeigt die Sitzungs-ID für die Anfrage ab.

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, genauso wie die Installation von Anwendungen nicht immer erfolgreich ist. Eine fehlgeschlagene Installation kann folgende Gründe haben: zu wenig Speicherplatz auf dem Gerät, keine Netzwerkverbindung oder der Nutzer ist nicht im Google Play Store angemeldet. Vorschläge dazu, wie Sie diese Situationen aus Sicht des Nutzers optimal handhaben können, finden Sie in unseren UX-Richtlinien für die On-Demand-Auslieferung.

In Bezug auf den Code sollten Sie Fehler beim Herunterladen oder Installieren eines Moduls mit addOnFailureListener() wie unten gezeigt beheben:

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 Ihre App möglicherweise verarbeiten muss:

Fehlercode Beschreibung Vorgeschlagene Maßnahme
ACTIVE_SESSIONS_LIMIT_EXCEEDED (Aktiv) Die Anfrage wurde abgelehnt, da derzeit mindestens eine Anfrage heruntergeladen wird. Prüfen Sie, ob es Anfragen gibt, die noch heruntergeladen werden, wie im obigen Beispiel gezeigt.
MODULE_UNVERFÜGBAR 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.
UNGÜLTIGE_ANFRAGE Google Play hat die Anfrage erhalten, aber sie ist ungültig. Prüfen Sie, ob die in der Anfrage enthaltenen Informationen vollständig und genau sind.
SITZUNG_NICHT_GEFUNDEN Für eine bestimmte 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_NICHT_VERFÜGBAR Die Play Feature Delivery Library wird auf dem aktuellen Gerät nicht unterstützt. Das bedeutet, dass auf dem Gerät keine Features bei Bedarf heruntergeladen und installiert werden können. Auf Geräten mit Android 4.4 (API-Level 20) oder niedriger solltest du bei der Installation Funktionsmodule mit dem Manifest-Attribut dist:fusing einbinden. Weitere Informationen finden Sie unter Funktionsmodul-Manifest.
NETWORK_ERROR Die Anfrage ist aufgrund eines Netzwerkfehlers fehlgeschlagen. Fordern Sie den Nutzer auf, entweder eine Netzwerkverbindung herzustellen oder zu einem anderen Netzwerk zu wechseln.
ZUGRIFF_DENIED Die App kann die Anfrage aufgrund unzureichender Berechtigungen nicht registrieren. Dies ist normalerweise der Fall, wenn die App im Hintergrund ausgeführt wird. Senden Sie die Anfrage, wenn die App in den Vordergrund zurückkehrt.
INKOMPATIBLE_MIT_VORHANDENEM_SESSION Die Anfrage enthält ein oder mehrere Module, die bereits angefordert, aber noch nicht installiert wurden. Erstellen Sie entweder eine neue Anfrage, die keine Module enthält, die Ihre Anwendung bereits angefordert hat, oder warten Sie, bis alle derzeit angeforderten Module installiert sind, bevor Sie die Anfrage wiederholen.

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

SERVICE_DIED Der für die Verarbeitung der Anfrage zuständige Dienst ist inaktiv. Wiederholen Sie die Anfrage.

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

INSUFFICIENT_STORAGE Das Gerät hat nicht genügend freien Speicherplatz, um das Feature-Modul zu installieren. Teilen Sie dem Nutzer mit, dass er nicht über genügend Speicherplatz verfügt, um dieses Feature zu installieren.
SPLITCOMPAT_VERIFICATION_ERROR, SPLITCOMPAT_EMULATION_ERROR, SPLITCOMPAT_COPY_ERROR SplitCompat konnte das Funktionsmodul nicht laden. Diese Fehler sollten nach dem nächsten App-Neustart automatisch behoben werden.
PLAY_STORE_NOT_FOUND Die Play Store App ist nicht auf dem Gerät installiert. Teile dem Nutzer mit, dass zum Herunterladen dieser Funktion die Play Store App erforderlich ist.
APP_NICHT_EIGENTUM Die App wurde nicht von Google Play installiert und 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 zu erhalten.
INTERNAL_ERROR Im Play Store ist ein interner Fehler aufgetreten. Wiederholen Sie die Anfrage.

Wenn ein Nutzer den Download eines On-Demand-Moduls anfordert und ein Fehler auftritt, kann ein Dialogfeld mit zwei Optionen angezeigt werden: Noch einmal versuchen, wodurch die Anfrage noch einmal gesendet wird, und Abbrechen, wodurch die Anfrage abgebrochen wird. Für weitere Unterstützung solltest du auch einen Hilfelink angeben, über den Nutzer zur Google Play-Hilfe gelangen.

Statusaktualisierungen verarbeiten

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

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 Vorgeschlagene Maßnahme
AUSSTEHEND Die Anfrage wurde akzeptiert und der Download sollte bald beginnen. UI-Komponenten wie eine Fortschrittsanzeige initialisieren, um dem Nutzer Feedback zum Download zu geben
REQUIRES_USER_CONFIRMATION Der Download erfordert eine Nutzerbestätigung. Am häufigsten tritt dieser Status 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 findest du im Abschnitt zum Einholen der Nutzerbestätigung.
WIRD HERUNTERGELADEN Download läuft. Wenn Sie eine Fortschrittsanzeige für den Download bereitstellen, verwenden Sie die Methoden SplitInstallSessionState.bytesDownloaded() und SplitInstallSessionState.totalBytesToDownload(), um die UI zu aktualisieren (siehe Codebeispiel über dieser Tabelle).
HERUNTERGELADEN Das Gerät hat das Modul heruntergeladen, aber die Installation hat 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 Featuremoduls zugreifen zu können.
WIRD INSTALLIERT Das Modul wird gerade auf dem Gerät installiert. Aktualisieren Sie die Fortschrittsanzeige. Dieser Status ist in der Regel kurz.
INSTALLIERT Das Modul ist auf dem Gerät installiert. Greifen Sie auf den Code und die Ressourcen im Modul zu, um die User Journey fortzusetzen.

Wenn das Modul für eine Android Instant App mit Android 8.0 (API-Level 26) oder höher vorgesehen ist, musst du splitInstallHelper verwenden, um App-Komponenten mit dem neuen Modul zu aktualisieren.

FEHLER Die Anfrage ist fehlgeschlagen, bevor das Modul auf dem Gerät installiert wurde. Fordere den Nutzer auf, die Anfrage zu wiederholen oder abzubrechen.
WIRD ABGEBROCHEN Die Anfrage wird gerade vom Gerät abgebrochen. Weitere Informationen finden Sie im Abschnitt zum Abbrechen einer Installationsanfrage.
GESTRICHEN Die Anfrage wurde abgebrochen.

Nutzerbestätigung einholen

In einigen Fällen benötigt Google Play möglicherweise eine Nutzerbestätigung, bevor eine Downloadanfrage ausgeführt wird. Das ist beispielsweise der Fall, wenn deine App nicht von Google Play installiert wurde oder wenn du versuchst, große Datenmengen über mobile Daten herunterzuladen. In solchen Fällen lautet der Status der Anfrage REQUIRES_USER_CONFIRMATION und Ihre App muss eine Nutzerbestätigung einholen, bevor das Gerät die Module in der Anfrage herunterladen und installieren kann. Um eine Bestätigung zu erhalten, sollte deine App den Nutzer so 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 Launcher für Aktivitätsergebnisse mit dem integrierten ActivityResultContracts.StartIntentSenderForResult-Vertrag registrieren. Siehe Aktivitätsergebnis-APIs.

Der Status der Anfrage wird abhängig von der Nutzerantwort aktualisiert:

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

Um einen Callback mit der Antwort des Nutzers zu erhalten, kannst du das 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 Anwendung eine Anfrage vor der Installation abbrechen muss, kann sie die Methode cancelInstall() mithilfe 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);

Auf Module zugreifen

Damit Sie nach dem Download aus einem heruntergeladenen Modul auf Code und Ressourcen zugreifen können, muss Ihre App die SplitCompat-Bibliothek sowohl für Ihre App als auch für jede Aktivität in den von Ihrer App heruntergeladenen Funktionsmodulen aktivieren.

Sie sollten jedoch beachten, dass für die Plattform nach dem Herunterladen des Moduls für eine gewisse Zeit (in einigen Fällen) für den Zugriff auf Inhalte eines Moduls die folgenden Einschränkungen gelten:

  • Die Plattform kann keine neuen Manifesteinträge anwenden, die durch das 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 Anwendung aufnehmen.

SplitCompat aktivieren

Damit Ihre Anwendung über ein heruntergeladenes Modul auf Code und Ressourcen zugreifen kann, müssen Sie SplitCompat nur mit einer der in den folgenden Abschnitten beschriebenen Methoden aktivieren.

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

SplitCompatApplication im Manifest deklarieren

Die einfachste Möglichkeit, SplitCompat zu aktivieren, besteht darin, SplitCompatApplication im Manifest Ihrer App als abgeleitete Application-Klasse zu deklarieren:

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

Nachdem die App auf einem Gerät installiert wurde, können Sie automatisch auf Code und Ressourcen aus den heruntergeladenen Featuremodulen zugreifen.

SplitCompat zur Laufzeit aufrufen

Sie können SplitCompat auch zur Laufzeit in bestimmten Aktivitäten oder Diensten aktivieren. Das Aktivieren von SplitCompat ist erforderlich, um Aktivitäten zu starten, die in Funktionsmodulen enthalten sind. Überschreiben Sie dazu attachBaseContext wie unten dargestellt.

Wenn Sie eine benutzerdefinierte Application-Klasse haben, lassen Sie sie stattdessen SplitCompatApplication erweitern, um SplitCompat für Ihre Anwendung zu aktivieren (siehe unten):

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 SplitCompatApplication durch die Klasse Application erweitert wird, können Sie die Methode attachBaseContext() 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 so 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. Dazu verwenden Sie 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

Eine in einem Funktionsmodul definierte Aktivität starten

Nachdem Sie SplitCompat aktiviert haben, können Sie mit startActivity() in Featuremodulen definierte Aktivitäten 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 bei Bedarf heruntergeladen haben, müssen Sie SplitCompat in der Aktivität aktivieren.

Einen in einem Funktionsmodul definierten Dienst starten

Nachdem Sie SplitCompat aktiviert haben, können Sie mit startService() in Featuremodulen definierte Dienste 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 optionale Module aufgenommen werden.

Das Build-System führt Manifesteinträge für alle Module im Basismodul zusammen. Wenn ein optionales Modul eine exportierte Komponente enthält, kann auf diese bereits vor der Installation zugegriffen werden. Dies kann beim Aufrufen von einer anderen Anwendung aufgrund von fehlendem Code zu einem Absturz führen.

Dies stellt kein Problem für interne Komponenten dar. Da auf sie nur die Anwendung zugreift, kann die Anwendung vor dem Zugriff auf die Komponente prüfen, ob das Modul installiert ist.

Wenn Sie eine exportierte Komponente benötigen und ihr Inhalt in einem optionalen Modul enthalten sein soll, sollten Sie ein Proxy-Muster implementieren. Dazu fügen Sie der Basis eine vom Proxy exportierte Komponente hinzu. Beim Zugriff kann die Proxy-Komponente 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 ein Intent starten und den Intent über die aufrufende App weiterleiten. Ist das Modul nicht vorhanden, kann die Komponente es herunterladen oder eine entsprechende Fehlermeldung an die aufrufende App zurückgeben.

Auf Code und Ressourcen aus installierten Modulen zugreifen

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

Auf Code aus einem anderen Modul zugreifen

Über ein Modul auf Basiscode zugreifen

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

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. Es ist jedoch indirekt mithilfe von Reflexion möglich.

Sie sollten aufgrund der Leistungskosten der Reflexion vorsichtig sein, wie oft dies geschieht. Verwenden Sie für komplexe Anwendungsfälle Abhängigkeitsinjektions-Frameworks wie Dagger 2, um einen einzigen Reflexionsaufruf pro Anwendungslebensdauer zu garantieren.

Um die Interaktionen mit dem Objekt nach der Instanziierung zu vereinfachen, empfiehlt es sich, eine Schnittstelle im Basismodul und deren Implementierung im Featuremodul 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

Sobald ein Modul installiert ist, können Sie auf Ressourcen und Assets innerhalb des Moduls wie gewohnt zugreifen. Es gibt jedoch zwei Einschränkungen:

  • Wenn Sie über ein anderes Modul auf eine Ressource zugreifen, hat das Modul keinen Zugriff auf die Ressourcenkennung. Auf die Ressource kann jedoch weiterhin über den Namen zugegriffen werden. Beachten Sie, dass das Paket, mit dem auf die Ressource verwiesen wird, das Paket des Moduls ist, in dem die Ressource definiert ist.
  • Wenn Sie auf Assets oder Ressourcen zugreifen möchten, die in einem neu installierten Modul über ein anderes installiertes Modul Ihrer Anwendung vorhanden sind, müssen Sie dies mithilfe des Anwendungskontexts tun. Der Kontext der Komponente, die versucht, auf die Ressourcen zuzugreifen, wird noch nicht aktualisiert. Alternativ können Sie diese Komponente neu erstellen (z. B. Activity.recreate() aufrufen) oder SplitCompat nach der Installation des Featuremoduls neu installieren.

Nativen Code per On-Demand-Bereitstellung in eine App laden

Wir empfehlen die Verwendung von ReLinker, um alle nativen Bibliotheken zu laden, wenn die On-Demand-Bereitstellung von Funktionsmodulen genutzt wird. ReLinker behebt ein Problem beim Laden nativer Bibliotheken nach der Installation eines Feature-Moduls. Weitere Informationen zu ReLinker finden Sie 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. Bei Instant-Apps sollten Sie diese spezielle Methode verwenden.

Wenn Sie System.loadLibrary() verwenden, um Ihren nativen Code zu laden, und Ihre native Bibliothek von einer anderen Bibliothek im Modul abhängig ist, müssen Sie diese andere Bibliothek zuerst manuell laden. Wenn Sie ReLinker verwenden, ist der entsprechende Vorgang Relinker.recursively().loadLibrary().

Wenn Sie dlopen() im nativen 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 Java-Code abzurufen und dann in deinem 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, kannst du mit einem aktualisierten App-Kontext auf den Code und die Ressourcen zugreifen. Ein Kontext, den Ihre Anwendung vor der Installation eines Moduls erstellt (z. B. ein Kontext, der bereits in einer Variablen gespeichert ist), enthält den Inhalt des neuen Moduls nicht. Aber ein neuer Kontext tut dies. Diesen erhalten Sie beispielsweise mit createPackageContext.

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, nachdem eine Installationsanfrage als INSTALLED gemeldet wird, müssen Sie die App durch einen Aufruf von SplitInstallHelper.updateAppInfo(Context context) mit dem Kontext des neuen Moduls aktualisieren. Andernfalls erkennt die Anwendung den Code und die Ressourcen des Moduls noch nicht. Nachdem Sie die Metadaten der Anwendung aktualisiert haben, sollten Sie den Inhalt des Moduls während des nächsten Hauptthread-Ereignisses laden, indem Sie ein neues 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 Sie C/C++-Bibliotheken aus einem Modul laden möchten, das bereits in einer Instant-App heruntergeladen wurde, verwenden Sie 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

  • Android WebView kann nicht in einer Aktivität verwendet werden, die über ein optionales Modul auf Ressourcen oder Assets zugreift. Dies liegt an einer Inkompatibilität zwischen WebView und SplitCompat unter Android API-Level 28 und niedriger.
  • Sie können ApplicationInfo-Objekte von Android, deren Inhalte oder Objekte, die sie enthalten, nicht im Cache Ihrer App im Cache speichern. 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 Featuremoduls 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. Daraufhin wird ein Set<String> der Namen der installierten Module zurückgegeben, wie unten gezeigt.

Kotlin

val installedModules: Set<String> = splitInstallManager.installedModules

Java

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

Module deinstallieren

Sie können das Deinstallieren von Modulen durch das Gerät anfordern, indem Sie SplitInstallManager.deferredUninstall(List<String> moduleNames) wie unten gezeigt aufrufen.

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"));

Die Deinstallation des Moduls erfolgt nicht sofort. Das heißt, sie werden vom Gerät im Hintergrund deinstalliert, um Speicherplatz zu sparen. Sie können prüfen, ob das Gerät ein Modul gelöscht hat. Dazu rufen Sie SplitInstallManager.getInstalledModules() auf und prüfen das Ergebnis, wie im vorherigen Abschnitt beschrieben.

Zusätzliche Sprachressourcen herunterladen

Mit App Bundles laden Geräte nur den Code und die Ressourcen herunter, die zum Ausführen Ihrer App erforderlich sind. Bei Sprachressourcen lädt das Gerät eines Nutzers also nur die Sprachressourcen Ihrer App herunter, die mit der oder mehreren Sprachen übereinstimmen, die derzeit in den Geräteeinstellungen ausgewählt sind.

Wenn Ihre App Zugriff auf zusätzliche Sprachressourcen haben soll, z. B. um eine In-App-Sprachauswahl zu implementieren, können Sie sie über die Play Feature Delivery Library bei Bedarf herunterladen. Der Vorgang ähnelt dem Herunterladen eines Featuremoduls, wie unten gezeigt.

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 wie eine Anfrage für ein Funktionsmodul behandelt. Das heißt, Sie können wie gewohnt den Anfragestatus überwachen.

Wenn deine App die zusätzlichen Sprachressourcen nicht sofort benötigt, kannst du die Installation wie unten gezeigt verschieben, wenn sie im Hintergrund ausgeführt wird.

Kotlin

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

Java

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

Auf heruntergeladene Sprachressourcen zugreifen

Um auf heruntergeladene Sprachressourcen zugreifen zu können, muss Ihre App die Methode SplitCompat.installActivity() innerhalb der Methode attachBaseContext() jeder Aktivität ausführen, die Zugriff auf diese Ressourcen benötigt (siehe unten).

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, die Sie von Ihrer App heruntergeladene Sprachressourcen verwenden möchten, den Basiskontext und legen Sie über die Configuration eine neue Sprache 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. Dazu können Sie 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 bei Funktionsmodulen können Sie jederzeit zusätzliche Ressourcen deinstallieren. Bevor Sie eine Deinstallation anfordern, sollten Sie zuerst prüfen, welche Sprachen derzeit installiert sind. Gehen Sie dazu so vor:

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 (siehe unten).

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 Library kannst du lokal testen, ob deine App Folgendes tun kann, ohne eine Verbindung zum Play Store herzustellen:

Auf dieser Seite wird beschrieben, wie Sie die aufgeteilten 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 Play Store zu simulieren.

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

  • Laden Sie die aktuelle Version von bundletool herunter und installieren Sie sie. Du benötigst bundletool, um einen neuen Satz installierbarer APKs aus dem Bundle deiner App zu erstellen.

APKs erstellen

Erstellen Sie die aufgeteilten APKs Ihrer App wie folgt, falls Sie dies noch nicht getan haben:

  1. Erstellen Sie mit einer der folgenden Methoden ein App-Bundle für Ihre App:
  2. Verwende 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 enthält Metadaten in den Manifesten deiner APKs, die es der Play Feature Delivery Library ermöglichen, die lokalen aufgeteilten APKs zum Testen der Installation von Funktionsmodulen zu verwenden, ohne eine Verbindung zum Play Store herzustellen.

App auf dem Gerät bereitstellen

Nachdem du mit dem Flag --local-testing einen Satz von APKs erstellt hast, verwende bundletool, um die Basisversion deiner App zu installieren und zusätzliche APKs in den lokalen Speicher deines Geräts zu übertragen. Mit dem folgenden Befehl können Sie beide Aktionen ausführen:

bundletool install-apks --apks my_app.apks

Wenn du jetzt deine App startest und den User Flow zum Herunterladen und Installieren eines Funktionsmoduls abgeschlossen hast, verwendet die Play Feature Delivery Library die APKs, die bundletool auf den lokalen Speicher des Geräts übertragen hat.

Netzwerkfehler simulieren

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

FakeSplitInstallManager enthält ein boolesches Flag, mit dem Sie einen Netzwerkfehler simulieren können, wenn Ihre Anwendung das nächste Mal die Installation eines Moduls anfordert. Um in Ihren Tests auf FakeSplitInstallManager zuzugreifen, können Sie mit FakeSplitInstallManagerFactory eine Instanz davon abrufen:

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);