Konfigurowanie wyświetlania na żądanie

Moduły funkcji pozwalają oddzielić określone funkcje i zasoby od podstawowego modułu aplikacji i uwzględnić je w pakiecie aplikacji. Dzięki Play Feature Delivery użytkownicy mogą na przykład pobierać i instalować te komponenty na żądanie już po zainstalowaniu podstawowego pliku APK Twojej aplikacji.

Weźmy na przykład aplikację do wysyłania SMS-ów, która zawiera funkcję robienia i wysyłania wiadomości z obrazem, ale tylko niewielki odsetek użytkowników wysyła takie wiadomości. Możesz dodać funkcję przesyłania wiadomości z obrazami jako pobierany moduł funkcji. Dzięki temu początkowe pobranie aplikacji jest mniejsze dla wszystkich użytkowników, a tylko użytkownicy, którzy wysyłają wiadomości z obrazami, muszą pobrać ten dodatkowy komponent.

Pamiętaj, że ten typ modułowości wymaga więcej pracy i możliwego przebudowania dotychczasowego kodu aplikacji. Dlatego dokładnie zastanów się, które z funkcji aplikacji najlepiej sprawdzą się w ramach funkcji na żądanie. Aby lepiej zrozumieć optymalne przypadki użycia i wskazówki dotyczące funkcji na żądanie, przeczytaj sprawdzone metody dotyczące wygody użytkownika w przypadku funkcji na żądanie.

Jeśli chcesz stopniowo dzielić funkcje aplikacji na moduły, nie włączając zaawansowanych opcji przesyłania, takich jak przesyłanie na żądanie, skonfiguruj przesyłanie w momencie 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 Android Studio 3.5 lub nowszej wersji oraz wtyczki Android Gradle 3.5.0 lub nowszej.

Konfigurowanie nowego modułu do dostarczania na żądanie

Najłatwiejszym sposobem utworzenia nowego modułu funkcji jest użycie Android Studio 3.5 lub nowszego. Ponieważ moduły funkcji są nieodłącznie 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 za pomocą Android Studio, wykonaj te czynności:

  1. Jeśli jeszcze tego nie zrobiono, otwórz projekt aplikacji w IDE.
  2. Na pasku menu wybierz File > New > New Module (Plik > Nowy > Nowy moduł).
  3. W oknie Create New Module (Utwórz nowy moduł) wybierz Dynamic Feature Module (Moduł dynamicznych funkcji) i kliknij Next (Dalej).
  4. W sekcji Skonfiguruj nowy moduł wykonaj te czynności:
    1. W menu wybierz Moduł podstawowej aplikacji dla projektu aplikacji.
    2. Podaj nazwę modułu. IDE używa tej nazwy do identyfikowania modułu jako podprojektu Gradle w pliku ustawień Gradle. Podczas kompilowania pakietu aplikacji Gradle używa ostatniego elementu nazwy podprojektu, aby wstrzyknąć atrybut <manifest split> do pliku 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 interfejsu 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. Podaj Tytuł modułu, który może mieć maksymalnie 50 znaków. Platforma używa tego tytułu, aby zidentyfikować moduł dla użytkowników na przykład przy potwierdzaniu, czy użytkownik chce go pobrać. Z tego powodu moduł podstawowy aplikacji musi zawierać tytuł modułu jako zasób ciągu tekstowego, który możesz przetłumaczyć. Podczas tworzenia modułu w Android Studio IDE automatycznie dodaje do modułu podstawowego zasób ciągu znaków i wstrzykuje do pliku manifestu modułu funkcji następujący wpis:

      <dist:module
          ...
          dist:title="@string/feature_title">
      </dist:module>
      
    2. W menu Uwzględnienie w czasie instalacji wybierz Nie uwzględniaj modułu w czasie instalacji. Android Studio wstrzykuje do pliku manifestu modułu następujące informacje:

      <dist:module ... >
        <dist:delivery>
            <dist:on-demand/>
        </dist:delivery>
      </dist:module>
      
    3. Zaznacz pole obok opcji Fusing, jeśli chcesz, aby ten moduł był dostępny na urządzeniach z Androidem 4.4 (poziom interfejsu API 20) lub starszym i włączony w zestawie wielu plików APK. Oznacza to, że możesz włączyć działanie na żądanie w tym module i wyłączyć funkcję fusing, aby pomijać ją na urządzeniach, które nie obsługują pobierania i instalowania dzielonych pakietów APK. Android Studio wstrzykuje do pliku manifestu modułu następujące informacje:

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

