توفير التحديثات داخل التطبيق (الإصدار الأصلي)

يوضّح هذا الدليل كيفية دعم داخل التطبيق التحديثات في تطبيقك باستخدام رمز برمجي أصلي (C أو C++). تتوفّر أدلة منفصلة للحالات التي يتم فيها استخدام عملية التنفيذ. لغة البرمجة Kotlin أو برمجة Java واللغة، والحالات التي عملية التنفيذ باستخدام Unity.

نظرة عامة على حزمة تطوير البرامج (SDK) الأصلية

حزمة تطوير البرامج (SDK) الأصلية لمكتبة Play الأساسية هي جزء من Play Core مجموعة حزم تطوير البرامج (SDK). مؤسسة The Native تتضمن حزمة SDK ملف عنوان C، app_update.h، يلتف AppUpdateManager من مكتبة التحديث داخل التطبيق في Java Play. ويسمح ملف الرأس هذا لتطبيقك يمكنك استدعاء واجهة برمجة التطبيقات للحصول على التحديثات داخل التطبيق مباشرةً من الرمز الأصلي.

إعداد بيئة التطوير

تنزيل Play Core Native SDK

قبل التنزيل، يجب الموافقة على الأحكام والشروط التالية.

الأحكام والشروط

Last modified: September 24, 2020
  1. By using the Play Core Software Development Kit, you agree to these terms in addition to the Google APIs Terms of Service ("API ToS"). If these terms are ever in conflict, these terms will take precedence over the API ToS. Please read these terms and the API ToS carefully.
  2. For purposes of these terms, "APIs" means Google's APIs, other developer services, and associated software, including any Redistributable Code.
  3. “Redistributable Code” means Google-provided object code or header files that call the APIs.
  4. Subject to these terms and the terms of the API ToS, you may copy and distribute Redistributable Code solely for inclusion as part of your API Client. Google and its licensors own all right, title and interest, including any and all intellectual property and other proprietary rights, in and to Redistributable Code. You will not modify, translate, or create derivative works of Redistributable Code.
  5. Google may make changes to these terms at any time with notice and the opportunity to decline further use of the Play Core Software Development Kit. Google will post notice of modifications to the terms at https://developer.android.com/guide/playcore/license. Changes will not be retroactive.
تنزيل Play Core Native SDK

