On-Demand-Auslieferung konfigurieren

Mit Funktionsmodulen können Sie bestimmte Funktionen und Ressourcen vom Basismodul Ihrer App trennen und in Ihr 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 Ihrer App installiert haben.

Angenommen, eine Textnachrichten-App bietet Funktionen zum Erfassen und Senden von Bildnachrichten, aber nur ein kleiner Prozentsatz der Nutzer sendet Bildnachrichten. Es kann sinnvoll sein, Bildnachrichten als herunterladbares Funktionsmodul hinzuzufügen. Auf diese Weise ist der anfängliche Anwendungs-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 und möglicherweise eine Refaktorierung des vorhandenen Codes Ihrer Anwendung erfordert. Überlegen Sie sich daher genau, welche Funktionen Ihrer App am meisten von einer On-Demand-Verfügbarkeit Ihrer Anwendung 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 die Anwendungsfeatures im Laufe der Zeit nach und nach modularisieren möchten, ohne erweiterte Bereitstellungsoptionen wie die On-Demand-Bereitstellung zu aktivieren, konfigurieren Sie die Bereitstellung bei der Installation.

Auf dieser Seite erfahren Sie, wie Sie Ihrem App-Projekt ein Funktionsmodul 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-Bereitstellung konfigurieren

Am einfachsten lässt sich ein neues Funktionsmodul mit Android Studio 3.5 oder höher erstellen. Da Featuremodule eine inhärente Abhängigkeit vom Basisanwendungsmodul haben, können Sie sie nur vorhandenen Anwendungsprojekten 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 noch nicht geschehen.
  2. Wählen Sie in der Menüleiste File > New > New Module aus.
  3. Wählen Sie im Dialogfeld Neues Modul erstellen die Option Dynamisches Funktionsmodul aus und klicken Sie auf Weiter.
  4. Führen Sie im Abschnitt 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. 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 Stammpakets des Basismoduls mit dem im vorherigen Schritt angegebenen Modulnamen kombiniert.
    4. Wähle das Mindest-API-Level aus, das das Modul unterstützen soll. Dieser Wert sollte mit dem Wert des Basismoduls übereinstimmen.
  5. Klicke auf Weiter.
  6. Führen Sie im Abschnitt Module Download Options (Optionen zum Download des Moduls) die folgenden 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 App den Modultitel als Stringressource enthalten, die übersetzt werden kann. Beim Erstellen des Moduls mit Android Studio fügt die IDE dem Basismodul die String-Ressource hinzu und schleust 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 der Installation die Option Modul bei der Installation nicht einschließen aus. Android Studio schleust 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 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 auszuschließen, die das Herunterladen und Installieren von unterteilten APKs nicht unterstützen. Android Studio schleust 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, überprüfen Sie seinen Inhalt im Bereich Projekt. Wählen Sie dazu in der Menüleiste Ansicht > Toolfenster > Projekt aus. Der Standardcode, die Ressourcen und die Organisation sollten denen des Standardanwendungsmoduls ähnlich sein.

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

Play Feature Delivery Library in Ihr Projekt einbinden

Bevor Sie beginnen können, müssen Sie Ihrem Projekt zuerst die Play Feature Delivery Library hinzufügen.

On-Demand-Modul anfordern

Wenn deine App ein Funktionsmodul verwenden muss, kann sie über die Klasse SplitInstallManager eines anfordern, während es im Vordergrund ausgeführt wird. Wenn Sie eine Anfrage stellen, muss Ihre App den Namen des Moduls angeben, wie durch das Element split im Manifest des Zielmoduls definiert. Wenn Sie mit Android Studio ein Funktionsmodul erstellen, verwendet das Build-System den von Ihnen angegebenen Modulnamen, um diese Eigenschaft bei der Kompilierung in das Manifest des Moduls einzufügen. Weitere Informationen finden Sie unter Manifeste für Featuremodule.

