پیکربندی تحویل به‌درخواست

واحدهای ویژگی به شما امکان می‌دهند ویژگی‌ها و منابع خاصی را از واحد پایه برنامه‌تان جدا کنید و آن‌ها را در دسته برنامه‌تان قرار دهید. ازطریق «ویژگی تحویل Play»، کاربران می‌توانند، برای مثال، بعداً آن مؤلفه‌ها را درصورت درخواست بارگیری و نصب کنند، پس‌از اینکه قبلاً APK پایه برنامه‌تان را نصب کرده‌اند.

برای مثال، برنامه پیام‌رسانی نوشتاری را درنظر بگیرید که عملکردی برای گرفتن و ارسال پیام‌های تصویری دارد، اما فقط درصد کمی از کاربران پیام‌های تصویری ارسال می‌کنند. شاید منطقی باشد که پیام‌رسانی تصویری را به‌عنوان واحد ویژگی بارگیری‌شدنی اضافه کنید. به این ترتیب، بارگیری اولیه برنامه برای همه کاربران کوچک‌تر است و فقط کاربرانی که پیام تصویری ارسال می‌کنند باید آن مؤلفه اضافی را بارگیری کنند.

به‌خاطر داشته باشید که این نوع مدولارسازی به تلاش بیشتری نیاز دارد و احتمالاً کد موجود برنامه‌تان را بازسازی می‌کند، بنابراین به‌دقت بررسی کنید که کدام‌یک از ویژگی‌های برنامه‌تان بیشترین بهره را از دردسترس بودن برای کاربران به‌صورت درخواستی می‌برد. برای درک بهتر موارد استفاده بهینه و دستورالعمل‌های ویژگی‌های درخواستی، روال‌های مطلوب تجربه کاربری برای ارائه درخواستی را بخوانید.

اگر می‌خواهید به‌تدریج ویژگی‌های برنامه را درطول زمان مدولار کنید، بدون اینکه گزینه‌های پیشرفته توزیع را فعال کنید، مثلاً توزیع درخواستی، به‌جای آن توزیع در زمان نصب را پیکربندی کنید.

این صفحه به شما کمک می‌کند واحد ویژگی را به پروژه برنامه‌تان اضافه کنید و آن را برای تحویل درخواستی پیکربندی کنید. قبل‌از شروع، مطمئن شوید که از Android Studio 3.5 یا بالاتر و «افزایه Android Gradle» نسخه ۳.۵.۰ یا بالاتر استفاده می‌کنید.

پیکربندی کردن واحد جدید برای تحویل درخواستی

آسان‌ترین راه برای ایجاد واحد ویژگی جدید استفاده از Android Studio 3.5 یا بالاتر است. چون پیمانه‌های ویژگی وابستگی ذاتی به پیمانه برنامه پایه دارند، فقط می‌توانید آن‌ها را به پروژه‌های برنامه موجود اضافه کنید.

برای افزودن واحد ویژگی به پروژه برنامه‌تان بااستفاده از «استودیو Android»، به‌صورت زیر عمل کنید:

  1. اگر قبلاً این کار را نکرده‌اید، پروژه برنامه‌تان را در IDE باز کنید.
  2. فایل > جدید > ماژول جدید را از نوار منو انتخاب کنید.
  3. در کادر گفتگوی ایجاد واحد جدید، واحد ویژگی پویا را انتخاب کنید و روی بعدی کلیک کنید.
  4. در بخش پیکربندی واحد جدید، موارد زیر را تکمیل کنید:
    1. واحد برنامه پایه را برای پروژه برنامه‌تان از منوِ کرکره‌ای انتخاب کنید.
    2. نام واحد را مشخص کنید. IDE از این نام برای شناسایی ماژول به‌عنوان زیرپروژه Gradle در فایل تنظیمات Gradle شما استفاده می‌کند. وقتی دسته برنامه را می‌سازید، Gradle از آخرین عنصر نام زیرپروژه برای تزریق کردن مشخصه <manifest split> در مانیفست واحد ویژگی استفاده می‌کند.
    3. نام بسته واحد را مشخص کنید. به‌طور پیش‌فرض، Android Studio نام بسته‌ای را پیشنهاد می‌کند که نام بسته ریشه واحد پایه و نام واحدی را که در مرحله قبلی مشخص کرده‌اید ترکیب می‌کند.
    4. حداقل سطح API را که می‌خواهید واحد از آن پشتیبانی کند انتخاب کنید. این مقدار باید با مقدار واحد پایه مطابقت داشته باشد.
  5. روی بعدی کلیک کنید.
  6. در بخش گزینه‌های بارگیری واحد، موارد زیر را تکمیل کنید:

    1. عنوان پیمانه را با حداکثر ۵۰ نویسه مشخص کنید. پلاتفرم از این عنوان برای شناسایی واحد به کاربران استفاده می‌کند، مثلاً هنگام تأیید اینکه آیا کاربر می‌خواهد واحد را بارگیری کند یا نه. به‌همین دلیل، ماژول پایه برنامه‌تان باید عنوان ماژول را به‌عنوان منبع رشته داشته باشد تا بتوانید آن را ترجمه کنید. هنگام ایجاد واحد بااستفاده از Android Studio، محیط توسعه یکپارچه منبع رشته را به واحد پایه اضافه می‌کند و ورودی زیر را در مانیفست واحد ویژگی تزریق می‌کند:

      <dist:module
          ...
          dist:title="@string/feature_title">
      </dist:module>
      
    2. در منوِ کرکره‌ای زیر گنجاندن در زمان نصب، ماژول در زمان نصب گنجانده نشود را انتخاب کنید. «استودیو Android» موارد زیر را در مانیفست واحد تزریق می‌کند تا انتخاب شما را منعکس کند:

      <dist:module ... >
        <dist:delivery>
            <dist:on-demand/>
        </dist:delivery>
      </dist:module>
      
    3. اگر می‌خواهید این واحد برای دستگاه‌های دارای Android نسخه ۴.۴ (سطح API‏ ۲۰) و پایین‌تر دردسترس باشد و در چند APK گنجانده شود، چارگوش کنار Fusing را علامت بزنید. این یعنی می‌توانید رفتار درخواستی را برای این واحد فعال کنید و ادغام را غیرفعال کنید تا آن را از دستگاه‌هایی که از بارگیری و نصب APK جداشده پشتیبانی نمی‌کنند حذف کنید. «استودیو Android» موارد زیر را در مانیفست واحد تزریق می‌کند تا انتخاب شما را منعکس کند:

      <dist:module ...>
          <dist:fusing dist:include="true | false" />
      </dist:module>
      
  7. روی پایان کلیک کنید.

