Konfigurowanie wyświetlania na żądanie

Moduły funkcji umożliwiają oddzielenie niektórych funkcji i zasobów od modułu podstawowego aplikacji i uwzględnienie ich w pakiecie aplikacji. Dzięki dostarczaniu funkcji w Google Play użytkownicy mogą na przykład później pobrać i zainstalować te komponenty na żądanie po zainstalowaniu podstawowego pliku APK aplikacji.

Weźmy na przykład aplikację do wysyłania SMS-ów, która umożliwia przechwytywanie i wysyłanie wiadomości z obrazkami, ale tylko niewielki odsetek użytkowników wysyła takie wiadomości. Warto rozważyć uwzględnienie wiadomości z obrazkami jako modułu funkcji do pobrania. Dzięki temu początkowe pobieranie aplikacji jest mniejsze dla wszystkich użytkowników, a tylko ci, którzy wysyłają wiadomości z obrazkami, muszą pobrać ten dodatkowy komponent.

Pamiętaj, że ten rodzaj modularizacji wymaga więcej wysiłku i może wiązać się z refaktoryzacją istniejącego kodu aplikacji. Zastanów się więc, które funkcje aplikacji przyniosą największe korzyści, jeśli będą dostępne dla użytkowników na żądanie. Aby lepiej poznać optymalne przypadki użycia i wytyczne dotyczące funkcji na żądanie, przeczytaj artykuł Sprawdzone metody dotyczące wygody użytkownika w przypadku dostawy na żądanie.

Jeśli chcesz stopniowo modularyzować funkcje aplikacji w miarę upływu czasu bez włączania zaawansowanych opcji przesyłania, takich jak przesyłanie na żądanie, skonfiguruj przesyłanie podczas instalacji.

Na tej stronie dowiesz się, jak dodać moduł funkcji do projektu aplikacji i skonfigurować go pod kątem dostarczania na żądanie. Zanim zaczniesz, upewnij się, że używasz Androida Studio w wersji 3.5 lub nowszej oraz wtyczki Androida do obsługi Gradle w wersji 3.5.0 lub nowszej.

Konfigurowanie nowego modułu dostawy na żądanie

Najłatwiej utworzyć nowy moduł funkcji za pomocą Androida Studio 3.5 lub nowszego. Ponieważ moduły funkcji są zależne od modułu aplikacji podstawowej, możesz je dodawać tylko do istniejących projektów aplikacji.

Aby dodać moduł funkcji do projektu aplikacji w Android Studio, wykonaj te czynności:

  1. Jeśli nie zostało to jeszcze zrobione, otwórz projekt aplikacji w IDE.
  2. Na pasku menu wybierz Plik > Nowy > Nowy moduł.
  3. W oknie Create New Module (Utwórz nowy moduł) wybierz Dynamic Feature Module (Moduł funkcji dynamicznych) i kliknij Next (Dalej).
  4. W sekcji Skonfiguruj nowy moduł wykonaj te czynności:
    1. W menu wybierz moduł aplikacji podstawowej dla projektu aplikacji.
    2. Określ nazwę modułu. IDE używa tej nazwy do identyfikowania modułu jako podprojektu Gradle w pliku ustawień Gradle. Gdy tworzysz pakiet aplikacji, Gradle używa ostatniego elementu nazwy podprojektu, aby wstawić atrybut <manifest split> do manifestu modułu funkcji.
    3. Podaj nazwę pakietu modułu. Domyślnie Android Studio sugeruje nazwę pakietu, która łączy nazwę pakietu głównego modułu podstawowego i nazwę modułu określoną w poprzednim kroku.
    4. Wybierz minimalny poziom API, który ma być obsługiwany przez moduł. Ta wartość powinna być zgodna z wartością modułu podstawowego.
  5. Kliknij Dalej.
  6. W sekcji Opcje pobierania modułu wykonaj te czynności:

    1. Określ tytuł modułu (maksymalnie 50 znaków). Platforma używa tego tytułu, aby identyfikować moduł przed użytkownikami, np. gdy potwierdzają oni, czy chcą go pobrać. Dlatego moduł podstawowy aplikacji musi zawierać tytuł modułu jako zasób w postaci ciągu tekstowego, który możesz przetłumaczyć. Podczas tworzenia modułu w Android Studio środowisko IDE dodaje do modułu podstawowego zasób w postaci ciągu znaków i wstawia w pliku manifestu modułu funkcji ten wpis:

      <dist:module
          ...
          dist:title="@string/feature_title">
      </dist:module>
      
    2. W menu pod nagłówkiem Uwzględnianie w momencie instalacji wybierz Nie uwzględniaj modułu w momencie instalacji. Android Studio wstrzykuje do pliku manifestu modułu te informacje, aby odzwierciedlić Twój wybór:

      <dist:module ... >
        <dist:delivery>
            <dist:on-demand/>
        </dist:delivery>
      </dist:module>
      
    3. Jeśli chcesz, aby ten moduł był dostępny na urządzeniach z Androidem 4.4 (API na poziomie 20) lub starszym i był uwzględniony w zestawach wielu plików APK, zaznacz pole obok opcji Łączenie. Oznacza to, że możesz włączyć działanie na żądanie w przypadku tego modułu i wyłączyć łączenie, aby pominąć go na urządzeniach, które nie obsługują pobierania i instalowania podzielonych plików APK. Android Studio wstrzykuje do pliku manifestu modułu te informacje, aby odzwierciedlić Twój wybór:

      <dist:module ...>
          <dist:fusing dist:include="true | false" />
      </dist:module>
      
  7. Kliknij Zakończ.

