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

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

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

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

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

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

یک ماژول جدید برای تحویل در صورت تقاضا پیکربندی کنید

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

برای افزودن یک ماژول ویژگی به پروژه برنامه خود با استفاده از Android Studio، به صورت زیر عمل کنید:

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

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

      <dist:module
          ...
          dist:title="@string/feature_title">
      </dist:module>
      
    2. در منوی کرکره‌ای زیر Install-time inclusion ، ماژول در زمان نصب شامل نشود را انتخاب کنید. Android Studio موارد زیر را در مانیفست ماژول تزریق می کند تا انتخاب شما را منعکس کند:

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

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

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

در مرحله بعد، باید قابلیت نصب بر اساس تقاضا را با استفاده از کتابخانه Play Feature Delivery پیاده سازی کنید.

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

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

ماژول درخواستی را درخواست کنید

هنگامی که برنامه شما نیاز به استفاده از یک ماژول ویژگی دارد، می‌تواند زمانی که در پیش‌زمینه است، از طریق کلاس 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 برای برنامه های فوری اندروید مورد نیاز نیست.

نصب ماژول های درخواستی را به تعویق بیندازید

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

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

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

برای اینکه بتوانید نوار پیشرفت را به‌روزرسانی کنید، پس از نصب یک intent اجرا کنید، یا به‌خوبی خطای درخواست را مدیریت کنید، باید به‌روزرسانی‌های وضعیت را از وظیفه 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 4.4 (سطح API 20) یا پایین‌تر، باید ماژول‌های ویژگی را در زمان نصب با استفاده از ویژگی dist:fusing manifest اضافه کنید. برای کسب اطلاعات بیشتر، درباره مانیفست ماژول ویژگی بخوانید.
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 Store روی دستگاه نصب نشده است. به کاربر اطلاع دهید که برای دانلود این ویژگی به برنامه Play Store نیاز است.
APP_NOT_OWNED این برنامه توسط گوگل پلی نصب نشده است و این ویژگی قابل دانلود نیست. این خطا فقط برای نصب های معوق رخ می دهد. اگر می‌خواهید کاربر برنامه را در 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 8.0 (سطح API 26) یا بالاتر اجرا می‌شود، باید از 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 داخلی، یک راه‌انداز نتیجه فعالیت ثبت کنید. APIهای نتیجه فعالیت را ببینید.

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

  • اگر کاربر تاییدیه را بپذیرد، وضعیت درخواست به 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 لغو کنید.

اگر یک کلاس Application سفارشی دارید، در عوض از آن بخواهید 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);
}
دسترسی به اجزای تعریف شده در ماژول های ویژگی یک فعالیت تعریف شده در یک ماژول ویژگی را شروع کنید

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

کاتلین
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(...));
یک جزء تعریف شده در یک ماژول ویژگی را صادر کنید

شما نباید اجزای اندروید صادر شده را در ماژول های اختیاری قرار دهید.

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

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

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

کد بومی را از یک ماژول اختیاری بارگیری کنید

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

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

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

به برنامه‌های Instant 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();
        }
    }
}
برنامه‌های فوری اندروید در اندروید ۸.۰ و بالاتر

هنگام درخواست ماژول درخواستی برای یک برنامه Instant Android در Android 8.0 (سطح API 26) و بالاتر، پس از گزارش درخواست نصب به‌عنوان INSTALLED ، باید از طریق تماس با SplitInstallHelper.updateAppInfo(Context context) ، برنامه را با زمینه ماژول جدید به‌روزرسانی کنید. 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++ را از ماژولی که دستگاه قبلاً در برنامه Instant دانلود کرده است بارگیری کنید، از 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 API سطح 28 و پایین تر است.
  • نمی‌توانید اشیاء 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 برای دانلود آن‌ها در صورت درخواست استفاده کنید. فرآیند مشابه دانلود یک ماژول ویژگی است، همانطور که در زیر نشان داده شده است.

کاتلین
// 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 اجازه می‌دهد بدون اتصال به فروشگاه Play، از APK‌های تقسیم‌شده محلی برای آزمایش نصب ماژول‌های ویژگی استفاده کند.

برنامه خود را روی دستگاه نصب کنید

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

bundletool install-apks --apks my_app.apks

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

یک خطای شبکه را شبیه سازی کنید

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

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