پس‌از اینکه «استودیو Android» ایجاد کردن واحد را به‌پایان رساند، محتوای آن را خودتان از پانل پروژه بررسی کنید (مشاهده > پنجره‌های ابزار > پروژه را از نوار منو انتخاب کنید). کد، منابع، و سازمان پیش‌فرض باید مشابه کد، منابع، و سازمان واحد برنامه استاندارد باشد.

سپس، باید عملکرد نصب درخواستی را بااستفاده از کتابخانه «ویژگی تحویل Play» پیاده‌سازی کنید.

گنجاندن «کتابخانه ویژگی تحویل Play» در پروژه

قبل‌از شروع، ابتدا باید کتابخانه Play Feature Delivery را به پروژه‌تان اضافه کنید.

درخواست کردن واحد درخواستی

وقتی برنامه‌تان نیاز به استفاده از واحد ویژگی دارد، می‌تواند درحالی‌که در پیش‌زمینه است، ازطریق کلاس SplitInstallManager درخواست واحد ویژگی کند. هنگام درخواست، برنامه شما باید نام ماژول را همان‌طور که توسط عنصر split در مانیفست ماژول هدف تعریف شده است، مشخص کند. وقتی بااستفاده از Android Studio واحد ویژگی ایجاد می‌کنید، سیستم ساخت از نام واحد که ارائه می‌دهید استفاده می‌کند تا این ویژگی را در زمان ترجمه به مانیفست واحد تزریق کند. برای اطلاعات بیشتر، درباره مانیفست‌های واحد ویژگی بخوانید.

برای مثال، برنامه‌ای را درنظر بگیرید که دارای یک ماژول درخواستی برای ضبط و ارسال پیام‌های تصویری بااستفاده از دوربین دستگاه است، و این ماژول درخواستی split="pictureMessages" را در مانیفست خود مشخص می‌کند. نمونه زیر از SplitInstallManager برای درخواست واحد pictureMessages (به‌همراه یک واحد اضافی برای برخی فیلترهای تبلیغاتی) استفاده می‌کند:

کاتلین

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

جاوا

// 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() مشخص کنید که واحدی بعداً بارگیری شود، همان‌طور که در زیر نشان داده شده است. و برخلاف SplitInstallManager.startInstall()، برنامه شما برای شروع درخواست نصب معوقه نیازی به قرار گرفتن در پیش‌زمینه ندارد.

کاتلین

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

جاوا

// 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() برای درخواست آن استفاده کنید، همان‌طور که در بخش قبلی نشان داده شده است.

پایش کردن وضعیت درخواست

برای اینکه بتوانید نوار پیشرفت را به‌روز کنید، پس‌از نصب، قصدی را فعال کنید، یا خطای درخواست را به‌خوبی مدیریت کنید، باید به‌روزرسانی‌های وضعیت را از تکلیف ناهمگام SplitInstallManager.startInstall() گوش دهید. قبل‌از اینکه بتوانید به‌روزرسانی‌های درخواست نصب را دریافت کنید، شنونده‌ای را ثبت کنید و شناسه جلسه را برای درخواست دریافت کنید، همان‌طور که در زیر نشان داده شده است.