Gdy Android Studio skończy tworzyć moduł, sprawdź jego zawartość w panelu Project (na pasku menu wybierz View > Tool Windows > Project). Domyślny kod, zasoby i organizacja powinny być podobne do tych w standardowym module aplikacji.

Następnie musisz wdrożyć funkcję instalacji na żądanie za pomocą biblioteki Play Feature Delivery.

Dodawanie biblioteki Play Feature Delivery do projektu

Zanim zaczniesz, musisz najpierw dodać do projektu bibliotekę dostarczania funkcji w Google Play.

Prośba o moduł na żądanie

Gdy aplikacja potrzebuje modułu funkcji, może o niego poprosić, gdy jest na pierwszym planie, za pomocą klasy SplitInstallManager. Podczas wysyłania żądania aplikacja musi podać nazwę modułu zdefiniowaną przez element split w pliku manifestu modułu docelowego. Gdy utworzysz moduł funkcji w Android Studio, system kompilacji użyje podanej przez Ciebie nazwy modułu, aby wstrzyknąć tę właściwość do pliku manifestu modułu w czasie kompilacji. Więcej informacji znajdziesz w artykule o plikach manifestu modułu funkcji.

Rozważmy na przykład aplikację, która ma moduł na żądanie do robienia i wysyłania wiadomości z obrazkami za pomocą aparatu urządzenia. Ten moduł na żądanie określa w swoim pliku manifestu wartość split="pictureMessages". W tym przykładzie użyto metody SplitInstallManager, aby poprosić o moduł pictureMessages (wraz z dodatkowym modułem dla niektórych filtrów promocyjnych):

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 -> { ... });

Gdy aplikacja zażąda modułu na żądanie, biblioteka Play Feature Delivery zastosuje strategię „wyślij i zapomnij”. Oznacza to, że wysyła żądanie pobrania modułu na platformę, ale nie monitoruje, czy instalacja się powiodła. Aby kontynuować proces po instalacji lub prawidłowo obsługiwać błędy, monitoruj stan żądania.

Uwaga: możesz poprosić o moduł funkcji, który jest już zainstalowany na urządzeniu. Jeśli interfejs API wykryje, że moduł jest już zainstalowany, natychmiast uzna żądanie za zrealizowane. Po zainstalowaniu modułu Google Play automatycznie go aktualizuje. Oznacza to, że gdy prześlesz nową wersję pakietu aplikacji, platforma zaktualizuje wszystkie zainstalowane pliki APK należące do Twojej aplikacji. Więcej informacji znajdziesz w artykule Zarządzanie aktualizacjami aplikacji.

Aby mieć dostęp do kodu i zasobów modułu, aplikacja musi włączyć SplitCompat. Pamiętaj, że w przypadku aplikacji błyskawicznych na Androida nie jest wymagana biblioteka SplitCompat.

Odłożona instalacja modułów na żądanie

Jeśli nie musisz od razu pobierać i instalować modułu na żądanie, możesz odłożyć instalację do momentu, gdy aplikacja będzie działać w tle. Na przykład jeśli chcesz wstępnie wczytać materiały promocyjne przed późniejszym wprowadzeniem aplikacji.

Moduł do pobrania w późniejszym czasie możesz określić za pomocą metody deferredInstall(), jak pokazano poniżej. W przeciwieństwie do SplitInstallManager.startInstall() Twoja aplikacja nie musi być na pierwszym planie, aby zainicjować żądanie odroczonej instalacji.

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

Żądania odroczonych instalacji są obsługiwane w miarę możliwości i nie można śledzić ich postępu. Zanim spróbujesz uzyskać dostęp do modułu określonego do odroczonej instalacji, sprawdź, czy został on zainstalowany. Jeśli chcesz, aby moduł był dostępny od razu, użyj zamiast tego metody SplitInstallManager.startInstall(), jak pokazano w poprzedniej sekcji.

