ربط Gradle بمكتبتك الأصلية

لتضمين مشروع المكتبة الأصلية كتبعية لإنشاء Gradle، ستحتاج إلى تزويد Gradle بالمسار إلى ملف النص البرمجي CMake أو ndk-build. عند إنشاء تطبيقك، تشغّل Gradle أداة CMake أو ndk-build، وتنشئ حِزمًا للمكتبات المشتركة مع تطبيقك. وتستخدم Gradle أيضًا النص البرمجي للإصدار لمعرفة الملفات التي سيتم نقلها إلى مشروع استوديو Android، كي تتمكّن من الوصول إليها من نافذة المشروع. إذا لم يكن لديك نص إصدار للمصادر المدمجة مع المحتوى، يجب إنشاء نص برمجي لإنشاء CMake قبل المتابعة.

يمكن ربط كل وحدة في مشروع Android بملف نص برمجي واحد فقط CMake أو ndk-build. على سبيل المثال، إذا كنت تريد إنشاء مخرجات وتجميعها من مشاريع CMake المتعددة، عليك استخدام ملف CMakeLists.txt واحد كنص برمجي للإصدار CMake عالي المستوى (الذي تربط به بعد ذلك Gradle) و إضافة مشاريع CMake الأخرى كتبعيات لنص الإصدار هذا. وبالمثل، إذا كنت تستخدم ndk-build، يمكنك تضمين ملفات Makefiles أخرى في ملف النص البرمجي Android.mk ذي المستوى الأعلى.

بعد ربط Gradle بمشروع أصلي، يعدّل "استوديو Android" لوحة المشروع لعرض ملفات المصدر والمكتبات الأصلية في مجموعة cpp والنصوص البرمجية للإصدارات الخارجية في مجموعة ملفات الإصدارات الخارجية.

ملاحظة: عند إجراء تغييرات على إعدادات Gradle، احرِص على تطبيق التغييرات من خلال النقر على مزامنة المشروع في شريط الأدوات. بالإضافة إلى ذلك، عند إجراء تغييرات على ملف النص البرمجي CMake أو ndk-build بعد ربطه مسبقًا بتطبيق Gradle، عليك مزامنة Android Studio مع التغييرات التي أجريتها من خلال اختيار إنشاء > إعادة تحميل مشاريع C++ المرتبطة من شريط القوائم.

يمكنك ربط Gradle بمشروع CMake أو ndk-build خارجي باستخدام واجهة مستخدم "استوديو Android":

  1. افتح لوحة المشروع من الجانب الأيمن من بيئة التطوير المتكاملة (IDE) واختَر عرض Android.
  2. انقر بزر الماوس الأيمن على الوحدة التي تريد ربطها بمكتبتك الأصلية، مثل وحدة التطبيق، واختَر ربط مشروع C++ بـ Gradle من القائمة. من المفترض أن يظهر مربّع حوار مشابه للمربّع الذي يظهر في الشكل 4.
  3. من القائمة المنسدلة، اختَر إما CMake أو ndk-build.
    1. إذا اخترت CMake (أو CMake)، استخدم الحقل بجانب Project Path (مسار المشروع) لتحديد ملف النص البرمجي CMakeLists.txt لمشروع CMake الخارجي.
    2. إذا اخترت ndk-build، استخدِم الحقل بجانب مسار المشروع لتحديد ملف النص البرمجي Android.mk لمشروع إصدار ndk الخارجي. يتضمّن "استوديو Android" أيضًا ملف Application.mk إذا كان في الدليل نفسه الذي يتضمّن ملف Android.mk.

    الشكل 4. ربط مشروع خارجي بلغة C++ باستخدام مربّع حوار "استوديو Android".

  4. انقر على حسنًا.

إعداد Gradle يدويًا

لإعداد تطبيق Gradle يدويًا للربط بمكتبتك الأصلية، عليك إضافة مجموعة externalNativeBuild إلى ملف build.gradle على مستوى الوحدة وضبطه باستخدام مجموعة cmake أو ndkBuild:

رائع

android {
  ...
  defaultConfig {...}
  buildTypes {...}

  // Encapsulates your external native build configurations.
  externalNativeBuild {

    // Encapsulates your CMake build configurations.
    cmake {

      // Provides a relative path to your CMake build script.
      path "CMakeLists.txt"
    }
  }
}

Kotlin

android {
  ...
  defaultConfig {...}
  buildTypes {...}

  // Encapsulates your external native build configurations.
  externalNativeBuild {

    // Encapsulates your CMake build configurations.
    cmake {

      // Provides a relative path to your CMake build script.
      path = file("CMakeLists.txt")
    }
  }
}

ملاحظة: إذا كنت تريد ربط Gradle بمشروع ndk-build حالي، استخدِم المجموعة ndkBuild بدلاً من المجموعة cmake، وقدِّم مسارًا نسبيًا لملف Android.mk. وتتضمّن أداة Gradle أيضًا ملف Application.mk إذا كان في الدليل نفسه الذي يتضمّن ملف Android.mk.

تحديد عمليات الضبط الاختيارية