play-core-native-sdk-1.14.0.zip

  1. عليك القيام بأي مما يلي:

  2. تحضير "استوديو Android" للتطوير المحلّي من خلال استخدام SDK Manager لتثبيت أحدث إصدار CMake وAndroid Native Development Kit (NDK) لمزيد من المعلومات حول إنشاء مشاريع مدمجة مع المحتوى أو استيرادها، راجع بدء استخدام NDK.

  3. يمكنك تنزيل ملف ZIP واستخراجه بجانب مشروعك.

    رابط التنزيل حجم الملف المجموع الاختباري لخوارزمية SHA-256
    36 ميبيبايت 782a8522d937848c83a715c9a258b95a3ff2879a7cd71855d137b41c00786a5e
  4. عدِّل ملف build.gradle الخاص بتطبيقك على النحو الموضّح أدناه:

    Groovy

        // App build.gradle
    
        plugins {
          id 'com.android.application'
        }
    
        // Define a path to the extracted Play Core SDK files.
        // If using a relative path, wrap it with file() since CMake requires absolute paths.
        def playcoreDir = file('../path/to/playcore-native-sdk')
    
        android {
            defaultConfig {
                ...
                externalNativeBuild {
                    cmake {
                        // Define the PLAYCORE_LOCATION directive.
                        arguments "-DANDROID_STL=c++_static",
                                  "-DPLAYCORE_LOCATION=$playcoreDir"
                    }
                }
                ndk {
                    // Skip deprecated ABIs. Only required when using NDK 16 or earlier.
                    abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
                }
            }
            buildTypes {
                release {
                    // Include Play Core Library proguard config files to strip unused code while retaining the Java symbols needed for JNI.
                    proguardFile '$playcoreDir/proguard/common.pgcfg'
                    proguardFile '$playcoreDir/proguard/gms_task.pgcfg'
                    proguardFile '$playcoreDir/proguard/per-feature-proguard-files'
                    ...
                }
                debug {
                    ...
                }
            }
            externalNativeBuild {
                cmake {
                    path 'src/main/CMakeLists.txt'
                }
            }
        }
    
        dependencies {
            // Import these feature-specific AARs for each Google Play Core library.
            implementation 'com.google.android.play:app-update:2.1.0'
            implementation 'com.google.android.play:asset-delivery:2.2.2'
            implementation 'com.google.android.play:integrity:1.4.0'
            implementation 'com.google.android.play:review:2.0.1'
    
            // Import these common dependencies.
            implementation 'com.google.android.gms:play-services-tasks:18.0.2'
            implementation files("$playcoreDir/playcore-native-metadata.jar")
            ...
        }
        

    Kotlin

    // App build.gradle
    
    plugins {
        id("com.android.application")
    }
    
    // Define a path to the extracted Play Core SDK files.
    // If using a relative path, wrap it with file() since CMake requires absolute paths.
    val playcoreDir = file("../path/to/playcore-native-sdk")
    
    android {
        defaultConfig {
            ...
            externalNativeBuild {
                cmake {
                    // Define the PLAYCORE_LOCATION directive.
                    arguments += listOf("-DANDROID_STL=c++_static", "-DPLAYCORE_LOCATION=$playcoreDir")
                }
            }
            ndk {
                // Skip deprecated ABIs. Only required when using NDK 16 or earlier.
                abiFilters.clear()
                abiFilters += listOf("armeabi-v7a", "arm64-v8a", "x86", "x86_64")
            }
        }
        buildTypes {
            release {
                // Include Play Core Library proguard config files to strip unused code while retaining the Java symbols needed for JNI.
                proguardFile("$playcoreDir/proguard/common.pgcfg")
                proguardFile("$playcoreDir/proguard/gms_task.pgcfg")
                proguardFile("$playcoreDir/proguard/per-feature-proguard-files")
                ...
            }
            debug {
                ...
            }
        }
        externalNativeBuild {
            cmake {
                path = "src/main/CMakeLists.txt"
            }
        }
    }
    
    dependencies {
        // Import these feature-specific AARs for each Google Play Core library.
        implementation("com.google.android.play:app-update:2.1.0")
        implementation("com.google.android.play:asset-delivery:2.2.2")
        implementation("com.google.android.play:integrity:1.4.0")
        implementation("com.google.android.play:review:2.0.1")
    
        // Import these common dependencies.
        implementation("com.google.android.gms:play-services-tasks:18.0.2")
        implementation(files("$playcoreDir/playcore-native-metadata.jar"))
        ...
    }
    
  5. عدِّل ملفات CMakeLists.txt في تطبيقك على النحو الموضّح أدناه:

    cmake_minimum_required(VERSION 3.6)
    
    ...
    
    # Add a static library called “playcore” built with the c++_static STL.
    include(${PLAYCORE_LOCATION}/playcore.cmake)
    add_playcore_static_library()
    
    // In this example “main” is your native code library, i.e. libmain.so.
    add_library(main SHARED
            ...)
    
    target_include_directories(main PRIVATE
            ${PLAYCORE_LOCATION}/include
            ...)
    
    target_link_libraries(main
            android
            playcore
            ...)
    

جمع البيانات

قد تجمع حزمة تطوير البرامج (SDK) الأصلية لمكتبة Play الأساسية البيانات ذات الصلة بالإصدار للسماح لشركة Google تحسين المنتج، بما في ذلك:

  • اسم حزمة التطبيق
  • إصدار حزمة التطبيق
  • إصدار Play Core Native SDK

