Konfigurowanie wyświetlania na żądanie

Moduły funkcji umożliwiają oddzielenie niektórych funkcji i zasobów od modułu podstawowego aplikacji oraz uwzględnienie ich w pakiecie aplikacji. Dzięki Play Feature Delivery użytkownicy mogą na przykład pobrać i zainstalować te komponenty na żądanie, gdy już zainstalują podstawowy plik APK aplikacji.

Weźmy na przykład aplikację do obsługi SMS-ów, która umożliwia tworzenie i wysyłanie wiadomości graficznych, ale tylko niewielki odsetek użytkowników wysyła takie wiadomości. Warto dodać wiadomości ze zdjęciami jako moduł funkcji do pobrania. Dzięki temu wstępne pobieranie aplikacji będzie mniejsze w przypadku wszystkich użytkowników i tylko ci, którzy wysyłają wiadomości z obrazem, będą musieli pobrać dodatkowy komponent.

Pamiętaj, że ten typ modularyzacji wymaga więcej wysiłku i prawdopodobnie refaktoryzacji istniejącego kodu aplikacji, więc dobrze się zastanów, które funkcje aplikacji najbardziej skorzystałyby na udostępnieniu użytkownikom na żądanie. Aby lepiej zrozumieć optymalne przypadki użycia i wytyczne dotyczące funkcji na żądanie, zapoznaj się ze sprawdzonymi metodami UX dotyczącymi wyświetlania na żądanie.

Jeśli chcesz stopniowo grupować funkcje aplikacji w czasie bez włączania zaawansowanych opcji dostarczania, takich jak dostarczanie na żądanie, zamiast tego skonfiguruj dostarczanie w czasie instalacji.

Na tej stronie znajdziesz informacje o dodawaniu modułu funkcji do projektu aplikacji i konfigurowaniu go pod kątem dostarczania na żądanie. Zanim zaczniesz, upewnij się, że korzystasz z Androida Studio w wersji 3.5 lub nowszej i wtyczki Androida do obsługi Gradle w wersji 3.5.0 lub nowszej.

Konfigurowanie nowego modułu na potrzeby dostawy na żądanie

Najłatwiejszym sposobem utworzenia nowego modułu funkcji jest użycie Androida Studio w wersji 3.5 lub nowszej. Moduły funkcji są nieodłączną zależnością od podstawowego modułu aplikacji, więc 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. Otwórz projekt aplikacji w IDE, jeśli nie został jeszcze otwarty.
  2. Na pasku menu wybierz File > New > New Module (Plik > Nowy moduł > Nowy moduł).
  3. W oknie Create New Module (Utwórz nowy moduł) wybierz Dynamic Feature Module i kliknij Next (Dalej).
  4. W sekcji Skonfiguruj nowy moduł wykonaj te czynności:
    1. Wybierz z menu moduł aplikacji podstawowej dla projektu aplikacji.
    2. Wypełnij pole Nazwa 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 wstrzyknąć atrybut <manifest split> w 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 z nazwą modułu określoną w poprzednim kroku.
    4. Wybierz Minimalny poziom interfejsu API, który ma obsługiwać moduł. Ta wartość powinna być zgodna z wartością modułu podstawowego.
  5. Kliknij Dalej.
  6. W sekcji Module Download Options (Opcje pobierania modułu) wykonaj te czynności:

    1. Określ Tytuł modułu za pomocą maksymalnie 50 znaków. Platforma używa tego tytułu do identyfikowania modułu użytkownikom, na przykład aby potwierdzić, że użytkownik chce go pobrać. Z tego powodu podstawowy moduł aplikacji musi zawierać tytuł modułu jako zasób w postaci ciągu, który można przetłumaczyć. Podczas tworzenia modułu za pomocą Android Studio IDE dodaje ciąg znaków do modułu podstawowego i wstrzykuje ten wpis w pliku manifestu modułu funkcji:

      <dist:module
          ...
          dist:title="@string/feature_title">
      </dist:module>
      
    2. Z menu w sekcji Uwzględnienie czasu instalacji wybierz Nie uwzględniaj modułu w momencie instalacji. Android Studio wstawia w pliku manifestu modułu te informacje, aby odzwierciedlić Twój wybór:

      <dist:module ... >
        <dist:delivery>
            <dist:on-demand/>
        </dist:delivery>
      </dist:module>
      
    3. Zaznacz pole Łączenie, jeśli chcesz, aby ten moduł był dostępny na urządzeniach z Androidem 4.4 (poziom interfejsu API 20) lub starszym i zawarty w wielu plikach APK. Oznacza to, że możesz włączyć działanie na żądanie w tym module i wyłączyć fusing, aby pominąć ją na urządzeniach, które nie obsługują pobierania i instalowania dzielonych pakietów APK. Android Studio wstawia w 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 utworzy moduł, samodzielnie sprawdź jego zawartość w panelu Projekt (z paska menu wybierz Widok > Okna narzędzi > Projekt). Domyślny kod, zasoby i organizacja powinny być takie same jak w standardowym module aplikacji.

