สตูดิโอ Android, gradle และ NDK


153

ฉันยังใหม่ต่อการเรียนรู้ทั้งหมดและการสนับสนุน Android Studio ฉันได้ทำการแปลงโปรเจค Android ของฉันเพื่อไล่ระดับโดยใช้ตัวเลือกการส่งออก

แต่ฉันกำลังมองหาเอกสารบางอย่างหรือจุดเริ่มต้นวิธีรวม NDK build เข้ากับกระบวนการสร้าง gradle

ถ้าเป็นไปได้ฉันต้องการลำดับ "หลัง" ที่คัดลอกไบนารีการสร้าง (ไฟล์. so) ไปยังไดเรกทอรีสินทรัพย์


ฉันโพสต์คำตอบของฉันในลิงค์ด้านล่างที่กล่าวถึง stackoverflow.com/questions/20900814/…
Ahmad Ali Nasir

24
ผู้อ่านใหม่: โปรดทราบว่าคำถามนี้ถูกถามในขั้นต้นในช่วงเบต้าของ Android Studio คำตอบมีการเปลี่ยนแปลงตลอดเวลา ให้ความสนใจกับรุ่น Gradle ที่กล่าวถึงในคำตอบเช่นเดียวกับเมื่อคำตอบถูกโพสต์จริง
หาดฌอน

หากมีอะไรเปลี่ยนแปลงจริง ๆ ฉันจะแก้ไขคำถามเพื่อเลือกสถานะอีกครั้ง
plaisthos

Android Studio 1.3 ที่ canary channel รองรับ NDK ได้อย่างเต็มที่ การอ้างอิง: tools.android.com/download/studio/canary/latest
Vikasdeep Singh

18 มิถุนายน 2558: Android Studio 1.3 Beta มีวางจำหน่ายแล้วในช่องเบต้า! ขออภัยโครงสร้างนี้ยังไม่มีการสนับสนุน C / C ++ แหล่งที่มา: tools.android.com/recent/androidstudio13betaavailable
fastr.de

คำตอบ:


85

เราได้เปิดตัวรุ่นแรกของการรวมเป็นตัวอย่างใน 1.3: http://tools.android.com/tech-docs/android-ndk-preview

การรวมจะยังคงอยู่ในพรีวิวแม้หลังจาก 1.3 กลายเป็นที่สิ้นสุด ไม่มีการทางพิเศษแห่งประเทศไทยปัจจุบันว่าเมื่อใดจะเป็นที่สุด (ณ วันที่ 2015/07/53)

ข้อมูลเพิ่มเติมที่นี่: http://tools.android.com/tech-docs/android-ndk-preview


2
จะดีถ้าฉันสามารถใช้ NDK และเสร็จสิ้นคำสั่งที่มีการแก้จุดบกพร่องภายใต้ Android สตูดิโอ (และ Gradle สนับสนุน)
powder366

1
@GREnvoy - เราจะกำหนดค่าตัวสร้าง NDK ที่เหมาะสมในสตูดิโอ Android ได้อย่างไร กรุณาช่วยบอกขั้นตอนให้ฉันได้ไหม :)
Shravan

7
@DirtyBeach ทำไมถึงล้าสมัย? ยังไม่มีการรวมกันของ NDK ในสตูดิโอ เรากำลังดำเนินการอยู่ แต่ไม่มีการทางพิเศษแห่งประเทศไทยในขณะนี้
Xavier Ducrohet

2
การกระทำของฉันขึ้นอยู่กับวิธีที่ฉันนิยาม "การรวม" ฉันเข้าใจว่าหมายถึง "วิธีการใช้ NDK กับ gradle" ซึ่งตอนนี้มีอยู่แล้วแม้ว่าจะไม่มีวิธีใดที่ยอดเยี่ยม อย่างไรก็ตามจากความคิดเห็นของคุณดูเหมือนว่าทีมของคุณมีอย่างอื่นในใจสำหรับสิ่งที่บูรณาการที่แท้จริงอาจจะเป็น ฉันเพิกถอนคำสั่งก่อนหน้าของฉัน
Sean Beach

2
การผสานรวม NDK ได้รับการประกาศใน Google IO 2015 มีให้ใน Android Studio 1.3 (สามารถดาวน์โหลดตัวอย่างได้ในไม่ช้าฉันจะโพสต์ลิงก์เมื่อพร้อมให้บริการ)
Cypress Frankenfeld

43

อัปเดต: Android Studio พร้อมการรองรับ NDK สิ้นสุดแล้ว: http://tools.android.com/tech-docs/android-ndk-preview

สำหรับการสร้างด้วยสคริปต์โซลูชัน gradle ด้านล่างควรทำงาน:

ฉันใช้สคริปต์บิลด์และเพิ่มลงในไฟล์ของฉัน (ดูเหมือนว่าจะใช้ได้0.8+): ดูเหมือนว่าจะเทียบเท่ากับโซลูชันด้านล่าง (แต่ดูดีกว่าในไฟล์ gradle):

 android {
    sourceSets {
        main {
            jniLibs.srcDirs = ['native-libs']
            jni.srcDirs = [] //disable automatic ndk-build
        }
    }
 }

การสร้างโชคไม่ดีที่ล้มเหลวหากไม่มีไดเรกทอรีอยู่หรือไม่มี.soไฟล์


5
มันไม่ทำงานกับ Android Studio เวอร์ชั่นใหม่อีกต่อไป
powder366

@ powder366 ดูคำตอบของฉัน
Leandros

2
บิตของมายากล tasks.withType(com.android.build.gradle.tasks.PackageApplication) { it.jniFolders = [file("libs")] as Set }Groovy: ขอบคุณมากสำหรับความช่วยเหลือ!
trnl

ขั้นตอนสำหรับ android Studio 0.8.9 คืออะไร
Pandiri Deepak