سيتم جمع هذه البيانات عند تحميل حزمة تطبيقك. Play Console. لإيقاف عملية جمع البيانات هذه، عليك إزالة عملية استيراد $playcoreDir/playcore-native-metadata.jar في ملف Build.gradle.

يُرجى العلم أنّ عملية جمع البيانات هذه المتعلّقة باستخدامك لحزمة تطوير البرامج (SDK) الأصلية لمكتبة Play الأساسية إنّ استخدام Google للبيانات التي يتم جمعها هو استخدام منفصل ومستقل عن مجموعة من تبعيات المكتبة المعرَّفة في Gradle عند تحميل تطبيقك حزمة إلى Play Console.

بعد دمج حزمة تطوير البرامج (SDK) الأصلية لمكتبة Play الأساسية في مشروعك، عليك تضمين السطر التالي في الملفات التي تحتوي على طلبات بيانات من واجهة برمجة التطبيقات:

#include "play/app_update.h"

إعداد واجهة برمجة تطبيقات التحديث داخل التطبيق

عندما تستخدم واجهة برمجة تطبيقات التحديث داخل التطبيق، يمكنك إعدادها أولاً من خلال طلب AppUpdateManager_init() كما هو موضح في المثال التالي التي تم إنشاؤها باستخدام android_native_app_glue.h:

void android_main(android_app* app) {
  app->onInputEvent = HandleInputEvent;

  AppUpdateErrorCode error_code =
    AppUpdateManager_init(app->activity->vm, app->activity->clazz);
  if (error_code == APP_UPDATE_NO_ERROR) {
    // You can use the API.
  }
}

التحقّق من توفّر تحديثات

قبل طلب إجراء تحديث، تحقَّق مما إذا كان هناك تحديث متوفّر التطبيق. AppUpdateManager_requestInfo() تبدأ طلبًا غير متزامن يجمع المعلومات المطلوبة لبدء التشغيل تدفق التحديث داخل التطبيق لاحقًا. تعرض الدالة APP_UPDATE_NO_ERROR إذا كانت بدء الطلب بنجاح.

AppUpdateErrorCode error_code = AppUpdateManager_requestInfo()

if (error_code == APP_UPDATE_NO_ERROR) {
    // The request has successfully started, check the result using
    // AppUpdateManager_getInfo.
}

يمكنك تتبُّع العملية الجارية ونتيجة الطلب باستخدام AppUpdateManager_getInfo() بالإضافة إلى رمز الخطأ، تُرجع هذه الدالة دالة AppUpdateInfo غامضة، والتي يمكنك استخدامها لاسترداد معلومات حول التحديث طلبك. على سبيل المثال، قد ترغب في استدعاء هذه الدالة في كل حلقة ألعاب حتى تعرض نتيجة غير فارغة لـ info:

AppUpdateInfo* info;
GameUpdate() {

   // Keep calling this in every game loop until info != nullptr
   AppUpdateErrorCode error_code = AppUpdateManager_getInfo(&info);


   if (error_code == APP_UPDATE_NO_ERROR && info != nullptr) {
       // Successfully started, check the result in the following functions
   }
...
}

التحقّق من مدى قِدم التحديث

بالإضافة إلى التحقق مما إذا كان هناك تحديث متوفر أم لا، قد تحتاج أيضًا إلى التحقّق من مقدار الوقت المنقضي منذ آخر إشعار للمستخدم بالتحديث من خلال "متجر Play". يمكن أن يساعدك هذا في تحديد ما إذا كان يجب عليك بدء أو تحديث مرن أو تحديث فوري. على سبيل المثال، قد تنتظر بضعة أيام قبل إبلاغ المستخدم بتحديث مرن، وبعد بضعة أيام قبل طلب التحديث الفوري.

استخدام AppUpdateInfo_getClientVersionStalenessDays() للتحقّق من عدد الأيام التي مرّت منذ أن أصبح التحديث متاحًا على Play المتجر:

int32_t staleness_days = AppUpdateInfo_getClientVersionStalenessDays(info);

التأكّد من أولوية التحديث