Gdy Android Studio zakończy tworzenie modułu, sprawdź jego zawartość w panelu Projekt (na pasku menu wybierz Widok > Okna narzędziowe > Projekt). Domyślny kod, zasoby i organizacja powinny być podobne do tych w standardowym module aplikacji.

Następnie musisz zaimplementować 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ę funkcji Google Play.

Poproś o moduł na żądanie

Gdy aplikacja musi użyć modułu funkcji, może go zażądać, gdy znajduje się na pierwszym planie, za pomocą klasy SplitInstallManager. Podczas wysyłania żądania aplikacja musi podać nazwę modułu zgodnie z definicją elementu split w pliku manifestu modułu docelowego. Gdy tworzysz moduł funkcji za pomocą Android Studio, system kompilacji używa podanej przez Ciebie nazwy modułu, aby wstrzyknąć tę właściwość do pliku manifestu modułu w momencie kompilacji. Więcej informacji znajdziesz w pliku manifestu modułu funkcji.

Wyobraź sobie na przykład aplikację, która ma moduł na żądanie do robienia i wysyłania wiadomości z obrazem za pomocą aparatu urządzenia. Moduł ten określa w swoim pliku manifestu wartość split="pictureMessages". W tym przykładzie SplitInstallManager jest używany do wysyłania żądania do modułu pictureMessages (oraz dodatkowego modułu do 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 żąda modułu na żądanie, biblioteka Play Feature Delivery stosuje strategię „wypal i zapomnij”. Oznacza to, że wysyła żądanie pobrania modułu na platformę, ale nie sprawdza, czy instalacja się powiodła. Aby kontynuować ścieżkę użytkownika po instalacji lub w sposób sprawny obsługiwać błędy, monitoruj stan żądania.

Uwaga: możesz poprosić o moduł funkcji, który jest już zainstalowany na urządzeniu. Jeśli wykryje, że moduł jest już zainstalowany, interfejs API natychmiast uzna żądanie za zrealizowane. Dodatkowo po zainstalowaniu modułu Google Play automatycznie aktualizuje go. 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 uzyskać dostęp do kodu i zasobów modułu, aplikacja musi włączyć opcję SplitCompat. Pamiętaj, że w przypadku aplikacji błyskawicznych na Androida nie jest wymagane użycie interfejsu SplitCompat.

Odrocz instalację modułów na żądanie

Jeśli nie potrzebujesz aplikacji do natychmiastowego pobierania i instalowania modułu na żądanie, możesz odroczyć instalację, gdy aplikacja działa w tle. Możesz to zrobić na przykład, jeśli chcesz wstępnie załadować materiały promocyjne na potrzeby późniejszego uruchomienia aplikacji.

Aby określić moduł do pobrania później, użyj metody deferredInstall(), jak pokazano poniżej. Ponadto w przeciwieństwie do SplitInstallManager.startInstall() aplikacja nie musi być na pierwszym planie, aby można było wysłać żą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"));

Prośby o odroczone instalacje są realizowane zgodnie z zasadą możliwie najlepszej obsługi i nie można śledzić ich postępów. Dlatego zanim spróbujesz uzyskać dostęp do modułu, który został przez Ciebie oznaczony jako opóźniony, sprawdź, czy moduł został zainstalowany. Jeśli chcesz, aby moduł był dostępny od razu, poproś o niego, używając właściwości SplitInstallManager.startInstall(), jak pokazano w poprzedniej sekcji.

Monitorowanie stanu żądania

Aby móc aktualizować pasek postępu, wywołać intencję po instalacji lub prawidłowo obsłużyć błąd żądania, musisz nasłuchiwać aktualizacji stanu z niesynchronizowanego zadania SplitInstallManager.startInstall(). Zanim zaczniesz otrzymywać aktualizacje dotyczące żądania instalacji, zarejestruj odbiorczy i uzyskaj identyfikator sesji dla żądania, 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 udać, podobnie jak instalacja aplikacji. Niemożność zainstalowania może być spowodowana problemami takimi jak za mało miejsca na urządzeniu, brak połączenia z internetem lub brak zalogowania się użytkownika w Sklepie Google Play. Aby dowiedzieć się, jak łagodnie rozwiązywać takie sytuacje z perspektywy użytkownika, zapoznaj się z wskazówkami dotyczącymi interfejsu użytkownika w przypadku dostawy na żądanie.

W kodzie należy obsłużyć błędy pobierania lub instalowania modułu za pomocą 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 stany błędów, które może być konieczne w przypadku Twojej aplikacji:

Kod błędu Opis Sugerowane działanie
ACTIVE_SESSIONS_LIMIT_EXCEEDED Żądanie zostało odrzucone, ponieważ istnieje co najmniej 1 istniejące żądanie, które jest obecnie pobierane. Sprawdź, czy są jakieś żądania, które są nadal pobierane, jak pokazano na powyższym przykładzie.
MODULE_NIEDOSTĘPNY Google Play nie może znaleźć żądanego modułu na podstawie obecnie zainstalowanej wersji aplikacji, urządzenia lub konta Google Play użytkownika. Jeśli użytkownik nie ma dostępu do modułu, powiadom go o tym.
NIEPRAWIDŁOWE_ŻĄDANIE Google Play otrzymało prośbę, ale jest ona nieprawidłowa. Sprawdź, czy informacje zawarte w prośbie są kompletne i poprawne.
SESSION_NOT_FOUND Nie znaleziono sesji o podanym identyfikatorze. Jeśli próbujesz monitorować stan żądania według identyfikatora sesji, upewnij się, że identyfikator sesji jest prawidłowy.
API_NOT_AVAILABLE (niedostępny) Biblioteka funkcji Google Play nie jest obsługiwana na bieżącym urządzeniu. Oznacza to, że urządzenie nie może pobierać i instalować funkcji na żądanie. W przypadku urządzeń z Androidem 4.4 (poziom interfejsu API 20) lub starszym należy uwzględnić moduły funkcji w momencie instalacji, używając właściwości manifestu dist:fusing. Więcej informacji znajdziesz w pliku manifestu modułu funkcji.
NETWORK_ERROR Żądanie nie zostało zrealizowane z powodu błędu sieci. Poprowad użytkownika o ustanowienie połączenia z siecią lub o przełączenie się na inną sieć.
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 wysłać prośbę, gdy aplikacja wróci na pierwszy plan.
INCOMPATIBLE_WITH_EXISTING_SESSION Żądanie zawiera co najmniej 1 moduł, który został już zażądany, ale nie został jeszcze zainstalowany. Utwórz nowe żądanie, które nie zawiera modułów, których aplikacja już zażądała, lub poczekaj, aż wszystkie obecnie żądane moduły zostaną zainstalowane, zanim spróbujesz ponownie wysłać żądanie.

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

WYKONANY_USŁUGA Usługa odpowiedzialna za obsługę żądania przestała działać. Ponownie prześlij prośbę.

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

INSUFFICIENT_STORAGE Na urządzeniu jest za mało wolnego miejsca na zainstalowanie modułu funkcji. poinformować użytkownika, że nie ma wystarczającej ilości miejsca na dane, aby zainstalować tę funkcję;
SPLITCOMPAT_VERIFICATION_ERROR, SPLITCOMPAT_EMULATION_ERROR, SPLITCOMPAT_CONTENT_ERROR, SplitCompat nie może 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ępować tylko w przypadku odroczonych instalacji. Jeśli chcesz, aby użytkownik pobierał aplikację z Google Play, użyj opcji startInstall(), która może uzyskać niezbędne potwierdzenie użytkownika.
INTERNAL_ERROR W Sklepie Play wystąpił błąd wewnętrzny. Ponownie prześlij prośbę.

Jeśli użytkownik poprosi o pobranie modułu na żądanie i wystąpi błąd, rozważ wyświetlenie mu okna z 2 opcjami: Spróbuj ponownie (co spowoduje ponowne przesłanie żądania) lub Anuluj (co spowoduje rezygnację z żądania). Aby uzyskać dodatkową pomoc, możesz też podać link do Centrum pomocy, który przekieruje użytkowników do Centrum pomocy Google Play.

Aktualizacje stanu uchwytu

Po zarejestrowaniu listenera i zarejestrowaniu identyfikatora sesji dla żądania użyj funkcji 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 opisaliśmy w tabeli poniżej.

Stan żądania Opis Sugerowane działanie
OCZEKUJĄCA Prośba została zaakceptowana i wkrótce rozpocznie się pobieranie. Zainicjuj komponenty interfejsu, takie jak pasek postępu, aby przekazać użytkownikom opinię o pobieraniu.
REQUIRES_USER_CONFIRMATION Pobieranie wymaga potwierdzenia przez użytkownika. Najczęściej ten stan występuje, gdy aplikacja nie została zainstalowana za pomocą Google Play. Poproś użytkownika o potwierdzenie pobrania funkcji z Google Play. Aby dowiedzieć się więcej, zapoznaj się z sekcją dotyczącą uzyskiwania potwierdzenia od użytkownika.
POBIERANIE Pobieranie w toku. Jeśli udostępniasz pasek postępu pobierania, zaktualizuj interfejs za pomocą metod SplitInstallSessionState.bytesDownloaded() i SplitInstallSessionState.totalBytesToDownload() (zobacz przykładowy kod nad tabelą).
POBRANE Moduł został pobrany na urządzenie, ale instalacja jeszcze się nie rozpoczęła. Aplikacje powinny włączać SplitCompat, aby mieć dostęp do pobranych modułów i nie wyświetlać tego stanu. Jest to konieczne, aby uzyskać dostęp do kodu i zasobów modułu funkcji.
INSTALUJĘ Urządzenie instaluje moduł. Zaktualizuj pasek postępu. Ten stan jest zwykle krótki.
ZAINSTALOWANO Moduł jest zainstalowany na urządzeniu. Kod dostępu i zasoby w module, aby kontynuować ścieżkę użytkownika.

Jeśli moduł jest przeznaczony do aplikacji błyskawicznej na Androida działającej na Androidzie 8.0 (poziom interfejsu API 26) lub nowszym, 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. poproś użytkownika, aby spróbował ponownie lub anulował żądanie.
ANULOWANIE Urządzenie anuluje żądanie. Więcej informacji znajdziesz w sekcji Anulowanie prośby o instalację.
ODWOŁANY Prośba została anulowana.

Uzyskiwanie potwierdzenia użytkownika

W niektórych przypadkach przed spełnieniem żądania pobrania Google Play może wymagać potwierdzenia przez użytkownika. Dzieje się tak na przykład wtedy, gdy aplikacja nie została zainstalowana przez Google Play lub jeśli próbujesz pobrać dużą ilość danych przez mobilną transmisję danych. W takich przypadkach stan żądania zgłasza REQUIRES_USER_CONFIRMATION, a aplikacja musi uzyskać potwierdzenie użytkownika, zanim urządzenie będzie mogło pobrać i zainstalować moduły w żądaniu. Aby uzyskać potwierdzenie, aplikacja powinna wyświetlić użytkownikowi takie prompty:

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ć program uruchamiający wyniki aktywności, korzystając z wbudowanej umowy ActivityResultContracts.StartIntentSenderForResult. Zapoznaj się z artykułem Interfejsy API wyników działań.

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 i pobieranie będzie kontynuowane.
  • Jeśli użytkownik odrzuci potwierdzenie, stan prośby zmieni się na CANCELED.
  • Jeśli użytkownik nie dokona wyboru przed zniszczeniem okna, stan żądania pozostanie na poziomie REQUIRES_USER_CONFIRMATION. Aplikacja może ponownie poprosić użytkownika o wykonanie żądania.

Aby otrzymać wywołanie zwrotne z odpowiedzią użytkownika, możesz zastąpić metodę 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 jego zainstalowaniem, może wywołać metodę cancelInstall(), korzystając z 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);