يمكنك تحديد وسيطات وعلامات اختيارية لـ CMake أو ndk-build من خلال ضبط وحدة externalNativeBuild أخرى داخل مجموعة defaultConfig من ملف build.gradle على مستوى الوحدة. كما هي الحال مع السمات الأخرى في مجموعة defaultConfig، يمكنك إلغاء هذه السمات لكلّ صيغة منتج في إعدادات تصميمك.

على سبيل المثال، إذا كان مشروع CMake أو ndk-build يحدد عدة مكتبات أصلية وملفات تنفيذية، يمكنك استخدام السمة targets لإنشاء وتجميع مجموعة فرعية فقط من هذه العناصر لصيغة منتج معيّنة. ويوضّح نموذج الرمز التالي بعض السمات التي يمكنك ضبطها:

رائع

android {
  ...
  defaultConfig {
    ...
    // This block is different from the one you use to link Gradle
    // to your CMake or ndk-build script.
    externalNativeBuild {

      // For ndk-build, instead use the ndkBuild block.
      cmake {

        // Passes optional arguments to CMake.
        arguments "-DANDROID_ARM_NEON=TRUE", "-DANDROID_TOOLCHAIN=clang"

        // Sets a flag to enable format macro constants for the C compiler.
        cFlags "-D__STDC_FORMAT_MACROS"

        // Sets optional flags for the C++ compiler.
        cppFlags "-fexceptions", "-frtti"
      }
    }
  }

  buildTypes {...}

  productFlavors {
    ...
    demo {
      ...
      externalNativeBuild {
        cmake {
          ...
          // Specifies which native libraries or executables to build and package
          // for this product flavor. The following tells Gradle to build only the
          // "native-lib-demo" and "my-executible-demo" outputs from the linked
          // CMake project. If you don't configure this property, Gradle builds all
          // executables and shared object libraries that you define in your CMake
          // (or ndk-build) project. However, by default, Gradle packages only the
          // shared libraries in your app.
          targets "native-lib-demo",
                  // You need to specify this executable and its sources in your CMakeLists.txt
                  // using the add_executable() command. However, building executables from your
                  // native sources is optional, and building native libraries to package into
                  // your app satisfies most project requirements.
                  "my-executible-demo"
        }
      }
    }

    paid {
      ...
      externalNativeBuild {
        cmake {
          ...
          targets "native-lib-paid",
                  "my-executible-paid"
        }
      }
    }
  }

  // Use this block to link Gradle to your CMake or ndk-build script.
  externalNativeBuild {
    cmake {...}
    // or ndkBuild {...}
  }
}

Kotlin

android {
  ...
  defaultConfig {
    ...
    // This block is different from the one you use to link Gradle
    // to your CMake or ndk-build script.
    externalNativeBuild {

      // For ndk-build, instead use the ndkBuild block.
      cmake {

        // Passes optional arguments to CMake.
        arguments += listOf("-DANDROID_ARM_NEON=TRUE", "-DANDROID_TOOLCHAIN=clang")

        // Sets a flag to enable format macro constants for the C compiler.
        cFlags += listOf("-D__STDC_FORMAT_MACROS")

        // Sets optional flags for the C++ compiler.
        cppFlags += listOf("-fexceptions", "-frtti")
      }
    }
  }

  buildTypes {...}

  productFlavors {
    ...
    create("demo") {
      ...
      externalNativeBuild {
        cmake {
          ...
          // Specifies which native libraries or executables to build and package
          // for this product flavor. The following tells Gradle to build only the
          // "native-lib-demo" and "my-executible-demo" outputs from the linked
          // CMake project. If you don't configure this property, Gradle builds all
          // executables and shared object libraries that you define in your CMake
          // (or ndk-build) project. However, by default, Gradle packages only the
          // shared libraries in your app.
          targets += listOf("native-lib-demo",
                  // You need to specify this executable and its sources in your CMakeLists.txt
                  // using the add_executable() command. However, building executables from your
                  // native sources is optional, and building native libraries to package into
                  // your app satisfies most project requirements.
                  "my-executible-demo")
        }
      }
    }

    create("paid") {
      ...
      externalNativeBuild {
        cmake {
          ...
          targets += listOf("native-lib-paid",
                  "my-executible-paid")
        }
      }
    }
  }

  // Use this block to link Gradle to your CMake or ndk-build script.
  externalNativeBuild {
    cmake {...}
    // or ndkBuild {...}
  }
}

للاطّلاع على مزيد من المعلومات حول ضبط نكهات المنتجات وخيارات التصميم، انتقِل إلى ضبط خيارات الإصدار. للحصول على قائمة بالمتغيّرات التي يمكنك ضبطها لإنشاء CMake باستخدام السمة arguments، راجِع المقالة استخدام متغيرات CMake.

تضمين المكتبات الأصلية المُنشأة مسبقًا

إذا كنت تريد من Gradle أن تجمع مكتبات أصلية مسبقة الإنشاء وغير مستخدَمة في أي إصدار خارجي، يمكنك إضافتها إلى دليل src/main/jniLibs/ABI في وحدتك.