تتيح لك واجهة Google Play Developer API تحديد أولوية كل تحديث. ويسمح هذا الإجراء لتطبيقك بتحديد مدى اقتراح تحديث للمستخدم. على سبيل المثال، يمكنك اتّباع الاستراتيجية التالية لضبط أولوية التعديل:

  • تحسينات طفيفة في واجهة المستخدم: تحديث ذو أولوية منخفضة، لا تطلب نهجًا مرنًا أو تحديث فوري. التعديل فقط في حال عدم تفاعل المستخدم مع تطبيقك.
  • تحسينات الأداء: تحديث ذو أولوية متوسطة وطلب صورة تحديث.
  • تحديث أمان مهم: تحديث ذو أولوية عالية وطلب إجراء فوري تحديث.

لتحديد الأولوية، يستخدم Google Play قيمة عددية بين 0 و5 مع 0. ويمثل العدد الافتراضي و5 يمثل الأولوية القصوى. لتعيين أولوية تحديث، استخدم الحقل inAppUpdatePriority ضمن Edits.tracks.releases في Google Play Developer API. جميع الإصدارات التي تمت إضافتها مؤخرًا في الإصدار يحظى بالأولوية نفسها التي يحظى بها الإصدار. لا يمكن ضبط الأولوية إلا عندما طرح إصدار جديد ولا يمكن تغييره لاحقًا

تحديد الأولوية باستخدام واجهة Google Play Developer API، كما هو موضَّح في Play واجهة برمجة تطبيقات المطور ذات الصلة. حدِّد أولوية التحديث داخل التطبيق في Edit.tracks المورد الذي تم تمريره في Edit.tracks: update . يوضح المثال التالي إطلاق تطبيق برمز إصدار 88 وinAppUpdatePriority 5:

{
  "releases": [{
      "versionCodes": ["88"],
      "inAppUpdatePriority": 5,
      "status": "completed"
  }]
}

في رمز التطبيق، يمكنك التحقّق من مستوى الأولوية لتحديث معيّن باستخدام AppUpdateInfo_getPriority():

int32_t priority = AppUpdateInfo_getPriority(info);

بدء تحديث

بعد التأكّد من توفّر تحديث، يمكنك طلب التحديث باستخدام AppUpdateManager_requestStartUpdate() قبل طلب إجراء تعديل، عليك الحصول على أحدث عنصر من "AppUpdateInfo" إنشاء AppUpdateOptions لتهيئة تدفق التحديث. يعرّف كائن AppUpdateOptions الخيارات لتدفق التحديث داخل التطبيق، بما في ذلك ما إذا كان ينبغي مرن أو فوري.

ينشئ المثال التالي كائن AppUpdateOptions لإجراء تعديل مرن. التدفق:

// Creates an AppUpdateOptions configuring a flexible in-app update flow.
AppUpdateOptions* options;
AppUpdateErrorCode error_code = AppUpdateOptions_createOptions(APP_UPDATE_TYPE_FLEXIBLE, &options);

ينشئ المثال التالي كائن AppUpdateOptions لعملية شراء فورية تدفق التحديث:

// Creates an AppUpdateOptions configuring an immediate in-app update flow.
AppUpdateOptions* options;
AppUpdateErrorCode error_code = AppUpdateOptions_createOptions(APP_UPDATE_TYPE_IMMEDIATE, &options);

يحتوي الكائن AppUpdateOptions أيضًا على حقل AllowAssetPackDeletion. تحدِّد ما إذا كان التعديل مسموحًا له بمحو مادة العرض الحزم في حال انخفاض مساحة التخزين على الجهاز. هذا النمط على false تلقائيًا، ولكن يمكنك استخدام AppUpdateOptions_setAssetPackDeletionAllowed() لضبطها على true بدلاً من ذلك:

bool allow = true;
AppUpdateErrorCode error_code = AppUpdateOptions_setAssetPackDeletionAllowed(options, allow);