کاتلین

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

جاوا

// 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» باشد. برای پیشنهادهایی درباره نحوه مدیریت این موقعیت‌ها به‌شیوه‌ای مناسب از دیدگاه کاربر، دستورالعمل‌های UX برای تحویل درخواستی ما را بررسی کنید.

ازنظر کد، باید بااستفاده از addOnFailureListener()، همان‌طور که در زیر نشان داده شده است، خطاهای بارگیری یا نصب ماژول را مدیریت کنید:

کاتلین

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

جاوا

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 نسخه ۴.۴ (سطح API‏ ۲۰) یا پایین‌تر دارند، باید واحدهای ویژگی را در زمان نصب بااستفاده از ویژگی مانیفست dist:fusing اضافه کنید. برای کسب اطلاعات بیشتر، درباره مانیفست واحد ویژگی بخوانید.
NETWORK_ERROR درخواست به‌دلیل خطای شبکه ناموفق بود. از کاربر بخواهید اتصال شبکه برقرار کند یا به شبکه دیگری برود.
ACCESS_DENIED برنامه به‌دلیل نداشتن اجازه‌های کافی نمی‌تواند درخواست را ثبت کند. این اتفاق معمولاً زمانی رخ می‌دهد که برنامه در پس‌زمینه باشد. وقتی برنامه به پیش‌زمینه برمی‌گردد، درخواست را امتحان کنید.
INCOMPATIBLE_WITH_EXISTING_SESSION درخواست حاوی یک یا چند ماژول است که قبلاً درخواست شده‌اند اما هنوز نصب نشده‌اند. یا درخواست جدیدی ایجاد کنید که شامل واحدهایی که برنامه‌تان قبلاً درخواست کرده است نباشد، یا قبل‌از امتحان مجدد درخواست، منتظر بمانید تا نصب همه واحدهای درخواست‌شده فعلی به‌پایان برسد.

به‌خاطر داشته باشید که درخواست کردن واحدی که قبلاً نصب شده است منجر به خطا نمی‌شود.

SERVICE_DIED سرویس مسئول رسیدگی به درخواست ازکار افتاده است. درخواست را دوباره امتحان کنید.

SplitInstallStateUpdatedListener شما یک SplitInstallSessionState با این کد خطا، وضعیت FAILED و شناسه جلسه -1 دریافت می‌کند.

INSUFFICIENT_STORAGE دستگاه فضای ذخیره‌سازی آزاد کافی برای نصب واحد ویژگی ندارد. به کاربر اطلاع دهید که فضای ذخیره‌سازی کافی برای نصب این ویژگی ندارد.
SPLITCOMPAT_VERIFICATION_ERROR, SPLITCOMPAT_EMULATION_ERROR, SPLITCOMPAT_COPY_ERROR SplitCompat نتوانست واحد ویژگی را بار کند. این خطاها باید به‌طور خودکار پس‌از بازراه‌اندازی بعدی برنامه برطرف شوند.
PLAY_STORE_NOT_FOUND برنامه «فروشگاه Play» در دستگاه نصب نشده است. به کاربر اطلاع دهید که برای بارگیری این ویژگی، به برنامه «فروشگاه Play» نیاز است.
APP_NOT_OWNED این برنامه توسط Google Play نصب نشده است و این ویژگی را نمی‌توان بارگیری کرد. این خطا فقط برای نصب‌های معوقه ممکن است رخ دهد. اگر می‌خواهید کاربر برنامه را در Google Play دریافت کند، از startInstall() استفاده کنید که می‌تواند تأییدیه کاربر لازم را دریافت کند.
INTERNAL_ERROR خطای داخلی در «فروشگاه Play» روی داد. درخواست را دوباره امتحان کنید.

اگر کاربری درخواست بارگیری یک مدول درخواستی را داشته باشد و خطایی رخ دهد، نمایش یک کادر گفتگویی را درنظر بگیرید که دو گزینه برای کاربر فراهم می‌کند: دوباره امتحان کنید (که درخواست را دوباره امتحان می‌کند) و لغو (که درخواست را رها می‌کند). برای پشتیبانی بیشتر، باید پیوند راهنما را نیز ارائه دهید که کاربران را به مرکز راهنمایی Google Play هدایت کند.

رسیدگی به به‌روزرسانی‌های وضعیت

پس‌از ثبت شنونده و ضبط شناسه جلسه برای درخواستتان، از StateUpdatedListener.onStateUpdate() برای مدیریت تغییرات وضعیت استفاده کنید، همان‌طور که در زیر نشان داده شده است.

کاتلین

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

جاوا

@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» است که در Android نسخه ۸.۰ (سطح میانای برنامه‌سازی کاربردی ۲۶) یا بالاتر اجرا می‌شود، باید از splitInstallHelper برای به‌روزرسانی مؤلفه‌های برنامه با ماژول جدید استفاده کنید.