Monitorowanie stanu prośby

Aby móc aktualizować pasek postępu, uruchamiać intencję po instalacji lub prawidłowo obsługiwać błąd żądania, musisz nasłuchiwać aktualizacji stanu z asynchronicznego zadania SplitInstallManager.startInstall(). Zanim zaczniesz otrzymywać aktualizacje dotyczące prośby o instalację, zarejestruj odbiorcę i uzyskaj identyfikator sesji dla prośby, jak pokazano poniżej.

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

Obsługa błędów żądań

Pamiętaj, że instalacja modułów funkcji na żądanie może czasami się nie powieść, podobnie jak instalacja aplikacji nie zawsze się udaje. Przyczyną niepowodzenia instalacji mogą być problemy takie jak mała ilość miejsca na urządzeniu, brak połączenia z siecią lub brak zalogowania użytkownika w Sklepie Google Play. Wskazówki dotyczące tego, jak z perspektywy użytkownika poradzić sobie z takimi sytuacjami, znajdziesz w naszych wskazówkach UX dotyczących dostawy na żądanie.

W kodzie błędy pobierania lub instalowania modułu należy obsługiwać za pomocą funkcji addOnFailureListener(), jak pokazano poniżej:

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

W tabeli poniżej znajdziesz opis stanów błędów, które aplikacja może obsługiwać:

Kod błędu Opis Sugerowane działanie
ACTIVE_SESSIONS_LIMIT_EXCEEDED Żądanie zostało odrzucone, ponieważ istnieje co najmniej 1 żądanie, które jest obecnie pobierane. Sprawdź, czy są jakieś żądania, które nadal się pobierają, jak pokazano na powyższym przykładzie.
MODULE_UNAVAILABLE Google Play nie może znaleźć żądanego modułu na podstawie aktualnie zainstalowanej wersji aplikacji, urządzenia i konta Google Play użytkownika. Jeśli użytkownik nie ma dostępu do modułu, powiadom go o tym.
NIEPRAWIDŁOWE_ŻĄDANIE Otrzymaliśmy Twoją prośbę, ale jest ona nieprawidłowa. Sprawdź, czy informacje zawarte w prośbie są kompletne i dokładne.
SESSION_NOT_FOUND Nie znaleziono sesji o podanym identyfikatorze. Jeśli chcesz monitorować stan żądania za pomocą identyfikatora sesji, upewnij się, że jest on prawidłowy.
API_NOT_AVAILABLE Biblioteka dostarczania funkcji z Google Play nie jest obsługiwana na tym urządzeniu. Oznacza to, że urządzenie nie może pobrać i zainstalować funkcji na żądanie. W przypadku urządzeń z Androidem 4.4 (API na poziomie 20) lub starszym należy uwzględnić moduły funkcji w momencie instalacji za pomocą właściwości manifestu dist:fusing. Więcej informacji znajdziesz w artykule o pliku manifestu modułu funkcji.
NETWORK_ERROR Żądanie nie zostało zrealizowane z powodu błędu sieci. Poproś użytkownika o nawiązanie połączenia sieciowego lub zmianę sieci.
ACCESS_DENIED Aplikacja nie może zarejestrować żądania z powodu niewystarczających uprawnień. Zwykle dzieje się tak, gdy aplikacja działa w tle. Spróbuj przesłać prośbę, gdy aplikacja wróci na pierwszy plan.
INCOMPATIBLE_WITH_EXISTING_SESSION Żądanie zawiera co najmniej 1 moduł, który został już zgłoszony, ale nie został jeszcze zainstalowany. Utwórz nowe żądanie, które nie obejmuje modułów, o które aplikacja już poprosiła, lub poczekaj, aż wszystkie obecnie żądane moduły zostaną zainstalowane, a potem spróbuj ponownie.

Pamiętaj, że żądanie modułu, który został już zainstalowany, nie powoduje błędu.

SERVICE_DIED Usługa odpowiedzialna za obsługę żądania została zamknięta. Ponów prośbę.

Twój SplitInstallStateUpdatedListener otrzymuje SplitInstallSessionState z tym kodem błędu, stanem FAILED i identyfikatorem sesji -1.