بعد توفُّر عنصر AppUpdateInfo حديث وضبطه بشكل صحيح عنصر AppUpdateOptions، عليك طلب AppUpdateManager_requestStartUpdate() من أجل طلب تدفق التحديث بشكل غير متزامن، مع تمرير نشاط Android jobject للمعلمة النهائية.

AppUpdateErrorCode request_error_code =
AppUpdateManager_requestStartUpdate(info, options, app->activity->clazz);

لإخلاء بعض الموارد، يمكنك إصدار مثيلات AppUpdateInfo و AppUpdateOptions الذي لم تعُد بحاجة إليه عن طريق الاتصال AppUpdateInfo_destroy() أو AppUpdateOptions_destroy()، على التوالي.

AppUpdateInfo_destroy(info);
AppUpdateOptions_destroy(options);

يعرض Google Play صفحة تأكيد المستخدم لإجراء عملية التحديث فورًا. عندما يقبل المستخدم الطلب، يتم تنزيل Google Play تلقائيًا يثبّت التحديث في المقدّمة، ثم يعيد تشغيل التطبيق إلى الإصدار المحدَّث الإصدار في حالة نجاح التثبيت.

لإجراء عملية تعديل مرنة، يمكنك الاستمرار في طلب أحدث إصدار من "AppUpdateInfo". لتتبع حالة التحديث الحالية بينما يواصل المستخدم التفاعل مع التطبيق. بعد انتهاء عملية التنزيل بنجاح، يجب تؤدي إلى إكمال التحديث من خلال استدعاء AppUpdateManager_requestCompleteUpdate(), كما هو موضح في المثال التالي:

AppUpdateStatus status = AppUpdateInfo_getStatus(info);
if (status == APP_UPDATE_DOWNLOADED) {
    AppUpdateErrorCode error_code = AppUpdateManager_requestCompleteUpdate();
    if (error_code != APP_UPDATE_NO_ERROR)
    {
      // There was an error while completing the update flow.
    }
}

يمكنك إخلاء الموارد من خلال طلب AppUpdateManager_destroy() بعد انتهاء تطبيقك من استخدام واجهة برمجة التطبيقات.

خطأ أثناء المعالجة

يصف هذا القسم حلول الأخطاء الشائعة المشار إليها من خلال AppUpdateErrorCode القيم التالية:

  • يشير رمز الخطأ -110, APP_UPDATE_INITIALIZATION_NEEDED إلى أنّ لم يتم إعداد واجهة برمجة التطبيقات بنجاح. الاتصال بـ AppUpdateManager_init() من أجل تهيئة واجهة برمجة التطبيقات.
  • يشير رمز الخطأ -4, APP_UPDATE_INVALID_REQUEST إلى أنّ بعض معلمات طلب مسار التحديث مكتوبة بشكل غير صحيح. يُرجى التحقّق من ذلك العنصران AppUpdateInfo وAppUpdateOptions غير فارغين بتنسيق صحيح.
  • يشير رمز الخطأ -5, APP_UPDATE_UNAVAILABLE إلى عدم وجود يتوفر تحديث قابل للتطبيق. تأكَّد من أنّ الإصدار المستهدَف يحتوي على الإصدار نفسه اسم الحزمة، رقم تعريف التطبيق ومفتاح التوقيع. إذا كان هناك تحديث متاح، يُرجى محو ذاكرة التخزين المؤقت للتطبيق والاتصال بـ AppUpdateManager_requestAppUpdateInfo() مرة أخرى إعادة تحميل AppUpdateInfo
  • يشير رمز الخطأ -6, APP_UPDATE_NOT_ALLOWED إلى نوع التحديث. غير مسموح بها التي يشير إليها كائن AppUpdateOption. تحقق مما إذا كانت يشير الكائن AppUpdateInfo إلى السماح بنوع التحديث قبل وبدء تدفق التحديث.

الخطوات التالية

اختبار تحديثات تطبيقك داخل التطبيق من أجل والتحقق من أن عملية الدمج تعمل بشكل صحيح.