ناموفق درخواست پیش‌از نصب واحد در دستگاه ناموفق بود. از کاربر بخواهید درخواست را دوباره امتحان کند یا آن را لغو کند.
درحال لغو کردن دستگاه درحال لغو کردن درخواست است. برای کسب اطلاعات بیشتر، به بخش مربوط به نحوه لغو کردن درخواست نصب بروید.
لغو شد درخواست لغو شده است.

دریافت تأیید کاربر

در برخی موارد، ممکن است Google Play قبل‌از برآورده کردن درخواست بارگیری، به تأیید کاربر نیاز داشته باشد. برای مثال، اگر برنامه‌تان ازطریق Google Play نصب نشده باشد یا اگر می‌خواهید بارگیری بزرگی را ازطریق داده تلفن همراه انجام دهید. در چنین مواردی، وضعیت درخواست REQUIRES_USER_CONFIRMATION را گزارش می‌کند و برنامه‌تان باید قبل‌از اینکه دستگاه بتواند ماژول‌های موجود در درخواست را بارگیری و نصب کند، تأیید کاربر را دریافت کند. برای دریافت تأیید، برنامه‌تان باید به‌صورت زیر از کاربر درخواست کند:

کاتلین

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

جاوا

@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 Result را ببینید.

وضعیت درخواست بسته به پاسخ کاربر به‌روز می‌شود:

  • اگر کاربر تأیید را بپذیرد، وضعیت درخواست به PENDING تغییر می‌کند و بارگیری ادامه می‌یابد.
  • اگر کاربر تأیید را رد کند، وضعیت درخواست به CANCELED تغییر می‌کند.
  • اگر کاربر قبل‌از بسته شدن کادر گفتگو انتخابی انجام ندهد، وضعیت درخواست به‌صورت REQUIRES_USER_CONFIRMATION باقی می‌ماند. برنامه‌تان می‌تواند دوباره از کاربر بخواهد درخواست را تکمیل کند.

برای دریافت تماس برگشتی با پاسخ کاربر، می‌توانید ActivityResultCallback را همان‌طور که در زیر نشان داده شده است لغو کنید.

کاتلین

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

جاوا

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() را فراخوانی کند، همان‌طور که در زیر نشان داده شده است.

کاتلین

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

جاوا

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

پیمانه‌های دسترسی

برای دسترسی به کد و منابع از واحد بارگیری‌شده پس‌از بارگیری آن، برنامه‌تان باید کتابخانه SplitCompat را هم برای برنامه‌تان و هم برای هر فعالیت در واحدهای ویژگی که برنامه‌تان بارگیری می‌کند فعال کند.

بااین‌حال، باید توجه داشته باشید که پلاتفرم برای مدتی (در برخی موارد، چند روز) پس‌از بارگیری کردن واحد، با محدودیت‌های زیر برای دسترسی به محتوای واحد مواجه می‌شود:

  • پلاتفرم نمی‌تواند ورودی‌های مانیفست جدیدی را که توسط ماژول معرفی شده است اعمال کند.
  • پلاتفرم نمی‌تواند به منابع ماژول برای مؤلفه‌های واسط کاربر سیستم، مثل اعلان‌ها، دسترسی پیدا کند. اگر لازم است فوراً از چنین منابعی استفاده کنید، آن منابع را در واحد پایه برنامه‌تان قرار دهید.

فعال کردن SplitCompat

برای اینکه برنامه‌تان بتواند به کد و منابع از ماژول بارگیری‌شده دسترسی پیدا کند، باید SplitCompat را فقط بااستفاده از یکی از روش‌های شرح‌داده‌شده در بخش‌های زیر فعال کنید.

پس‌از فعال کردن SplitCompat برای برنامه‌تان، باید SplitCompat را برای هر فعالیت در واحد ویژگی که می‌خواهید برنامه‌تان به آن دسترسی داشته باشد نیز فعال کنید.

اعلام SplitCompatApplication در مانیفست

ساده‌ترین روش برای فعال کردن SplitCompat این است که SplitCompatApplication را به‌عنوان زیرکلاس Application در مانیفست برنامه‌تان اعلام کنید، همان‌طور که در زیر نشان داده شده است:

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

پس‌از نصب برنامه در دستگاه، می‌توانید به‌طور خودکار به کد و منابع واحدهای ویژگی بارگیری‌شده دسترسی پیدا کنید.

فراخوانی SplitCompat در زمان اجرا

همچنین می‌توانید SplitCompat را در فعالیت‌ها یا سرویس‌های خاص در زمان اجرا فعال کنید. فعال کردن SplitCompat از این طریق برای راه‌اندازی فعالیت‌های موجود در واحدهای ویژگی لازم است. برای انجام این کار، attachBaseContext را همان‌طور که در زیر نشان داده شده است لغو کنید.