1
@plaisthos ขอบคุณมากสำหรับการชี้ทิศทางที่ถูกต้อง! บรรทัดที่สองในสคริปต์การไล่ระดับสีjni.srcDirs = [] //disable automatic ndk-buildมีความสำคัญมากเนื่องจากจะป้องกันไม่ให้ Android Studio สร้างรหัสต้นฉบับ C / C ++ ขึ้นใหม่ ฉันพยายามคิดออกเป็นเวลาสองวันจนกระทั่งฉันเห็นโพสต์ของคุณและสิ่งนี้แก้ปัญหาของฉันได้ ฉันคิดว่า NDK build นั้นดีกว่าที่สร้างแยกต่างหากโดย makefile ของบรรทัดคำสั่ง Android.mk เท่านั้นไม่ใช่สคริปต์ gradle เนื่องจาก C / C ++ ถูกสร้างโดย Makefile มานานกว่า 40 ปี!
ตองก้า

40

ด้วยการอัปเดตของ Android Studio เป็น 1.0 เครื่องมือสนับสนุน NDK พัฒนาขึ้นอย่างมาก ( หมายเหตุ: โปรดอ่านการอัปเดตของฉันที่ด้านล่างของโพสต์นี้เพื่อดูการใช้งานด้วยปลั๊กอิน Gradle รุ่นใหม่และ Android Studio 1.5 )

Android Studio และ NDK นั้นถูกรวมเข้าด้วยกันอย่างเพียงพอดังนั้นคุณเพียงแค่ต้องสร้างบล็อก ndk {} ใน build.gradle ของโมดูลของคุณและตั้งค่าไฟล์ต้นฉบับของคุณลงในไดเรกทอรี (โมดูล) / src / main / jni - และคุณ ทำ!

ไม่มี ndk-build อีกต่อไปจากบรรทัดคำสั่ง

ฉันได้เขียนเกี่ยวกับเรื่องนี้ในบล็อกโพสต์ของฉันที่นี่: http://www.sureshjoshi.com/mobile/android-ndk-in-android-studio-with-swig/

จุดสำคัญคือ:

มีสองสิ่งที่คุณต้องรู้ที่นี่ โดยค่าเริ่มต้นหากคุณมี libs ภายนอกที่คุณต้องการโหลดลงในแอปพลิเคชัน Android พวกเขาจะค้นหาใน (โมดูล) / src / main / jniLibs โดยค่าเริ่มต้น คุณสามารถเปลี่ยนแปลงสิ่งนี้ได้โดยใช้การตั้งค่า sourceSets.main.jniLibs.srcDirs ใน build.gradle ของโมดูลของคุณ คุณจะต้องมีไดเรกทอรีย่อยพร้อมห้องสมุดสำหรับแต่ละสถาปัตยกรรมที่คุณกำหนดเป้าหมาย (เช่น x86, arm, mips, arm64-v8a, ฯลฯ …)

รหัสที่คุณต้องการรวบรวมโดยค่าเริ่มต้นโดย NDK toolchain จะอยู่ใน (โมดูล) / src / main / jni และในทำนองเดียวกันกับข้างต้นคุณสามารถเปลี่ยนได้โดยการตั้งค่า sourceSets.main.jni.srcDirs ใน build.gradle โมดูลของคุณ

และใส่สิ่งนี้ลงใน build.gradle ของโมดูลของคุณ:

ndk {
  moduleName "SeePlusPlus" // Name of C++ module (i.e. libSeePlusPlus)
  cFlags "-std=c++11 -fexceptions" // Add provisions to allow C++11 functionality
  stl "gnustl_shared" // Which STL library to use: gnustl or stlport
}

นั่นคือขั้นตอนการรวบรวมรหัส C ++ ของคุณจากตรงนั้นคุณต้องโหลดมันและสร้าง wrappers - แต่จากการตัดสินจากคำถามของคุณคุณก็รู้วิธีการทำทั้งหมดแล้วดังนั้นฉันจะไม่แฮชอีกครั้ง

นอกจากนี้ฉันได้วาง repo Github ของตัวอย่างนี้ที่นี่: http://github.com/sureshjoshi/android-ndk-swig-example

อัปเดต: 14 มิถุนายน 2558

เมื่อ Android Studio 1.3 ออกมาควรมีการสนับสนุน C ++ ผ่านทางปลั๊กอิน JetBrains CLion ขณะนี้ฉันอยู่ภายใต้สมมติฐานว่าจะอนุญาตให้พัฒนา Java และ C ++ จากภายใน Android Studio; อย่างไรก็ตามฉันคิดว่าเราจะต้องใช้ส่วน Gradle NDK ตามที่ฉันได้กล่าวไว้ข้างต้น นอกจากนี้ฉันคิดว่ายังคงมีความจำเป็นต้องเขียนไฟล์ตัวห่อ Java <-> C ++ ยกเว้นว่า CLion จะทำสิ่งเหล่านั้นโดยอัตโนมัติ

อัปเดต: 5 มกราคม 2559

ฉันได้อัปเดตบล็อกของฉันและ Github repo (ในสาขาที่กำลังพัฒนา) เพื่อใช้ Android Studio 1.5 กับปลั๊กอิน Gradle รุ่นทดลองล่าสุด (0.6.0-alpha3)

http://www.sureshjoshi.com/mobile/android-ndk-in-android-studio-with-swig/ http://github.com/sureshjoshi/android-ndk-swig-example

Gradle build สำหรับส่วน NDK ตอนนี้มีลักษณะดังนี้:

android.ndk {
    moduleName = "SeePlusPlus" // Name of C++ module (i.e. libSeePlusPlus)
    cppFlags.add("-std=c++11") // Add provisions to allow C++11 functionality
    cppFlags.add("-fexceptions")
    stl = "gnustl_shared" // Which STL library to use: gnustl or stlport
}

นอกจากนี้ Android Studio ยังมีระบบเติมข้อความอัตโนมัติสำหรับ C ++ - Java ที่สร้างโดยใช้คำสำคัญ 'native':