INSUFFICIENT_STORAGE Na urządzeniu nie ma wystarczająco dużo wolnego miejsca, aby zainstalować moduł funkcji. Powiadom użytkownika, że nie ma wystarczająco dużo miejsca na zainstalowanie tej funkcji.
SPLITCOMPAT_VERIFICATION_ERROR, SPLITCOMPAT_EMULATION_ERROR, SPLITCOMPAT_COPY_ERROR Nie udało się wczytać modułu funkcji. Te błędy powinny zniknąć automatycznie po ponownym uruchomieniu aplikacji.
PLAY_STORE_NOT_FOUND Aplikacja Sklep Play nie jest zainstalowana na urządzeniu. Poinformuj użytkownika, że do pobrania tej funkcji wymagana jest aplikacja Sklep Play.
APP_NOT_OWNED Aplikacja nie została zainstalowana przez Google Play i nie można pobrać tej funkcji. Ten błąd może wystąpić tylko w przypadku odroczonych instalacji. Jeśli chcesz, aby użytkownik pobrał aplikację z Google Play, użyj elementu startInstall(), który może uzyskać niezbędne potwierdzenie użytkownika.
INTERNAL_ERROR Wystąpił wewnętrzny błąd Sklepu Play. Ponów prośbę.

Jeśli użytkownik poprosi o pobranie modułu na żądanie i wystąpi błąd, rozważ wyświetlenie okna z 2 opcjami: Spróbuj ponownie (ponowna próba wysłania żądania) i Anuluj (rezygnacja z żądania). Aby uzyskać dodatkową pomoc, podaj też link do Pomocy, który kieruje użytkowników do Centrum pomocy Google Play.

Obsługa aktualizacji stanu

Po zarejestrowaniu odbiorcy i zarejestrowaniu identyfikatora sesji dla żądania użyj StateUpdatedListener.onStateUpdate() do obsługi zmian stanu, jak pokazano poniżej.

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.
        }
    }
}

Możliwe stany żądania instalacji zostały opisane w tabeli poniżej.

Stan żądania Opis Sugerowane działanie
OCZEKUJĄCA Prośba została zaakceptowana i pobieranie powinno wkrótce się rozpocząć. inicjować komponenty interfejsu, takie jak pasek postępu, aby informować użytkownika o pobieraniu.
REQUIRES_USER_CONFIRMATION Pobieranie wymaga potwierdzenia przez użytkownika. Ten stan najczęściej występuje, gdy aplikacja nie została zainstalowana z Google Play. Poproś użytkownika o potwierdzenie pobrania funkcji w Google Play. Więcej informacji znajdziesz w sekcji dotyczącej uzyskiwania potwierdzenia od użytkownika.
POBIERANIE Trwa pobieranie. Jeśli udostępniasz pasek postępu pobierania, użyj metod SplitInstallSessionState.bytesDownloaded()SplitInstallSessionState.totalBytesToDownload(), aby zaktualizować interfejs (patrz przykładowy kod powyżej tej tabeli).
POBRANE Urządzenie pobrało moduł, ale instalacja jeszcze się nie rozpoczęła. Aplikacje powinny włączyć SplitCompat, aby mieć dostęp do pobranych modułów i uniknąć tego stanu. Jest to wymagane, aby uzyskać dostęp do kodu i zasobów modułu funkcji.
INSTALUJĘ Urządzenie instaluje obecnie moduł. Zaktualizuj pasek postępu. Ten stan zwykle trwa krótko.
ZAINSTALOWANO Moduł zostanie zainstalowany na urządzeniu. Kod dostępu i zasoby w module umożliwiające kontynuowanie ścieżki użytkownika.

Jeśli moduł jest przeznaczony dla aplikacji natychmiastowej na Androida 8.0 (API na poziomie 26) lub nowszego, musisz użyć splitInstallHelper, aby zaktualizować komponenty aplikacji za pomocą nowego modułu.

BŁĄD Żądanie nie powiodło się, zanim moduł został zainstalowany na urządzeniu. zapytać użytkownika, czy chce ponowić żądanie, czy je anulować.
ANULOWANIE Urządzenie anuluje żądanie. Więcej informacji znajdziesz w sekcji poświęconej anulowaniu prośby o instalację.
ODWOŁANY Prośba została anulowana.

Uzyskiwanie potwierdzenia od użytkownika

W niektórych przypadkach Google Play może wymagać potwierdzenia przez użytkownika przed spełnieniem prośby o pobranie. Na przykład jeśli aplikacja nie została zainstalowana przez Google Play lub jeśli próbujesz pobrać duży plik przez sieć komórkową. W takich przypadkach stan żądania to REQUIRES_USER_CONFIRMATION, a aplikacja musi uzyskać potwierdzenie od użytkownika, zanim urządzenie będzie mogło pobrać i zainstalować moduły z żądania. Aby uzyskać potwierdzenie, aplikacja powinna wyświetlić użytkownikowi ten komunikat:

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

Możesz zarejestrować moduł uruchamiający wynik działania za pomocą wbudowanego kontraktu ActivityResultContracts.StartIntentSenderForResult. Więcej informacji znajdziesz w sekcji Interfejsy API wyników aktywności.