Angenommen, eine App hat ein On-Demand-Modul zum Aufnehmen und Senden von Bildnachrichten mit der Kamera des Geräts. Dieses Modul gibt in seinem Manifest split="pictureMessages" an. Im folgenden Beispiel wird mit SplitInstallManager das Modul pictureMessages angefordert (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, verfolgt die Play Feature Delivery Library eine Fire-and-Forget-Strategie. Das heißt, er sendet die Anfrage zum Herunterladen des Moduls an die Plattform, überwacht jedoch nicht, ob die Installation erfolgreich war. Wenn Sie den Kaufprozess nach der Installation fortsetzen oder Fehler ordnungsgemäß beheben möchten, müssen Sie den Anfragestatus überwachen.

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 feststellt, 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 Zugriff auf den Code und die Ressourcen des Moduls haben, muss Ihre Anwendung SplitCompat aktivieren. SplitCompat ist für Android Instant Apps nicht erforderlich.

Installation von On-Demand-Modulen auf später verschieben

Wenn Sie nicht möchten, dass Ihre App sofort ein On-Demand-Modul herunterlädt und installiert, können Sie die Installation auf einen späteren Zeitpunkt verschieben, an dem die App im Hintergrund ausgeführt wird. Dies ist beispielsweise der Fall, wenn Sie Werbematerial für eine spätere Veröffentlichung Ihrer App vorab laden möchten.

Mit der Methode deferredInstall() können Sie ein Modul angeben, das später heruntergeladen werden soll, wie unten gezeigt. Außerdem muss sich Ihre Anwendung 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 sind Best-Effort-Anforderungen und Sie können ihren Fortschritt nicht verfolgen. Bevor Sie also versuchen, auf ein Modul zuzugreifen, das Sie für die verzögerte Installation angegeben haben, sollten Sie prü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 Sie eine Fortschrittsanzeige aktualisieren, nach der Installation einen Intent auslösen oder einen Anfragefehler ordnungsgemäß beheben können, müssen Sie auf Statusaktualisierungen der asynchronen Aufgabe SplitInstallManager.startInstall() warten. Bevor Sie Updates für Ihre Installationsanfrage erhalten können, registrieren Sie einen Listener und rufen Sie die Sitzungs-ID für die Anfrage ab (siehe unten).

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 Featuremodulen gelegentlich fehlschlagen kann, genau wie die Installation von Anwendungen nicht immer erfolgreich ist. Fehler bei der Installation können beispielsweise auf zu wenig Speicherplatz auf dem Gerät, fehlende Netzwerkverbindung oder nicht angemeldete Nutzer im Google Play Store zurückzuführen sein. Vorschläge dazu, wie Sie mit diesen Situationen umgehen können, finden Sie in unseren UX-Richtlinien für die On-Demand-Bereitstellung.

In Bezug auf den Code sollten Sie Fehler beim Herunterladen oder Installieren eines Moduls mithilfe von addOnFailureListener() 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 Empfohlene Maßnahme
AKTIV_SESSIONS_LIMIT_EXCEEDED Die Anfrage wurde abgelehnt, weil gerade mindestens eine Anfrage heruntergeladen wird. Prüfen Sie, ob Anfragen vorliegen, die noch heruntergeladen werden (siehe Beispiel oben).
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 im Antrag enthaltenen Informationen vollständig und korrekt sind.
SITZUNG_NICHT_GEFUNDEN Es wurde keine Sitzung für eine bestimmte Sitzungs-ID 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. Auf dem Gerät können keine Features bei Bedarf heruntergeladen und installiert werden. Für Geräte mit Android 4.4 (API-Level 20) oder niedriger sollten Sie bei der Installation Funktionsmodule mit der Manifest-Property dist:fusing einbinden. Weitere Informationen findest du unter Manifest für Featuremodule.
NETWORK_ERROR Die Anfrage ist aufgrund eines Netzwerkfehlers fehlgeschlagen. Fordere den Nutzer auf, entweder eine Netzwerkverbindung herzustellen oder zu einem anderen Netzwerk zu wechseln.
ZUGRIFF_VERWEIGERT Die App kann die Anfrage aufgrund unzureichender Berechtigungen nicht registrieren. Das passiert in der Regel, wenn die App im Hintergrund ausgeführt wird. Die Anfrage senden, wenn die App wieder in den Vordergrund wechselt.
INKOMPATIBLE_MIT_VORHANDENER_SITZUNG 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 abgeschlossen sind, bevor Sie die Anfrage wiederholen.

Wenn Sie ein Modul anfordern, das bereits installiert ist, führt dies nicht zu einem Fehler.

SERVICE_DIED Der für die Verarbeitung der Anfrage zuständige Dienst ist nicht mehr verfügbar. Wiederholen Sie die Anfrage.

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

ZU wenig Speicher Auf dem Gerät ist nicht genügend freier Speicherplatz vorhanden, um das Funktionsmodul zu installieren. Teilen Sie dem Nutzer mit, dass nicht genügend Speicherplatz für die Installation dieses Features vorhanden ist.
SPLITCOMPAT_VERIFICATION_ERROR, SPLITCOMPAT_EMULATION_ERROR, SPLITCOMPAT_COPY_ERROR SplitCompat konnte das Funktionsmodul nicht laden. Diese Fehler sollten nach dem nächsten Neustart der Anwendung 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_GEWIESEN Die App wurde nicht von 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 kauft, verwende startInstall(), um die erforderliche Nutzerbestätigung abzurufen.
INTERNAL_ERROR Im 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, sollten Sie ein Dialogfeld mit zwei Optionen für ihn anzeigen lassen: Noch einmal versuchen, bei dem die Anfrage wiederholt wird, und Abbrechen, wenn 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 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.
ANFORDERUNG_NUTZERBESTÄTIGUNG Der Download erfordert eine Bestätigung durch den Nutzer. Meistens tritt dieser Status auf, wenn die App nicht über Google Play installiert wurde. Bitte den Nutzer, den Download der Funktion über Google Play zu bestätigen. Weitere Informationen finden Sie im Abschnitt zum Abrufen 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 Modul wurde auf das Gerät heruntergeladen, die Installation wurde jedoch noch nicht gestartet. Anwendungen sollten SplitCompat aktivieren, um Zugriff auf heruntergeladene Module zu haben und diesen Status nicht zu sehen. Dies ist erforderlich, um auf den Code und die Ressourcen des Feature-Moduls 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. Greife auf Code und Ressourcen im Modul zu, um die User Journey fortzusetzen.

Wenn das Modul für eine Android Instant App vorgesehen ist, die unter Android 8.0 (API-Level 26) oder höher ausgeführt wird, 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 entweder zu wiederholen oder abzubrechen.
WIRD STORNIERT Die Anfrage wird gerade auf dem 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 verlangt Google Play möglicherweise eine Nutzerbestätigung, bevor eine Downloadanfrage ausgeführt werden kann. Dies ist beispielsweise der Fall, wenn Ihre App nicht von Google Play installiert wurde oder wenn Sie versuchen, einen großen Download über mobile Daten durchzuführen. In solchen Fällen meldet 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 der Nutzer von Ihrer App so aufgefordert werden:

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 Aktivitätsergebnis-Launcher mit dem integrierten ActivityResultContracts.StartIntentSenderForResult-Vertrag registrieren. Siehe Activity Result 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.
  • Lehnt der Nutzer die Bestätigung ab, ä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, können Sie den ActivityResultCallback wie unten dargestellt ü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 dargestellt.

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 auf Code und Ressourcen aus einem heruntergeladenen Modul zugreifen können, muss Ihre Anwendung die SplitCompat Library sowohl für Ihre Anwendung als auch für jede Aktivität in den von Ihrer App heruntergeladenen Funktionsmodulen aktivieren.

Für die Plattform gelten jedoch die folgenden Einschränkungen für den Zugriff auf die Inhalte eines Moduls für einige Zeit (in manchen Fällen) nach dem Herunterladen des Moduls:

  • 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 diese Ressourcen sofort verwenden müssen, sollten Sie sie in das Basismodul Ihrer Anwendung aufnehmen.

SplitCompat aktivieren

Damit Ihre Anwendung 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

Die einfachste Möglichkeit, SplitCompat zu aktivieren, besteht darin, SplitCompatApplication wie unten gezeigt 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, 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. Das Aktivieren von SplitCompat ist erforderlich, um Aktivitäten zu starten, die in Featuremodulen 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, wie unten gezeigt:

Kotlin

class MyApplication : SplitCompatApplication() {
    ...
}

Java

public class MyApplication extends SplitCompatApplication {
    ...
}

SplitCompatApplication überschreibt einfach ContextWrapper.attachBaseContext() und schließt SplitCompat.install(Context applicationContext) ein. Wenn Sie nicht möchten, dass die Application-Klasse SplitCompatApplication erweitert, können Sie die Methode attachBaseContext() manuell ü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 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() so:

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 Komponenten zugreifen, die in Funktionsmodulen definiert sind

Eine in einem Funktionsmodul definierte Aktivität starten

Nachdem Sie SplitCompat aktiviert haben, können Sie mit startActivity() Aktivitäten starten, die in Featuremodulen definiert sind.

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 Anwendung und der zweite Parameter ist der vollständige Klassenname der Aktivität.

Wenn Sie eine Aktivität in einem nach Bedarf heruntergeladenen Funktionsmodul haben, müssen Sie SplitCompat in der Aktivität aktivieren.

In einem Funktionsmodul definierten Dienst starten

Sie können Dienste, die in Featuremodulen definiert sind, mit startService() starten, nachdem Sie SplitCompat aktiviert haben.

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

Sie sollten keine exportierten Android-Komponenten in optionale Module einfügen.

Das Build-System führt Manifesteinträge für alle Module im Basismodul zusammen. Wenn ein optionales Modul eine exportierte Komponente enthält, kann darauf noch vor der Installation des Moduls zugegriffen werden. Außerdem kann es beim Aufrufen von einer anderen App zu einem Absturz aufgrund von fehlendem Code kommen.

Dies stellt kein Problem für interne Komponenten dar. Auf sie kann nur von der Anwendung zugegriffen werden. Daher 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 die Implementierung eines Proxy-Musters in Betracht ziehen. Dazu fügen Sie in der Basis eine vom Proxy exportierte Komponente hinzu. Wenn darauf zugegriffen wird, kann die Proxy-Komponente das Vorhandensein des Moduls prüfen, das den Inhalt enthält. Wenn das Modul vorhanden ist, kann die Proxy-Komponente die interne Komponente aus dem Modul über einen Intent starten und den Intent von der aufrufenden App weiterleiten. Ist das Modul nicht vorhanden, kann die Komponente das Modul 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 Kontext Ihrer Basisanwendung und die Aktivitäten in Ihrem Funktionsmodul aktivieren, können Sie nach der Installation des optionalen Moduls den Code und die Ressourcen aus einem Funktionsmodul so verwenden, als ob es Teil des Basis-APKs wäre.

Code aus einem anderen Modul aufrufen

Über ein Modul auf Basiscode zugreifen

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

Über ein anderes Modul auf Modulcode zugreifen

Auf ein Objekt oder eine Klasse in einem Modul kann nicht direkt von einem anderen Modul aus zugegriffen werden, sondern nur indirekt über Reflexion.

Seien Sie vorsichtig, wie oft dies aufgrund der Leistungskosten der Reflexion passiert. Verwenden Sie für komplexe Anwendungsfälle Abhängigkeitsinjektions-Frameworks wie Dagger 2, um einen einzelnen 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 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();

Zugriff auf Ressourcen und Assets aus einem anderen Modul

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

  • Wenn Sie von einem anderen Modul aus auf eine Ressource zugreifen, hat das Modul keinen Zugriff auf die Ressourcen-ID. Die Ressource kann jedoch weiterhin über den Namen aufgerufen werden. Beachten Sie, dass das Paket, das zum Verweisen auf die Ressource verwendet werden soll, das Paket des Moduls ist, in dem die Ressource definiert ist.
  • Wenn Sie über ein anderes installiertes Modul Ihrer App auf Assets oder Ressourcen in einem neu installierten Modul zugreifen möchten, 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 die Komponente neu erstellen (z. B. durch Aufrufen von Activity.recreate()) oder nach der Installation des Funktionsmoduls SplitCompat neu installieren.

Nativen Code mit On-Demand-Auslieferung in eine App laden

Wir empfehlen die Verwendung von ReLinker, um alle Ihre nativen Bibliotheken bei der On-Demand-Bereitstellung von Featuremodulen zu laden. ReLinker behebt ein Problem beim Laden nativer Bibliotheken nach der Installation eines Funktionsmoduls. 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, seinen nativen Code über ReLinker zu laden. Für Instant Apps sollten Sie diese spezielle Methode verwenden.

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

Wenn Sie dlopen() in nativem Code verwenden, um eine Bibliothek zu laden, die in einem optionalen Modul definiert ist, funktioniert es nicht mit relativen Bibliothekspfaden. Die beste Lösung besteht darin, den absoluten Pfad der Bibliothek aus dem Java-Code über ClassLoader.findLibrary() abzurufen und ihn 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, kannst du über einen aktualisierten Kontext der App auf den zugehörigen 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 nicht den Inhalt des neuen Moduls. Ein neuer Kontext hingegen schon. Sie können dies 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 ein On-Demand-Modul für eine Android Instant App unter Android 8.0 (API-Level 26) und höher angefordert wird und eine Installationsanfrage als INSTALLED gemeldet wird, musst du die App über einen Aufruf von SplitInstallHelper.updateAppInfo(Context context) mit dem Kontext des neuen Moduls aktualisieren. Andernfalls kennt 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 Hauptthreadereignisses laden. Dazu rufen Sie ein neues Handler auf, 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 das Gerät bereits in einer Instant App heruntergeladen hat, 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 auf Ressourcen oder Assets aus einem optionalen Modul zugreift. Das liegt an einer Inkompatibilität zwischen WebView und SplitCompat unter Android API-Level 28 und niedriger.
  • Du kannst Android ApplicationInfo-Objekte, deren Inhalte oder Objekte, die sie in deiner App enthalten, nicht im Cache speichern. Du solltest 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 Feature-Moduls 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> der Namen der installierten Module zurückgegeben (siehe unten).

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. Rufen Sie dazu wie unten gezeigt SplitInstallManager.deferredUninstall(List<String> moduleNames) auf.

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

Deinstallationen erfolgen nicht sofort. Das heißt, sie werden je nach Bedarf im Hintergrund deinstalliert, um Speicherplatz zu sparen. Sie können prüfen, ob das Gerät ein Modul gelöscht hat. Rufen Sie dazu SplitInstallManager.getInstalledModules() auf und prüfen Sie 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 der App erforderlich sind. Bei Sprachressourcen lädt das Gerät eines Nutzers also nur die Sprachressourcen Ihrer App herunter, die der oder mehreren Sprachen entsprechen, 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 bei Bedarf über die Play Feature Delivery-Bibliothek herunterladen. Der Vorgang ähnelt dem Herunterladen eines Funktionsmoduls (siehe unten).

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 verarbeitet. Das heißt, Sie können den Anfragestatus wie gewohnt überwachen.

Wenn Ihre App die zusätzlichen Sprachressourcen nicht sofort benötigt, können Sie die Installation wie unten dargestellt verschieben, bis die App 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 Zugriff auf heruntergeladene Sprachressourcen zu erhalten, muss Ihre Anwendung 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 Sprachressourcen verwenden möchten, die von Ihrer App heruntergeladen wurden, 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 die Aktivität neu erstellen, nachdem die neue Sprache installiert und einsatzbereit ist. Sie können dazu 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 beantragen, sollten Sie zuerst ermitteln, welche Sprachen derzeit installiert sind. Gehen Sie dazu so vor:

Kotlin

val installedLanguages: Set<String> = splitInstallManager.installedLanguages

Java

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

Mit der Methode deferredLanguageUninstall() können Sie dann entscheiden, welche Sprachen deinstalliert werden sollen.

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 können Sie lokal testen, ob Ihre App für Folgendes geeignet ist, ohne eine Verbindung zum Play Store herzustellen:

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 Play Store zu simulieren.

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

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

Satz von APKs erstellen

Erstellen Sie die unterteilten APKs für Ihre App, 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 einen Satz 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 Ihrer APKs, wodurch die Play Feature Delivery Library weiß, dass die lokalen unterteilten APKs zum Testen der Installation von Funktionsmodulen verwendet werden können, ohne eine Verbindung zum Play Store herzustellen.

App auf dem Gerät bereitstellen

Nachdem Sie mit dem Flag --local-testing einen Satz 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. 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 abschließt, verwendet die Play Feature Delivery Library die APKs, die bundletool in den lokalen Speicher des Geräts übertragen hat.

Netzwerkfehler simulieren

Um Modulinstallationen aus dem Play Store zu simulieren, verwendet die Play Feature Delivery Library FakeSplitInstallManager als Alternative zum SplitInstallManager, 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 Library 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 Anwendung das nächste Mal ein Modul anfordert. Um in Ihren Tests auf FakeSplitInstallManager zuzugreifen, können Sie mit dem FakeSplitInstallManagerFactory eine Instanz 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);