Następnie musisz wdrożyć funkcję instalacji na żądanie, korzystając z biblioteki Play Feature Delivery.

Dodawanie do projektu biblioteki Play Feature Delivery

Zanim zaczniesz, musisz najpierw dodać Bibliotekę funkcji Play Feature Delivery do projektu.

Poproś o moduł na żądanie

Jeśli aplikacja musi korzystać z modułu funkcji, może go zażądać, gdy jest na pierwszym planie w klasie SplitInstallManager. Gdy aplikacja wysyła żądanie, musi określić nazwę modułu zdefiniowaną przez element split w pliku manifestu modułu docelowego. Gdy tworzysz moduł funkcji w Android Studio, system kompilacji używa podanej przez Ciebie nazwy modułu do wstrzyknięcia tej właściwości do pliku manifestu modułu podczas kompilacji. Więcej informacji znajdziesz w plikach manifestu modułów funkcji.

Weźmy na przykład aplikację, która ma moduł na żądanie do przechwytywania i wysyłania wiadomości o obrazach przy użyciu aparatu urządzenia. Ten moduł na żądanie określa split="pictureMessages" w swoim pliku manifestu. W tym przykładzie użyto parametru SplitInstallManager, aby zażądać modułu pictureMessages (wraz z dodatkowym modułem zawierającym niektóre filtry promocyjne):

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 wysyła żądanie modułu na żądanie, biblioteka funkcji 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ć podróż użytkownika po instalacji lub bezproblemowo obsługiwać błędy, monitoruj stan żądania.

Uwaga: możesz pobrać moduł funkcji, który jest już zainstalowany na urządzeniu. Gdy interfejs API wykryje, że moduł jest już zainstalowany, od razu uznaje żądanie za ukończone. Dodatkowo 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 aplikacja miała dostęp do kodu i zasobów modułu, musi włączyć SplitCompat. Pamiętaj, że w przypadku aplikacji błyskawicznych na Androida metoda SplitCompat nie jest wymagana.

Odłóż instalację modułów na żądanie

Jeśli nie chcesz od razu pobrać i zainstalować modułu na żądanie, możesz odroczyć instalację aplikacji, która działa w tle. Na przykład gdy chcesz wczytać wcześniej materiały promocyjne, które ułatwią Ci wprowadzenie aplikacji na rynek później.

Możesz wskazać moduł do pobrania później, korzystając z metody deferredInstall(), jak pokazano poniżej. W przeciwieństwie do SplitInstallManager.startInstall() aplikacja nie musi działać na pierwszym planie, aby 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ą wysyłane w miarę możliwości i nie możesz śledzić ich postępu. Zanim spróbujesz uzyskać dostęp do modułu wskazanego jako odroczona instalacja, sprawdź, czy moduł został zainstalowany. Jeśli chcesz, aby moduł był dostępny od razu, wyślij do niego żądanie SplitInstallManager.startInstall(), jak pokazano w poprzedniej sekcji.

Monitorowanie stanu żądania

Aby zaktualizować pasek postępu, uruchomić intencję po instalacji lub płynnie obsłużyć błąd żądania, musisz nasłuchiwać aktualizacji stanu z asynchronicznego zadania SplitInstallManager.startInstall(). Zanim zaczniesz otrzymywać aktualizacje dotyczące żądania instalacji, zarejestruj detektor i pobierz identyfikator sesji żą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);