Dostęp do modułów

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

Pamiętaj jednak, że po pobraniu modułu platforma ma dostęp do jego treści przez pewien czas (w niektórych przypadkach przez kilka dni):

  • Platforma nie może stosować żadnych nowych wpisów manifestu wprowadzonych przez moduł.
  • Platforma nie ma dostępu do zasobów modułu dla komponentów interfejsu użytkownika systemu, takich jak powiadomienia. Jeśli chcesz od razu używać takich zasobów, rozważ uwzględnienie ich w module podstawowym aplikacji.

Włącz SplitCompat

Aby aplikacja miała dostęp do kodu i zasobów z pobranej biblioteki, musisz włączyć SplitCompat, korzystając z jednej z metod opisanych w poniższych sekcjach.

Po włączeniu SplitCompat w aplikacji musisz też włączyć SplitCompat dla każdej aktywności w modułach funkcji, do których aplikacja ma mieć dostęp.

Zadeklaruj SplitCompatApplication w pliku manifestu

Najprostszym sposobem włączenia obsługi 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 automatycznie uzyskasz dostęp do kodu i zasobów z pobranych modułów funkcji.

Wywoływanie interfejsu SplitCompat w czasie wykonywania

Możesz też włączyć SplitCompat w określonych działaniach lub usługach w czasie wykonywania. Włączenie tej opcji w ten sposób jest wymagane do uruchamiania działań zawartych w modułach funkcji. Aby to zrobić, zastąpij attachBaseContext wartością widoczną poniżej.

