Moduły funkcji umożliwiają oddzielenie niektórych funkcji i zasobów od modułu podstawowego aplikacji i uwzględnienie ich w pakiecie aplikacji. Dzięki funkcji Play Feature Delivery użytkownicy mogą na przykład później pobrać i zainstalować te komponenty na żądanie, gdy już zainstalują podstawowy plik APK aplikacji.
Weźmy na przykład aplikację do obsługi wiadomości tekstowych, która umożliwia robienie i wysyłanie zdjęć, ale tylko niewielki odsetek użytkowników korzysta z tej funkcji. Warto rozważyć dołączenie wiadomości obrazkowych jako modułu funkcji do pobrania. Dzięki temu początkowe pobranie aplikacji jest mniejsze dla wszystkich użytkowników, a tylko ci, którzy wysyłają wiadomości graficzne, muszą pobrać dodatkowy komponent.
Pamiętaj, że ten typ modularyzacji wymaga więcej wysiłku i być może refaktoryzacji istniejącego kodu aplikacji, dlatego dokładnie zastanów się, które funkcje aplikacji najbardziej skorzystają na tym, że będą dostępne dla użytkowników na żądanie. Aby lepiej zrozumieć optymalne przypadki użycia i wytyczne dotyczące funkcji na żądanie, przeczytaj artykuł o sprawdzonych metodach dotyczących dostarczania na żądanie.
Jeśli chcesz stopniowo modularyzować funkcje aplikacji bez włączania zaawansowanych opcji dostarczania, takich jak dostarczanie na żądanie, skonfiguruj dostarczanie w czasie 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 w wersji 3.5 lub nowszej oraz wtyczki Androida do obsługi Gradle w wersji 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 w wersji 3.5 lub nowszej. Moduły funkcji są zależne od podstawowego modułu aplikacji, dlatego można je dodawać tylko do istniejących projektów aplikacji.
Aby dodać moduł funkcji do projektu aplikacji za pomocą Android Studio, wykonaj te czynności:
- Jeśli nie zostało to jeszcze zrobione, otwórz projekt aplikacji w środowisku IDE.
- Na pasku menu kliknij File > New > New Module (Plik > Nowy > Nowy moduł).
- W oknie Create New Module (Utwórz nowy moduł) wybierz Dynamic Feature Module (Dynamiczny moduł funkcji) i kliknij Next (Dalej).
- W sekcji Skonfiguruj nowy moduł wykonaj te czynności:
- W menu wybierz Podstawowy moduł aplikacji dla projektu aplikacji.
- Określ nazwę modułu. IDE używa tej nazwy do identyfikacji 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>do pliku manifestu modułu funkcji. - 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.
- Wybierz Minimalny poziom interfejsu API, który ma być obsługiwany przez moduł. Ta wartość powinna być zgodna z wartością modułu podstawowego.
- Kliknij Dalej.
W sekcji Opcje pobierania modułu wykonaj te czynności:
Wpisz tytuł modułu (maksymalnie 50 znaków). Platforma używa tego tytułu do identyfikowania modułu, np. gdy pyta użytkownika, czy chce go pobrać. Z tego powodu moduł podstawowy aplikacji musi zawierać tytuł modułu jako zasób tekstowy, który można przetłumaczyć. Gdy tworzysz moduł za pomocą Android Studio, IDE dodaje zasób tekstowy do modułu podstawowego i wstrzykuje ten wpis do pliku manifestu modułu funkcji:
<dist:module ... dist:title="@string/feature_title"> </dist:module>W menu w sekcji Uwzględnianie w czasie instalacji wybierz Nie uwzględniaj modułu w czasie instalacji. Android Studio wstrzykuje do pliku manifestu modułu te informacje, aby odzwierciedlić Twój wybór:
<dist:module ... > <dist:delivery> <dist:on-demand/> </dist:delivery> </dist:module>Zaznacz pole obok opcji Łączenie, jeśli chcesz, aby ten moduł był dostępny na urządzeniach z Androidem 4.4 (API na poziomie 20) lub starszym i był uwzględniany w wielu pakietach APK. Oznacza to, że możesz włączyć działanie na żądanie w przypadku tego modułu i wyłączyć scalanie, aby pominąć go na urządzeniach, które nie obsługują pobierania i instalowania dzielonych pakietów APK. Android Studio wstrzykuje do pliku manifestu modułu te informacje, aby odzwierciedlić Twój wybór:
<dist:module ...> <dist:fusing dist:include="true | false" /> </dist:module>
Kliknij Zakończ.
Gdy Android Studio zakończy tworzenie modułu, sprawdź jego zawartość w panelu Projekt (na pasku menu wybierz Widok > Okna narzędzi > Projekt). Domyślny kod, zasoby i organizacja powinny być podobne do tych w standardowym module aplikacji.
Następnie musisz zaimplementować funkcję instalacji na żądanie, korzystając z biblioteki Play Feature Delivery.
Dołączanie biblioteki Play Feature Delivery do projektu
Zanim zaczniesz, musisz najpierw dodać do projektu bibliotekę Play Feature Delivery.
Żądanie modułu na żądanie
Gdy aplikacja musi użyć modułu funkcji, może poprosić o niego, gdy działa na pierwszym planie, za pomocą klasy SplitInstallManager. Podczas wysyłania żądania aplikacja musi podać nazwę modułu zdefiniowaną przez element split w pliku manifestu modułu docelowego. Gdy 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 czasie kompilacji.
Więcej informacji znajdziesz w artykule o manifestach modułów funkcji.
Załóżmy na przykład, że aplikacja ma moduł na żądanie, który umożliwia robienie i wysyłanie zdjęć za pomocą aparatu urządzenia, a w pliku manifestu tego modułu na żądanie określono split="pictureMessages". W poniższym przykładzie użyto SplitInstallManager, aby zażądać modułu pictureMessages (oraz dodatkowego modułu dla niektórych filtrów promocyjnych):
Kotlin
// Creates an instance of SplitInstallManager. val splitInstallManager = SplitInstallManagerFactory.create(context) // Creates a request to install a module. val request = SplitInstallRequest .newBuilder() // You can download multiple on demand modules per // request by invoking the following method for each // module you want to install. .addModule("pictureMessages") .addModule("promotionalFilters") .build() splitInstallManager // Submits the request to install the module through the // asynchronous startInstall() task. Your app needs to be // in the foreground to submit the request. .startInstall(request) // You should also be able to gracefully handle // request state changes and errors. To learn more, go to // the section about how to Monitor the request state. .addOnSuccessListener { sessionId -> ... } .addOnFailureListener { exception -> ... }
Java
// Creates an instance of SplitInstallManager. SplitInstallManager splitInstallManager = SplitInstallManagerFactory.create(context); // Creates a request to install a module. SplitInstallRequest request = SplitInstallRequest .newBuilder() // You can download multiple on demand modules per // request by invoking the following method for each // module you want to install. .addModule("pictureMessages") .addModule("promotionalFilters") .build(); splitInstallManager // Submits the request to install the module through the // asynchronous startInstall() task. Your app needs to be // in the foreground to submit the request. .startInstall(request) // You should also be able to gracefully handle // request state changes and errors. To learn more, go to // the section about how to Monitor the request state. .addOnSuccessListener(sessionId -> { ... }) .addOnFailureListener(exception -> { ... });
Gdy aplikacja prosi o moduł na żądanie, biblioteka Play Feature Delivery stosuje strategię „uruchom i zapomnij”. Oznacza to, że wysyła do platformy żądanie pobrania modułu, ale nie sprawdza, czy instalacja się powiodła. Aby po instalacji kontynuować ścieżkę użytkownika lub prawidłowo obsługiwać błędy, monitoruj stan żądania.
Uwaga: możesz poprosić o moduł funkcji, który jest już zainstalowany na urządzeniu. Jeśli interfejs API wykryje, że moduł jest już zainstalowany, natychmiast uzna żądanie za zrealizowane. 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 mieć dostęp do kodu i zasobów modułu, aplikacja musi mieć włączoną funkcję SplitCompat. Pamiętaj, że SplitCompat nie jest wymagany w przypadku aplikacji błyskawicznych na Androida.
Odłóż instalację modułów na żądanie
Jeśli nie potrzebujesz, aby aplikacja natychmiast pobrała i zainstalowała moduł na żądanie, możesz odroczyć instalację do momentu, gdy aplikacja będzie działać w tle. Na przykład jeśli chcesz wstępnie załadować materiały promocyjne, aby później uruchomić aplikację.
Możesz określić moduł do pobrania później, używając metody deferredInstall(), jak pokazano poniżej. W przeciwieństwie do SplitInstallManager.startInstall() aplikacja nie musi działać na pierwszym planie, aby zainicjować żądanie odroczonej instalacji.
Kotlin
// Requests an on demand module to be downloaded when the app enters // the background. You can specify more than one module at a time. splitInstallManager.deferredInstall(listOf("promotionalFilters"))
Java
// Requests an on demand module to be downloaded when the app enters // the background. You can specify more than one module at a time. splitInstallManager.deferredInstall(Arrays.asList("promotionalFilters"));
Prośby o odroczone instalacje są realizowane w miarę możliwości i nie można śledzić ich postępów. Dlatego przed próbą uzyskania dostępu do modułu, który został określony do odroczonej instalacji, należy sprawdzić, czy moduł został zainstalowany. Jeśli potrzebujesz, aby moduł był dostępny natychmiast, użyj SplitInstallManager.startInstall(), aby o niego poprosić, jak pokazano w poprzedniej sekcji.
Monitorowanie stanu żądania
Aby móc aktualizować pasek postępu, uruchamiać intencję po instalacji lub prawidłowo obsługiwać błąd żądania, musisz nasłuchiwać aktualizacji stanu z asynchronicznego zadania SplitInstallManager.startInstall().
Zanim zaczniesz otrzymywać aktualizacje dotyczące prośby o instalację, zarejestruj detektor i pobierz identyfikator sesji dla prośby, jak pokazano poniżej.
Kotlin
// Initializes a variable to later track the session ID for a given request. var mySessionId = 0 // Creates a listener for request status updates. val listener = SplitInstallStateUpdatedListener { state -> if (state.sessionId() == mySessionId) { // Read the status of the request to handle the state update. } } // Registers the listener. splitInstallManager.registerListener(listener) ... splitInstallManager .startInstall(request) // When the platform accepts your request to download // an on demand module, it binds it to the following session ID. // You use this ID to track further status updates for the request. .addOnSuccessListener { sessionId -> mySessionId = sessionId } // You should also add the following listener to handle any errors // processing the request. .addOnFailureListener { exception -> // Handle request errors. } // When your app no longer requires further updates, unregister the listener. splitInstallManager.unregisterListener(listener)
Java
// Initializes a variable to later track the session ID for a given request. int mySessionId = 0; // Creates a listener for request status updates. SplitInstallStateUpdatedListener listener = state -> { if (state.sessionId() == mySessionId) { // Read the status of the request to handle the state update. } }; // Registers the listener. splitInstallManager.registerListener(listener); ... splitInstallManager .startInstall(request) // When the platform accepts your request to download // an on demand module, it binds it to the following session ID. // You use this ID to track further status updates for the request. .addOnSuccessListener(sessionId -> { mySessionId = sessionId; }) // You should also add the following listener to handle any errors // processing the request. .addOnFailureListener(exception -> { // Handle request errors. }); // When your app no longer requires further updates, unregister the listener. splitInstallManager.unregisterListener(listener);
Obsługa błędów żądań
Pamiętaj, że instalacja modułów funkcji na żądanie może się nie powieść, podobnie jak instalacja aplikacji. Niepowodzenie instalacji może być spowodowane problemami takimi jak mała ilość pamięci urządzenia, brak połączenia sieciowego lub brak zalogowania użytkownika w Sklepie Google Play. Sugestie dotyczące tego, jak radzić sobie z takimi sytuacjami z perspektywy użytkownika, znajdziesz w wytycznych dotyczących UX w przypadku dostawy na żądanie.
Jeśli chodzi o kod, błędy pobierania lub instalowania modułu należy obsługiwać 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 aplikacja może wymagać obsługi:
| 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 są jakieś żądania, które nadal są pobierane, jak pokazano w przykładzie powyżej. |
| MODULE_UNAVAILABLE | Google Play nie może znaleźć żądanego modułu na podstawie aktualnie zainstalowanej wersji aplikacji, urządzenia i konta Google Play użytkownika. | Jeśli użytkownik nie ma dostępu do modułu, powiadom go o tym. |
| INVALID_REQUEST | Google Play otrzymał żądanie, ale jest ono nieprawidłowe. | Sprawdź, czy informacje zawarte w prośbie są kompletne i dokładne. |
| 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 | Biblioteka Play Feature Delivery 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 (API na poziomie 20) lub starszym należy uwzględnić moduły funkcji podczas instalacji, używając właściwości manifestu dist:fusing. Więcej informacji znajdziesz w artykule o pliku manifestu modułu funkcji.
|
| NETWORK_ERROR | Żądanie nie zostało zrealizowane z powodu błędu sieci. | Poproś użytkownika o nawiązanie połączenia sieciowego lub przełączenie się na inną sieć. |
| ACCESS_DENIED | Aplikacja nie może zarejestrować prośby z powodu niewystarczających uprawnień. | Zwykle dzieje się tak, gdy aplikacja działa w tle. Spróbuj wysłać żądanie, gdy aplikacja powró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, o które aplikacja już prosiła, lub poczekaj, aż wszystkie obecnie żądane moduły zostaną zainstalowane, i ponów żądanie.
Pamiętaj, że żądanie modułu, który został już zainstalowany, nie powoduje błędu. |
| SERVICE_DIED | Usługa odpowiedzialna za obsługę żądania została wyłączona. | Spróbuj ponownie przesłać prośbę.
Twoja aplikacja |
| INSUFFICIENT_STORAGE | Na urządzeniu jest za mało wolnego miejsca, aby zainstalować moduł funkcji. | Powiadom użytkownika, że nie ma wystarczającej ilości miejsca na dane, aby zainstalować tę funkcję. |
| SPLITCOMPAT_VERIFICATION_ERROR, SPLITCOMPAT_EMULATION_ERROR, SPLITCOMPAT_COPY_ERROR | SplitCompat nie może wczytać modułu funkcji. | Te błędy powinny zostać automatycznie rozwiązane po następnym 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ć funkcji. Ten błąd może wystąpić tylko w przypadku odroczonych instalacji. | Jeśli chcesz, aby użytkownik pobrał aplikację z Google Play, użyj metody startInstall(), która może uzyskać niezbędne potwierdzenie od użytkownika. |
| INTERNAL_ERROR | W Sklepie Play wystąpił błąd wewnętrzny. | Spróbuj ponownie przesłać prośbę. |
Jeśli użytkownik poprosi o pobranie modułu na żądanie i wystąpi błąd, rozważ wyświetlenie okna z 2 opcjami: Spróbuj ponownie (co spowoduje ponowne wysłanie żądania) i Anuluj (co spowoduje porzucenie żądania). Aby zapewnić dodatkową pomoc, podaj też link do Centrum pomocy, który przekieruje użytkowników do Centrum pomocy Google Play.
Obsługa aktualizacji stanu
Po zarejestrowaniu detektora i zapisaniu identyfikatora sesji dla żądania użyj metody StateUpdatedListener.onStateUpdate(), aby obsłużyć zmiany 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ę opisano w tabeli poniżej.
| Stan żądania | Opis | Sugerowane działanie |
|---|---|---|
| OCZEKUJE | Prośba została zaakceptowana i pobieranie powinno się wkrótce rozpocząć. | Zainicjuj komponenty interfejsu, takie jak pasek postępu, aby przekazywać użytkownikowi informacje o pobieraniu. |
| REQUIRES_USER_CONFIRMATION | Pobieranie wymaga potwierdzenia przez użytkownika. Najczęściej ten stan występuje, gdy aplikacja nie została zainstalowana przez Google Play. | Poproś użytkownika o potwierdzenie pobrania funkcji z Google Play. Więcej informacji znajdziesz w sekcji dotyczącej uzyskiwania potwierdzenia od użytkownika. |
| POBIERANIE | Trwa pobieranie. | Jeśli udostępniasz pasek postępu pobierania, użyj metod SplitInstallSessionState.bytesDownloaded() i SplitInstallSessionState.totalBytesToDownload(), aby zaktualizować interfejs (zobacz przykładowy kod nad tą tabelą). |
| POBRANE | Urządzenie pobrało moduł, ale instalacja jeszcze się nie rozpoczęła. | Aplikacje powinny włączyć SplitCompat, aby mieć dostęp do pobranych modułów i uniknąć tego stanu. Jest to wymagane, aby uzyskać dostęp do kodu i zasobów modułu funkcji. |
| INSTALUJĘ | Urządzenie instaluje obecnie moduł. | Zaktualizuj pasek postępu. Ten stan jest zwykle krótkotrwały. |
| 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 dla aplikacji błyskawicznej na Androida działającej na Androidzie 8.0 (poziom API 26) lub nowszym, musisz użyć |
| NEGATYWNY | Żądanie nie powiodło się, zanim moduł został zainstalowany na urządzeniu. | Poproś użytkownika o ponowienie lub anulowanie żądania. |
| ANULOWANIE | Urządzenie jest w trakcie anulowania prośby. | Więcej informacji znajdziesz w sekcji poświęconej anulowaniu prośby o instalację. |
| ODWOŁANY | Żądanie zostało anulowane. |
Uzyskiwanie zgody użytkownika
W niektórych przypadkach Google Play może wymagać potwierdzenia przez użytkownika, zanim spełni prośbę o pobranie. Może się tak zdarzyć, jeśli aplikacja nie została zainstalowana z Google Play lub jeśli próbujesz pobrać duży plik przez mobilną transmisję danych. W takich przypadkach stan żądania to REQUIRES_USER_CONFIRMATION, a aplikacja musi uzyskać potwierdzenie użytkownika, zanim urządzenie będzie mogło pobrać i zainstalować moduły z żądania. Aby uzyskać potwierdzenie, aplikacja powinna wyświetlić użytkownikowi taki komunikat:
Kotlin
override fun onSessionStateUpdate(state: SplitInstallSessionState) { if (state.status() == SplitInstallSessionStatus.REQUIRES_USER_CONFIRMATION) { // Displays a confirmation for the user to confirm the request. splitInstallManager.startConfirmationDialogForResult( state, // an activity result launcher registered via registerForActivityResult activityResultLauncher) } ... }
Java
@Override void onSessionStateUpdate(SplitInstallSessionState state) { if (state.status() == SplitInstallSessionStatus.REQUIRES_USER_CONFIRMATION) { // Displays a confirmation for the user to confirm the request. splitInstallManager.startConfirmationDialogForResult( state, // an activity result launcher registered via registerForActivityResult activityResultLauncher); } ... }
Możesz zarejestrować moduł uruchamiający wynik aktywności za pomocą wbudowanej umowy ActivityResultContracts.StartIntentSenderForResult. Zobacz interfejsy API Activity Result.
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
PENDINGi rozpocznie się pobieranie. - Jeśli użytkownik odrzuci prośbę, jej stan zmieni się na
CANCELED. - Jeśli użytkownik nie dokona wyboru przed zamknięciem okna, stan żądania pozostanie jako
REQUIRES_USER_CONFIRMATION. Aplikacja może ponownie poprosić użytkownika o spełnienie żądania.
Aby otrzymać wywołanie zwrotne z odpowiedzią użytkownika, możesz zastąpić ActivityResultCallback, jak pokazano poniżej.
Kotlin
registerForActivityResult(StartIntentSenderForResult()) { result: ActivityResult -> { // Handle the user's decision. For example, if the user selects "Cancel", // you may want to disable certain functionality that depends on the module. } }
Java
registerForActivityResult( new ActivityResultContracts.StartIntentSenderForResult(), new ActivityResultCallback<ActivityResult>() { @Override public void onActivityResult(ActivityResult result) { // Handle the user's decision. For example, if the user selects "Cancel", // you may want to disable certain functionality that depends on the module. } });
Anulowanie prośby o instalację
Jeśli aplikacja musi anulować żądanie przed zainstalowaniem, może wywołać metodę cancelInstall(), używając identyfikatora sesji żądania, jak pokazano poniżej.
Kotlin
splitInstallManager // Cancels the request for the given session ID. .cancelInstall(mySessionId)
Java
splitInstallManager // Cancels the request for the given session ID. .cancelInstall(mySessionId);
Moduły dostępu
Aby uzyskać dostęp do kodu i zasobów z pobranego modułu, aplikacja musi mieć włączoną bibliotekę SplitCompat zarówno dla aplikacji, jak i dla każdej aktywności w pobieranych modułach funkcji.
Pamiętaj jednak, że przez pewien czas (w niektórych przypadkach przez kilka dni) po pobraniu modułu platforma ma następujące ograniczenia dostępu do jego zawartości:
- Platforma nie może zastosować żadnych nowych wpisów w pliku manifestu wprowadzonych przez moduł.
- Platforma nie ma dostępu do zasobów modułu dotyczących komponentów interfejsu systemu, takich jak powiadomienia. Jeśli musisz natychmiast użyć takich zasobów, rozważ umieszczenie ich w module podstawowym aplikacji.
Włączanie SplitCompat
Aby aplikacja mogła uzyskać dostęp do kodu i zasobów z pobranego modułu, musisz włączyć SplitCompat, używając tylko 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.
Deklarowanie SplitCompatApplication w pliku manifestu
Najprostszym sposobem na włączenie SplitCompat jest zadeklarowanie SplitCompatApplication jako podklasy Application w pliku manifestu aplikacji, jak pokazano poniżej:
<application
...
android:name="com.google.android.play.core.splitcompat.SplitCompatApplication">
</application>
Po zainstalowaniu aplikacji na urządzeniu możesz automatycznie uzyskać dostęp do kodu i zasobów z pobranych modułów funkcji.
Wywoływanie SplitCompat w czasie działania
Możesz też włączyć SplitCompat w określonych aktywnościach lub usługach w czasie działania.
Włączenie SplitCompat w ten sposób jest wymagane do uruchamiania aktywności zawartych w modułach funkcji. Aby to zrobić, zastąp attachBaseContext, jak pokazano poniżej.
Jeśli masz niestandardową klasę Application, rozszerz ją o SplitCompatApplication, aby włączyć SplitCompat w aplikacji, jak pokazano poniżej:
Kotlin
class MyApplication : SplitCompatApplication() { ... }
Java
public class MyApplication extends SplitCompatApplication { ... }
SplitCompatApplication po prostu zastępuje ContextWrapper.attachBaseContext(), aby uwzględnić SplitCompat.install(Context applicationContext). Jeśli nie chcesz, aby klasa Application rozszerzała klasę SplitCompatApplication, możesz ręcznie zastąpić metodę attachBaseContext() w ten sposób:
Kotlin
override fun attachBaseContext(base: Context) { super.attachBaseContext(base) // Emulates installation of future on demand modules using SplitCompat. SplitCompat.install(this) }
Java
@Override protected void attachBaseContext(Context base) { super.attachBaseContext(base); // Emulates installation of future on demand modules using SplitCompat. SplitCompat.install(this); }
Jeśli moduł na żądanie jest zgodny zarówno z aplikacjami błyskawicznymi, jak i aplikacjami instalowanymi, 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 aktywności modułu
Po włączeniu SplitCompat w aplikacji podstawowej musisz włączyć tę funkcję w przypadku 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
Uruchamianie aktywności zdefiniowanej w module funkcji
Po włączeniu SplitCompat możesz uruchamiać aktywności zdefiniowane w modułach funkcji za pomocą startActivity().
Kotlin
startActivity(Intent() .setClassName("com.package", "com.package.module.MyActivity") .setFlags(...))
Java
startActivity(new Intent() .setClassName("com.package", "com.package.module.MyActivity") .setFlags(...));
Pierwszy parametr setClassName to nazwa pakietu aplikacji, a drugi to pełna nazwa klasy działania.
Jeśli masz aktywność w module funkcji pobranym na żądanie, musisz włączyć w niej SplitCompat.
Uruchamianie usługi zdefiniowanej w module funkcji
Po włączeniu SplitCompat możesz uruchamiać usługi zdefiniowane w modułach funkcji za pomocą startService().
Kotlin
startService(Intent() .setClassName("com.package", "com.package.module.MyService") .setFlags(...))
Java
startService(new Intent() .setClassName("com.package", "com.package.module.MyService") .setFlags(...));
Eksportowanie komponentu zdefiniowanego w module funkcji
Nie należy umieszczać wyeksportowanych komponentów Androida w modułach opcjonalnych.
System kompilacji scala wpisy manifestu wszystkich modułów w module podstawowym. Jeśli moduł opcjonalny zawiera wyeksportowany komponent, będzie on dostępny nawet przed zainstalowaniem modułu i może spowodować awarię z powodu braku kodu, gdy zostanie wywołany z innej aplikacji.
Nie stanowi to problemu w przypadku komponentów wewnętrznych, ponieważ dostęp do nich ma tylko aplikacja, 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 module opcjonalnym, rozważ wdrożenie wzorca proxy.
Możesz to zrobić, dodając do bazy wyeksportowany komponent proxy. Po uzyskaniu dostępu komponent proxy może sprawdzić obecność modułu zawierającego treść. Jeśli moduł jest obecny, komponent proxy może uruchomić komponent wewnętrzny z modułu za pomocą Intent, przekazując intencję z aplikacji wywołującej. Jeśli moduł nie jest obecny, 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 dla kontekstu aplikacji podstawowej i aktywności w module funkcji, po zainstalowaniu modułu opcjonalnego możesz używać kodu i zasobów z modułu funkcji tak, jakby były częścią podstawowego pakietu 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ć niczego specjalnego – wystarczy zaimportować i użyć potrzebnych klas.
Uzyskiwanie dostępu do kodu modułu z innego modułu
Obiekt lub klasa w module nie mogą być bezpośrednio dostępne statycznie z innego modułu, ale można uzyskać do nich dostęp pośrednio, za pomocą refleksji.
Należy uważać na to, jak często to się dzieje, ze względu na koszty wydajności refleksji. W bardziej złożonych przypadkach używaj platform wstrzykiwania zależności, takich jak Dagger 2, aby zagwarantować jedno wywołanie refleksji w czasie działania aplikacji.
Aby uprościć interakcje z obiektem po utworzeniu instancji, zalecamy zdefiniowanie interfejsu w module podstawowym i 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();
Uzyskiwanie dostępu do zasobów i komponentów z innego modułu
Po zainstalowaniu modułu możesz uzyskiwać dostęp do zasobów i komponentów w nim zawartych w standardowy sposób, z 2 zastrzeżeniami:
- Jeśli uzyskujesz dostęp do zasobu z innego modułu, moduł nie będzie miał dostępu do identyfikatora zasobu, ale nadal będzie można uzyskać dostęp do zasobu według nazwy. Pamiętaj, że pakiet, którego należy użyć do odwołania się do zasobu, to pakiet modułu, w którym zasób jest zdefiniowany.
- Jeśli chcesz uzyskać dostęp do zasobów, które znajdują się w nowo zainstalowanym module, z innego zainstalowanego modułu aplikacji, musisz to zrobić przy użyciu kontekstu aplikacji. Kontekst komponentu, który próbuje uzyskać dostęp do zasobów, nie zostanie jeszcze zaktualizowany. Możesz też odtworzyć ten komponent (np. wywołując Activity.recreate()) lub ponownie zainstalować na nim SplitCompat po zainstalowaniu modułu funkcji.
Wczytywanie kodu natywnego w aplikacji przy użyciu przesyłania na żądanie
Jeśli korzystasz z dostarczania modułów funkcji na żądanie, zalecamy używanie narzędzia ReLinker do wczytywania wszystkich bibliotek natywnych. ReLinker rozwiązuje problem z wczytywaniem bibliotek natywnych po zainstalowaniu modułu funkcji. Więcej informacji o ReLinkerze znajdziesz w poradach dotyczących JNI na Androidzie.
Wczytywanie kodu natywnego z modułu opcjonalnego
Po zainstalowaniu podziału zalecamy wczytanie jego kodu natywnego za pomocą ReLinkera. W przypadku aplikacji błyskawicznych należy użyć tej specjalnej metody.
Jeśli do wczytywania kodu natywnego używasz System.loadLibrary(), a Twoja biblioteka natywna jest zależna od innej biblioteki w module, musisz najpierw ręcznie wczytać tę drugą bibliotekę.
Jeśli używasz ReLinkera, odpowiednikiem tej operacji jest Relinker.recursively().loadLibrary().
Jeśli używasz dlopen() w kodzie natywnym do wczytywania biblioteki zdefiniowanej w module opcjonalnym, nie będzie to działać ze względnymi ścieżkami biblioteki.
Najlepszym rozwiązaniem jest pobranie ścieżki bezwzględnej biblioteki z kodu Java za pomocą ClassLoader.findLibrary(), a następnie użycie jej w wywołaniu dlopen().
Zrób to przed wprowadzeniem kodu natywnego lub użyj wywołania JNI z kodu natywnego do Javy.
Dostęp do zainstalowanych aplikacji błyskawicznych na Androida
Gdy moduł aplikacji błyskawicznej na Androida zgłosi stan INSTALLED, możesz uzyskać dostęp do jego kodu i zasobów za pomocą odświeżonego kontekstu aplikacji. Kontekst, który aplikacja tworzy przed zainstalowaniem modułu (np. taki, który jest już przechowywany w zmiennej), nie zawiera treści nowego modułu. Można jednak użyć nowego kontekstu, który można 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 Androida w wersji 8.0 lub nowszej
Jeśli żądasz modułu na żądanie dla aplikacji błyskawicznej na Androida w wersji 8.0 (poziom API 26) lub nowszej, po zgłoszeniu żądania instalacji jako INSTALLED musisz zaktualizować aplikację, uwzględniając kontekst nowego modułu, przez wywołanie SplitInstallHelper.updateAppInfo(Context context).
W przeciwnym razie aplikacja nie będzie jeszcze znać kodu i zasobów modułu. Po zaktualizowaniu metadanych aplikacji należy załadować zawartość modułu podczas następnego zdarzenia w głównym wątku, 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 został już pobrany przez urządzenie w aplikacji błyskawicznej, użyj SplitInstallHelper.loadLibrary(Context context, String libName), jak pokazano poniżej:
Kotlin
override fun onStateUpdate(state: SplitInstallSessionState) { if (state.sessionId() == mySessionId) { when (state.status()) { SplitInstallSessionStatus.INSTALLED -> { // Updates the app’s context as soon as a module is installed. val newContext = context.createPackageContext(context.packageName, 0) // To load C/C++ libraries from an installed module, use the following API // instead of System.load(). SplitInstallHelper.loadLibrary(newContext, “my-cpp-lib”) ... } } } }
Java
public void onStateUpdate(SplitInstallSessionState state) { if (state.sessionId() == mySessionId) { switch (state.status()) { case SplitInstallSessionStatus.INSTALLED: // Updates the app’s context as soon as a module is installed. Context newContext = context.createPackageContext(context.getPackageName(), 0); // To load C/C++ libraries from an installed module, use the following API // instead of System.load(). SplitInstallHelper.loadLibrary(newContext, “my-cpp-lib”); ... } } }
Znane ograniczenia
- Nie można używać komponentu Android WebView w aktywności, która uzyskuje dostęp do zasobów z modułu opcjonalnego. Wynika to z niezgodności między WebView i SplitCompat na poziomie interfejsu API Androida 28 i niższym.
- Nie możesz przechowywać w pamięci podręcznej obiektów
ApplicationInfona Androidzie, ich zawartości ani obiektów, które je zawierają, w aplikacji. Zawsze pobieraj te obiekty w razie potrzeby z kontekstu aplikacji. Zapisywanie takich obiektów w pamięci podręcznej może spowodować awarię aplikacji podczas instalowania modułu funkcji.
Zarządzanie zainstalowanymi modułami
Aby sprawdzić, które moduły funkcji są obecnie zainstalowane na urządzeniu, możesz wywołać metodę SplitInstallManager.getInstalledModules(), która zwraca Set<String> nazw zainstalowanych modułów, jak pokazano poniżej.
Kotlin
val installedModules: Set<String> = splitInstallManager.installedModules
Java
Set<String> installedModules = splitInstallManager.getInstalledModules();
Odinstalowywanie modułów
Możesz poprosić urządzenie o odinstalowanie modułów, wywołując 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"));
Moduły nie są odinstalowywane natychmiast. Oznacza to, że urządzenie odinstalowuje je w tle, gdy jest to konieczne, aby zwolnić miejsce na dane.
Aby sprawdzić, czy urządzenie usunęło moduł, wywołaj SplitInstallManager.getInstalledModules() i sprawdź wynik zgodnie z opisem w poprzedniej sekcji.
Pobieranie dodatkowych zasobów językowych
Dzięki pakietom 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ą językom wybranym w ustawieniach urządzenia.
Jeśli chcesz, aby aplikacja miała dostęp do dodatkowych zasobów językowych, na przykład w celu zaimplementowania selektora języka w aplikacji, możesz użyć biblioteki Play Feature Delivery, aby pobierać je na żądanie. Proces jest podobny do pobierania modułu funkcji, jak pokazano poniżej.
Kotlin
// Captures the user’s preferred language and persists it // through the app’s SharedPreferences. sharedPrefs.edit().putString(LANGUAGE_SELECTION, "fr").apply() ... // Creates a request to download and install additional language resources. val request = SplitInstallRequest.newBuilder() // Uses the addLanguage() method to include French language resources in the request. // Note that country codes are ignored. That is, if your app // includes resources for “fr-FR” and “fr-CA”, resources for both // country codes are downloaded when requesting resources for "fr". .addLanguage(Locale.forLanguageTag(sharedPrefs.getString(LANGUAGE_SELECTION))) .build() // Submits the request to install the additional language resources. splitInstallManager.startInstall(request)
Java
// Captures the user’s preferred language and persists it // through the app’s SharedPreferences. sharedPrefs.edit().putString(LANGUAGE_SELECTION, "fr").apply(); ... // Creates a request to download and install additional language resources. SplitInstallRequest request = SplitInstallRequest.newBuilder() // Uses the addLanguage() method to include French language resources in the request. // Note that country codes are ignored. That is, if your app // includes resources for “fr-FR” and “fr-CA”, resources for both // country codes are downloaded when requesting resources for "fr". .addLanguage(Locale.forLanguageTag(sharedPrefs.getString(LANGUAGE_SELECTION))) .build(); // Submits the request to install the additional language resources. splitInstallManager.startInstall(request);
Żądanie jest obsługiwane tak, jakby dotyczyło modułu funkcji. Oznacza to, że możesz sprawdzać stan żądania tak jak zwykle.
Jeśli aplikacja nie wymaga natychmiast dodatkowych zasobów językowych, możesz odroczyć instalację, gdy aplikacja działa w tle, jak pokazano poniżej.
Kotlin
splitInstallManager.deferredLanguageInstall( Locale.forLanguageTag(sharedPrefs.getString(LANGUAGE_SELECTION)))
Java
splitInstallManager.deferredLanguageInstall( Locale.forLanguageTag(sharedPrefs.getString(LANGUAGE_SELECTION)));
Dostęp do pobranych zasobów językowych
Aby uzyskać dostęp do pobranych zasobów językowych, aplikacja musi uruchomić metodę SplitCompat.installActivity() w metodzie attachBaseContext() każdej aktywności, która wymaga dostępu do tych zasobów, jak pokazano poniżej.
Kotlin
override fun attachBaseContext(base: Context) { super.attachBaseContext(base) SplitCompat.installActivity(this) }
Java
@Override protected void attachBaseContext(Context base) { super.attachBaseContext(base); SplitCompat.installActivity(this); }
W przypadku każdej aktywności, w której chcesz używać zasobów językowych pobranych przez aplikację, zaktualizuj kontekst podstawowy i ustaw nowe ustawienia regionalne za pomocą metody Configuration:
Kotlin
override fun attachBaseContext(base: Context) { val configuration = Configuration() configuration.setLocale(Locale.forLanguageTag(sharedPrefs.getString(LANGUAGE_SELECTION))) val context = base.createConfigurationContext(configuration) super.attachBaseContext(context) SplitCompat.install(this) }
Java
@Override protected void attachBaseContext(Context base) { Configuration configuration = new Configuration(); configuration.setLocale(Locale.forLanguageTag(sharedPrefs.getString(LANGUAGE_SELECTION))); Context context = base.createConfigurationContext(configuration); super.attachBaseContext(context); SplitCompat.install(this); }
Aby te zmiany zaczęły obowiązywać, musisz ponownie utworzyć aktywność po zainstalowaniu nowego języka i przygotowaniu go do użycia. Możesz użyć metody Activity#recreate().
Kotlin
when (state.status()) { SplitInstallSessionStatus.INSTALLED -> { // Recreates the activity to load resources for the new language // preference. activity.recreate() } ... }
Java
switch (state.status()) { case SplitInstallSessionStatus.INSTALLED: // Recreates the activity to load resources for the new language // preference. activity.recreate(); ... }
Odinstalowywanie dodatkowych zasobów językowych
Podobnie jak w przypadku modułów funkcji, dodatkowe zasoby możesz odinstalować w każdej chwili. Zanim poprosisz o odinstalowanie, możesz najpierw sprawdzić, które języki są obecnie zainstalowane. Aby to zrobić:
Kotlin
val installedLanguages: Set<String> = splitInstallManager.installedLanguages
Java
Set<String> installedLanguages = splitInstallManager.getInstalledLanguages();
Następnie możesz zdecydować, które języki chcesz odinstalować, używając metody deferredLanguageUninstall(), jak pokazano poniżej.
Kotlin
splitInstallManager.deferredLanguageUninstall( Locale.forLanguageTag(sharedPrefs.getString(LANGUAGE_SELECTION)))
Java
splitInstallManager.deferredLanguageUninstall( Locale.forLanguageTag(sharedPrefs.getString(LANGUAGE_SELECTION)));
Lokalne testowanie instalacji modułów
Biblioteka Play Feature Delivery umożliwia lokalne testowanie możliwości aplikacji w zakresie:
- prosić o instalację modułów i monitorować ją;
- Obsługuj błędy instalacji.
- Użyj
SplitCompat, aby uzyskać dostęp do modułów.
Na tej stronie dowiesz się, jak wdrożyć dzielone pakiety APK aplikacji na urządzeniu testowym, aby funkcja Play Feature Delivery automatycznie używała tych pakietów APK do symulowania żądania, pobierania i instalowania modułów ze Sklepu Play.
Nie musisz wprowadzać żadnych zmian w logice aplikacji, ale musisz spełnić te wymagania:
- Pobierz i zainstaluj najnowszą wersję
bundletool. Aby utworzyć nowy zestaw pakietów APK do zainstalowania z pakietu aplikacji, potrzebujeszbundletool.
Tworzenie zestawu plików APK
Jeśli jeszcze nie masz dzielonych pakietów APK aplikacji, utwórz je w ten sposób:
- Utwórz pakiet aplikacji, korzystając z jednej z tych metod:
- Użyj Android Studio i wtyczki Androida do obsługi Gradle, aby utworzyć i podpisać pakiet Android App Bundle.
- Tworzenie pakietu aplikacji z poziomu wiersza poleceń
Użyj
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 manifestach plików APK, które informują bibliotekę Play Feature Delivery, że do testowania instalacji modułów funkcji ma używać lokalnych dzielonych pakietów APK 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 bundletool, aby zainstalować podstawową wersję aplikacji i przenieść dodatkowe pliki APK do pamięci lokalnej urządzenia. Obie te czynności możesz wykonać za pomocą tego polecenia:
bundletool install-apks --apks my_app.apks
Teraz, gdy uruchomisz aplikację i wykonasz wzorzec przeglądania, aby pobrać i zainstalować moduł funkcji, biblioteka Play Feature Delivery użyje plików APK, które narzędzie bundletool przeniosło 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, czyli FakeSplitInstallManager, do żądania modułu. Gdy używasz polecenia bundletool z flagą --local-testing, aby utworzyć zestaw plików APK i wdrożyć je na urządzeniu testowym, zawiera on metadane, które instruują bibliotekę Play Feature Delivery, aby automatycznie przełączała wywołania interfejsu API aplikacji na wywołania FakeSplitInstallManager zamiast SplitInstallManager.
FakeSplitInstallManager zawiera flagę logiczną, którą możesz włączyć, aby zasymulować błąd sieci przy następnej próbie zainstalowania modułu przez aplikację. Aby uzyskać dostęp do FakeSplitInstallManager w testach, możesz pobrać jego instancję za pomocą FakeSplitInstallManagerFactory, jak pokazano poniżej:
Kotlin
// Creates an instance of FakeSplitInstallManager with the app's context. val fakeSplitInstallManager = FakeSplitInstallManagerFactory.create(context) // Tells Play Feature Delivery Library to force the next module request to // result in a network error. fakeSplitInstallManager.setShouldNetworkError(true)
Java
// Creates an instance of FakeSplitInstallManager with the app's context. FakeSplitInstallManager fakeSplitInstallManager = FakeSplitInstallManagerFactory.create(context); // Tells Play Feature Delivery Library to force the next module request to // result in a network error. fakeSplitInstallManager.setShouldNetworkError(true);