Postępowanie w przypadku błędów żądań

Pamiętaj, że instalacja modułów funkcji na żądanie może czasem się nie udać, tak samo jak instalacja aplikacji nie zawsze się uda. Przyczyną nieudanej 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, jak postępować w takich sytuacjach z perspektywy użytkownika, znajdziesz w naszych wskazówkach dotyczących UX podczas wyświetlania na żądanie.

Jeśli chodzi o kod, postępuj zgodnie z instrukcjami dotyczącymi pobierania lub instalowania modułu za pomocą addOnFailureListener():

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 informacje o stanach błędu, które może obsługiwać aplikacja:

Kod błędu Opis Sugerowane działanie
ACTIVE_SESSIONS_LIMIT_EXCEEDED Żądanie zostało odrzucone, ponieważ istnieje co najmniej jedno żądanie, które jest obecnie pobierane. Sprawdź, czy masz jakieś żądania, które są nadal pobierane, jak pokazano w przykładzie powyżej.
MODULE_UNAVAILABLE Google Play nie może znaleźć żądanego modułu na podstawie obecnie zainstalowanej wersji aplikacji, urządzenia i konta Google Play użytkownika. Jeśli użytkownik nie ma dostępu do modułu, powiadom go.
NIEPRAWIDŁOWE_ŻĄDANIE Google Play otrzymało żądanie, ale jest nieprawidłowe. Sprawdź, czy informacje zawarte w prośbie są kompletne i dokładne.
NIE_ZNALEZIONO_SESJI Nie znaleziono sesji o podanym identyfikatorze. Jeśli chcesz monitorować stan żądania według jego identyfikatora sesji, upewnij się, że jest on prawidłowy.
Interfejs API_NOT_AVAILABLE Biblioteka dostawy funkcji w Google Play nie jest obsługiwana na tym urządzeniu. Oznacza to, że nie da się na nie pobierać ani instalować funkcji. W przypadku urządzeń z Androidem 4.4 (poziom interfejsu API 20) lub niższym należy podczas instalacji uwzględniać moduły funkcji za pomocą właściwości dist:fusing w pliku manifestu. Więcej informacji znajdziesz w pliku manifestu modułu funkcji.
BŁĄD_SIECI Żądanie nie zostało zrealizowane z powodu błędu sieci. Poproś użytkownika o nawiązanie połączenia sieciowego lub przełączenie się na inną sieć.
OBRONIONY_DOSTĘP Aplikacja nie może zarejestrować żądania z powodu niewystarczających uprawnień. Zwykle dzieje się tak, gdy aplikacja działa w tle. Wysłać żądanie, gdy aplikacja wróci na pierwszy plan.
INCOMPATIBLE_WITH_EXISTING_SESSION Żądanie zawiera co najmniej 1 moduł, którego żądanie zostało już wysłane, ale nie zostało jeszcze zainstalowane. Utwórz nowe żądanie, które nie będzie zawierać modułów, o które żądała już Twoja aplikacja, lub poczekaj, aż wszystkie obecnie żądane moduły zostaną zainstalowane, zanim spróbujesz ponownie.

Pamiętaj, że przesłanie prośby o zainstalowany moduł nie spowoduje błędu.

USŁUGA_USŁUGI Usługa odpowiedzialna za obsługę żądania przestała działać. Ponów prośbę.

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

ZA MAŁO_MIEJSCA Na urządzeniu jest za mało wolnego miejsca, aby zainstalować moduł funkcji. Powiadom użytkownika, że nie ma wystarczającej ilości miejsca, aby zainstalować tę funkcję.
SPLITCOMPAT_VERIFICATION_ERROR, SPLITCOMPAT_EMULATION_ERROR, SPLITCOMPAT_COPY_ERROR Aplikacja SplitCompat nie może załadować modułu funkcji. Błędy te powinny automatycznie zniknąć 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 Ta aplikacja nie została zainstalowana z 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 pozyskał aplikację z Google Play, użyj funkcji startInstall(), która może uzyskać niezbędne potwierdzenie przez użytkownika.
BŁĄD_WEWNĘTRZNY W Sklepie Play wystąpił błąd wewnętrzny. Ponów prośbę.