Stan prośby jest aktualizowany w zależności od odpowiedzi użytkownika:

  • Jeśli użytkownik zaakceptuje potwierdzenie, stan prośby zmieni się na PENDING, a pobieranie zostanie rozpoczęte.
  • Jeśli użytkownik odrzuci potwierdzenie, stan prośby zmieni się na CANCELED.
  • Jeśli użytkownik nie dokona wyboru przed zamknięciem okna, stan żądania pozostanie REQUIRES_USER_CONFIRMATION. Aplikacja może ponownie poprosić użytkownika o zakończenie żądania.

Aby otrzymać wywołanie zwrotne z odpowiedzią użytkownika, możesz zastąpić ActivityResultCallback, jak pokazano poniżej.

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

Anulowanie prośby o instalację

Jeśli aplikacja musi anulować żądanie przed instalacją, może wywołać metodę cancelInstall(), używając identyfikatora sesji żądania, jak pokazano poniżej.

Kotlin

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

Java

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

Moduły dostępu

Aby uzyskać dostęp do kodu i zasobów z pobranego modułu, aplikacja musi włączyć bibliotekę SplitCompat zarówno w przypadku samej aplikacji, jak i każdej aktywności w modułach z funkcjami, które pobiera.

Pamiętaj jednak, że po pobraniu modułu platforma przez pewien czas (w niektórych przypadkach przez kilka dni) będzie miała następujące ograniczenia dostępu do jego zawartości:

  • Platforma nie może zastosować żadnych nowych wpisów w pliku manifestu wprowadzonych przez moduł.
  • Platforma nie ma dostępu do zasobów modułu w przypadku komponentów interfejsu systemu, takich jak powiadomienia. Jeśli musisz od razu użyć takich zasobów, rozważ umieszczenie ich w module podstawowym aplikacji.

Włączanie SplitCompat

Aby aplikacja mogła uzyskać dostęp do kodu i zasobów z pobranego modułu, musisz włączyć SplitCompat, korzystając tylko z jednej z metod opisanych w poniższych sekcjach.

Po włączeniu SplitCompat w aplikacji musisz też włączyć SplitCompat w każdym działaniu w modułach funkcji, do których aplikacja ma mieć dostęp.

Zadeklaruj SplitCompatApplication w pliku manifestu

Najprostszym sposobem na włączenie SplitCompat jest zadeklarowanie SplitCompatApplication jako podklasy Application w pliku manifestu aplikacji, jak pokazano poniżej:

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

Po zainstalowaniu aplikacji na urządzeniu możesz automatycznie uzyskiwać dostęp do kodu i zasobów z pobranych modułów funkcji.

Wywoływanie SplitCompat w czasie działania

Możesz też włączyć SplitCompat w określonych działaniach lub usługach w czasie działania. Włączenie SplitCompat w ten sposób jest wymagane do uruchamiania aktywności zawartych w modułach funkcji. Aby to zrobić, zastąp attachBaseContext, jak pokazano poniżej.

Jeśli masz niestandardową klasę Application, zamiast tego rozszerz ją o SplitCompatApplication, aby włączyć w aplikacji SplitCompat, jak pokazano poniżej:

Kotlin

class MyApplication : SplitCompatApplication() {
    ...
}

Java

public class MyApplication extends SplitCompatApplication {
    ...
}

SplitCompatApplication po prostu zastępuje ContextWrapper.attachBaseContext(), aby uwzględnić SplitCompat.install(Context applicationContext). Jeśli nie chcesz, aby klasa Application rozszerzała klasę SplitCompatApplication, możesz ręcznie zastąpić metodę attachBaseContext() w ten sposób:

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

Jeśli moduł na żądanie jest zgodny zarówno z aplikacjami błyskawicznymi, jak i zainstalowanymi, możesz wywołać SplitCompat warunkowo w ten sposób:

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

Włączanie SplitCompat w przypadku aktywności modułu

Po włączeniu SplitCompat w aplikacji podstawowej musisz włączyć SplitCompat w każdym działaniu, które aplikacja pobiera w module funkcji. Aby to zrobić, użyj metody 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);
}

Dostęp do komponentów zdefiniowanych w modułach funkcji

Uruchamianie aktywności zdefiniowanej w module funkcji

Po włączeniu SplitCompat możesz uruchamiać aktywności zdefiniowane w modułach funkcji za pomocą startActivity().

Kotlin

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

Java

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

Pierwszy parametr funkcji setClassName to nazwa pakietu aplikacji, a drugi to pełna nazwa klasy działania.

Jeśli w pobranym na żądanie module funkcji masz aktywność, musisz włączyć w niej SplitCompat.

Uruchamianie usługi zdefiniowanej w module funkcji

Po włączeniu SplitCompat możesz uruchamiać usługi zdefiniowane w modułach funkcji za pomocą startService().

