Android studio,gradle和NDK

pla*_*hos 151 android gradle android-ndk android-studio

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

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

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

Xav*_*het 84

我们在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

  • @DirtyBeach为什么它过时了?在Studio中仍然没有NDK的集成.我们正在努力,但此时没有ETA. (7认同)
  • 如果我可以在Android Studio(和Gradle支持)下使用NDK和命令完成调试,那将会很棒 (2认同)
  • 我的行动是基于我如何定义"整合".我理解它意味着"使用带有gradle的NDK的方法"现在确实存在,尽管它们都不是很棒的解决方案.但是,根据您的评论,您的团队似乎还有其他想法可以实现真正的整合.我撤回了我先前的陈述. (2认同)
  • NDK集成在Google IO 2015期间宣布.它可以在Android Studio 1.3中使用(预览可以很快下载.我会发布链接,当它可用时). (2认同)

pla*_*hos 43

更新:支持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
        }
    }
 }
Run Code Online (Sandbox Code Playgroud)

遗憾的是,如果目录不存在或者不包含任何.so文件,则构建不会失败.

  • 这不适用于新的Android Studio版本,解决方法? (5认同)
  • 一点Groovy魔术:`tasks.withType(com.android.build.gradle.tasks.PackageApplication){it.jniFolders = [file("libs")] as Set}`.谢谢你们的帮助! (2认同)

SJo*_*shi 40

随着Android Studio更新到1.0,NDK工具链支持得到了极大的改进(注意:请阅读本文底部的更新,了解新实验性Gradle插件和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工具链默认编译的代码将位于(module)/ 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
}
Run Code Online (Sandbox Code Playgroud)

这是编译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
}
Run Code Online (Sandbox Code Playgroud)

此外,非常棒的是,Android Studio已经自动完成了C++ - 使用"native"关键字生成Java包装器:

自动完成C++的例子 -  Java包装器

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

C++  -  Java包装器移动到正确的位置

更新:2017年10月15日

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

你仍然需要生成自己的JNI层代码,或者使用我上面提到的SWIG技术,但是现在Android项目中的C++脚手架是微不足道的.

在CMakeLists文件的变化(这是你把你的C++源文件)将搭载Android Studio中拾起,它会自动重新编译任何相关的库.


Cyp*_*eld 35

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

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

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

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

  1. 下载NDK
  2. 添加ANDROID_NDK_HOME到您的环境变量或添加ndk.dir=/path/to/ndk到您local.properties的Android Studio项目中.这允许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
        }
    
    }
    
    Run Code Online (Sandbox Code Playgroud)

请注意,这将忽略您的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
}
Run Code Online (Sandbox Code Playgroud)

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

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

tasks.withType(JavaCompile) {
    compileTask -> compileTask.dependsOn ndkBuild
}
Run Code Online (Sandbox Code Playgroud)

  • 我使用这个hack而不是禁用src dir所以我可以编辑ide`task.all {task - > if(task.name.contains('Ndk'))task.enabled = false}中的c/c ++文件. (4认同)

小智 23

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

这是我的项目

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


小智 18

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

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


Mat*_*gan 15

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

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

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

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

  4. 在app模块的main目录中,创建一个名为的新文件夹jni.

  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!");
}
Run Code Online (Sandbox Code Playgroud)

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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'])
}
Run Code Online (Sandbox Code Playgroud)

在这里找到一个非常相似的应用程序的完整源代码(减去NDK).


Ant*_*ony 8

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

android.ndk {
    moduleName "libraw"
}
Run Code Online (Sandbox Code Playgroud)

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

sourceSets.main {
    jni.srcDirs = 'path'
}
Run Code Online (Sandbox Code Playgroud)

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

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


ale*_*leb 7

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

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


归档时间:

查看次数:

171191 次

最近记录:

8 年,4 月 前