Jeśli użytkownik poprosi o pobranie modułu na żądanie i pojawi się błąd, rozważ wyświetlenie okna z 2 opcjami: Spróbuj ponownie (spróbuj ponownie) i Anuluj (spowoduje to pominięcie żądania). Możesz też podać link do Pomocy, który przekieruje użytkowników do Centrum pomocy Google Play.

Obsługa aktualizacji stanu

Gdy zarejestrujesz detektor i zarejestrujesz identyfikator 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 prośby o instalację zostały opisane w tabeli poniżej.

Stan żądania Opis Sugerowane działanie
OCZEKUJĄCA Prośba została zaakceptowana i wkrótce powinno się rozpocząć pobieranie. Zainicjuj komponenty UI, takie jak pasek postępu, aby przekazać użytkownikowi opinię o pobieraniu.
WYMAGA POTWIERDZENIA_UŻYTKOWNIKA Pobranie wymaga potwierdzenia przez użytkownika. Ten stan występuje najczęściej wtedy, gdy aplikacja nie została zainstalowana z Google Play. Poproś użytkownika o potwierdzenie pobrania funkcji z Google Play. Więcej informacji znajdziesz w sekcji dotyczącej uzyskiwania potwierdzenia użytkownika.
POBIERAM Trwa pobieranie. Jeśli udostępniasz pasek postępu pobierania, zaktualizuj interfejs użytkownika za pomocą metod SplitInstallSessionState.bytesDownloaded() i SplitInstallSessionState.totalBytesToDownload() (patrz przykładowy kod nad tą tabelą).
POBRANE Urządzenie pobrało moduł, ale instalacja jeszcze się nie rozpoczęła. Aby mieć dostęp do pobranych modułów i uniknąć wyświetlania tego stanu w aplikacjach, aplikacje powinny włączyć funkcję SplitCompat. Jest to wymagane w celu uzyskania dostępu do kodu i zasobów modułu funkcji.
INSTALUJĘ Urządzenie instaluje obecnie moduł. Zaktualizuj pasek postępu. Ten stan jest zwykle krótki.
ZAINSTALOWANO Moduł jest zainstalowany na urządzeniu. Kod dostępu i zasób w module, aby kontynuować podróż użytkownika.

Jeśli moduł dotyczy aplikacji błyskawicznej na Androida w Androidzie 8.0 (poziom interfejsu API 26) lub nowszym, musisz użyć splitInstallHelper, aby zaktualizować komponenty aplikacji za pomocą nowego modułu.

PORAŻKA Żądanie nie powiodło się przed zainstalowaniem modułu na urządzeniu. Poproś użytkownika, aby ponowił prośbę lub ją anulował.
ANULUJE Trwa anulowanie żądania na urządzeniu. Więcej informacji znajdziesz w sekcji dotyczącej anulowania prośby o instalację.
ODWOŁANY Prośba została anulowana.

Uzyskiwanie potwierdzenia użytkownika

W niektórych przypadkach Google Play może wymagać potwierdzenia przez użytkownika, zanim zgodzi się na jego pobranie. Dzieje się tak na przykład wtedy, gdy Twoja aplikacja nie została zainstalowana z Google Play lub próbujesz pobrać duży plik, korzystając z mobilnej transmisji 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ć takie potwierdzenie, aplikacja powinna wyświetlić użytkownikowi 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);
    }
    ...
 }

Menu z wynikami działań możesz zarejestrować za pomocą wbudowanej umowy ActivityResultContracts.StartIntentSenderForResult. Zobacz Interfejsy API wyników działań.

Stan żądania 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 odmówi potwierdzenia, stan prośby zmieni się na CANCELED.
  • Jeśli użytkownik nie dokona wyboru przed zniszczeniem okna, stan żądania pozostanie taki: 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ć funkcję 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 przed zainstalowaniem aplikacji musisz anulować żądanie, może ona wywołać metodę cancelInstall() przy użyciu 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 po pobraniu uzyskać dostęp do kodu i zasobów z pobranego modułu, aplikacja musi włączyć bibliotekę SplitCompat zarówno dla aplikacji, jak i dla każdej aktywności w modułach funkcji pobieranych przez aplikację.

