首页 文章

Android studio,gradle和NDK

提问于
浏览
148

我对这整个Gradle和Android Studio支持都很陌生 . 我已设法使用导出选项将我的android项目转换为gradle .

但我正在寻找一些文档或开始如何将NDK构建集成到gradle构建过程中 .

如果可能的话,我还需要某种“后”阶段,将构建二进制文件(.so文件)复制到资产目录 .

23 回答

  • 3

    正如Xavier所说,如果使用gradle 0.7.2,可以将预编译放在/ src / main / jniLibs /中

    取自:https://groups.google.com/d/msg/adt-dev/nQobKd2Gl_8/ctDp9viWaxoJ

  • 4

    我们在1.3中发布了第一版集成作为预览:http://tools.android.com/tech-docs/android-ndk-preview

    即使在1.3成为最终版之后,集成仍将保持预览 . 目前没有关于何时最终的ETA(截至2015/07/10) .

    更多信息:http://tools.android.com/tech-docs/android-ndk-preview

  • 1

    UPDATE: 支持NDK的Android Studio现已推出: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 文件,则构建不会失败 .

  • 4

    随着Android Studio更新到1.0,NDK工具链支持得到了极大的改进( note: please read my updates at the bottom of this post to see usage with the new experimental Gradle plugin and Android Studio 1.5 ) .

    Android Studio和NDK集成得非常好,您只需要在模块的build.gradle中创建一个ndk {}块,并将源文件设置到(module)/ src / main / jni目录中 - 你就是完成了!

    从命令行不再有ndk-build .

    我在我的博客文章中写了所有相关内容:http://www.sureshjoshi.com/mobile/android-ndk-in-android-studio-with-swig/

    重点是:

    这里有两件事你需要知道 . 默认情况下,如果您希望将外部库加载到Android应用程序中,则默认情况下会在(模块)/ src / main / jniLibs中查找它们 . 您可以通过在模块的build.gradle中设置sourceSets.main.jniLibs.srcDirs来更改此设置 . 你需要一个带有库的子目录,用于你所针对的每个架构(例如x86,arm,mips,arm64-v8a等等) . 你想要由NDK工具链默认编译的代码将位于(模块)中/ src / main / jni和上面类似,您可以通过在模块的build.gradle中设置sourceSets.main.jni.srcDirs来更改它

    并将其放入模块的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代码的过程,从那里你需要加载它,并创建包装器 - 但从你的问题判断,你已经知道如何做所有这些,所以我不会重新哈希 .

    另外,我在这里放置了一个这个例子的Github回购:http://github.com/sureshjoshi/android-ndk-swig-example

    更新:2015年6月14日

    当Android Studio 1.3问世时,应该通过JetBrains CLion插件更好地支持C语言 . 我目前假设这将允许在Android Studio中进行Java和C开发;但是我认为我们仍然需要使用Gradle NDK部分,如上所述 . 另外,我认为仍然需要编写Java < - > C包装器文件,除非CLion会自动执行这些操作 .

    更新:2016年1月5日

    我更新了我的博客和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

    NDK部分的Gradle构建现在看起来像这样:

    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使用“native”关键字为C -Java生成的包装器自动完成:

    Example of auto-complete of C++-Java wrapper

    但是,它并不完全乐观......如果您使用SWIG将库包装为自动生成代码,然后尝试使用native关键字自动生成,它会将代码放在Swig _wrap的错误位置.cxx文件...所以你需要将它移动到“extern C”块:

    C++-Java wrapper moved to correct location

    更新:2017年10月15日

    如果我没有提到Android Studio 2.2以后通过Gradle和CMake对NDK工具链提供了基本上“本机”(没有双关语)的支持,那将是我的疏忽 . 现在,当您创建一个新项目时,只需选择C支持,您就可以开始了 .

    您仍然需要生成自己的JNI层代码,或者使用我上面提到的SWIG技术,但Android项目中C的脚手架现在很简单 .

    安装工作室将拾取CMakeLists文件(您放置C源文件的位置)中的更改,它将自动重新编译任何关联的库 .

  • 3

    在Google IO 2015中,Google宣布在Android Studio 1.3中进行完整的NDK集成 .

    它现在已不可用,并且可供所有人使用:https://developer.android.com/studio/projects/add-native-code.html

    老答案:Gradle如果项目源中有jni目录,则自动调用ndk-build .

    这适用于Android studio 0.5.9(canary build) .

    • Download the NDK

    • ANDROID_NDK_HOME 添加到环境变量中或将 ndk.dir=/path/to/ndk 添加到Android Studio项目中的 local.properties . 这允许Android studio自动运行ndk .

    • 下载latest gradle sample projects以查看ndk项目的示例 . (它们位于页面底部) . 一个很好的示例项目是 ndkJniLib .

    • 从NDK示例项目中复制 gradle.build . 它看起来像这样 . 这个 gradle.build 为每个架构创建了一个不同的apk . 您必须使用 build variants 窗格选择所需的体系结构 .
      build variants pane

    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
    }
    

    此外,您可能希望明确地在gradle构建脚本中调用ndk-build,因为您刚刚禁用了自动调用 .

    task ndkBuild(type: Exec) {
       commandLine 'ndk-build', '-C', file('src/main/jni').absolutePath
    }
    
    tasks.withType(JavaCompile) {
        compileTask -> compileTask.dependsOn ndkBuild
    }
    
  • 1

    我发现“gradle 1.11 com.android.tools.build:gradle:0.9 . ”现在支持pre-build ndk,你可以将* .so放在dir src / main / jniLibs中 . 当 Build gradle将ndk打包到正确的位置 .

    这是我的项目

    Project:
    |--src
    |--|--main
    |--|--|--java
    |--|--|--jniLibs
    |--|--|--|--armeabi
    |--|--|--|--|--.so files
    |--libs
    |--|--other.jar
    
  • 18

    截至目前(Android Studio v0.8.6),它非常简单 . 以下是创建“Hello world”类型应用程序的步骤:

    • 下载Android NDK并将根文件夹放在某处 - 与SDK文件夹位于同一位置 .

    • 将以下内容添加到 local.properties 文件中: ndk.dir=<path-to-ndk>

    • 将以下内容添加到 defaultConfig 闭包内的build.gradle文件中,紧跟在 versionName 行之后: ndk { moduleName="hello-world" }

    • 在应用程序模块的 main 目录中,创建一个名为 jni 的新文件夹 .

    • 在该文件夹中,创建一个名为 hello-world.c 的文件,您将在下面看到 .

    • 有关如何在 hello-world.c 中调用方法(或者它是函数?)的示例,请参阅下面的示例 Activity 代码 .


    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'])
    }
    

    Find the full source code of a very similar app here (minus the NDK).

  • 81

    如果您使用的是unix,则最新版本(0.8)会添加ndk-build . 以下是添加方法:

    android.ndk {
        moduleName "libraw"
    }
    

    它希望在'src / main / jni'下找到JNI,否则您可以使用以下命令定义它:

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

    截至2014年1月28日,版本0.8的版本在Windows上打破,你必须禁用构建:

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

    优雅的解决方法显示在https://groups.google.com/d/msg/adt-dev/nQobKd2Gl_8/Z5yWAvCh4h4J中 .

    基本上你创建一个包含“lib / armeabi / yourlib.so”的jar,然后在构建中包含jar .

  • 42

    another (closed) thread中给出了一个很好的答案,可以自动编译容易编译的 .so 文件 . 为了实现这一点,我不得不改变这条线:

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

    成:

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

    如果没有此更改,则找不到 .so 文件,因此打包它们的任务将永远不会运行 .

  • 21

    @plaisthos的答案打破了最新的gradle版本,但仍有办法实现 . 在项目目录的根目录中创建一个 native-libs 目录,并将我们的所有库复制到此目录中 .

    将以下行添加到build.gradle中 . Build 并快乐 .

    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'
    
  • 1

    这是我用来从gradle使用android-ndk构建的代码 . 为此在 gradle.properties 中添加ndk目录路径ie . 添加 ndkdir=/home/user/android-ndk-r9d 并将所有jni文件放在 src/main/native 文件夹中,如下面的代码所示 . 它将创建具有本机库的jar,您可以正常使用 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'
    
  • 35

    我使用以下代码编译本机dropbox库,我使用的是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

    我使用了 ndk.dir=/usr/shareData/android-ndk-r11b // ndk的路径

    在android studio项目的 local.properties 文件中 . 并添加此行:
    android.useDeprecatedNdk=true

    在android studio项目的 gradle.properties 文件中 .

    更多信息:http://tools.android.com/tech-docs/android-ndk-preview

  • 1

    为了扩展Naxos所说的内容(感谢Naxos向我发送了正确的方向!),我从最近发布的NDK示例中学到了很多,并在此处发布了类似问题的答案 .

    How to configure NDK with Android Gradle plugin 0.7

    这篇文章详细介绍了如何将预构建的本机库链接到各种体系结构的应用程序中,以及有关如何直接向NDK支持添加NDK支持的信息 . build.gradle脚本 . 在大多数情况下,您不需要再进行zip和复制工作 .

  • 2

    以下是我在Android Studio项目中使用NDK的步骤 . 我用这个教程来帮助我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());
    
  • 0

    从eclipse在android studio中配置项目:你必须将eclipse ndk项目导入到android studio而不导出到gradle并且它可以工作,你还需要在local.properties中添加ndk的路径,如果显示错误则添加

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

    在build.gradle文件中然后使用终端创建jni文件夹和文件并运行它将工作

  • 0

    既然Android Studio处于稳定的通道中,那么运行_1747894就非常简单了 . 这些示例使用的是ndk experimental plugin,并且比Android NDK在线文档中链接的样本更新 . 一旦您知道它们可以工作,您就可以学习build.gradle,local.properties和gradle-wrapper.properties文件并相应地修改您的项目 . 以下是让它们工作的步骤 .

    • 转到设置,外观和行为,系统设置,Android SDK,选择SDK工具选项卡,然后检查列表底部的Android NDK版本1.0.0 . 这将下载NDK .

    • 指向新下载的NDK的位置 . 请注意,它将放在sdk / ndk-bundle目录中 . 通过选择文件,项目结构,SDK位置(左侧),并在Android NDK位置下提供路径来执行此操作 . 这将向local.properties添加一个ndk条目,类似于:

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

    我已经成功地以这种方式在存储库中构建和部署了所有项目,除了gles3gni,native-codec和builder . 我正在使用以下内容:

    Android Studio 1.3构建AI-141.2117773
    2015年7月28日发布的android-ndk样本(上面的链接)
    SDK工具24.3.3
    NDK r10e解压缩到C:\ Android \ sdk \ ndk-bundle
    Gradle 2.5
    Gradle插件0.2.0
    Windows 8.1 64位

  • 8

    NDK构建和gradle(基本)

    通常使用NDK构建就像正确指定到Android.mk的ndkBuild路径或到CMakeLists.txt的cmake路径一样简单 . 我推荐使用旧版Android.mk上的CMake,因为Android Studio的C / C支持基于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'])
    }
    

    将预建库添加到项目中(高级)

    NDK版本中的静态库(.a)将自动包含在内,但预构建的动态库(.so)将需要放在 jniLibs 中 . 这可以使用 sourceSets 配置,但您应该采用该标准 . 当包含预构建的库时,您在 build.gradle 中不需要任何其他命令 .

    jniLibs的布局

    您可以在Android Gradle Plugin User Guide中找到有关该结构的更多信息 .

    | --app:
    | - | --build.gradle
    | - | --src:
    | - | - | - 主
    | - | - | - | --java
    | - | - | - | --jni
    | - | - | - | - | --CMakeLists.txt
    | - | - | - | --jniLibs
    | - | - | - | - | --armeabi
    | - | - | - | - | - | - . so文件
    | - | - | - | - | --armeabi-V7A
    | - | - | - | - | - | - . so文件
    | - | - | - | - | --x86
    | - | - | - | - | - | - . so文件

    然后,您可以使用 unzip -l myApp.apk 验证生成的APK包含您的.so文件,通常在 build/outputs/apk/ 下列出内容 .

    构建共享库

    如果您在NDK中构建共享库,则无需进一步操作 . 它将被正确捆绑在APK中 .

  • 0

    只需将此行添加到app 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)
    }
    
  • 7

    now.I可以加载如此成功!

    1.将.so文件添加到此路径

    Project:
    

    | --src | - | --main| - | - | --java | - | - | --jniLibs | - | - | - | --armeabi | - | - | - | - | - .so档

    2.将此代码添加到gradle.build

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

    }

    1. System.loadLibrary("yousoname");
    • goodluck for you,gradle 1.2.3还可以
  • 0
    • 如果您的项目是从eclipse导出的,请在gradle文件中添加以下代码:
    android {
       sourceSets{
            main{
               jniLibs.srcDir['libs']  
          }  
        }
    }
    

    2.如果您在Android studio中创建项目:

    在src / main /中创建一个名为jniLibs的文件夹,并将* .so文件放在jniLibs文件夹中 .

    并在gradle文件中复制以下代码:

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

    虽然我相信SJoshi(oracle guy)有最完整的答案,但SWIG项目是一个特殊的案例,有趣且有用,但是对于大多数已经完成标准SDK ant项目NDK的项目都没有推广 . . 我们都希望现在最有可能使用Android工作室,或者想要一个更加CI友好的移动构建工具链,理论上可以提供gradle .

    我已经发布了我的方法,从某个地方借来的(我在SO上发现了这个,但是发布了应用build.gradle的一个要点:https://gist.github.com/truedat101/c45ff2b69e91d5c8e9c7962d4b96e841) . 简而言之,我建议如下:

    • 不要将项目升级到最新的gradle构建

    • 在项目根目录中使用com.android.tools.build:gradle:1.5.0

    • 在app项目中使用com.android.application

    • 确保gradle.properties具有:android.useDeprecatedNdk = true(如果它在抱怨)

    • 使用上述方法确保创建Android.mk文件的工作时间和小时数不会被丢弃 . 您可以控制要构建的目标拱 . 这些说明对Windows用户很友好,理论上他们应该能够在没有特殊问题的情况下构建Windows .

    Gradle for Android在我看来一直很混乱,就像我喜欢借用的maven概念和项目的目录结构一样 . 这个NDK功能已经“即将推出”近3年 .

相关问题