يلزم توفير إصدارات من مكوّن Android Gradle الإضافي قبل الإصدار 4.0، بما في ذلك أهداف IMPORTED في دليل jniLibs لتضمينها في تطبيقك. في حال نقل البيانات من إصدار سابق من المكوّن الإضافي، قد يواجهك خطأ، مثل الخطأ التالي:

* What went wrong:
Execution failed for task ':app:mergeDebugNativeLibs'.
> A failure occurred while executing com.android.build.gradle.internal.tasks.Workers$ActionFacade
   > More than one file was found with OS independent path 'lib/x86/libprebuilt.so'

إذا كنت تستخدم الإصدار 4.0 من Android Gradle Plugin.0، عليك نقل أيّ مكتبات يستخدمها IMPORTED CMake الأهداف خارج دليل jniLibs لتجنُّب هذا الخطأ.

تحديد واجهات ABI

بشكل تلقائي، ينشئ Gradle مكتبتك الأصلية في ملفات .so منفصلة للواجهات الثنائية للتطبيقات (ABIs) التي يتيحها NDK ويدمجها كلّها في تطبيقك. وإذا كنت تريد من أداة Gradle إنشاء وتجميع بعض إعدادات واجهة التطبيق الثنائية (ABI) فقط لمكتباتك الأصلية، يمكنك تحديدها باستخدام العلامة ndk.abiFilters في ملف build.gradle على مستوى الوحدة، كما هو موضّح أدناه:

رائع

android {
  ...
  defaultConfig {
    ...
    externalNativeBuild {
      cmake {...}
      // or ndkBuild {...}
    }

    // Similar to other properties in the defaultConfig block,
    // you can configure the ndk block for each product flavor
    // in your build configuration.
    ndk {
      // Specifies the ABI configurations of your native
      // libraries Gradle should build and package with your app.
      abiFilters 'x86', 'x86_64', 'armeabi', 'armeabi-v7a',
                   'arm64-v8a'
    }
  }
  buildTypes {...}
  externalNativeBuild {...}
}

Kotlin

android {
  ...
  defaultConfig {
    ...
    externalNativeBuild {
      cmake {...}
      // or ndkBuild {...}
    }

    // Similar to other properties in the defaultConfig block,
    // you can configure the ndk block for each product flavor
    // in your build configuration.
    ndk {
      // Specifies the ABI configurations of your native
      // libraries Gradle should build and package with your app.
      abiFilters += listOf("x86", "x86_64", "armeabi", "armeabi-v7a",
                   "arm64-v8a")
    }
  }
  buildTypes {...}
  externalNativeBuild {...}
}

وفي معظم الحالات، ما عليك سوى تحديد abiFilters في مجموعة ndk، على النحو الموضّح أعلاه، لأنّ ذلك يطلب من Gradle إنشاء وتجميع تلك النُسخ من مكتباتك الأصلية. مع ذلك، إذا كنت تريد التحكّم في المحتوى الذي يجب أن تنشئه أداة Gradle، بغض النظر عمّا تريد أن تضيفه إلى الحزمة في تطبيقك، يمكنك ضبط علامة abiFilters أخرى في مجموعة defaultConfig.externalNativeBuild.cmake (أو مجموعة defaultConfig.externalNativeBuild.ndkBuild). تنشئ أداة Gradle إعدادات واجهة التطبيق الثنائية (ABI) هذه، ولكنّها لا تقدّم سوى الإعدادات التي تحدّدها في مجموعة defaultConfig.ndk.

ننصح بالنشر باستخدام تنسيق "مجموعة حزمات تطبيق Android" لتقليل حجم تطبيقك بشكل أكبر، لأنّه لن يتم تلقّي سوى المكتبات الأصلية التي تطابق واجهة التطبيق الثنائية (ABI) لجهاز المستخدم مع عملية التنزيل.

بالنسبة إلى التطبيقات القديمة التي تنشر باستخدام حِزم APK (تم إنشاؤها قبل آب (أغسطس) 2021)، ننصحك بضبط عدة حِزم APK استنادًا إلى واجهة التطبيق الثنائية (ABI). وبدلاً من إنشاء حزمة APK كبيرة واحدة باستخدام جميع إصدارات مكتباتك الأصلية، تنشئ منصة Gradle حزمة APK منفصلة لكل واجهة تطبيق ABI تريد دعمها، ولا توفِّر سوى الملفات التي تحتاج إليها كل واجهة التطبيق الثنائية (ABI). في حال ضبط عدة حِزم APK لكل واجهة ABI بدون تحديد العلامة abiFilters كما هو موضّح في نموذج الرمز أعلاه، تنشئ أداة Gradle جميع إصدارات واجهة التطبيق الثنائية (ABI) المتوافقة مع مكتباتك الأصلية، ولكنها تنشئ فقط الحزم التي تحدِّدها في إعدادات حِزم APK المتعددة. لتجنُّب إنشاء إصدارات لا تريدها من مكتباتك الأصلية، يمكنك تقديم قائمة واجهات ABI نفسها لكل من العلامة abiFilters وإعدادات APK المتعددة لكل واجهة برمجة تطبيقات (ABI).