Zwróć jednak uwagę, że przez pewien czas (w niektórych przypadkach) po pobraniu modułu na platformie obowiązują te ograniczenia dostępu do zawartości modułu:

  • Platforma nie może stosować żadnych nowych wpisów w pliku manifestu wprowadzonych przez moduł.
  • Platforma nie ma dostępu do zasobów modułu związanych z komponentami interfejsu systemu, takimi jak powiadomienia. Jeśli potrzebujesz tych zasobów od razu, zastanów się nad umieszczeniem ich w module podstawowym aplikacji.

Włącz SplitCompat

Aby aplikacja miała dostęp do kodu i zasobów z pobranego modułu, musisz włączyć SplitCompat tylko za pomocą jednej z metod opisanych w kolejnych sekcjach.

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

Zadeklarowanie SplitCompatApplication w pliku manifestu

Najprostszym sposobem włączenia 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>

Gdy aplikacja zostanie zainstalowana na urządzeniu, automatycznie uzyskasz dostęp do kodu i zasobów z pobranych modułów funkcji.

Wywołuj SplitCompat w czasie działania

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

Jeśli masz niestandardową klasę Application, rozwiń ją SplitCompatApplication, aby włączyć SplitCompat w Twojej aplikacji:

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 przedłużał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 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łącz SplitCompat dla aktywności modułu

Po włączeniu SplitCompat w aplikacji podstawowej musisz włączyć SplitCompat dla każdej aktywności pobieranej przez aplikację w module funkcji. Użyj do tego 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 działania zdefiniowanego w module funkcji

Po włączeniu SplitCompat możesz uruchamiać działania 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 setClassName to nazwa pakietu aplikacji, a drugi to pełna nazwa klasy aktywności.

Gdy w module funkcji pobranym na żądanie masz jakieś działanie, musisz w nim włączyć 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

Wyeksportowanych komponentów Androida nie należy umieszczać w modułach opcjonalnych.

System kompilacji scala z modułem podstawowym wpisy w pliku manifestu wszystkich modułów. Jeśli opcjonalny moduł zawiera wyeksportowany komponent, jest on dostępny nawet przed jego zainstalowaniem i może spowodować awarię z powodu brakującego kodu po wywołaniu z innej aplikacji.

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

Jeśli potrzebujesz wyeksportowanego komponentu i chcesz, aby jego zawartość znajdowała się w module opcjonalnym, możesz zaimplementować wzorzec serwera proxy. Aby to zrobić, dodaj do bazy danych wyeksportowany komponent serwera proxy. Po uzyskaniu dostępu komponent serwera proxy może sprawdzić, czy jest moduł zawierający treść. Jeśli moduł jest obecny, komponent proxy może uruchomić komponent wewnętrzny z modułu przez Intent, przekazując intencję z aplikacji wywołującej. Jeśli moduł nie jest obecny, komponent może pobrać moduł lub zwrócić odpowiedni komunikat o błędzie do aplikacji wywołującej.

Kod dostępu i zasoby z zainstalowanych modułów

Jeśli włączysz SplitCompat dla podstawowego kontekstu aplikacji i działań w module funkcji, po zainstalowaniu modułu funkcji możesz używać kodu i zasobów z modułu funkcji tak, jakby był on częścią podstawowego pliku APK.

Kod dostępu z innego modułu

Dostęp do kodu podstawowego z modułu

Kod, który znajduje się w module podstawowym, może być używany bezpośrednio przez inne moduły. Nie musisz nic robić. Po prostu zaimportuj potrzebne zajęcia i zacznij z nich korzystać.

Uzyskaj dostęp do kodu modułu z innego modułu

Do obiektu lub klasy wewnątrz modułu nie można uzyskać dostępu statycznego bezpośrednio z innego modułu, ale można uzyskać do nich dostęp pośrednio przez odbicie.

