ลิงก์ Gradle กับไลบรารีแบบเนทีฟ

หากต้องการรวมโปรเจ็กต์ไลบรารีเนทีฟเป็นทรัพยากร Dependency ของบิลด์ Gradle เพื่อให้ Gradle แสดงเส้นทางไปยังไฟล์สคริปต์ CMake หรือ ndk-build ของคุณ วันและเวลา คุณสร้างแอป Gradle จะเรียกใช้ CMake หรือ ndk-build และแพ็กเกจที่แชร์ ไลบรารีไปกับแอปของคุณ Gradle ยังใช้สคริปต์บิลด์เพื่อให้ทราบว่าไฟล์ใด ให้เข้าถึงโปรเจ็กต์ Android Studio ของคุณ เพื่อเข้าถึงโปรเจ็กต์เหล่านั้นจาก หน้าต่างโปรเจ็กต์ หากคุณไม่มีสคริปต์บิลด์สำหรับโฆษณาเนทีฟ คุณต้องสร้าง โปรดสร้างสคริปต์บิลด์ก่อนดำเนินการต่อ

แต่ละโมดูลในโปรเจ็กต์ Android สามารถลิงก์กับ CMake หรือ ndk-build ได้เพียงรายการเดียวเท่านั้น ไฟล์สคริปต์ ตัวอย่างเช่น หากคุณต้องการสร้างและจัดแพ็กเกจเอาต์พุตจาก โปรเจ็กต์ CMake หลายรายการต้องใช้ไฟล์ CMakeLists.txt ไฟล์เดียว เป็นสคริปต์บิลด์ CMake ระดับบนสุด (ซึ่งคุณลิงก์ Gradle ไปยัง) และ เพิ่มโปรเจ็กต์ CMake อื่นๆ เป็น ทรัพยากร Dependency ของสคริปต์บิลด์นั้น ในทำนองเดียวกัน ถ้าคุณใช้ ndk-build คุณสามารถ สามารถรวม Makefile อื่นๆ ในระดับบนสุดได้ Android.mk ไฟล์สคริปต์

เมื่อคุณลิงก์ Gradle กับโปรเจ็กต์แบบเนทีฟแล้ว Android Studio จะอัปเดต แผงโครงการเพื่อแสดงไฟล์ต้นฉบับและไลบรารีแบบเนทีฟ ในกลุ่ม cpp และสคริปต์บิลด์ภายนอกในส่วน กลุ่มไฟล์บิลด์ภายนอก

หมายเหตุ: เมื่อเปลี่ยนแปลงการกำหนดค่า Gradle ใช้การเปลี่ยนแปลงโดยคลิกซิงค์โปรเจ็กต์ ในแถบเครื่องมือ นอกจากนี้ เมื่อคุณทำการเปลี่ยนแปลงใน CMake หรือ ndk-build หลังจากที่คุณลิงก์กับ Gradle แล้ว คุณควรซิงค์ Android Studio พร้อมการเปลี่ยนแปลงของคุณโดยเลือกสร้าง > รีเฟรช C++ ที่ลิงก์ โปรเจ็กต์จากแถบเมนู

คุณสามารถลิงก์ Gradle กับโปรเจ็กต์ CMake ภายนอกหรือ ndk-build ได้โดยใช้ UI ของ Android Studio

  1. เปิดแผงโครงการจากด้านซ้ายของ IDE และ เลือกมุมมอง Android
  2. คลิกขวาบนโมดูลที่คุณต้องการลิงก์กับไลบรารีเนทีฟ เช่น โมดูล app แล้วเลือกลิงก์ C++ Project ด้วย Gradle จากเมนู คุณควรเห็นกล่องโต้ตอบที่คล้ายกับ รูปที่ 4 แสดงในรูปที่ 4
  3. เลือก CMake หรือ จากเมนูแบบเลื่อนลง ndk-build
    1. หากคุณเลือก CMake ให้ใช้ช่องข้างๆ เส้นทางโครงการเพื่อระบุสคริปต์ CMakeLists.txt สำหรับโปรเจ็กต์ CMake ภายนอก
    2. หากคุณเลือก ndk-build ให้ใช้ช่องถัดจาก เส้นทางโครงการ เพื่อระบุไฟล์สคริปต์ Android.mk สำหรับ โปรเจ็กต์ ndk-build ภายนอกของคุณ Android Studio ยังมี Application.mk หากไฟล์อยู่ในไดเรกทอรีเดียวกับ Android.mk ไฟล์

    รูปที่ 4 การลิงก์โปรเจ็กต์ C++ ภายนอกโดยใช้ กล่องโต้ตอบ Android Studio

  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 by กำลังกำหนดค่า อื่น บล็อก 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 ที่ต้องใช้ รวมถึง 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 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 {...}
}

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 ควรสร้าง โดยไม่ขึ้นอยู่กับสิ่งที่คุณต้องการ ลงในแอปของคุณ ให้กำหนดค่า Flag abiFilters อื่นใน defaultConfig.externalNativeBuild.cmake บล็อก (หรือ defaultConfig.externalNativeBuild.ndkBuild) เกรเดิล สร้างการกำหนดค่า ABI เหล่านั้น แต่สร้างแพ็กเกจเฉพาะรายการที่คุณระบุใน บล็อก defaultConfig.ndk

ขอแนะนำให้เผยแพร่โดยใช้ Android App Bundle เพื่อลด ขนาดของแอป เนื่องจากมีเพียงไลบรารีแบบเนทีฟที่ตรงกับ ABI ของผู้ใช้ อุปกรณ์จะมาพร้อมกับการดาวน์โหลด

สําหรับแอปเดิมที่เผยแพร่โดยใช้ APK (สร้างก่อนเดือนสิงหาคม 2021) ให้พิจารณา การกำหนดค่า APK หลายรายการที่ใช้ ABI แทนที่จะสร้าง APK ขนาดใหญ่ 1 รายการพร้อมด้วย ของไลบรารีเนทีฟในเวอร์ชันต่างๆ Gradle สร้าง APK แยกต่างหากสำหรับ ABI แต่ละรายการ ที่ต้องการรองรับและจัดแพ็กเกจเฉพาะไฟล์ที่ ABI แต่ละรายการต้องการ หากคุณ กำหนดค่า APK หลายรายการต่อ ABI โดยไม่ระบุ abiFilters Flag ตามที่ปรากฏในตัวอย่างโค้ดด้านบน, บิลด์ของ Gradle ไลบรารีเนทีฟเวอร์ชัน ABI ที่สนับสนุนทั้งหมด แต่สร้างแพ็กเกจเฉพาะ ที่คุณระบุไว้ในการกำหนดค่า APK หลายรายการ เพื่อหลีกเลี่ยงการสร้างเวอร์ชัน ไลบรารีเนทีฟที่คุณไม่ต้องการ ให้รายการ ABI เดียวกันสำหรับ ทั้ง Flag abiFilters และ APK หลายรายการต่อ ABI ของคุณ การกำหนดค่า