Gradle را به کتابخانه بومی خود پیوند دهید

برای گنجاندن پروژه کتابخانه بومی خود به عنوان وابستگی ساخت Gradle، باید مسیر فایل اسکریپت CMake یا ndk-build را به Gradle ارائه دهید. هنگامی که برنامه خود را می سازید، Gradle CMake یا ndk-build را اجرا می کند و کتابخانه های مشترک را با برنامه شما بسته بندی می کند. Gradle همچنین از اسکریپت ساخت استفاده می‌کند تا بداند کدام فایل‌ها را باید به پروژه Android Studio خود بکشد، بنابراین می‌توانید از پنجره Project به آنها دسترسی داشته باشید. اگر اسکریپت ساختی برای منابع بومی خود ندارید، قبل از ادامه باید یک اسکریپت ساخت CMake ایجاد کنید .

هر ماژول در پروژه اندروید شما می تواند تنها به یک فایل اسکریپت CMake یا ndk-build پیوند دهد. بنابراین، برای مثال، اگر می‌خواهید خروجی‌های چند پروژه CMake را بسازید و بسته‌بندی کنید، باید از یک فایل CMakeLists.txt به عنوان اسکریپت ساخت سطح بالای CMake خود استفاده کنید (که سپس Gradle را به آن پیوند می‌دهید) و پروژه‌های دیگر CMake را به عنوان وابستگی اضافه کنید. از آن اسکریپت ساخت. به طور مشابه، اگر از ndk-build استفاده می‌کنید، می‌توانید Makefiles دیگر را در فایل اسکریپت سطح بالای Android.mk خود قرار دهید.

هنگامی که Gradle را به یک پروژه بومی پیوند دادید، Android Studio پنجره پروژه را به‌روزرسانی می‌کند تا فایل‌های منبع و کتابخانه‌های بومی شما را در گروه cpp و اسکریپت‌های ساخت خارجی شما را در گروه فایل‌های ساخت خارجی نشان دهد.

توجه: هنگام ایجاد تغییرات در پیکربندی Gradle، مطمئن شوید که تغییرات خود را با کلیک روی همگام‌سازی پروژه اعمال کرده‌اید. در نوار ابزار علاوه بر این، هنگامی که فایل اسکریپت CMake یا ndk-build خود را پس از اینکه قبلاً به Gradle پیوند داده اید، تغییراتی ایجاد می کنید، باید Android Studio را با تغییرات خود با انتخاب Build > Refresh Linked C++ Projects از نوار منو، همگام سازی کنید.

می‌توانید Gradle را با استفاده از رابط کاربری Android Studio به یک پروژه CMake یا ndk-build خارجی پیوند دهید:

  1. پنجره Project را از سمت چپ IDE باز کنید و نمای Android را انتخاب کنید.
  2. روی ماژولی که می‌خواهید به کتابخانه بومی خود پیوند دهید، مانند ماژول برنامه ، راست کلیک کنید و از منو گزینه Link C++ Project with Gradle را انتخاب کنید. شما باید دیالوگی مشابه آنچه در شکل 4 نشان داده شده است ببینید.
  3. از منوی کشویی، CMake یا ndk-build را انتخاب کنید.
    1. اگر CMake را انتخاب کردید، از فیلد کنار Project Path برای تعیین فایل اسکریپت CMakeLists.txt برای پروژه CMake خارجی خود استفاده کنید.
    2. اگر ndk-build را انتخاب کنید، از فیلد کنار Project Path برای تعیین فایل اسکریپت Android.mk برای پروژه ndk-build خارجی خود استفاده کنید. اندروید استودیو اگر فایل Application.mk در همان دایرکتوری فایل Android.mk شما قرار داشته باشد نیز شامل می شود.

    شکل 4. پیوند دادن یک پروژه C++ خارجی با استفاده از گفتگوی Android Studio.

  4. روی OK کلیک کنید.

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

کاتلین

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 موجود پیوند دهید، به جای بلوک cmake از بلوک ndkBuild استفاده کنید و یک مسیر نسبی برای فایل Android.mk خود ارائه دهید. اگر فایل Application.mk در همان فهرستی که فایل Android.mk شما قرار دارد، Gradle نیز شامل می شود.

تنظیمات اختیاری را مشخص کنید

می‌توانید آرگومان‌ها و پرچم‌های اختیاری را برای 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 {...}
  }
}

کاتلین

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 از جمله اهداف CMake 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'

اگر از Android Gradle Plugin 4.0 استفاده می‌کنید، برای جلوگیری از بروز این خطا، کتابخانه‌هایی را که توسط هدف‌های IMPORTED CMake استفاده می‌شود، از فهرست jniLibs خود خارج کنید.

ABI ها را مشخص کنید

به‌طور پیش‌فرض، Gradle کتابخانه بومی شما را در فایل‌های .so جداگانه برای رابط‌های باینری برنامه (ABI) می‌سازد که 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 {...}
}

کاتلین

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 App Bundles منتشر کنید، زیرا تنها کتابخانه های بومی مطابق با ABI دستگاه کاربر با دانلود تحویل داده می شود.

برای برنامه‌های قدیمی که با استفاده از APK منتشر می‌شوند (که قبل از آگوست 2021 ایجاد شده‌اند)، پیکربندی چند APK را بر اساس ABI در نظر بگیرید — به جای ایجاد یک APK بزرگ با تمام نسخه‌های کتابخانه‌های بومی شما، Gradle برای هر ABI که می‌خواهید پشتیبانی کنید یک APK جداگانه ایجاد می‌کند. فایل های مورد نیاز هر ABI را بسته بندی می کند. اگر همانطور که در نمونه کد بالا نشان داده شده است چندین APK را در هر ABI بدون مشخص کردن پرچم abiFilters پیکربندی کنید، Gradle همه نسخه‌های ABI پشتیبانی شده کتابخانه‌های بومی شما را می‌سازد، اما فقط آن‌هایی را که در پیکربندی APK چندگانه خود مشخص کرده‌اید، بسته‌بندی می‌کند. برای جلوگیری از ساختن نسخه‌هایی از کتابخانه‌های بومی خود که نمی‌خواهید، فهرست یکسانی از ABI‌ها را هم برای پرچم abiFilters و هم برای پیکربندی چندگانه APK هر ABI ارائه کنید.