Zastanów się, jak często tak się dzieje, ponieważ wiąże się to z kosztami refleksji. W złożonych przypadkach użycia korzystaj z platform wstrzykiwania zależności, takich jak Dagger 2, aby gwarantować jedno wywołanie refleksji w każdym okresie użytkowania aplikacji.

Aby uprościć interakcje z obiektem po utworzeniu instancji, zalecamy zdefiniowanie interfejsu w module podstawowym i jego implementację 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 z innego modułu

Po zainstalowaniu modułu możesz w standardowy sposób uzyskiwać dostęp do jego zasobów i zasobów z dwoma zastrzeżeniami:

  • Jeśli uzyskujesz dostęp do zasobu z innego modułu, moduł nie będzie miał dostępu do jego identyfikatora, chociaż nadal będzie można uzyskać do niego dostęp po nazwie. Pamiętaj, że pakiet, który ma służyć do odwoływania się do zasobu, to pakiet modułu, w którym ten zasób jest zdefiniowany.
  • Jeśli chcesz uzyskać dostęp do zasobów znajdujących się w nowo zainstalowanym module z innego zainstalowanego modułu Twojej aplikacji, musisz to zrobić z poziomu 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ć w nim SplitCompat po zainstalowaniu modułu funkcji.

Wczytywanie kodu natywnego w aplikacji przy użyciu dostawy na żądanie

Podczas przesyłania modułów funkcji na żądanie zalecamy używanie narzędzia ReLinker do wczytywania wszystkich bibliotek natywnych. Narzędzie ReLinker rozwiązuje problem z wczytywaniem bibliotek natywnych po zainstalowaniu modułu funkcji. Więcej informacji o ReLinker znajdziesz we wskazówkach dotyczących JNI na Androidzie.

Wczytaj kod natywny z modułu opcjonalnego

Po zainstalowaniu podziału zalecamy wczytanie kodu natywnego za pomocą narzędzia ReLinker. W przypadku aplikacji błyskawicznych użyj tej specjalnej metody.

Jeśli używasz języka System.loadLibrary() do wczytywania kodu natywnego, a biblioteka natywna zależy od innej biblioteki w module, musisz ją najpierw załadować ręcznie. Jeśli używasz obiektu ReLinker, równoważną operację to Relinker.recursively().loadLibrary().

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

Dostęp do zainstalowanych aplikacji błyskawicznych na Androida

Gdy moduł aplikacji błyskawicznej na Androida zgłasza INSTALLED, możesz uzyskać dostęp do jego kodu i zasobów przy użyciu odświeżonego kontekstu aplikacji. Kontekst, który aplikacja tworzy, przed zainstalowaniem modułu (np. zapisanego już w zmiennej), nie zawiera zawartości nowego modułu. Jednak nowy kontekst można 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

Jeśli wysyłasz żądanie modułu na żądanie dla aplikacji błyskawicznej na Androida na Androidzie 8.0 (poziom interfejsu API 26) lub nowszym, po tym, jak żądanie instalacji zgłasza INSTALLED, musisz zaktualizować aplikację o kontekst nowego modułu, wywołując metodę SplitInstallHelper.updateAppInfo(Context context). W przeciwnym razie aplikacja nie wie jeszcze o kodzie i zasobach modułu. Po zaktualizowaniu metadanych aplikacji należy wczytać zawartość modułu podczas następnego zdarzenia wątku głównego, wywołując nowy obiekt 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 zostało już pobrane w aplikacji błyskawicznej, użyj metody 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ć komponentu WebView Androida w aktywności, która uzyskuje dostęp do zasobów z opcjonalnego modułu. Wynika to z braku zgodności między WebView a SplitCompat w interfejsie API Androida na poziomie 28 i niższym.
  • Obiekty ApplicationInfo Androida, ich zawartości ani obiekty, które zawierają je w aplikacji, nie mogą być przechowywane w pamięci podręcznej. Obiekty te należy zawsze pobierać w razie potrzeby z kontekstu aplikacji. Przechowywanie takich obiektów w pamięci podręcznej może spowodować awarię aplikacji podczas instalowania modułu funkcji.

Zarządzaj 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 metodę 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"));