اگر کلاس برنامه سفارشی دارید، آن را به‌جای SplitCompatApplication گسترش دهید تا SplitCompat برای برنامه‌تان فعال شود، همان‌طور که در زیر نشان داده شده است:

کاتلین

class MyApplication : SplitCompatApplication() {
    ...
}

جاوا

public class MyApplication extends SplitCompatApplication {
    ...
}

SplitCompatApplication به‌سادگی ContextWrapper.attachBaseContext() را لغو می‌کند تا SplitCompat.install(Context applicationContext) را لحاظ کند. اگر نمی‌خواهید کلاس Application شما SplitCompatApplication را گسترش دهد، می‌توانید به‌صورت دستی روش attachBaseContext() را به‌صورت زیر لغو کنید:

کاتلین

override fun attachBaseContext(base: Context) {
    super.attachBaseContext(base)
    // Emulates installation of future on demand modules using SplitCompat.
    SplitCompat.install(this)
}

جاوا

@Override
protected void attachBaseContext(Context base) {
    super.attachBaseContext(base);
    // Emulates installation of future on demand modules using SplitCompat.
    SplitCompat.install(this);
}

اگر واحد درخواستی شما با برنامه‌های فوری و برنامه‌های نصب‌شده سازگار است، می‌توانید SplitCompat را به‌صورت شرطی به‌شرح زیر فراخوانی کنید:

کاتلین

override fun attachBaseContext(base: Context) {
    super.attachBaseContext(base)
    if (!InstantApps.isInstantApp(this)) {
        SplitCompat.install(this)
    }
}

جاوا

@Override
protected void attachBaseContext(Context base) {
    super.attachBaseContext(base);
    if (!InstantApps.isInstantApp(this)) {
        SplitCompat.install(this);
    }
}

فعال کردن SplitCompat برای فعالیت‌های واحد

پس‌از فعال کردن SplitCompat برای برنامه پایه‌تان، باید SplitCompat را برای هر فعالیتی که برنامه‌تان در واحد ویژگی بارگیری می‌کند فعال کنید. برای انجام این کار، از روش SplitCompat.installActivity() به‌صورت زیر استفاده کنید:

کاتلین

override fun attachBaseContext(base: Context) {
    super.attachBaseContext(base)
    // Emulates installation of on demand modules using SplitCompat.
    SplitCompat.installActivity(this)
}

جاوا

@Override
protected void attachBaseContext(Context base) {
    super.attachBaseContext(base);
    // Emulates installation of on demand modules using SplitCompat.
    SplitCompat.installActivity(this);
}

دسترسی به مؤلفه‌های تعریف‌شده در واحدهای ویژگی

شروع فعالیتی که در واحد ویژگی تعریف شده است

می‌توانید فعالیت‌های تعریف‌شده در واحدهای ویژگی را بااستفاده از startActivity() پس‌از فعال کردن SplitCompat راه‌اندازی کنید.

کاتلین

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

جاوا

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

پارامتر اول برای setClassName نام بسته برنامه است و پارامتر دوم نام کلاس کامل فعالیت است.

وقتی فعالیتی در واحد ویژگی‌ای دارید که به‌صورت درخواستی بارگیری کرده‌اید، باید SplitCompat را در فعالیت فعال کنید.

شروع سرویس تعریف‌شده در واحد ویژگی

می‌توانید سرویس‌های تعریف‌شده در واحدهای ویژگی را بااستفاده از startService() پس‌از فعال کردن SplitCompat راه‌اندازی کنید.

کاتلین

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

جاوا

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

صادر کردن مؤلفه تعریف‌شده در واحد ویژگی

نباید مؤلفه‌های صادرشده Android را در داخل ماژول‌های اختیاری قرار دهید.

سیستم ساخت ورودی‌های مانیفست را برای همه واحدها در واحد پایه ادغام می‌کند؛ اگر واحدی اختیاری حاوی مؤلفه صادرشده‌ای باشد، حتی قبل‌از نصب واحد دردسترس خواهد بود و می‌تواند هنگام فراخوانی از برنامه‌ای دیگر به‌دلیل نبود کد باعث ازکارافتادن شود.

این موضوع برای مؤلفه‌های داخلی مشکلی ایجاد نمی‌کند؛ فقط برنامه به آن‌ها دسترسی دارد، بنابراین برنامه می‌تواند قبل‌از دسترسی به مؤلفه، بررسی کند که ماژول نصب شده است یا نه.

اگر به مؤلفه صادرشده نیاز دارید و می‌خواهید محتوای آن در یک ماژول اختیاری باشد، پیاده‌سازی الگوی پراکسی را درنظر بگیرید. می‌توانید این کار را با افزودن مؤلفه صادرشده پراکسی در پایه انجام دهید؛ هنگام دسترسی، مؤلفه پراکسی می‌تواند وجود ماژول حاوی محتوا را بررسی کند. اگر ماژول وجود داشته باشد، مؤلفه پراکسی می‌تواند مؤلفه داخلی را ازطریق Intent از ماژول شروع کند و هدف را از برنامه تماس‌گیرنده رله کند. اگر ماژول وجود نداشته باشد، مؤلفه می‌تواند ماژول را بارگیری کند یا پیام خطای مناسبی به برنامه تماس‌گیرنده برگرداند.