Kotlin

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

Java

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

Eksportowanie komponentu zdefiniowanego w module funkcji

Nie należy umieszczać wyeksportowanych komponentów Androida w modułach opcjonalnych.

System kompilacji scala wpisy w manifestach wszystkich modułów w moduł podstawowy. Jeśli moduł opcjonalny zawierał wyeksportowany komponent, byłby on dostępny jeszcze przed zainstalowaniem modułu i mógłby powodować awarię z powodu brakującego kodu, gdyby był wywoływany z innej aplikacji.

Nie stanowi to problemu w przypadku komponentów wewnętrznych, ponieważ dostęp do nich ma tylko aplikacja. Może ona więc sprawdzić, czy moduł jest zainstalowany, zanim uzyska dostęp do komponentu.

Jeśli potrzebujesz wyeksportowanego komponentu i chcesz, aby jego zawartość znajdowała się w opcjonalnym module, rozważ wdrożenie wzorca proxy. Możesz to zrobić, dodając do bazy wyeksportowany komponent proxy. Po uzyskaniu do niego dostępu komponent proxy może sprawdzić obecność modułu zawierającego treść. Jeśli moduł jest obecny, komponent proxy może uruchomić wewnętrzny komponent z modułu za pomocą Intent, przekazując intencję z aplikacji wywołującej. Jeśli modułu nie ma, komponent może pobrać moduł lub zwrócić odpowiedni komunikat o błędzie do aplikacji wywołującej.

Dostęp do kodu i zasobów z zainstalowanych modułów

Jeśli włączysz SplitCompat w przypadku kontekstu aplikacji podstawowej i aktywności w module funkcji, po zainstalowaniu modułu opcjonalnego możesz używać kodu i zasobów z modułu funkcji tak, jakby były częścią podstawowego pliku APK.

Kod dostępu z innego modułu

Dostęp do kodu podstawowego z modułu

Kod znajdujący się w module podstawowym może być bezpośrednio używany przez inne moduły. Nie musisz nic robić. Wystarczy zaimportować i użyć potrzebnych klas.

Dostęp do kodu modułu z innego modułu

Do obiektu lub klasy w module nie można uzyskać dostępu statycznego bezpośrednio z innego modułu, ale można to zrobić pośrednio, używając refleksji.

Ze względu na koszty wydajności odbicia należy uważać na to, jak często się to zdarza. W przypadku złożonych przypadków użycia stosuj platformy wstrzykiwania zależności, takie jak Dagger 2, aby zagwarantować jedno wywołanie odbicia w okresie istnienia aplikacji.

Aby uprościć interakcje z obiektem po utworzeniu jego instancji, zalecamy zdefiniowanie interfejsu w module podstawowym i jego implementacji w module funkcji. Przykład:

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

Dostęp do zasobów i komponentów z innego modułu

Po zainstalowaniu modułu możesz uzyskać dostęp do zasobów i komponentów w modułach w standardowy sposób, z 2 wyjątkami:

  • Jeśli uzyskujesz dostęp do zasobu z innego modułu, moduł nie będzie mieć dostępu do identyfikatora zasobu, ale nadal będzie można uzyskać dostęp do zasobu według nazwy. Pamiętaj, że pakiet, którego należy użyć do odwołania się do zasobu, to pakiet modułu, w którym zdefiniowano zasób.
  • Jeśli chcesz uzyskać dostęp do zasobów lub plików, które znajdują się w nowo zainstalowanym module, z innego zainstalowanego modułu aplikacji, musisz to zrobić za pomocą kontekstu aplikacji. Kontekst komponentu, który próbuje uzyskać dostęp do zasobów, nie zostanie jeszcze zaktualizowany. Możesz też ponownie utworzyć ten komponent (np. wywołując Activity.recreate()) lub ponownie zainstalować SplitCompat po zainstalowaniu modułu funkcji.

Ładowanie kodu natywnego w aplikacji za pomocą dostarczania na żądanie

Jeśli używasz dostarczania modułów funkcji na żądanie, zalecamy używanie ReLinkera do wczytywania wszystkich bibliotek natywnych. ReLinker rozwiązuje problem z wczytywaniem bibliotek natywnych po zainstalowaniu modułu funkcji. Więcej informacji o ReLinker znajdziesz w wskazówkach dotyczących JNI na Androidzie.

Wczytywanie kodu natywnego z modułu opcjonalnego

Po zainstalowaniu podziału zalecamy wczytanie jego kodu natywnego za pomocą ReLinkera. W przypadku aplikacji natychmiastowych należy użyć tej specjalnej metody.