Jeśli masz niestandardową klasę Application, zamiast niej rozszerz klasę SplitCompatApplication, aby umożliwić korzystanie z SplitCompat w aplikacji, jak pokazano poniżej:

Kotlin

class MyApplication : SplitCompatApplication() {
    ...
}

Java

public class MyApplication extends SplitCompatApplication {
    ...
}

SplitCompatApplication zastępuje tylko ContextWrapper.attachBaseContext(), aby uwzględnić SplitCompat.install(Context applicationContext). Jeśli nie chcesz, aby klasa Application rozszerzyła 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 z zainstalowanymi aplikacjami, 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 dla działań modułu

Po włączeniu obsługi SplitCompat w aplikacji podstawowej musisz włączyć obsługę SplitCompat dla każdej aktywności, którą aplikacja pobiera w module funkcji. Aby to zrobić, użyj metody SplitCompat.installActivity() w ten sposób:

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

Rozpoczynanie aktywności zdefiniowanej w module funkcji

Po włączeniu SplitCompat możesz uruchamiać aktywności zdefiniowane w modułach funkcji za pomocą funkcji 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 ramach modułu funkcji, który został pobrany na żądanie, masz działanie, musisz włączyć w nim obsługę Split Compat.

Uruchamianie usługi zdefiniowanej w module funkcji