دسترسی به کد و منابع از پودمان‌های نصب‌شده

اگر SplitCompat را برای بافت برنامه پایه و فعالیت‌های موجود در واحد ویژگی‌تان فعال کنید، می‌توانید از کد و منابع واحد ویژگی استفاده کنید، گویی که بخشی از APK پایه است، پس‌از اینکه واحد اختیاری نصب شد.

دسترسی به کد از واحدی دیگر

دسترسی به کد پایه از واحد

کدی که داخل واحد پایه شما است می‌تواند مستقیماً توسط واحدهای دیگر استفاده شود. لازم نیست کار خاصی انجام دهید؛ فقط کلاس‌های موردنیازتان را وارد و استفاده کنید.

دسترسی به کد واحد از واحدی دیگر

یک شیء یا کلاس درون یک ماژول نمی‌تواند به‌طور ایستا از ماژول دیگری به‌طور مستقیم دسترسی داشته باشد، اما می‌تواند به‌طور غیرمستقیم بااستفاده از بازتاب دسترسی داشته باشد.

باید مراقب باشید که این اتفاق چندوقت یک‌بار رخ می‌دهد، زیرا بازتابش هزینه عملکردی دارد. برای موارد استفاده پیچیده، از چارچوب‌های تزریق وابستگی مانند Dagger 2 استفاده کنید تا یک فراخوانی بازتابی واحد در هر طول عمر برنامه تضمین شود.

برای ساده کردن تعاملات با شیء پس‌از نمونه‌سازی، توصیه می‌شود میانایی در واحد پایه و پیاده‌سازی آن در واحد ویژگی تعریف شود. برای نمونه:

کاتلین

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

جاوا

// 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 مشکلی را در بار کردن کتابخانه‌های بومی پس‌از نصب واحد ویژگی برطرف می‌کند. در نکات JNI Android می‌توانید اطلاعات بیشتری درباره ReLinker کسب کنید.

بار کردن کد بومی از واحد اختیاری

پس‌از نصب تقسیم، توصیه می‌کنیم کد بومی آن را ازطریق ReLinker بار کنید. برای برنامه‌های فوری باید از این روش ویژه استفاده کنید.

اگر از System.loadLibrary() برای بار کردن کد بومی‌تان استفاده می‌کنید و کتابخانه بومی‌تان به کتابخانه دیگری در ماژول وابسته است، باید ابتدا آن کتابخانه دیگر را به‌صورت دستی بار کنید. اگر از ReLinker استفاده می‌کنید، عملیات معادل آن Relinker.recursively().loadLibrary() است.

اگر از dlopen() در کد بومی برای بار کردن کتابخانه تعریف‌شده در مدول اختیاری استفاده می‌کنید، این کد با مسیرهای کتابخانه نسبی کار نخواهد کرد. بهترین راه‌حل این است که مسیر مطلق کتابخانه را از کد Java ازطریق ClassLoader.findLibrary() بازیابی کنید و سپس از آن در تماس dlopen() استفاده کنید. این کار را قبل‌از وارد کردن کد بومی انجام دهید یا از تماس JNI از کد بومی‌تان به Java استفاده کنید.

دسترسی به «برنامه‌های فوری Android» نصب‌شده

پس‌از اینکه یک ماژول «برنامه فوری Android» به‌عنوان INSTALLED گزارش شد، می‌توانید بااستفاده از زمینه برنامه بازآوری‌شده به کد و منابع آن دسترسی پیدا کنید. بافتی که برنامه‌تان قبل‌از نصب کردن ماژول ایجاد می‌کند (برای مثال، بافتی که قبلاً در متغیری ذخیره شده است) حاوی محتوای ماژول جدید نیست. اما زمینه جدید این کار را می‌کند—این را می‌توان، برای مثال، بااستفاده از createPackageContext به‌دست آورد.

کاتلین

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

جاوا

// 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 در Android نسخه ۸.۰ و بالاتر

هنگام درخواست یک ماژول درخواستی برای یک برنامه فوری Android در Android 8.0 (سطح API 26) و بالاتر، پس از اینکه یک درخواست نصب به عنوان INSTALLED گزارش شد، باید برنامه را با زمینه ماژول جدید ازطریق فراخوانی به SplitInstallHelper.updateAppInfo(Context context) به‌روز کنید. درغیراین‌صورت، برنامه هنوز از کد و منابع واحد مطلع نیست. پس‌از به‌روزرسانی فراداده برنامه، باید محتوای ماژول را درطول رویداد رشته اصلی بعدی با فراخوانی Handler جدید بار کنید، همان‌طور که در زیر نشان داده شده است:

کاتلین

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