Jeśli do wczytywania kodu natywnego używasz funkcji System.loadLibrary(), a biblioteka natywna jest zależna od innej biblioteki w module, musisz najpierw ręcznie wczytać tę drugą bibliotekę. Jeśli używasz ReLinkera, odpowiednikiem tej operacji jest Relinker.recursively().loadLibrary().

Jeśli używasz funkcji dlopen() w kodzie natywnym do wczytywania biblioteki zdefiniowanej w module opcjonalnym, nie będzie ona działać ze ścieżkami względnymi biblioteki. Najlepszym rozwiązaniem jest pobranie bezwzględnej ścieżki biblioteki z kodu Java za pomocą ClassLoader.findLibrary(), a następnie użycie jej w wywołaniu dlopen(). Zrób to przed wprowadzeniem kodu natywnego lub użyj wywołania JNI z kodu natywnego do Javy.

Dostęp do zainstalowanych aplikacji błyskawicznych na Androida

Gdy moduł aplikacji błyskawicznej na Androida zgłosi stan INSTALLED, możesz uzyskać dostęp do jego kodu i zasobów za pomocą odświeżonego kontekstu aplikacji. Kontekst utworzony przez aplikację przed zainstalowaniem modułu (np. kontekst, który jest już przechowywany w zmiennej) nie zawiera treści nowego modułu. Świeży kontekst już tak – można go uzyskać np. za pomocą funkcji 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();
        }
    }
}

Aplikacje błyskawiczne na Androida w wersji 8.0 lub nowszej

Gdy zgłaszasz prośbę o moduł na żądanie w przypadku aplikacji natychmiastowej na Androida w wersji 8.0 (poziom 26 interfejsu API) lub nowszej, po tym, jak prośba o instalację zostanie oznaczona jako INSTALLED, musisz zaktualizować aplikację za pomocą kontekstu nowego modułu, wywołując funkcję SplitInstallHelper.updateAppInfo(Context context). W przeciwnym razie aplikacja nie będzie jeszcze znać kodu modułu ani jego zasobów. Po zaktualizowaniu metadanych aplikacji wczytaj zawartość modułu podczas następnego zdarzenia głównego wątku, wywołując nowy Handler, jak pokazano poniżej:

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();
                        ...
                    }
                });
            }
        }
    }
}

Wczytywanie bibliotek C/C++

Jeśli chcesz wczytać biblioteki C/C++ z modułu, który urządzenie pobrało już w aplikacji błyskawicznej, użyj SplitInstallHelper.loadLibrary(Context context, String libName), jak pokazano poniżej:

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

Znane ograniczenia

  • Nie można używać Androida WebView w aktywności, która uzyskuje dostęp do zasobów lub komponentów z modułu opcjonalnego. Jest to spowodowane niezgodnością między WebView a SplitCompat na Androidzie na poziomie interfejsu API 28 i niższym.
  • Nie możesz buforować obiektów ApplicationInfo na Androidzie, ich zawartości ani obiektów, które je zawierają, w swojej aplikacji. Zawsze pobieraj te obiekty w razie potrzeby z kontekstu aplikacji. Buforowanie takich obiektów może spowodować awarię aplikacji podczas instalowania modułu funkcji.

Zarządzanie zainstalowanymi modułami

Aby sprawdzić, które moduły funkcji są obecnie zainstalowane na urządzeniu, możesz wywołać metodę SplitInstallManager.getInstalledModules(), która zwraca Set<String> z nazwami zainstalowanych modułów, jak pokazano poniżej.

Kotlin

val installedModules: Set<String> = splitInstallManager.installedModules

Java

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

Odinstalowywanie modułów

Możesz poprosić urządzenie o odinstalowanie modułów, wywołując SplitInstallManager.deferredUninstall(List<String> moduleNames), jak pokazano poniżej.

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

Odinstalowywanie modułów nie następuje natychmiast. Oznacza to, że urządzenie odinstalowuje je w tle w razie potrzeby, aby zaoszczędzić miejsce na dane. Aby potwierdzić, że urządzenie usunęło moduł, wywołaj funkcję SplitInstallManager.getInstalledModules() i sprawdź wynik, jak opisano w poprzedniej sekcji.

Pobieranie dodatkowych zasobów językowych

W przypadku pakietów aplikacji urządzenia pobierają tylko kod i zasoby potrzebne do uruchomienia aplikacji. W przypadku zasobów językowych urządzenie użytkownika pobiera tylko te zasoby językowe aplikacji, które odpowiadają jednemu lub kilku językom wybranym w ustawieniach urządzenia.

Jeśli chcesz, aby aplikacja miała dostęp do dodatkowych zasobów językowych, np. w celu zaimplementowania selektora języka w aplikacji, możesz użyć biblioteki Play Feature Delivery, aby pobrać je na żądanie. Proces jest podobny do pobierania modułu funkcji, jak pokazano poniżej.

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