Po włączeniu SplitCompat możesz uruchamiać usługi zdefiniowane w modułach funkcji za pomocą funkcji 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ć w modułach opcjonalnych komponentów wyeksportowanych z Androida.

System kompilacji scala wpisy w pliku manifestu dla wszystkich modułów z modułem podstawowym. Jeśli opcjonalny moduł zawierałby wyeksportowany komponent, byłby on dostępny nawet przed zainstalowaniem modułu i mógłby spowodować awarię z powodu braku kodu, gdy zostanie wywołany z innej aplikacji.

W przypadku komponentów wewnętrznych nie ma to znaczenia, ponieważ są one dostępne tylko dla aplikacji, która może 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ż zaimplementowanie wzorca proxy. Możesz to zrobić, dodając do bazy komponent zastępczy wyeksportowany z podstawy. Po uzyskaniu dostępu komponent zastępczy może sprawdzić, czy istnieje moduł zawierający treści. Jeśli moduł jest obecny, komponent pośredniczący może uruchomić komponent wewnętrzny z modułu za pomocą Intent, przekazując intencję z aplikacji wywołującej. Jeśli moduł jest nieobecny, komponent może go pobrać 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 kontekście podstawowej aplikacji i aktywności w module funkcji, po zainstalowaniu opcjonalnego modułu 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ć używany bezpośrednio przez inne moduły. Nie musisz robić nic specjalnego. Wystarczy zaimportować potrzebne klasy i z nich korzystać.

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

