מודולים של תכונות מאפשרים לכם להפריד תכונות ומשאבים מסוימים מהמודול הבסיסי של האפליקציה ולכלול אותם בחבילת האפליקציות. עד באמצעות Play Feature Delivery, המשתמשים יכולים, לדוגמה, להוריד ולהתקין את האפליקציות האלה מאוחר יותר על פי דרישה אחרי שהם כבר התקינו את ה-APK הבסיסי של האפליקציה.
לדוגמה, כדאי להשתמש באפליקציה להודעות טקסט שכוללת פונקציונליות תיעוד ושליחה של הודעות תמונה, אבל רק אחוז קטן מהמשתמשים לשלוח הודעות תמונה. יכול להיות שיהיה הגיוני לכלול את התכונה 'הודעות תמונה' כמודול תכונה שניתן להורדה. כך, גודל ההורדה הראשונית של האפליקציה קטן יותר לכל המשתמשים, ורק משתמשים ששולחים הודעות תמונה צריכים להוריד את הרכיב הנוסף הזה.
חשוב לזכור שמודולריזציה מהסוג הזה דורשת מאמץ נוסף, ולפעמים הוא לארגן מחדש את הקוד הקיים של האפליקציה, לכן חשוב לשקול היטב התכונות של האפליקציה יפיקו את התועלת הרבה ביותר אם הן יהיו זמינות למשתמשים על פי דרישה. כדי להבין טוב יותר את התרחישים לדוגמה וההנחיות האופטימליים לתכונות על פי דרישה, כדאי לקרוא את המאמר שיטות מומלצות לשיפור חוויית המשתמש לאספקה על פי דרישה.
אם ברצונך לשנות בהדרגה את התכונות באפליקציה עם הזמן, ללא להפעיל אפשרויות מתקדמות להצגת מודעות, כמו הצגת מודעות על פי דרישה, במקום הגדרת מסירה בזמן ההתקנה.
הדף הזה עוזר לכם להוסיף מודול של פיצ'ר לפרויקט האפליקציה שלכם. להגדיר אותו למסירה על פי דרישה. לפני שמתחילים, חשוב לוודא שאתם משתמשים ב-Android Studio 3.5 ואילך וב-Android Gradle Plugin 3.5.0 ואילך.
הגדרת מודול חדש למסירה על פי דרישה
הדרך הקלה ביותר ליצור מודול חדש של תכונות היא באמצעות Android Studio 3.5 ואילך. מכיוון שלמודולים של תכונות יש או תלות מובנית במודול האפליקציה הבסיסית, אפשר להוסיף אותן רק פרויקטים של אפליקציות.
כדי להוסיף מודול תכונה לפרויקט האפליקציה באמצעות Android Studio:
- אם עדיין לא עשיתם זאת, פותחים את פרויקט האפליקציה בסביבת הפיתוח המשולבת.
- בוחרים באפשרות File > (קובץ >) חדש > מודול חדש מסרגל התפריטים.
- בתיבת הדו-שיח Create New Module בוחרים מודול תכונות דינמיות ולוחצים על הבא.
- בקטע הגדרת המודול החדש, מבצעים את הפעולות הבאות:
הבאים:
- בתפריט הנפתח, בוחרים את Base application module לפרויקט האפליקציה.
- מציינים שם מודול. סביבת הפיתוח המשולבת משתמשת בשם הזה כדי לזהות
בתור פרויקט משנה של Gradle
קובץ הגדרות Gradle. אחרי ש
לבניית ה-App Bundle שלך, Gradle משתמשת ברכיב האחרון של פרויקט המשנה
כדי להחדיר את המאפיין
<manifest split>
בתוך המניפסט של מודול התכונה. - מציינים את שם החבילה של המודול. כברירת מחדל, Android Studio מציע שם חבילה שמשלב את שם החבילה ברמה הבסיסית של המודול הבסיסי ואת שם המודול שציינתם בשלב הקודם.
- בוחרים את רמת ה-API המינימלית שרוצים שהמודול יתמוך בה. הערך הזה צריך להיות זהה לערך של המודול הבסיסי.
- לוחצים על הבא.
בקטע אפשרויות הורדה של מודול, מבצעים את הפעולות הבאות:
מציינים את שם המודול באורך של עד 50 תווים. הפלטפורמה משתמש בכותרת הזו כדי לזהות את המודול בפני המשתמשים כאשר, לדוגמה, ומאשרת אם המשתמש רוצה להוריד את המודול. לכן, מודול הבסיס של האפליקציה צריך לכלול את שם המודול כמשאב מחרוזת, שאפשר לתרגם. כשיוצרים את המודול באמצעות Android Studio, סביבת הפיתוח המשולבת מוסיפה את משאב המחרוזת למודול הבסיס ומחדירה את הערך הבא למניפסט של מודול התכונה:
<dist:module ... dist:title="@string/feature_title"> </dist:module>
בתפריט הנפתח, בקטע הכללה בזמן ההתקנה, בוחרים באפשרות לא לכלול כוללים את המודול בזמן ההתקנה. כדי לשקף את הבחירה שלכם, Android Studio מזין את הפרטים הבאים במניפסט של המודול:
<dist:module ... > <dist:delivery> <dist:on-demand/> </dist:delivery> </dist:module>
אם רוצים שהמודול הזה יהיה זמין, מסמנים את התיבה לצד Fusing למכשירים שמותקנת בהם גרסת Android 4.4 (רמת API 20) ומטה ומופיעים חבילות APK מרובות. כלומר, אפשר להפעיל במודול הזה התנהגות על פי דרישה ומשביתים את ההיתוך כדי להשמיט אותו ממכשירים שלא תומכים הורדה והתקנה של חבילות APK מפוצלות. כדי לשקף את הבחירה שלכם, Android Studio מזין את הפרטים הבאים במניפסט של המודול:
<dist:module ...> <dist:fusing dist:include="true | false" /> </dist:module>
לוחצים על סיום.
כשיצירת המודול מ-Android Studio, בודקים את התוכן שלו בחלונית Project (בוחרים באפשרות View > Tool Windows > Project (תצוגה > כלי Windows > פרויקט) מסרגל התפריטים). קוד ברירת המחדל, המשאבים והארגון צריכים להיות דומים לאלה של מודול האפליקציה הסטנדרטי.
בשלב הבא, תצטרכו להטמיע את הפונקציונליות של התקנה על פי דרישה באמצעות הספרייה של Play Feature Delivery.
הוספת ספריית Play Feature Delivery לפרויקט
לפני שמתחילים, מוסיפים את ספריית העברת התכונות של Play לפרויקט.
בקשת מודול על פי דרישה
כשהאפליקציה צריכה להשתמש במודול תכונות, היא יכולה לבקש אחד כשהוא בחזית באמצעות הכיתה SplitInstallManager
. בעת ביצוע
האפליקציה שלך צריכה לציין את שם המודול כפי שהוא מוגדר
split
במניפסט של מודול היעד. אחרי ש
ליצור מודול של תכונה
באמצעות Android Studio, מערכת ה-build משתמשת בשם המודול שסיפקת
כדי להחדיר את המאפיין הזה למניפסט של המודול בזמן הידור.
למידע נוסף, קראו את המאמר מניפסטים של מודולי תכונות.
לדוגמה, נניח שיש לך אפליקציה עם מודול על פי דרישה שמאפשרת לתעד ולשלוח אותו
הודעות תמונה באמצעות המצלמה של המכשיר, והמודול הזה על פי דרישה
מציין את split="pictureMessages"
במניפסט שלו. בדוגמה הבאה נעשה שימוש ב-SplitInstallManager
כדי לבקש את המודול pictureMessages
(יחד עם מודול נוסף למסנני קידום מכירות מסוימים):
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 -> { ... });
כשהאפליקציה מבקשת מודול על פי דרישה, ספריית העברת התכונות של Play מתבססת על אסטרטגיית "אש ושכח". כלומר, היא שולחת את הבקשה להוריד את את המודול לפלטפורמה, אבל הוא לא עוקב אחרי ההתקנה הצליחה. כדי להמשיך את תהליך השימוש של המשתמש אחרי ההתקנה או לטפל בשגיאות בצורה חלקה, חשוב לעקוב אחרי סטטוס הבקשה.
הערה: אפשר לבקש מודול תכונות שכבר מותקן במכשיר. ה-API מתייחס לבקשה כאל הושלמה באופן מיידי אם הוא מזהה שהמודול כבר מותקן. בנוסף, אחרי שמתקינים מודול, Google Play מעדכן אותו באופן אוטומטי. כלומר, כשאתם מעלים גרסה חדשה של חבילת האפליקציות, הפלטפורמה מעדכנת את כל חבילות ה-APK שהותקנו וששייכות לאפליקציה. למידע נוסף, קראו את המאמר ניהול עדכוני האפליקציות.
כדי לקבל גישה לקוד ולמשאבים של המודול, צריך להפעיל את SplitCompat באפליקציה. לתשומת ליבכם: SplitCompat נדרש לאפליקציות ללא התקנה ל-Android.
דחיית ההתקנה של מודולים על פי דרישה
אם אין לך צורך באפליקציה כדי להוריד ולהתקין באופן מיידי אפליקציה על פי דרישה אפשר לדחות את ההתקנה כשהאפליקציה פועלת ברקע. לדוגמה, אם אתם רוצים לטעון מראש קצת חומר פרסומי לקראת השקת האפליקציה.
ניתן לציין מודול להורדה מאוחר יותר באמצעות
deferredInstall()
ל-Assistant, כפי שמוצג בהמשך. ובניגוד לכך,
SplitInstallManager.startInstall()
,
האפליקציה לא צריכה להיות בחזית כדי לשלוח בקשה
עיכוב בהתקנה.
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"));
בקשות להתקנות שנדחו הן התוצאה הטובה ביותר ולא ניתן לעקוב אחר
על ההתקדמות במשחק. לכן, לפני שמנסים לגשת למודול שציינתם
להתקנה,
לבדוק שהמודול הותקן. אם אתם צריכים שהמודול יהיה זמין באופן מיידי, תוכלו להשתמש במקום זאת בפקודה SplitInstallManager.startInstall()
כדי לבקש אותו, כפי שמתואר בקטע הקודם.
מעקב אחרי מצב הבקשה
כדי שיהיה אפשר לעדכן סרגל התקדמות, צריך להפעיל Intent אחרי
או לטפל באלגנטיות בשגיאת בקשה, עליכם להאזין
עדכוני מצב מהמשימה האסינכרונית SplitInstallManager.startInstall()
.
לפני שמתחילים לקבל עדכונים לגבי בקשת ההתקנה, צריך לרשום
ה-listener וקבל את מזהה הסשן של הבקשה, כמו שמוצג בהמשך.
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);
טיפול בשגיאות בבקשות
חשוב לזכור שהתקנה על פי דרישה של מודולים של תכונות עשויה להיכשל לפעמים, בדיוק כמו שהתקנה של אפליקציות לא תמיד מצליחה. התקלה יכולה לנבוע מבעיות כמו נפח אחסון נמוך במכשיר, חוסר קישוריות לרשת או חוסר כניסה של המשתמש לחשבון בחנות Google Play. כדי לקבל הצעות לטיפול במצבים האלה בצורה נעימה מנקודת המבט של המשתמש, כדאי לעיין בהנחיות שלנו בנושא חוויית משתמש לשליחה על פי דרישה.
מבחינת הקוד, צריך לטפל בכשלים בהורדה או בהתקנה של מודול
באמצעות 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. } } } }); }
בטבלה הבאה מתוארים מצבי השגיאה שייתכן שהאפליקציה צריכה לטפל בהם:
קוד שגיאה | תיאור | הצעה לפעולה |
---|---|---|
ACTIVE_SESSIONS_LIMIT_EXCEEDED | הבקשה נדחתה כי יש לפחות בקשה אחת קיימת שמופעלת כרגע הורדה שלה. | בודקים אם יש בקשות שעדיין נמצאות בתהליך הורדה, כפי שמוצג בדוגמה שלמעלה. |
MODULE_UNAVAILABLE | ב-Google Play לא ניתן למצוא את המודול המבוקש בגרסה המותקנת הנוכחית של האפליקציה, המכשיר ו-Google Play של המשתמש חשבון. | אם למשתמש אין גישה למודול, צריך להודיע לו על כך. |
INVALID_REQUEST | Google Play קיבלה את הבקשה, אבל הבקשה אינו חוקי. | אימות המידע שנכלל בבקשה מלאה ומדויקת. |
SESSION_NOT_FOUND | לא נמצא סשן למזהה סשן נתון. | אם אתם מנסים לעקוב אחרי מצב הבקשה לפי מזהה הסשן שלה, חשוב לוודא שמזהה הסשן נכון. |
API_NOT_AVAILABLE | במכשיר הנוכחי אין תמיכה בספרייה להעברת תכונות ב-Play. כלומר, המכשיר לא יכול להוריד ולהתקין תכונות על פי דרישה. | עבור מכשירים שבהם פועל Android 4.4 (רמת API 20) ומטה, עליך
כוללים מודולים של תכונות בזמן ההתקנה באמצעות
מאפיין dist:fusing למניפסט. לקבלת מידע נוסף, אפשר לקרוא על
מניפסט של מודול התכונה.
|
שגיאת רשת | הבקשה נכשלה בגלל שגיאת רשת. | הצגת בקשה למשתמש ליצור חיבור לרשת או לעבור לרשת אחרת. |
ACCESS_DENIED | האפליקציה לא יכולה לרשום את הבקשה בגלל שההרשאות לא מספיקות. | בדרך כלל זה קורה כשהאפליקציה פועלת ברקע. מנסים לשלוח את הבקשה כשהאפליקציה חוזרת לחזית. |
INCOMPATIBLE_WITH_EXISTING_SESSION | הבקשה מכילה מודול אחד או יותר שכבר המבוקשים, אבל הם עדיין לא הותקנו. | צריך ליצור בקשה חדשה שלא כוללת מודולים שכבר נשלחו מהאפליקציה, או להמתין עד שכל המודולים שנשלחו יישלמו את ההתקנה לפני ששולחים שוב את הבקשה.
חשוב לזכור: בקשה למודול שכבר הותקן לא תגרום לשגיאה. |
SERVICE_DIED | השירות שאחראי לטיפול בבקשה נפטר. | אפשר לנסות לשלוח את הבקשה שוב.
|
INSUFFICIENT_STORAGE | אין במכשיר מספיק נפח אחסון פנוי להתקנת מודול התכונה. | להודיע למשתמש שאין לו מספיק נפח אחסון כדי להתקין את התכונה הזו. |
SPLITCOMPAT_ תואם_ERROR, SPLITCOMPAT_EMULATION_ERROR, SPLITCOMPAT_COPY_ERROR | לא ניתן היה לטעון את מודול התכונה ב-SplitCompat. | השגיאות האלה אמורות להיפתר באופן אוטומטי אחרי האפליקציה הבאה להפעיל מחדש. |
PLAY_STORE_NOT_FOUND | אפליקציית Play Store לא מותקנת במכשיר. | עליכם להודיע למשתמש שצריך להוריד את אפליקציית Play Store כדי להוריד את התכונה הזו. |
APP_NOT_OWNED | האפליקציה לא הותקנה על ידי Google Play ואי אפשר להוריד את התכונה. השגיאה הזו יכולה לקרות רק בהתקנות שנדחו. | אם רוצים שהמשתמש יוריד את האפליקציה מ-Google Play, צריך להשתמש ב-startInstall() , שיכול לקבל את אישור המשתמש הנדרש. |
שגיאה פנימית | אירעה שגיאה פנימית בחנות Play. | מנסים שוב לשלוח את הבקשה. |
אם משתמש מבקש להוריד מודול על פי דרישה ונוצרת שגיאה, מומלץ להציג תיבת דו-שיח עם שתי אפשרויות למשתמש: Try again (ניסיון חוזר) ו-Cancel (ביטול הבקשה). לקבלת תמיכה נוספת, כדאי גם לספק קישור לעזרה שיפנה את המשתמשים אל מרכז העזרה של Google Play.
טיפול בעדכוני מצב
אחרי שרושמים מאזינים ומתעדים את מזהה הסשן של הבקשה,
להשתמש ב-StateUpdatedListener.onStateUpdate()
כדי לטפל בשינויים במצב, כפי שמתואר בהמשך.
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. } } }
הסטטוסים האפשריים של בקשת ההתקנה מתוארים בטבלה שבהמשך.
מצב הבקשה | תיאור | הצעה לפעולה |
---|---|---|
בהמתנה | הבקשה אושרה ההורדה אמורה להתחיל בקרוב. | לאתחל רכיבי ממשק משתמש, כגון סרגל התקדמות, כדי לתת למשתמשים משוב על ההורדה. |
REQUIRES_USER_CONFIRMATION | ההורדה מחייבת אישור משתמש. הסטטוס הזה מופיע בדרך כלל אם האפליקציה לא הותקנה דרך Google Play. | מבקשים מהמשתמש לאשר את הורדת התכונה דרך Google Play. מידע נוסף זמין בקטע קבלת אישור מהמשתמשים. |
הורדה | ההורדה מתבצעת. | אם אתם מספקים סרגל התקדמות להורדה, צריך להשתמש בשיטות SplitInstallSessionState.bytesDownloaded() ו-SplitInstallSessionState.totalBytesToDownload() כדי לעדכן את ממשק המשתמש (ראו את דוגמת הקוד שמעל הטבלה הזו). |
הורדו | המודול הורדה למכשיר, אבל ההתקנה עדיין לא התחילה. | כדי לקבל גישה למודולים שהורדתם ולמנוע את הצגת הסטטוס הזה, עליכם להפעיל את SplitCompat באפליקציות. הפעולה הזו נדרשת כדי לגשת לקוד של מודול התכונה במשאבי אנוש. |
מתקין | המכשיר מתקין כרגע את המודול. | מעדכנים את סרגל ההתקדמות. המצב הזה בדרך כלל קצר. |
מותקן | המודול מותקן במכשיר. | קוד גישה ומשאבים במודול כדי להמשיך בתהליך ההרשמה.
אם המודול מיועד לאפליקציית Android Instant שפועלת ב-Android 8.0 (רמת API 26) ואילך, צריך להשתמש ב- |
הפעולה נכשלה | הבקשה נכשלה לפני שהמודול במכשיר. | להנחות את המשתמש לנסות לשלוח את הבקשה שוב או לבטל אותה. |
מתבצע ביטול | המכשיר בתהליך ביטול הבקשה. | מידע נוסף זמין בקטע לבטל בקשת התקנה. |
בוטלה | הבקשה בוטלה. |
קבלת אישור מהמשתמש
במקרים מסוימים, יכול להיות שמערכת Google Play תדרוש אישור מהמשתמשים לפני שתספק בקשת הורדה. לדוגמה, אם האפליקציה שלך לא הותקנה על ידי Google
הפעלה או אם אתם מנסים לבצע הורדה גדולה באמצעות חבילת גלישה. במקרים כאלה, הסטטוס של הבקשה הוא REQUIRES_USER_CONFIRMATION
, והאפליקציה צריכה לקבל אישור מהמשתמש לפני שהמכשיר יוכל להוריד ולהתקין את המודולים שבבקשה. כדי לקבל אישור, האפליקציה צריכה
לשלוח למשתמש בקשה באופן הבא:
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); } ... }
ניתן לרשום מרכז אפליקציות לתוצאת פעילות באמצעות
ActivityResultContracts.StartIntentSenderForResult
חוזה. למידע נוסף, אפשר לקרוא את המאמר ממשקי Activity Recommendation API.
סטטוס הבקשה מתעדכן בהתאם לתגובת המשתמש:
- אם המשתמש יאשר את האישור, סטטוס הבקשה ישתנה ל-
PENDING
וההורדה ממשיכה. - אם המשתמש דוחה את האישור, סטטוס הבקשה ישתנה ל-
CANCELED
. - אם המשתמש לא יבצע בחירה לפני שתיבת הדו-שיח תושמד, סטטוס הבקשה יישאר
REQUIRES_USER_CONFIRMATION
. האפליקציה יכולה לבקש מהמשתמש להשלים את הבקשה שוב.
כדי לקבל התקשרות חזרה עם תגובת המשתמש, אפשר לשנות את ActivityתוצאהCallback כמו שמוצג בהמשך.
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. } });
ביטול בקשת התקנה
אם האפליקציה צריכה לבטל בקשה לפני שהיא מותקנת, היא יכולה להפעיל את השיטה cancelInstall()
באמצעות מזהה הסשן של הבקשה, כפי שמתואר בהמשך.
Kotlin
splitInstallManager // Cancels the request for the given session ID. .cancelInstall(mySessionId)
Java
splitInstallManager // Cancels the request for the given session ID. .cancelInstall(mySessionId);
גישה למודולים
כדי לגשת לקוד ולמשאבים ממודול שהורדתם אחרי ההורדה, עליכם להפעיל את SplitCompat Library גם באפליקציה וגם בכל פעילות במודולים של התכונות שהאפליקציה שלכם מורידת.
עם זאת, שימו לב שהפלטפורמה חוותה הגבלות על הגישה לתוכן של מודול, למשך זמן מסוים (בימים מסוימים, במקרים מסוימים) לאחר הורדת המודול:
- הפלטפורמה לא יכולה להחיל רשומות מניפסט חדשות שנוספו על ידי המודול.
- הפלטפורמה לא יכולה לגשת למשאבי המודול לרכיבי ממשק המשתמש של המערכת, כמו התראות. אם עליך להשתמש במשאבים כאלה באופן מיידי, כדאי לשקול כולל המשאבים האלה במודול הבסיסי של האפליקציה.
הפעלת SplitCompat
כדי שהאפליקציה תוכל לגשת לקוד ולמשאבים ממודול שהורדתם, עליכם להפעיל את SplitCompat באמצעות אחת מהשיטות שמתוארות בקטעים הבאים.
אחרי שמפעילים את SplitCompat באפליקציה, צריך גם להפעיל את SplitCompat על כל פעילות במודולים של התכונות רוצים שלאפליקציה תהיה גישה אליהם.
הצהרה על SplitCompatApplication במניפסט
הדרך הפשוטה ביותר להפעיל את SplitCompat היא להצהיר על SplitCompatApplication
בתור מחלקת המשנה Application
ב-
המניפסט של האפליקציה, כפי שמוצג בהמשך:
<application
...
android:name="com.google.android.play.core.splitcompat.SplitCompatApplication">
</application>
אחרי שמתקינים את האפליקציה במכשיר, אפשר לגשת באופן אוטומטי לקוד ולמשאבים ממודולים של תכונות שהורדתם.
קריאה ל-SplitCompat בסביבת זמן הריצה
אפשר גם להפעיל את SplitCompat בפעילויות או בשירותים ספציפיים בזמן הריצה.
כדי להפעיל פעילויות שכלולות במודולים של תכונות, צריך להפעיל את SplitCompat באופן הזה. כדי לעשות זאת, משנים את הערך של attachBaseContext
כפי שמתואר בהמשך.
אם יש לכם סוג Application בהתאמה אישית, תוכלו להרחיב אותו במקום זאת ל-SplitCompatApplication
כדי להפעיל את SplitCompat באפליקציה, כפי שמתואר בהמשך:
Kotlin
class MyApplication : SplitCompatApplication() { ... }
Java
public class MyApplication extends SplitCompatApplication { ... }
SplitCompatApplication
פשוט מבטל את ContextWrapper.attachBaseContext()
כדי לכלול את SplitCompat.install(Context applicationContext)
. אם אתם לא רוצים שהקלאס Application
יהיה צאצא של SplitCompatApplication
, תוכלו לשנות את השיטה attachBaseContext()
באופן ידני באופן הבא:
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); }
אם המודול שלך על פי דרישה תואם באמצעות אפליקציות ללא התקנה וגם עם אפליקציות מותקנות, אפשר להפעיל את SplitCompat באופן מותנה, כך:
Kotlin
override fun attachBaseContext(base: Context) { super.attachBaseContext(base) if (!InstantApps.isInstantApp(this)) { SplitCompat.install(this) } }
Java
@Override protected void attachBaseContext(Context base) { super.attachBaseContext(base); if (!InstantApps.isInstantApp(this)) { SplitCompat.install(this); } }
הפעלת SplitCompat לפעילויות מודול
אחרי שמפעילים את SplitCompat באפליקציה הבסיסית, צריך להפעיל את SplitCompat לכל פעילות שהאפליקציה מורידת במודול תכונות. כדי לעשות זאת, משתמשים בשיטה SplitCompat.installActivity()
באופן הבא:
Kotlin
override fun attachBaseContext(base: Context) { super.attachBaseContext(base) // Emulates installation of on demand modules using SplitCompat. SplitCompat.installActivity(this) }
Java
@Override protected void attachBaseContext(Context base) { super.attachBaseContext(base); // Emulates installation of on demand modules using SplitCompat. SplitCompat.installActivity(this); }
גישה לרכיבים שהוגדרו במודולים של מאפיינים
התחלת פעילות שהוגדרה במודול של תכונות
אחרי שמפעילים את SplitCompat, אפשר להפעיל פעילויות שהוגדרו במודולים של תכונות באמצעות startActivity()
.
Kotlin
startActivity(Intent() .setClassName("com.package", "com.package.module.MyActivity") .setFlags(...))
Java
startActivity(new Intent() .setClassName("com.package", "com.package.module.MyActivity") .setFlags(...));
הפרמטר הראשון של setClassName
הוא שם החבילה של האפליקציה, והפרמטר השני הוא שם הכיתה המלא של הפעילות.
אם יש לכם פעילות במודול של מאפיינים שהורדתם על פי דרישה, אתם צריכים מפעילים את SplitCompat בפעילות.
הפעלת שירות שהוגדר במודול תכונות
אחרי שמפעילים את SplitCompat, אפשר להפעיל שירותים שהוגדרו במודולים של תכונות באמצעות startService()
.
Kotlin
startService(Intent() .setClassName("com.package", "com.package.module.MyService") .setFlags(...))
Java
startService(new Intent() .setClassName("com.package", "com.package.module.MyService") .setFlags(...));
ייצוא רכיב שמוגדר במודול תכונות
אין לכלול רכיבי Android שיוצאו במודולים אופציונליים.
מערכת ה-build משלבת את הרשומות של המניפסט של כל המודולים במודול הבסיס. אם מודול אופציונלי מכיל רכיב שיוצא, תהיה אליו גישה גם לפני ההתקנה של המודול, והוא עלול לגרום לקריסה בגלל קוד חסר כשמפעילים אותו מאפליקציה אחרת.
זה לא בעיה ברכיבים פנימיים, כי רק האפליקציה יכולה לגשת אליהם, כך שהיא יכולה לבדוק אם המודול מותקן לפני הגישה לרכיב.
אם אתם צריכים רכיב מיוצא ואתם רוצים שהתוכן שלו יהיה
כדאי ליישם דפוס של שרת proxy.
כדי לעשות זאת, מוסיפים ל-base רכיב proxy שיוצאו. כשנכנסים לרכיב ה-proxy, הוא יכול לבדוק אם המודול שמכיל את התוכן נמצא. אם המודול נמצא, רכיב ה-proxy יכול להפעיל את הרכיב הפנימי מהמודול באמצעות Intent
, ולהעביר את ה-intent מאפליקציית הקריאה. אם המודול לא נמצא, הרכיב יכול להוריד את המודול או להחזיר הודעת שגיאה מתאימה לאפליקציית הקריאה.
גישה לקוד ולמשאבים ממודולים מותקנים
אם מפעילים את SplitCompat להקשר של האפליקציה הבסיסית ולפעילויות במודול התכונה, אפשר להשתמש בקוד ובמשאבים ממודול התכונה כאילו הם חלק מ-APK הבסיסי, אחרי התקנת המודול האופציונלי.
גישה לקוד ממודול אחר
גישה לקוד הבסיס ממודול
מודולים אחרים יכולים להשתמש ישירות בקוד שנמצא בתוך מודול הבסיס. לא צריך לעשות שום דבר מיוחד. פשוט לייבא את הכיתות הרצויות ולהשתמש בהן.
קוד מודול גישה ממודול אחר
אי אפשר לגשת באופן סטטי לאובייקט או לכיתה בתוך מודול ממדול אחר, אבל אפשר לגשת אליהם באופן עקיף באמצעות רפלקציה.
חשוב לשים לב באיזו תדירות זה קורה, בגלל עלויות הביצועים של ההחזרה. בתרחישים מורכבים לדוגמה, כדאי להשתמש ב-frameworks של הזרקת תלות כמו Dagger 2 שמבטיח שיחת השתקפות אחת לכל משך החיים של האפליקציה.
כדי לפשט את האינטראקציות עם האובייקט אחרי היצירה שלו, מומלץ להגדיר ממשק במודול הבסיס ולהטמיע אותו במודול התכונות. לדוגמה:
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();
גישה למשאבים ולנכסים מתוך מודול אחר
אחרי שמתקינים מודול, אפשר לגשת למשאבים ולנכסים בתוך המודול בדרך הרגילה, עם שתי оговорки:
- אם אתם ניגשים למשאב מממשק אחר, לממשק לא תהיה גישה למזהה המשאב, אבל עדיין תוכלו לגשת למשאב לפי שם. שימו לב שהחבילה שבה צריך להשתמש כדי להפנות למשאב היא החבילה של המודול שבו מוגדר המשאב.
- אם רוצים לגשת לנכסים או למשאבים שנמצאים במודול שהותקן לאחרונה מתוך מודול אחר שהותקן באפליקציה, צריך לעשות זאת באמצעות הקשר האפליקציה. ההקשר של הרכיב שמנסה לגשת למשאבים עדיין לא יתעדכן. לחלופין, אפשר ליצור מחדש את הרכיב הזה (למשל, באמצעות הקריאה Activity.recreate()) או להתקין מחדש את SplitCompat אחרי התקנת מודול התכונה.
טעינת קוד מקורי באפליקציה באמצעות מסירה על פי דרישה
מומלץ להשתמש ב-ReLinker כדי לטעון את כל בספריות המקוריות שלכם כשאתם משתמשים במסירה לפי דרישה של מודולים של מאפיינים. ReLinker פותר בעיה בטעינה של ספריות נייטיב לאחר ההתקנה של של התכונה. מידע נוסף על ReLinker זמין טיפים ל-Android JNI.
טעינת קוד מקורי ממודול אופציונלי
אחרי שמתקינים פיצול, מומלץ לטעון את הקוד המקורי שלו באמצעות ReLinker. באפליקציות מיידיות צריך להשתמש בשיטה המיוחדת הזו.
אם אתם משתמשים ב-System.loadLibrary()
כדי לטעון את קוד ה-Native
תלויה בספרייה אחרת במודול, עליך להשתמש באופן ידני
לטעון את הספרייה השנייה קודם.
אם אתם משתמשים ב-ReLinker, הפעולה המקבילה היא
Relinker.recursively().loadLibrary()
אם משתמשים ב-dlopen()
בקוד מקומי כדי לטעון ספרייה שמוגדרת במודול אופציונלי, היא לא תפעל עם נתיבים יחסיים לספריות.
הפתרון הטוב ביותר הוא לאחזר את הנתיב המוחלט של הספרייה מקוד Java
דרך ClassLoader.findLibrary()
, ולאחר מכן להשתמש בה בשיחה שלך עם dlopen()
.
יש לעשות זאת לפני הזנת קוד ה-Native או להשתמש בקריאת JNI
ב-Java.
גישה לאפליקציות אינסטנט ל-Android שמותקנות במכשיר
אחרי שמודול של אפליקציה ללא התקנה ל-Android מדווח כ-INSTALLED
, אפשר לגשת אליו
את הקוד והמשאבים באמצעות אפליקציה שעברה רענון
הקשר. הקשר שהאפליקציה יוצרת לפני התקנת מודול (לדוגמה, הקשר שכבר מאוחסן במשתנה) לא מכיל את התוכן של המודול החדש. אבל הקשר חדש כן עוזר – אפשר לקבל אותו, למשל, באמצעות 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(); } } }
אפליקציות אינסטנט ל-Android בגרסה 8.0 ואילך
כששולחים בקשה למודול על פי דרישה לאפליקציה ללא התקנה ל-Android ב-Android 8.0
(רמת API 26) ואילך, לאחר בקשת התקנה מדווחת כ-INSTALLED
,
תצטרכו לעדכן את האפליקציה בהקשר של המודול החדש באמצעות קריאה
SplitInstallHelper.updateAppInfo(Context context)
.
אחרת, האפליקציה עדיין לא מודעת לקוד ולמשאבים של המודול. אחרי שמעדכנים את המטא-נתונים של האפליקציה, צריך לטעון את תוכן המודול במהלך האירוע הבא של שרשור הראשי, על ידי קריאה ל-Handler
חדש, כפי שמתואר בהמשך:
Kotlin
override fun onStateUpdate(state: SplitInstallSessionState ) { if (state.sessionId() == mySessionId) { when (state.status()) { ... SplitInstallSessionStatus.INSTALLED -> { // You need to perform the following only for Android Instant Apps // running on Android 8.0 (API level 26) and higher. if (BuildCompat.isAtLeastO()) { // Updates the app’s context with the code and resources of the // installed module. SplitInstallHelper.updateAppInfo(context) Handler().post { // Loads contents from the module using AssetManager val am = context.assets ... } } } } } }
Java
@Override public void onStateUpdate(SplitInstallSessionState state) { if (state.sessionId() == mySessionId) { switch (state.status()) { ... case SplitInstallSessionStatus.INSTALLED: // You need to perform the following only for Android Instant Apps // running on Android 8.0 (API level 26) and higher. if (BuildCompat.isAtLeastO()) { // Updates the app’s context with the code and resources of the // installed module. SplitInstallHelper.updateAppInfo(context); new Handler().post(new Runnable() { @Override public void run() { // Loads contents from the module using AssetManager AssetManager am = context.getAssets(); ... } }); } } } }
טעינת ספריות C/C++
אם רוצים לטעון ספריות C/C++ ממודול שכבר הורדתם למכשיר באפליקציית Instant, צריך להשתמש ב-SplitInstallHelper.loadLibrary(Context context, String libName)
, כפי שמתואר בהמשך:
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”); ... } } }
מגבלות ידועות
- לא ניתן להשתמש ב-Android WebView בפעילות שיש לה גישה משאבים או נכסים ממודול אופציונלי. הסיבה לכך היא חוסר תאימות בין WebView ל-SplitCompat בגרסאות Android API ברמה 28 ומטה.
- אי אפשר לשמור אובייקטים מסוג
ApplicationInfo
של Android, את התוכן שלהם או אובייקטים שמכילים אותם באפליקציה במטמון. תמיד צריך לאחזר את האובייקטים האלה לפי הצורך מההקשר של האפליקציה. שמירת אובייקטים כאלה במטמון עלולה לגרום לקריסת האפליקציה במהלך התקנת מודול תכונות.
ניהול המודולים המותקנים
כדי לבדוק אילו מודולים של תכונות מותקנים כרגע במכשיר:
אפשר להתקשר
SplitInstallManager.getInstalledModules()
,
שתחזיר Set<String>
של שמות המודולים המותקנים, כפי שמוצג
שלמטה.
Kotlin
val installedModules: Set<String> = splitInstallManager.installedModules
Java
Set<String> installedModules = splitInstallManager.getInstalledModules();
הסרת מודולים
כדי לבקש מהמכשיר להסיר מודולים, מפעילים את הפונקציה SplitInstallManager.deferredUninstall(List<String> moduleNames)
, כפי שמתואר בהמשך.
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"));
הסרות של מודולים לא מתרחשות באופן מיידי. כלומר, המכשיר מנתק אותן ברקע לפי הצורך כדי לחסוך מקום באחסון.
כדי לוודא שהמכשיר מחק מודול, אפשר להפעיל את הפונקציה SplitInstallManager.getInstalledModules()
ולבדוק את התוצאה, כפי שמתואר בקטע הקודם.
הורדת משאבים נוספים בשפות
כשמשתמשים בחבילות אפליקציות, המכשירים מורידים רק את הקוד ואת המשאבים שנדרשים להפעלת האפליקציה. לכן, לגבי משאבי שפה, המכשיר של המשתמש מוריד רק את משאבי השפה של האפליקציה שתואמים לשפה אחת או יותר שנבחרה כרגע בהגדרות המכשיר.
אם אתם רוצים שלאפליקציה תהיה גישה למשאבי שפה נוספים – לדוגמה, כדי להטמיע בוחר שפה בתוך האפליקציה, אפשר להשתמש ב-Play Feature Delivery ספרייה להורדה לפי דרישה. התהליך דומה לתהליך ההורדה של מודול תכונות, כפי שמתואר בהמשך.
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);
הבקשה מטופלת כאילו היא בקשה למודול תכונה. כלומר, אפשר לעקוב אחרי מצב הבקשה כרגיל.
אם האפליקציה לא דורשת את משאבי השפה הנוספים באופן מיידי, יכול לדחות את ההתקנה כשהאפליקציה פועלת ברקע, כפי שמוצג שלמטה.
Kotlin
splitInstallManager.deferredLanguageInstall( Locale.forLanguageTag(sharedPrefs.getString(LANGUAGE_SELECTION)))
Java
splitInstallManager.deferredLanguageInstall( Locale.forLanguageTag(sharedPrefs.getString(LANGUAGE_SELECTION)));
גישה למשאבי שפה שהורדו
כדי לקבל גישה למשאבי שפה שהורדת, האפליקציה שלך צריכה להריץ את
אמצעי תשלום SplitCompat.installActivity()
בתוך ה-method attachBaseContext()
של כל פעילות שדורשת גישה למשאבים האלה, כפי שמוצג בהמשך.
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); }
בכל פעילות שבה רוצים להשתמש במשאבי שפה שהאפליקציה הורידה, צריך לעדכן את ההקשר הבסיסי ולהגדיר אזור חדש באמצעות 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); }
כדי שהשינויים האלה ייכנסו לתוקף, תצטרכו ליצור מחדש את הפעילות אחרי שהשפה החדשה תותקן ותהיה מוכנה לשימוש. אפשר להשתמש
אמצעי תשלום אחד (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(); ... }
הסרת משאבי שפות נוספים
בדומה למודולים של תכונות, ניתן להסיר משאבים נוספים ב בכל שלב. לפני שמבקשים הסרה, כדאי לבדוק קודם מותקנות כעת, כמפורט למטה.
Kotlin
val installedLanguages: Set<String> = splitInstallManager.installedLanguages
Java
Set<String> installedLanguages = splitInstallManager.getInstalledLanguages();
לאחר מכן תוכלו להחליט אילו שפות להסיר באמצעות השיטה deferredLanguageUninstall()
, כפי שמתואר בהמשך.
Kotlin
splitInstallManager.deferredLanguageUninstall( Locale.forLanguageTag(sharedPrefs.getString(LANGUAGE_SELECTION)))
Java
splitInstallManager.deferredLanguageUninstall( Locale.forLanguageTag(sharedPrefs.getString(LANGUAGE_SELECTION)));
בדיקה מקומית של התקנות של מודולים
ספריית העברת התכונות של Play מאפשרת לבדוק באופן מקומי את היכולת של האפליקציה לבצע הבאים, בלי להתחבר לחנות Play:
- שליחת בקשות להתקנת מודולים ומעקב אחריהן.
- טיפול בשגיאות בהתקנה.
- משתמשים ב-
SplitCompat
כדי לגשת למודולים.
בדף הזה נסביר איך לפרוס את חבילות ה-APK המפוצלות של האפליקציה למכשיר הבדיקה כדי ש-Play Feature Delivery משתמש באופן אוטומטי בחבילות ה-APK האלה כדי לדמות בקשות, הורדה, ולהתקין מודולים מחנות Play.
אין צורך לבצע שינויים בלוגיקה של האפליקציה, אבל צריך לעמוד בדרישות הבאות:
- מורידים ומתקינים את הגרסה האחרונה של
bundletool
. יש צורך ב-bundletool
כדי ליצור קבוצה חדשה של חבילות APK להתקנה מתוך האפליקציה חבילה.
בניית קבוצה של חבילות APK
אם עדיין לא עשית זאת, עליך ליצור את חבילות ה-APK המפוצלות של האפליקציה באופן הבא:
- אפשר ליצור App Bundle לאפליקציה באחת מהשיטות הבאות:
- שימוש ב-Android Studio ובפלאגין Android ל-Gradle כדי ליצור ולחתום על Android App Bundle.
- איך יוצרים את חבילת האפליקציה משורת הפקודה
השתמש ב-
bundletool
כדי ליצור קבוצה של חבילות APK לכל המכשירים באמצעות הפקודה הבאה:bundletool build-apks --local-testing --bundle my_app.aab --output my_app.apks
הדגל --local-testing
כולל מטא-נתונים במניפסטים של קובצי ה-APK, שמאפשרים לספריית Play Feature Delivery להשתמש בקובצי ה-APK המקומיים המפוצלים כדי לבדוק את התקנת המודולים של התכונות, בלי להתחבר לחנות Play.
פורסים את האפליקציה במכשיר
אחרי שיוצרים קבוצת חבילות APK באמצעות הדגל --local-testing
,
יש להשתמש ב-bundletool
כדי להתקין את גרסת הבסיס של האפליקציה ולהעביר גרסאות נוספות
חבילות APK לאחסון המקומי במכשיר שלכם. אפשר לבצע את שתי הפעולות באמצעות הפקודה הבאה:
bundletool install-apks --apks my_app.apks
עכשיו, כשאתם מפעילים את האפליקציה ומסיימים את תהליך ההורדה וההתקנה של מודול התכונה, ספריית Play Feature Delivery משתמשת בקובצי ה-APK ש-bundletool
העביר לאחסון המקומי של המכשיר.
הדמיה של שגיאת רשת
כדי לדמות התקנות של מודולים מחנות Play, ספריית העברת התכונות של Play משתמשת ב-
היא חלופה ל-SplitInstallManager
, שנקראת
FakeSplitInstallManager
,
כדי לבקש את המודול. כשמשתמשים ב-bundletool
עם הדגל --local-testing
כדי ליצור קבוצה של חבילות APK ולפרוס אותן במכשיר הבדיקה, ה-build כולל מטא-נתונים שמנחים את ספריית Play Feature Delivery להעביר באופן אוטומטי את הקריאות ל-API של האפליקציה להפעלת FakeSplitInstallManager
במקום SplitInstallManager
.
FakeSplitInstallManager
כולל סימון בוליאני שאפשר להפעיל כדי
הדמיה של שגיאת רשת בפעם הבאה שהאפליקציה תבקש להתקין מודול. שפת תרגום
ניגשים אל FakeSplitInstallManager
בבדיקות, אפשר לקבל מופע כלשהו
באמצעות
FakeSplitInstallManagerFactory
,
כפי שמוצג בהמשך:
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);