ตัวอย่างของการเติม C ++ อัตโนมัติ - Java wrapper

อย่างไรก็ตามมันไม่ได้เป็นสีดอกกุหลาบอย่างสมบูรณ์ ... หากคุณใช้ SWIG เพื่อห่อไลบรารีเพื่อสร้างรหัสอัตโนมัติจากนั้นลองใช้คำหลักที่สร้างโดยอัตโนมัติในรุ่นนั้นคำหลักนั้นจะวางโค้ดผิดที่ใน Swig _wrap ของคุณ ไฟล์. cxx ... ดังนั้นคุณต้องย้ายไปไว้ในบล็อก "extern C":

C ++ - Java wrapper ถูกย้ายไปยังตำแหน่งที่ถูกต้อง

อัปเดต: 15 ตุลาคม 2017

ฉันจะสะเพร่าถ้าฉันไม่ได้พูดถึงว่า Android Studio 2.2 เป็นต้นไปมีการสนับสนุน 'ดั้งเดิม' (ไม่เล่นสำนวน) สำหรับ NDK toolchain ผ่าน Gradle และ CMake ตอนนี้เมื่อคุณสร้างโครงการใหม่เพียงแค่เลือกการสนับสนุน C ++ และคุณก็พร้อมที่จะไป

คุณจะต้องสร้างรหัสเลเยอร์ JNI ของคุณเองหรือใช้เทคนิค SWIG ที่ฉันได้กล่าวถึงข้างต้น แต่การนั่งร้านของ C ++ ในโครงการ Android นั้นเป็นเรื่องเล็กน้อย

การเปลี่ยนแปลงในไฟล์ CMakeLists (ซึ่งเป็นที่ที่คุณวางไฟล์ต้นฉบับ C ++) จะถูกเลือกโดย Android Studio และจะรวบรวมไลบรารีที่เกี่ยวข้องอีกครั้งโดยอัตโนมัติ


1
ใส่ * ดังนั้นใน (โมดูล) / src / main / jniLibs
Fawkes

เหตุใด NDEBUG จึงถูกตั้งค่าเสมอเมื่อใช้ Android Studio แม้ในการสร้างการดีบัก
pt123

35

ใน Google IO 2015 Google ประกาศรวม NDK แบบเต็มใน Android Studio 1.3

ตอนนี้เป็นภาพตัวอย่างและทุกคนสามารถใช้ได้: https://developer.android.com/studio/projects/add-native-code.html

คำตอบเก่า: Gradle จะโทรโดยอัตโนมัติndk-buildหากคุณมีjniไดเรกทอรีในแหล่งโครงการของคุณ

สิ่งนี้ทำงานบน Android studio 0.5.9 (canary build)

  1. ดาวน์โหลด NDK

  2. เพิ่มANDROID_NDK_HOMEตัวแปรสภาพแวดล้อมของคุณหรือเพิ่มndk.dir=/path/to/ndkที่คุณlocal.propertiesในโครงการของคุณ Android สตูดิโอ สิ่งนี้ทำให้ Android studio สามารถรัน ndk ได้โดยอัตโนมัติ

  3. ดาวน์โหลดโครงการตัวอย่าง gradle ล่าสุดเพื่อดูตัวอย่างของโครงการ ndk (อยู่ด้านล่างของหน้า) ndkJniLibโครงการตัวอย่างที่ดีคือ

  4. คัดลอกgradle.buildจากโครงการตัวอย่าง NDK มันจะมีลักษณะเช่นนี้ สิ่งนี้gradle.buildสร้าง apk ที่แตกต่างกันสำหรับแต่ละสถาปัตยกรรม คุณต้องเลือกสถาปัตยกรรมที่คุณต้องการใช้build variantsบานหน้าต่าง บานหน้าต่างสร้างสายพันธุ์

    apply plugin: 'android'
    
    dependencies {
        compile project(':lib')
    }
    
    android {
        compileSdkVersion 19
        buildToolsVersion "19.0.2"
    
        // This actual the app version code. Giving ourselves 100,000 values [0, 99999]
        defaultConfig.versionCode = 123
    
        flavorDimensions "api", "abi"
    
        productFlavors {
            gingerbread {
                flavorDimension "api"
                minSdkVersion 10
                versionCode = 1
            }
            icecreamSandwich {
                flavorDimension "api"
                minSdkVersion 14
                versionCode = 2
            }
            x86 {
                flavorDimension "abi"
                ndk {
                    abiFilter "x86"
                }
                // this is the flavor part of the version code.
                // It must be higher than the arm one for devices supporting
                // both, as x86 is preferred.
                versionCode = 3
            }
            arm {
                flavorDimension "abi"
                ndk {
                    abiFilter "armeabi-v7a"
                }
                versionCode = 2
            }
            mips {
                flavorDimension "abi"
                ndk {
                    abiFilter "mips"
                }
                versionCode = 1
            }
            fat {
                flavorDimension "abi"
                // fat binary, lowest version code to be
                // the last option
                versionCode = 0
            }
        }
    
        // make per-variant version code
        applicationVariants.all { variant ->
            // get the version code of each flavor
            def apiVersion = variant.productFlavors.get(0).versionCode
            def abiVersion = variant.productFlavors.get(1).versionCode
    
            // set the composite code
            variant.mergedFlavor.versionCode = apiVersion * 1000000 + abiVersion * 100000 + defaultConfig.versionCode
        }
    
    }

โปรดทราบว่าสิ่งนี้จะเป็นการละเว้นไฟล์ Android.mk และ Application.mk ของคุณ คุณสามารถบอกให้ gradle ปิดการใช้งานการเรียก atuomatic ndk-build จากนั้นระบุไดเรกทอรีสำหรับแหล่ง ndk ด้วยตนเอง