جاوا

@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++‎ را از ماژولی که دستگاه قبلاً در «برنامه فوری» بارگیری کرده است بار کنید، از SplitInstallHelper.loadLibrary(Context context, String libName) استفاده کنید، همان‌طور که در زیر نشان داده شده است:

کاتلین

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

جاوا

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 است.
  • نمی‌توانید اشیای Android ApplicationInfo، محتوای آن‌ها، یا اشیایی را که حاوی آن‌ها هستند در برنامه‌تان ذخیره کنید. همیشه باید این اشیا را درصورت نیاز از بافت برنامه واکشی کنید. ذخیره کردن این اشیاء در حافظه نهان می‌تواند باعث ازکار افتادن برنامه هنگام نصب واحد ویژگی شود.

مدیریت پیمانه‌های نصب‌شده

برای بررسی اینکه کدام پیمانه‌های ویژگی درحال‌حاضر در دستگاه نصب شده‌اند، می‌توانید SplitInstallManager.getInstalledModules() را فراخوانی کنید، که Set<String> نام پیمانه‌های نصب‌شده را برمی‌گرداند، همان‌طور که در زیر نشان داده شده است.

کاتلین

val installedModules: Set<String> = splitInstallManager.installedModules

جاوا

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

حذف نصب پیمانه‌ها

می‌توانید با فراخوانی SplitInstallManager.deferredUninstall(List<String> moduleNames)، همان‌طور که در زیر نشان داده شده است، از دستگاه بخواهید تا ماژول‌ها را حذف نصب کند.

کاتلین

// Specifies two feature modules for deferred uninstall.
splitInstallManager.deferredUninstall(listOf("pictureMessages", "promotionalFilters"))

جاوا

// Specifies two feature modules for deferred uninstall.
splitInstallManager.deferredUninstall(Arrays.asList("pictureMessages", "promotionalFilters"));

حذف نصب واحد بلافاصله انجام نمی‌شود. یعنی دستگاه درصورت نیاز آن‌ها را در پس‌زمینه حذف نصب می‌کند تا فضای ذخیره‌سازی را ذخیره کند. می‌توانید با فراخوانی SplitInstallManager.getInstalledModules() و بررسی نتیجه، همان‌طور که در بخش قبلی توضیح داده شد، تأیید کنید که دستگاه ماژول را حذف کرده است.

بارگیری منابع زبانی بیشتر

با دسته‌های برنامه، دستگاه‌ها فقط کد و منابعی را بارگیری می‌کنند که برای اجرای برنامه‌تان نیاز دارند. بنابراین، برای منابع زبان، دستگاه کاربر فقط منابع زبان برنامه‌تان را بارگیری می‌کند که با یک یا چند زبانی که درحال‌حاضر در تنظیمات دستگاه انتخاب شده است مطابقت داشته باشد.

اگر می‌خواهید برنامه‌تان به منابع زبانی بیشتری دسترسی داشته باشد—برای مثال، برای پیاده‌سازی انتخابگر زبان درون‌برنامه، می‌توانید از «کتابخانه Play Feature Delivery» برای بارگیری آن‌ها درصورت درخواست استفاده کنید. این فرایند مشابه فرایند بارگیری واحد ویژگی است، همان‌طور که در زیر نشان داده شده است.

کاتلین

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

جاوا

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

درخواست به‌گونه‌ای رسیدگی می‌شود که گویی درخواستی برای واحد ویژگی است. یعنی می‌توانید وضعیت درخواست را مثل همیشه پایش کنید.

اگر برنامه‌تان فوراً به منابع زبان اضافی نیاز ندارد، می‌توانید نصب را به زمانی که برنامه در پس‌زمینه است موکول کنید، همان‌طور که در زیر نشان داده شده است.

کاتلین

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

جاوا

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

دسترسی به منابع زبانی بارگیری‌شده

برای دسترسی به منابع زبانی بارگیری‌شده، برنامه‌تان باید روش SplitCompat.installActivity() را در روش attachBaseContext() هر فعالیتی که به دسترسی به آن منابع نیاز دارد اجرا کند، همان‌طور که در زیر نشان داده شده است.

کاتلین

override fun attachBaseContext(base: Context) {
  super.attachBaseContext(base)
  SplitCompat.installActivity(this)
}

جاوا

@Override
protected void attachBaseContext(Context base) {
  super.attachBaseContext(base);
  SplitCompat.installActivity(this);
}

برای هر فعالیتی که می‌خواهید از منابع زبانی که برنامه‌تان بارگیری کرده است استفاده کنید، بافت پایه را به‌روز کنید و ازطریق Configuration آن، زبان جدیدی تنظیم کنید:

کاتلین

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

جاوا

@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() استفاده کنید.

کاتلین

when (state.status()) {
  SplitInstallSessionStatus.INSTALLED -> {
      // Recreates the activity to load resources for the new language
      // preference.
      activity.recreate()
  }
  ...
}