Obiekt lub klasa w module nie mogą być dostępne statycznie z innego modułu, ale można uzyskać do nich dostęp pośrednio, korzystając z odzwierciedlenia.

Zwracaj uwagę na to, jak często się to zdarza, ponieważ koszty działania są związane z odczuciem. W złożonych przypadkach używaj platform wstrzykiwania zależności, takich jak Dagger 2, aby zagwarantować pojedyncze wywołanie odczucia w czasie życia aplikacji.

Aby uprościć interakcje z obiektem po jego instancjowaniu, zalecamy zdefiniowanie interfejsu w module podstawowym, a jego implementację w module funkcji. Na 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 module w standardowy sposób, z dwoma wyjątkami:

  • Jeśli uzyskujesz dostęp do zasobu z innego modułu, moduł nie będzie mieć dostępu do identyfikatora zasobu, ale zasób będzie nadal dostępny 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, które znajdują się w nowo zainstalowanym module z poziomu innego zainstalowanego modułu aplikacji, musisz to zrobić w kontekście 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 metodę Activity.recreate()) lub ponownie zainstalować SplitCompat po zainstalowaniu modułu funkcji.

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

Zalecamy używanie ReLinkera do ładowania wszystkich natywnych bibliotek podczas dostarczania modułów funkcji na żądanie. ReLinker rozwiązuje problem z wczytywaniem bibliotek natywnych po zainstalowaniu modułu funkcji. Więcej informacji o ReLinker znajdziesz w artykule Wskazówki dotyczące JNI na Androidzie.

Wczytywanie kodu natywnego z opcjonalnego modułu

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

Jeśli używasz funkcji System.loadLibrary() do wczytania kodu natywnego, a biblioteka natywnych funkcji jest zależna od innej biblioteki w module, musisz najpierw wczytać tę inną bibliotekę ręcznie. Jeśli używasz ReLinkera, odpowiednią operacją jest Relinker.recursively().loadLibrary().

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

Dostęp do zainstalowanych aplikacji błyskawicznych na Androida

Gdy moduł aplikacji błyskawicznej na Androida zostanie zgłoszony jako 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. zapisany w zmiennej) nie zawiera treści nowego modułu. Nowy kontekst jest jednak potrzebny. Można go uzyskać, na przykład, za pomocą 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 Androidzie w wersji 8.0 lub nowszej

Gdy żądasz przesłania modułu na żądanie do aplikacji błyskawicznej na Androida w wersji 8.0 (poziom interfejsu API 26) lub nowszej, po zgłoszeniu prośby o instalację (INSTALLED) musisz zaktualizować aplikację, dodając kontekst nowego modułu za pomocą wywołania SplitInstallHelper.updateAppInfo(Context context). W przeciwnym razie aplikacja nie ma jeszcze dostępu do kodu i zasobów modułu. Po zaktualizowaniu metadanych aplikacji załaduj zawartość modułu podczas następnego zdarzenia głównego wątku, wywołując nową funkcję 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 został już pobrany na urządzenie w ramach 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ć interfejsu WebView w Androidzie w aktywności, która uzyskuje dostęp do zasobów lub zasobów multimedialnych z opcjonalnego modułu. Wynika to z niezgodności między WebView a SplitCompat w Androidzie na poziomie interfejsu API 28 lub niższym.
  • Nie możesz przechowywać w pamięci podręcznej obiektów ApplicationInfo Androida, ich zawartości ani obiektów, które je zawierają, w swojej aplikacji. Zawsze pobieraj te obiekty w miarę potrzeby z kontekstu aplikacji. Buforowanie takich obiektów może spowodować zawieszenie 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 zwróci Set<String> nazw zainstalowanych modułów, jak pokazano poniżej.

Kotlin

val installedModules: Set<String> = splitInstallManager.installedModules