Żądanie jest obsługiwane tak, jakby dotyczyło modułu funkcji. Oznacza to, że możesz monitorować stan prośby w standardowy sposób.

Jeśli aplikacja nie wymaga od razu dodatkowych zasobów językowych, możesz odłożyć instalację na czas, gdy aplikacja będzie działać w tle, jak pokazano poniżej.

Kotlin

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

Java

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

Dostęp do pobranych zasobów językowych

Aby uzyskać dostęp do pobranych zasobów językowych, aplikacja musi uruchomić metodę SplitCompat.installActivity() w metodzie attachBaseContext() każdej aktywności, która wymaga dostępu do tych zasobów, jak pokazano poniżej.

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

W przypadku każdej aktywności, w której chcesz używać zasobów językowych pobranych przez aplikację, zaktualizuj kontekst podstawowy i ustaw nowe ustawienia regionalne za pomocą metody Configuration:

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

Aby te zmiany zaczęły obowiązywać, musisz ponownie utworzyć aktywność po zainstalowaniu nowego języka i przygotowaniu go do użycia. Możesz użyć metody Activity#recreate().

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();
  ...
}

Odinstalowywanie dodatkowych zasobów językowych

Podobnie jak w przypadku modułów z funkcjami, dodatkowe zasoby możesz odinstalować w dowolnym momencie. Zanim poprosisz o odinstalowanie, sprawdź, które języki są obecnie zainstalowane.

Kotlin

val installedLanguages: Set<String> = splitInstallManager.installedLanguages

Java

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

Następnie możesz zdecydować, które języki chcesz odinstalować, korzystając z metody deferredLanguageUninstall(), jak pokazano poniżej.

Kotlin

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

Java

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

Lokalne testowanie instalacji modułów

Biblioteka dostarczania funkcji w Google Play umożliwia lokalne testowanie możliwości aplikacji w zakresie:

Na tej stronie opisujemy, jak wdrożyć podzielone pliki APK aplikacji na urządzeniu testowym, aby Play Feature Delivery automatycznie używał tych plików APK do symulowania żądania, pobierania i instalowania modułów ze Sklepu Play.

Nie musisz wprowadzać żadnych zmian w logice aplikacji, ale musisz spełniać te wymagania:

  • Pobierz i zainstaluj najnowszą wersję bundletool. Musisz bundletool utworzyć nowy zestaw plików APK do zainstalowania z pakietu aplikacji.

Tworzenie zestawu plików APK

Jeśli jeszcze tego nie zrobiono, utwórz podzielone pliki APK aplikacji w ten sposób:

  1. Utwórz pakiet aplikacji, korzystając z jednej z tych metod:
  2. Użyj polecenia bundletool, aby wygenerować zestaw plików APK dla wszystkich konfiguracji urządzeń:

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

Flaga --local-testing zawiera metadane w plikach manifestu APK, które informują bibliotekę dostarczania funkcji Play, że ma używać lokalnych podzielonych plików APK do testowania instalowania modułów funkcji bez łączenia się ze Sklepem Play.

Wdrażanie aplikacji na urządzeniu

Po utworzeniu zestawu plików APK za pomocą flagi --local-testing użyj polecenia bundletool, aby zainstalować podstawową wersję aplikacji i przenieść dodatkowe pliki APK do pamięci lokalnej urządzenia. Obie czynności możesz wykonać za pomocą tego polecenia:

bundletool install-apks --apks my_app.apks

Teraz, gdy uruchomisz aplikację i wykonasz proces pobierania i instalowania modułu funkcji, Biblioteka dostarczania funkcji Play użyje plików APK, które bundletoolprzeniesiono do pamięci lokalnej urządzenia.

Symulowanie błędu sieci

Aby symulować instalacje modułów ze Sklepu Play, biblioteka Play Feature Delivery używa alternatywy dla SplitInstallManager, zwanej FakeSplitInstallManager, do wysyłania żądań dotyczących modułów. Gdy używasz bundletool z flagą --local-testing do tworzenia zestawu plików APK i wdrażania ich na urządzeniu testowym, zawiera on metadane, które instruują bibliotekę dostarczania funkcji Play, aby automatycznie przełączała wywołania interfejsu API aplikacji na wywoływanie FakeSplitInstallManager zamiast SplitInstallManager.

FakeSplitInstallManager zawiera flagę logiczną, którą możesz włączyć, aby symulować błąd sieci przy następnym żądaniu instalacji modułu przez aplikację. Aby uzyskać dostęp do FakeSplitInstallManager w testach, możesz utworzyć jego instancję za pomocą FakeSplitInstallManagerFactory, jak pokazano poniżej:

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