جاوا

switch (state.status()) {
  case SplitInstallSessionStatus.INSTALLED:
      // Recreates the activity to load resources for the new language
      // preference.
      activity.recreate();
  ...
}

حذف نصب منابع زبان اضافی

مشابه پیمانه‌های ویژگی، می‌توانید منابع اضافی را هروقت خواستید حذف نصب کنید. قبل‌از درخواست حذف نصب، شاید بخواهید ابتدا تعیین کنید کدام زبان‌ها درحال‌حاضر نصب شده‌اند. برای این کار، مراحل زیر را دنبال کنید.

کاتلین

val installedLanguages: Set<String> = splitInstallManager.installedLanguages

جاوا

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

سپس می‌توانید تصمیم بگیرید که کدام زبان‌ها را بااستفاده از روش deferredLanguageUninstall() حذف نصب کنید، همان‌طور که در زیر نشان داده شده است.

کاتلین

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

جاوا

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

نصب‌های واحد آزمایشی محلی

«کتابخانه ویژگی تحویل Play» به شما امکان می‌دهد توانایی برنامه‌تان را برای انجام کارهای زیر به‌صورت محلی و بدون اتصال به «فروشگاه Play» آزمایش کنید:

این صفحه توضیح می‌دهد که چگونه APKهای جداشده برنامه‌تان را در دستگاه آزمایشی‌تان مستقر کنید تا «ویژگی تحویل Play» به‌طور خودکار از آن APKها برای شبیه‌سازی درخواست، بارگیری، و نصب کردن پیمانه‌ها از «فروشگاه Play» استفاده کند.

اگرچه لازم نیست تغییری در منطق برنامه‌تان ایجاد کنید، باید الزامات زیر را برآورده کنید:

  • جدیدترین نسخه bundletool را بارگیری و نصب کنید. برای ساختن مجموعه جدیدی از APKهای نصب‌شدنی از دسته برنامه، به bundletool نیاز دارید.

ساختن مجموعه‌ای از APKها

اگر قبلاً این کار را نکرده‌اید، APK جداشده برنامه‌تان را به‌صورت زیر بسازید:

  1. بااستفاده از یکی از روش‌های زیر، دسته برنامه‌ای برای برنامه‌تان بسازید:
  2. از bundletool برای تولید مجموعه‌ای از فایل‌های APK برای همه پیکربندی‌های دستگاه با فرمان زیر استفاده کنید:

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

پرچم --local-testing شامل فراداده‌ای در مانیفست‌های APK شما است که به «کتابخانه تحویل ویژگی Play» اطلاع می‌دهد که از APKهای جداشده محلی برای آزمایش نصب واحدهای ویژگی، بدون اتصال به «فروشگاه Play»، استفاده کند.

برنامه را در دستگاه مستقر کنید

پس‌از اینکه بااستفاده از پرچم --local-testing مجموعه‌ای از APKها را ساختید، از bundletool برای نصب نسخه پایه برنامه‌تان و انتقال APKهای اضافی به فضای ذخیره‌سازی محلی دستگاهتان استفاده کنید. می‌توانید هر دو کنش را با فرمان زیر انجام دهید:

bundletool install-apks --apks my_app.apks

اکنون، وقتی برنامه‌تان را شروع می‌کنید و جریان کاربر را برای بارگیری و نصب واحد ویژگی تکمیل می‌کنید، «کتابخانه تحویل ویژگی Play» از فایل‌های APK که bundletool به فضای ذخیره‌سازی محلی دستگاه منتقل کرده است استفاده می‌کند.

شبیه‌سازی خطای شبکه

برای شبیه‌سازی نصب‌های واحد از «فروشگاه Play»، «کتابخانه ویژگی تحویل Play» از جایگزینی برای SplitInstallManager، به‌نام FakeSplitInstallManager، برای درخواست واحد استفاده می‌کند. وقتی از bundletool با پرچم --local-testing برای ساختن مجموعه‌ای از APK-ها و استقرار آن‌ها در دستگاه آزمایشی‌تان استفاده می‌کنید، این ابزار شامل فراداده‌ای است که به «کتابخانه Play Feature Delivery» دستور می‌دهد تا به‌طور خودکار فراخوانی‌های میانای برنامه‌سازی کاربردی برنامه‌تان را برای فراخوانی FakeSplitInstallManager به‌جای SplitInstallManager تغییر دهد.

FakeSplitInstallManager شامل پرچم بولی است که می‌توانید آن را فعال کنید تا دفعه بعد که برنامه‌تان درخواست نصب ماژول می‌کند، خطای شبکه را شبیه‌سازی کنید. برای دسترسی به FakeSplitInstallManager در آزمایش‌هایتان، می‌توانید نمونه‌ای از آن را بااستفاده از FakeSplitInstallManagerFactory دریافت کنید، همان‌طور که در زیر نشان داده شده است:

کاتلین

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

جاوا

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