Java

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

Odinstaluj moduły

Możesz poprosić urządzenie o odinstalowanie modułów, wywołując SplitInstallManager.deferredUninstall(List<String> moduleNames) w sposób pokazany 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"));

Odinstalowania modułu nie następują natychmiast. Oznacza to, że urządzenie odinstalowuje je w tle, gdy zajdzie taka potrzeba, aby zwolnić miejsce na dane. Możesz sprawdzić, czy moduł został usunięty z urządzenia, wywołując metodę SplitInstallManager.getInstalledModules() i sprawdzając wynik w sposób opisany w poprzedniej sekcji.

Pobieranie dodatkowych zasobów językowych

W przypadku pakietów aplikacji urządzenia pobierają tylko kod i zasoby, których potrzebują do uruchomienia aplikacji. W przypadku zasobów językowych urządzenie użytkownika pobiera tylko te zasoby językowe aplikacji, które odpowiadają co najmniej jednemu językowi wybranemu w ustawieniach urządzenia.

Jeśli chcesz, aby Twoja aplikacja miała dostęp do dodatkowych zasobów językowych (np. do implementowania selektora języka), możesz pobrać je na żądanie z biblioteki funkcji Google Play. 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 było żądaniem modułu funkcji. Oznacza to, że możesz monitorować stan prośby tak jak zwykle.

Jeśli aplikacja nie wymaga natychmiastowego zainstalowania dodatkowych zasobów językowych, możesz odłożyć instalację na czas, gdy aplikacja działa w tle (patrz 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 ramach metody attachBaseContext() w ramach 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 nowy język 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 uruchomieniu go. 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 funkcji, dodatkowe zasoby możesz odinstalować w dowolnym momencie. Zanim poprosisz o odinstalowanie, możesz najpierw sprawdzić, jakie języki są obecnie zainstalowane, w następujący sposób:

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

Testowanie lokalnie instalacji modułu

Biblioteka Play Feature Delivery pozwala lokalnie przetestować, czy aplikacja może wykonywać te czynności bez łączenia się ze Sklepem Play:

  • Wysyłanie żądań i monitorowanie instalacji modułów.
  • Postępowanie w przypadku błędów instalacji.
  • Użyj SplitCompat, aby otworzyć moduły.

Z tego artykułu dowiesz się, jak wdrożyć dzielone pliki APK aplikacji na urządzeniu testowym, aby usługa Play Feature Delivery automatycznie używała tych plików APK do symulacji wysyłania żądań, pobierania i instalowania modułów ze Sklepu Play.

Chociaż nie musisz wprowadzać żadnych zmian w logice aplikacji, musisz spełnić te wymagania:

Tworzenie zestawu plików APK

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

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

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

Flaga --local-testing zawiera metadane w pliku manifestu APK, które informują Bibliotekę Play Feature Delivery o tym, że należy użyć lokalnie 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 opcji bundletool, aby zainstalować podstawową wersję aplikacji i przekazać dodatkowe pliki APK do pamięci lokalnej urządzenia. Możesz wykonać obie te czynności za pomocą tego polecenia:

bundletool install-apks --apks my_app.apks

Gdy teraz uruchomisz aplikację i przejdziesz przez proces pobierania i instalowania modułu funkcji, Biblioteka funkcji w Google Play użyje plików APK, które bundletoolzostały przeniesione 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 o nazwie FakeSplitInstallManager, aby zażądać modułu. Jeśli używasz bundletool z flagą --local-testing do utworzenia zestawu plików APK i wdrożenia ich na urządzeniu testowym, zawiera on metadane, które instruują bibliotekę Play Feature Delivery, aby automatycznie przełączały wywołania interfejsu API aplikacji na wywołanie FakeSplitInstallManager zamiast SplitInstallManager.

FakeSplitInstallManager zawiera flagę logiczną, którą możesz włączyć, aby symulować błąd sieci następnym razem, gdy aplikacja poprosi o zainstalowanie modułu. Aby uzyskać dostęp do FakeSplitInstallManager w testach, możesz uzyskać jego instancję za pomocą funkcji 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);