Odinstalowania modułu nie następują natychmiast. Oznacza to, że urządzenie odinstalowuje je w tle w razie potrzeby, aby zaoszczędzić miejsce. Aby sprawdzić, czy urządzenie usunęło moduł, wywołaj metodę SplitInstallManager.getInstalledModules() i sprawdź wynik w sposób opisany w poprzedniej sekcji.

Pobierz dodatkowe zasoby językowe

Dzięki pakietom aplikacji urządzenia pobierają tylko kod i zasoby niezbędne do uruchomienia aplikacji. W przypadku zasobów językowych urządzenie użytkownika pobiera tylko te zasoby, które są zgodne z językiem wybranym obecnie w ustawieniach urządzenia.

Jeśli chcesz, aby aplikacja miała dostęp do dodatkowych zasobów językowych – na przykład aby zaimplementować selektor języka w aplikacji, możesz pobrać je na żądanie za pomocą biblioteki Play Feature Delivery. Proces ten przypomina pobieranie modułu funkcji, co widać 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);

Jest ono traktowane tak, jakby było żądaniem modułu funkcji. Oznacza to, że możesz monitorować stan żądania w zwykły sposób.

Jeśli aplikacja nie wymaga od razu dodatkowych zasobów językowych, możesz odroczyć instalację, aby uruchomić ją 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żdego działania, które 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 korzystać z zasobów językowych pobranych przez aplikację, zaktualizuj kontekst podstawowy i ustaw nowy język w narzędziu 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 gotowym 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();
  ...
}

Odinstaluj dodatkowe zasoby językowe

Podobnie jak w przypadku modułów funkcji, w każdej chwili możesz odinstalować dodatkowe zasoby. Zanim poprosisz o odinstalowanie, możesz najpierw ustalić, jakie języki są obecnie zainstalowane. Możesz to zrobić w ten sposób.

Kotlin

val installedLanguages: Set<String> = splitInstallManager.installedLanguages

Java

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

Następnie za pomocą metody deferredLanguageUninstall() możesz określić, które języki chcesz odinstalować, 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łu

Biblioteka dostawy funkcji w Play umożliwia lokalne przetestowanie tych funkcji aplikacji bez łączenia się ze Sklepem Play:

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

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

  • Pobierz i zainstaluj najnowszą wersję bundletool. bundletool jest potrzebny, aby utworzyć nowy zestaw możliwych do zainstalowania plików APK z pakietu aplikacji.

Tworzenie zestawu plików APK

Utwórz podzielone pakiety APK aplikacji w ten sposób:

  1. Utwórz pakiet aplikacji, korzystając z jednej z tych metod:
  2. Użyj bundletool, aby za pomocą tego polecenia 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 plików APK, dzięki czemu Biblioteka dostawy funkcji Play ma informację o tym, że ma używać lokalnych podzielonych pakietów APK do testowania instalacji modułów funkcji bez łączenia się ze Sklepem Play.

Wdróż aplikację na urządzeniu

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

bundletool install-apks --apks my_app.apks

Teraz gdy uruchomisz aplikację i dokończysz proces pobierania i instalowania modułu funkcji, biblioteka Play Feature Delivery korzysta z plików APK przesłanych bundletooldo pamięci lokalnej urządzenia.

Symulowanie błędu sieci

Aby symulować instalacje modułów ze Sklepu Play, biblioteka Play Feature Delivery korzysta z alternatywnego rozwiązania SplitInstallManager o nazwie FakeSplitInstallManager do wysyłania żądań modułu. Jeśli użyjesz funkcji bundletool z flagą --local-testing do utworzenia zestawu plików APK i wdrożenia ich na urządzeniu testowym, będą w nim zawarte metadane, które instruują bibliotekę Play Feature Delivery, aby automatycznie przełączała wywołania interfejsu API Twojej aplikacji w celu wywołania FakeSplitInstallManager zamiast SplitInstallManager.

FakeSplitInstallManager zawiera flagę wartości logicznej, którą możesz włączyć, aby symulować błąd sieci, gdy aplikacja zażąda zainstalowania modułu. Aby uzyskać dostęp do funkcji FakeSplitInstallManager w testach, możesz uzyskać jej instancję, korzystając z 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);