sourceSets.main {
    jniLibs.srcDir 'src/main/libs' // use the jni .so compiled from the manual ndk-build command
    jni.srcDirs = [] //disable automatic ndk-build call
}

นอกจากนี้คุณอาจต้องการเรียก ndk-build ในสคริปต์ build gradle ของคุณอย่างชัดเจนเนื่องจากคุณเพิ่งปิดใช้งานการโทรอัตโนมัติ

task ndkBuild(type: Exec) {
   commandLine 'ndk-build', '-C', file('src/main/jni').absolutePath
}

tasks.withType(JavaCompile) {
    compileTask -> compileTask.dependsOn ndkBuild
}

ใช่. แต่นั่นใช้งานได้ภายใต้แพลตฟอร์ม Unix เท่านั้นและยัง จำกัด หากคุณซับซ้อนกว่าการกำหนดค่า / makefiles ndk ที่ง่ายมาก
plaisthos

ใช่มันจะสร้างไฟล์อัตโนมัติสำหรับสิ่งที่ จำกัด ซึ่งคุณสามารถตั้งค่าในไฟล์ gradle build ได้อย่างไรก็ตามมีวิธีแก้ไขปัญหา ฉันเพิ่มลงในคำตอบของฉัน
Cypress Frankenfeld

1
การเรียกใช้ ndk-build จะทำงานที่บรรทัดคำสั่งเท่านั้นไม่ใช่จากใน Android Studio
Cameron Lowell Palmer

แม้ว่านี่ไม่ใช่คำตอบล่าสุด แต่ดูเหมือนว่าจะเป็นคำตอบที่ถูกต้องที่สุด ให้ความสนใจเป็นพิเศษกับขั้นตอนที่ 3: "ดาวน์โหลดโครงการตัวอย่างระดับสูงสุดล่าสุด "
หาดฌอน

4
ฉันใช้แฮ็คนี้แทนการปิดการใช้งาน src dir ดังนั้นฉันจึงสามารถแก้ไขไฟล์ c / c ++ ภายใน IDE ได้tasks.all { task -> if (task.name.contains('Ndk')) task.enabled = false }
sherpya

23

ฉันพบ "gradle 1.11 com.android.tools.build:gradleoul.9.+" รองรับ pre-build ndk ตอนนี้คุณสามารถใส่ * .so ลงใน dir src / main / jniLibs เมื่อการสร้าง gradle จะจัดแพ็คเกจ ndk ให้ถูกที่

นี่คือโครงการของฉัน

โครงการ:
| --src
| - | --main
| - | - | --java
| - | - | --jniLibs
| - | - | - | --armeabi
| - - - - - - - - -. - ดังนั้นไฟล์
| --libs
| - | --other.jar

18

ดังที่ซาเวียร์กล่าวว่าคุณสามารถใส่สิ่งปลูกสร้างล่วงหน้าใน / src / main / jniLibs / หากคุณใช้ gradle 0.7.2+

นำมาจาก: https://groups.google.com/d/msg/adt-dev/nQobKd2Gl_8/ctDp9viWaxoJ


เราจะดูตัวอย่างที่กล่าวถึงใน 0.7.2 ndkJniLib ได้อย่างไร
Ryan Heitner

มีประโยชน์สำหรับการใช้ไลบรารีเช่น SqlCipher
personne3000

16

ณ ตอนนี้ (Android Studio v0.8.6) มันค่อนข้างง่าย นี่คือขั้นตอนในการสร้างแอปประเภท "Hello world":

  1. ดาวน์โหลด Android NDK และวางโฟลเดอร์รากไว้ที่ไหนสักแห่งในตำแหน่งเดียวกับโฟลเดอร์ SDK

  2. เพิ่มสิ่งต่อไปนี้ในlocal.propertiesไฟล์ของคุณ: ndk.dir=<path-to-ndk>

  3. เพิ่มสิ่งต่อไปนี้ในไฟล์ build.gradle ของคุณด้านในของการdefaultConfigปิดทันทีหลังversionNameบรรทัด:ndk { moduleName="hello-world" }

  4. ในโมดูลของแอปไดเรกทอรีสร้างโฟลเดอร์ใหม่ที่เรียกว่าmainjni

  5. ในโฟลเดอร์นั้นให้สร้างไฟล์ชื่อhello-world.cซึ่งคุณจะเห็นด้านล่าง

  6. ดูตัวอย่างActivityโค้ดด้านล่างสำหรับตัวอย่างของวิธีการที่จะเรียกวิธีการ (หรือมันเป็นฟังก์ชั่น?) hello-world.cใน


hello-world.c

#include <string.h>
#include <jni.h>

jstring
Java_me_mattlogan_ndktest_MainActivity_stringFromJNI(JNIEnv* env, jobject thiz)
{
    return (*env)->NewStringUTF(env, "Hello world!");
}

MainActivity.java

public class MainActivity extends Activity {

    static {
        System.loadLibrary("hello-world");
    }

    public native String stringFromJNI();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        String testString = stringFromJNI();

        TextView mainText = (TextView) findViewById(R.id.main_text);
        mainText.setText(testString);
    }
}

build.gradle

apply plugin: 'com.android.application'

android {
    compileSdkVersion 20
    buildToolsVersion "20.0.0"

    defaultConfig {
        applicationId "me.mattlogan.ndktest"
        minSdkVersion 15
        targetSdkVersion 20
        versionCode 1
        versionName "1.0"

        ndk {
            moduleName "hello-world"
        }
    }
    buildTypes {
        release {
            runProguard false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
}

ค้นหาซอร์สโค้ดแบบเต็มของแอพที่คล้ายกันมากที่นี่ (ลบ NDK)


ฉันทำตามคำแนะนำในโครงการปัจจุบันของฉัน แต่สิ่ง NDK ยังคงไม่ถูกสร้างขึ้น ความคิดใด ๆ ดูเหมือนว่ามันจะสร้างทุกอย่าง แต่เพียงแค่ข้ามสิ่งที่ jni
alice.harrison

@NanuoLei ขอบคุณฉันพยายาม แต่ฉันได้รับปัญหาที่. so ไม่ได้ถูกสร้างขึ้น ทุกอย่างอื่นดูเหมือนว่าจะทำงาน แต่เมื่อฉันเรียกใช้ apkg ในโปรแกรมจำลองมันบ่นว่ามันไม่สามารถโหลดวัตถุที่ใช้ร่วมกัน
aaa90210

@ aaa90210 อีมูเลเตอร์ของคุณใช้ภาพ x86 หรือไม่? โดยค่าเริ่มต้น NDK จะสร้างไลบรารี ARMEABI เท่านั้นหากคุณต้องการสร้างภาพ x86 คุณสามารถเพิ่มบรรทัดนี้ลงใน Application.mk: APP_ABI: = armeabi x86
Leo รองรับ Monica Cellio

1
มันทำงานกับฉัน PS: ทุกคนเห็นคำตอบนี้อย่าลืมที่จะเปลี่ยนJava_me_mattlogan_ndktest_MainActivity_stringFromJNIเป็นของคุณเอง :)
AbdulMomen عبدالمؤمن

8

หากคุณใช้ยูนิกซ์เวอร์ชันล่าสุด (0.8) จะเพิ่ม ndk-build นี่คือวิธีการเพิ่ม:

android.ndk {
    moduleName "libraw"
}

คาดว่าจะพบ JNI ภายใต้ 'src / main / jni' มิฉะนั้นคุณสามารถกำหนดด้วย:

sourceSets.main {
    jni.srcDirs = 'path'
}

ตั้งแต่วันที่ 28 มกราคม 2014 ด้วยรุ่น 0.8 บิลด์เสียบน windows คุณต้องปิดใช้งานบิลด์ด้วย:

sourceSets.main {
    jni.srcDirs = [] //disable automatic ndk-build call (currently broken for windows)
}

1
มีเอกสารใดเกี่ยวกับคุณสมบัตินั้นหรือไม่? ฉันไม่พบสิ่งใด ตอนนี้ดูเหมือนว่าฉันจะไม่สนใจ Android.mk/Application.mk ของฉัน
plaisthos

ฉันไม่พบอะไรเลย มันอาจจะแอบเข้าไปในสิ่งก่อสร้าง ฉันอยู่บน windows ดังนั้นฉันสามารถยืนยันได้เท่านั้นว่าไม่สามารถเรียกสคริปต์ unix ndk-build ได้ ไม่มีเหตุผลอื่นใดที่จะเรียกสิ่งนั้นว่าเพื่อรวมการคอมไพล์เนทีฟในเกรเดียนต์ คุณอยู่ในระบบยูนิกซ์หรือไม่?
แอนโทนี่


คาดว่าจะพบไฟล์ * .so ที่สร้างไว้ล่วงหน้าใน jniLibs.srcDirs
อัลไพน์

ฉันไม่เห็นด้วยตามความจริงที่ว่าเกิดปัญหาในการเรียก ndk-build ซึ่งไม่จำเป็นอย่างยิ่งถ้ามันต้องมีห้องสมุดที่สร้างขึ้น ฉันไม่สามารถยืนยันได้เนื่องจากฉันไม่มีเวลาที่จะ vm Linux ในขณะนี้
แอนโทนี่

7

วิธีแก้ปัญหาที่สง่างามที่ปรากฏอยู่ในhttps://groups.google.com/d/msg/adt-dev/nQobKd2Gl_8/Z5yWAvCh4h4J

โดยทั่วไปคุณสร้าง jar ซึ่งมี "lib / armeabi / yourlib.so" แล้วรวม jar ในบิลด์


ใช่. วิธีนี้ใช้งานได้ดีถ้าคุณไม่เปลี่ยนรหัสดั้งเดิมบ่อยๆ และคุณจะต้องรวมไฟล์ไบนารี jar ในที่เก็บ มิฉะนั้นคุณจะจบลงด้วยการสร้างสคริปต์ที่สร้างขวดได้ทันที
plaisthos

1
ฉันได้แก้ไขตัวอย่าง Hello-JNI ของ Androidด้วยสคริปต์ทุบตีแบบง่ายๆที่ล้อมรอบndk-buildสร้าง.jars สำหรับแต่ละรายการ.soและวางไว้ในเส้นทางการสร้างของ Gradle เพื่อบรรเทาความเจ็บปวดนี้ ลองดูสิ
dbro

4

คำตอบที่ดีอัตโนมัติบรรจุภัณฑ์ของที่รวบรวมได้อย่างง่ายดาย.so-Files จะได้รับในอีก (ปิด) ด้าย เพื่อให้ทำงานได้ฉันต้องเปลี่ยนสาย:

from fileTree(dir: 'libs', include: '**/*.so')

เป็น:

from fileTree(dir: 'src/main/libs', include: '**/*.so') 

หากไม่มีการเปลี่ยนแปลงนี้.soจะไม่พบไฟล์และงานสำหรับทำแพ็กเกจจะไม่ทำงาน


อัปเดต: โปรดทราบว่าในแอนดรอยด์สตูดิโอที่ใหม่กว่า (อย่างน้อยใน 1.5) โค้ดเนทีฟนั้นดีกว่ามากและไม่จำเป็นต้องแยกบรรจุโค้ดของคุณ
HYS

4

คำตอบจาก @plaisthos แตกหักในเวอร์ชั่น gradle ล่าสุด แต่ยังมีวิธีที่จะทำ สร้างnative-libsไดเรกทอรีในรากของไดเรกทอรีโครงการของคุณและคัดลอก libs ทั้งหมดของเราลงในไดเรกทอรีนี้

เพิ่มบรรทัดต่อไปนี้ใน build.gradle ของคุณ สร้างและมีความสุข

task copyNativeLibs(type: Copy) {
    from(new File(project(':<your project>').getProjectDir(), 'native-libs')) { include '**/*.so' }
    into new File(buildDir, 'native-libs')
}

tasks.withType(Compile) { compileTask -> compileTask.dependsOn copyNativeLibs }

clean.dependsOn 'cleanCopyNativeLibs'

3

นี่คือรหัสที่ฉันใช้ในการสร้างโดยใช้ android-ndk จาก gradle สำหรับเส้นทางไดเรกทอรี add ndk นี้gradle.propertiesคือ เพิ่มndkdir=/home/user/android-ndk-r9dและวางไฟล์ JNI ทั้งหมดในโฟลเดอร์nativeในsrc/main/ขณะที่คุณสามารถดูจากรหัสโพสต์ด้านล่าง มันจะสร้าง jar ที่มี libs ดั้งเดิมซึ่งคุณสามารถใช้งานได้ตามปกติSystem.loadLibrary("libraryname");

dependencies {
    compile fileTree(dir: "$buildDir/native-libs", include: '*.jar')
}

task ndkBuild(type: Exec) {
    commandLine "$ndkdir/ndk-build", "--directory", "$projectDir/src/main/native", '-j', Runtime.runtime.availableProcessors(),
            "APP_PLATFORM=android-8",
            "APP_BUILD_SCRIPT=$projectDir/src/main/native/Android.mk",
            "NDK_OUT=$buildDir/native/obj",
            "NDK_APP_DST_DIR=$buildDir/native/libs/\$(TARGET_ARCH_ABI)"
}

task nativeLibsToJar(type: Jar, description: 'create a jar with native libs') {
    destinationDir file("$buildDir/native-libs")
    baseName 'native-libs'
    from fileTree(dir: "$buildDir/native/libs", include: '**/*.so')
    into 'lib/'
}

tasks.withType(JavaCompile) {
    compileTask -> compileTask.dependsOn nativeLibsToJar
}

nativeLibsToJar.dependsOn 'ndkBuild'

3

ฉันใช้รหัสต่อไปนี้เพื่อรวบรวมไลบรารีดรอปบ็อกซ์ดั้งเดิมฉันใช้ Android Studio v1.1

task nativeLibsToJar(type: Zip) {
    destinationDir file("$buildDir/native-libs")
    baseName 'native-libs'
    extension 'jar'
    from fileTree(dir: 'src/main/libs', include: '**/*.so')
    into 'lib/'
}

tasks.withType(JavaCompile) {
    compileTask -> compileTask.dependsOn(nativeLibsToJar)
}


1

เพื่อขยายสิ่งที่ Naxos พูด (ขอบคุณ Naxos ที่ส่งฉันไปในทิศทางที่ถูกต้อง!) ฉันได้เรียนรู้เล็กน้อยจากตัวอย่าง NDK ที่เพิ่งเปิดตัวและโพสต์คำตอบในคำถามที่คล้ายกันที่นี่

วิธีกำหนดค่า NDK ด้วย Android Gradle plugin 0.7

โพสต์นี้มีรายละเอียดทั้งหมดเกี่ยวกับการเชื่อมโยงไลบรารี่ที่สร้างไว้ล่วงหน้าลงในแอพของคุณสำหรับสถาปัตยกรรมต่างๆรวมถึงข้อมูลเกี่ยวกับวิธีเพิ่มการรองรับ NDK โดยตรงกับสคริปต์ build.gradle ส่วนใหญ่คุณไม่จำเป็นต้องทำงานกับรหัสไปรษณีย์และคัดลอกอีกต่อไป


1

นี่คือขั้นตอนที่ฉันใช้เพื่อให้ NDK ทำงานในโครงการ Android Studio ของฉัน ฉันใช้บทช่วยสอนนี้เพื่อช่วยฉันออก https://software.intel.com/en-us/videos/using-the-ndk-with-android-studio

ในการใช้ NDK คุณต้องเพิ่มบรรทัด NDK ใน local.properties ดังนั้นภายใต้ sdk.dir ของคุณเพิ่ม

ndk.dir=C\:\\MyPathToMyNDK\ndk

ในแอพของฉัน build.gradle ฉันมีรหัสต่อไปนี้

        ndk {
            moduleName "myLib"
            ldLibs "log"
            stl "gnustl_shared"
            cFlags "-std=c++11 -frtti -fexceptions -pthread"
        }

moduleName เป็นชื่อที่คุณต้องการให้รหัสพื้นเมืองของคุณ ฉันเชื่อว่านี่คือสิ่งที่ไลบรารีที่แบ่งใช้จะถูกเรียก ldLibs อนุญาตให้ฉันเข้าสู่ LogCat, stl เป็น stl ที่คุณต้องการนำเข้า มีตัวเลือกมากมายเช่นเดียวกับ Eclipse NDK ( http://www.kandroid.org/ndk/docs/CPLUSPLUS-SUPPORT.html )

cFlags ยังคงเป็นเวทย์มนตร์ดำสำหรับฉัน ฉันไม่พบแหล่งที่ดีสำหรับตัวเลือกทั้งหมดและสิ่งที่พวกเขาให้ฉัน ค้นหา StackOverflow สำหรับสิ่งที่คุณต้องการนั่นคือสิ่งที่ฉันพบ ฉันรู้ว่า c ++ 11 อนุญาตให้ฉันใช้มาตรฐาน c ++ 11 ใหม่

นี่คือตัวอย่างของวิธีการที่ฉันเข้าสู่ LogCat จากรหัสพื้นเมือง

__android_log_print(ANDROID_LOG_DEBUG, "TestApp", "Adding - String %d has a field name of %s and a value of %s", i, lKeyUTF8.c_str(), lValueUTF8.c_str());

1

กำหนดค่าโครงการในandroid studioจาก eclipse: คุณต้องนำเข้าโครงการ eclipse ndk ไปยัง android studio โดยไม่ต้องส่งออกไปยัง gradle และใช้งานได้คุณต้องเพิ่มเส้นทางของ ndk ในlocal.propertiesหากแสดงข้อผิดพลาดแล้วเพิ่ม

sourceSets.main {
        jniLibs.srcDir 'src/main/libs' 
        jni.srcDirs = [] //disable automatic ndk-build callenter code here
    }

ในbuild.gradleไฟล์แล้วสร้างJNIโฟลเดอร์และไฟล์โดยใช้ขั้วและเรียกมันจะทำงาน


1
ดูคำตอบของฉันเอง นั่นเป็นวิธีแก้ปัญหาที่ฉันใช้อยู่ในปัจจุบัน แต่มันก็ไม่ใช่วิธีแก้ปัญหาจริงๆ
plaisthos

1

ตอนนี้ Android Studio อยู่ในช่องสัญญาณที่เสถียรแล้วมันค่อนข้างตรงไปตรงมาที่จะทำให้Android-ndk ตัวอย่างทำงานได้ ตัวอย่างเหล่านี้ใช้ปลั๊กอินทดลอง ndkและใหม่กว่าปลั๊กอินที่เชื่อมโยงกับจากเอกสารออนไลน์ Android NDK เมื่อคุณรู้ว่ามันทำงานได้คุณสามารถศึกษาไฟล์ build.gradle, local.properties และ gradle-wrapper.properties และแก้ไขโครงการของคุณตามนั้น ต่อไปนี้เป็นขั้นตอนเพื่อให้พวกเขาทำงาน

  1. ไปที่การตั้งค่าลักษณะและพฤติกรรมการตั้งค่าระบบ Android SDK เลือกแท็บเครื่องมือ SDK และตรวจสอบ Android NDK เวอร์ชัน 1.0.0 ที่ด้านล่างของรายการ นี่จะดาวน์โหลด NDK

  2. ชี้ไปที่ตำแหน่งของ NDK ที่ดาวน์โหลดใหม่ โปรดทราบว่ามันจะถูกวางไว้ในไดเรกทอรี sdk / ndk-bundle ทำได้โดยเลือกไฟล์โครงสร้างโครงการตำแหน่ง SDK (ด้านซ้าย) และจัดหาเส้นทางภายใต้ตำแหน่ง Android NDK สิ่งนี้จะเพิ่มรายการ ndk ลงใน local.properties คล้ายกับสิ่งนี้:

    Mac / Linux: ndk.dir = / Android / sdk / ndk-bundle
    Windows: ndk.dir = C: \ Android \ sdk \ ndk-bundle

ฉันได้สร้างและปรับใช้โครงการทั้งหมดในที่เก็บเรียบร้อยแล้วด้วยวิธีนี้ยกเว้น gles3gni, native-codec และ builder ฉันใช้สิ่งต่อไปนี้:

Android Studio 1.3 build AI-141.2117773
ตัวอย่าง android-ndk ที่เผยแพร่เมื่อวันที่ 28 กรกฎาคม 2558 (ลิงก์ด้านบน)
เครื่องมือ SDK 24.3.3
NDK r10e ที่แยกไปยัง C: \ Android \ sdk \ ndk-bundle
Gradle 2.5
Gradle plugin 0.2.0
Windows 8.1 64 บิต


1

NDK สร้างและไล่ระดับ (ขั้นพื้นฐาน)

โดยทั่วไปการสร้างด้วย NDK นั้นง่ายพอ ๆ กับการระบุเส้นทาง ndkBuild ไปยัง Android.mk หรือเส้นทาง cmake ไปยัง CMakeLists.txt อย่างถูกต้อง ฉันแนะนำ CMake เหนือ Android.mk รุ่นเก่าเนื่องจากการสนับสนุน C / C ++ ของ Android Studio นั้นขึ้นอยู่กับ CLion และใช้ CMake เป็นรูปแบบโครงการ จากประสบการณ์ของฉันมีแนวโน้มที่จะทำให้ IDE ตอบสนองได้ดีขึ้นในโครงการขนาดใหญ่ ทุกสิ่งที่รวบรวมในโครงการของคุณจะถูกสร้างและคัดลอกลงใน APK โดยอัตโนมัติ

apply plugin: 'com.android.library'

android {
    compileSdkVersion 19
    buildToolsVersion "25.0.2"

    defaultConfig {
        minSdkVersion 19
        targetSdkVersion 19

        ndk {
            abiFilters 'armeabi', 'armeabi-v7a', 'x86'
            // 64-bit support requires an Android API level higher than 19; Namely 21 and higher
            //abiFilters 'armeabi', 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
        }

        externalNativeBuild {
            cmake {
                arguments '-DANDROID_TOOLCHAIN=clang',
                        '-DANDROID_PLATFORM=android-19',
                        '-DANDROID_STL=gnustl_static',
                        '-DANDROID_ARM_NEON=TRUE'

            }
        }
    }

    externalNativeBuild {
        cmake {
            path 'src/main/jni/CMakeLists.txt'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
}

การเพิ่มไลบรารีที่สร้างไว้ล่วงหน้าลงในโครงการ (ขั้นสูง)

สแตติกไลบรารี (.a) ในบิลด์ NDK ของคุณจะถูกรวมโดยอัตโนมัติ แต่จะต้องวางjniLibsไลบรารี่แบบไดนามิก (.so) ไว้ล่วงหน้า สามารถกำหนดค่าได้โดยใช้sourceSetsแต่คุณควรใช้มาตรฐาน คุณไม่จำเป็นต้องมีคำสั่งเพิ่มเติมใด ๆ ในbuild.gradleเมื่อรวมถึงไลบรารีที่สร้างไว้ล่วงหน้า

เค้าโครงของ jniLibs

คุณสามารถค้นหาข้อมูลเพิ่มเติมเกี่ยวกับโครงสร้างในส่วนคู่มือการใช้งาน Android Gradle ปลั๊กอิน

|--app:
|--|--build.gradle
|--|--src:
|--|--|--main
|--|--|--|--java
|--|--|--|--jni
|--|--|--|--|--CMakeLists.txt
|--|--|--|--jniLibs
|--|--|--|--|--armeabi
|--|--|--|--|--|--.so Files
|--|--|--|--|--armeabi-v7a
|--|--|--|--|--|--.so Files
|--|--|--|--|--x86
|--|--|--|--|--|--.so Files

จากนั้นคุณสามารถตรวจสอบความถูกต้องของ APK ที่เกิดขึ้นซึ่งมีไฟล์. so ของคุณซึ่งโดยทั่วไปจะbuild/outputs/apk/ใช้unzip -l myApp.apkแสดงรายการเนื้อหา

การสร้างห้องสมุดสาธารณะ

หากคุณกำลังสร้างห้องสมุดสาธารณะใน NDK คุณไม่จำเป็นต้องทำอะไรเพิ่มเติม จะรวมอยู่ใน APK อย่างถูกต้อง


0

เพียงเพิ่มบรรทัดนี้ลงในแอป build.gradle

dependencies {
    ...
    compile fileTree(dir: "$buildDir/native-libs", include: 'native-libs.jar')
}

task nativeLibsToJar(type: Zip, description: 'create a jar archive of the native libs') {
    destinationDir file("$buildDir/native-libs")
    baseName 'native-libs'
    extension 'jar'
    from fileTree(dir: 'libs', include: '**/*.so')
    into 'lib/armeabi/'
}

tasks.withType(JavaCompile) {
    compileTask -> compileTask.dependsOn(nativeLibsToJar)
}

ฉันคิดว่าวิธีการ jniLibs.srcDirs นั้นสะอาดกว่านี้เพราะคุณสามารถใช้ abiFilter / รสชาติได้ แต่วิธีการของคุณก็ควรใช้งานเช่นกัน
plaisthos

0

ตอนนี้ฉันสามารถโหลดได้สำเร็จ!

1. เพิ่มไฟล์. so ไปที่พา ธ นี้

Project:

| --src | - | - หลัก | - | - | - | - | - | - | - | - | - | - | - | - - | - | - | -. ดังนั้นไฟล์

2. เพิ่มรหัสนี้เพื่อ gradle.build

android {
splits {
    abi {
        enable true
        reset()
        include 'x86', 'x86_64', 'arm64-v8a', 'armeabi-v7a', 'armeabi'
        universalApk false
    }
}

}

3System.loadLibrary("yousoname");

  1. goodluck สำหรับคุณมันใช้ได้กับ gradle 1.2.3

0
  1. หากโครงการของคุณส่งออกจาก eclipse ให้เพิ่มรหัสด้านล่างในไฟล์ gradle:

    android {
       sourceSets{
            main{
               jniLibs.srcDir['libs']  
          }  
        }
    }

2. ถ้าคุณสร้างโครงการใน Android studio:

สร้างโฟลเดอร์ชื่อ jniLibs ใน src / main /, และใส่ไฟล์ * .so ของคุณลงในโฟลเดอร์ jniLibs

และคัดลอกรหัสด้านล่างในไฟล์ gradle ของคุณ:

android {
    sourceSets{  
       main{  
         jniLibs.srcDir['jniLibs']  
      }  
    }
}

0

ในขณะที่ฉันเชื่อว่า SJoshi (oracle guy) มีคำตอบที่สมบูรณ์ที่สุดโครงการ SWIG เป็นกรณีพิเศษที่น่าสนใจและมีประโยชน์ในตอนนั้น แต่ไม่ได้สรุปสำหรับโครงการส่วนใหญ่ที่ทำได้ดีกับโครงการตามมาตรฐาน SDK Ant + NDK เราทุกคนต้องการที่จะใช้สตูดิโอ Android ตอนนี้มีแนวโน้มมากที่สุดหรือต้องการ Toolchain สร้าง CI ที่เป็นมิตรมากขึ้นสำหรับมือถือซึ่ง gradle ในทางทฤษฎีเสนอ

ฉันโพสต์วิธีการของฉันยืมมาจากที่อื่น (ฉันพบสิ่งนี้ใน SO แต่โพสต์สรุปสาระสำคัญสำหรับแอพ build.gradle: https://gist.github.com/truedat101/c45ff2b69e91d5c8e9c7962d4b96e841 ) สั้นฉันขอแนะนำดังต่อไปนี้:

  • อย่าอัปเกรดโครงการของคุณเป็นงานสร้างเกรดล่าสุด
  • ใช้ com.android.tools.build:gradle:1.5.0 ในรูทโปรเจ็กต์ของคุณ
  • ใช้ com.android.application ในโครงการแอปของคุณ
  • ตรวจสอบให้แน่ใจว่า gradle.properties มี: android.useDeprecatedNdk = จริง (ในกรณีที่มีการร้องเรียน)
  • ใช้วิธีการด้านบนเพื่อให้แน่ใจว่าเวลาและความพยายามในการสร้างไฟล์ Android.mk ของคุณจะไม่ถูกโยนทิ้ง คุณสามารถควบคุมเป้าหมายที่จะสร้างได้ และคำแนะนำเหล่านี้มีประโยชน์ต่อผู้ใช้ Windows ซึ่งควรจะสามารถสร้างบน windows ได้โดยไม่มีปัญหาพิเศษ

Gradle สำหรับ Android ได้รับความยุ่งเหยิงในความคิดของฉันมากที่สุดเท่าที่ฉันชอบแนวคิด maven ยืมและโครงสร้างความเห็นของไดเรกทอรีสำหรับโครงการ ฟีเจอร์ NDK นี้ "กำลังจะมาเร็ว ๆ นี้" เป็นเวลาเกือบ 3 ปีแล้ว

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.