參考资料:
【android ndk】macos环境下Android Studio中利用gradle编译jni模块及配置:http://demo.netfoucs.com/ashqal/article/details/21869151
ANDROID STUDIO, GRADLE AND NDK INTEGRATION:http://ph0b.com/android-studio-gradle-and-ndk-integration/

实践证明:
0.4.2仅仅有在gradle1.10版本号下创建仅仅包括AndroidLibrary模块的project时才干正常编译,gradle1.9版本号不能够。
0.4.6使用gradle1.10能够。
0.5.0不管是gradle1.10还是gradle1.11版本号都能够生成so库。
0.5.5的不能编译NDK,不管是gradle1.10还是gradle1.11版本号都不能生成so库,屙血尿脓。

下载AndroidStudio
AndroidStudio的历史版本号下载列表:http://tools.android.com/download/studio/canary

下载NDK:
下载链接:http://developer.android.com/tools/sdk/ndk/index.html,注意NDK一定要r9+版本号的,否则编译时会出现例如以下错误:
  1. Execution failed for task ':hellojni:compileDebugNdk'.
  2. > com.android.ide.common.internal.LoggedErrorException: Failed to run command:
  3. D:\ndk\ndk-build.cmd NDK_PROJECT_PATH=null APP_BUILD_SCRIPT=F:\androidstudio\test\hellojni\build\ndk\debug\Android.mk APP_PLATFORM=android-19 NDK_OUT=F:\androidstudio\test\hellojni\build\ndk\debug\obj NDK_LIBS_OUT=F:\androidstudio\test\hellojni\build\ndk\debug\lib APP_ABI=armeabi,armeabi-v7a
  4. Error Code:
  5. 2
  6. Output:
  7. D:/ndk/build/core/setup-app.mk:63: *** Android NDK: Aborting . Stop.

下载gradle:



通过“AndroidStudio历史版本号下载列表”下载的历史版本号一般是绿色的压缩包,能够直接解压缩使用,可是不包括SDK,须要额外下载SDK,因为之前下载了ADT(版本号:adt20131030),所以后面直接使用ADT文件夹下的SDK。通过http://developer.android.com/sdk/installing/studio.html首页下载的AndroidStudio为安装版本号,包括了SDK,能够下载后直接安装,首次使用创建项目会比較慢,能够參考“AndroidStudio创建项目时一直处于building“project
name”gradle project info的解决的方法
”来解决。


创建项目:
执行AndroidStudio后,创建新项目,新项目会有一个默认的Module,这里项目名称为JNIDemo,Module为app。
然后通过向导完毕项目的创建。

AndroidStudio还是很慢的,长时间处于这样的状态:
经过漫长的等待后最终完毕项目的创建,然后在这个项目下创建一个Module,New Module->Android Library:
不勾选“Create activity”然后点击“Finish”完毕创建,此时项目结构如图:
app和hellojni均为JNIDemo下的两个Module,这里把hellojni作为生成so库的NDK开发层,把app作为调用so库的APK引用开发层。

在hellojni模块的src/main下创建jni文件夹,并在jni文件夹下新建文件main.cpp,代码例如以下:
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <jni.h>
  4. #include <assert.h>
  5. #include <sys/types.h>
  6. #include <android/log.h>
  7.  
  8. #define LOG_TAG "Hellojni"
  9. #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
  10. #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
  11.  
  12. //注冊native api的类#define JNIREG_CLASS "com/example/test9/app/MainActivity"
  13.  
  14. extern "C" {
  15. JNIEXPORT void msg(JNIEnv *env, jobject clazz, jstring str);
  16. };
  17.  
  18. //jstring to char* char* jstringTostring(JNIEnv* env, jstring jstr)
  19. {
  20. char* rtn = NULL;
  21. jclass clsstring = env->FindClass("java/lang/String");
  22. jstring strencode = env->NewStringUTF("utf-8");
  23. jmethodID mid = env->GetMethodID(clsstring, "getBytes", "(Ljava/lang/String;)[B");
  24. jbyteArray barr= (jbyteArray)env->CallObjectMethod(jstr, mid, strencode);
  25. jsize alen = env->GetArrayLength(barr);
  26. jbyte* ba = env->GetByteArrayElements(barr, JNI_FALSE);
  27. if (alen > 0)
  28. {
  29. rtn = (char*)malloc(alen + 1);
  30. memcpy(rtn, ba, alen);
  31. rtn[alen] = 0;
  32. }
  33. env->ReleaseByteArrayElements(barr, ba, 0);
  34. return rtn;
  35. }
  36.  
  37. JNIEXPORT void msg(JNIEnv *env, jobject clazz, jstring str)
  38. {
  39. char *pszstr = NULL;
  40.  
  41. pszstr = jstringTostring(env, str);
  42. LOGI("%s", pszstr);
  43. free(pszstr);
  44. }
  45.  
  46. /**
  47. * Table of methods associated with a single class.
  48. */static JNINativeMethod gMethods[] = {
  49. { "msg", "(Ljava/lang/String;)V", (void*)msg},
  50. };
  51.  
  52. /*
  53. * Register native methods for all classes we know about.
  54. */static int registerNativeMethods(JNIEnv* env)
  55. {
  56. int nError = 0;
  57. jclass clazz = NULL;
  58.  
  59. clazz = env->FindClass(JNIREG_CLASS);
  60. if (clazz == NULL) {
  61. LOGE("clazz is null");
  62. return JNI_FALSE;
  63. }
  64.  
  65. nError = env->RegisterNatives(clazz, gMethods, sizeof(gMethods) / sizeof(gMethods[0]) );
  66. if ( nError < 0 ) {
  67. LOGE("RegisterNatives error: %d num: %d",nError, sizeof(gMethods) / sizeof(gMethods[0]) );
  68. return JNI_FALSE;
  69. }
  70.  
  71. return JNI_TRUE;
  72. }
  73.  
  74. /*
  75. * Set some test stuff up.
  76. *
  77. * Returns the JNI version on success, -1 on failure.
  78. */
  79. JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved)
  80. {
  81. JNIEnv* env = NULL;
  82. jint result = -1;
  83.  
  84. if(vm->GetEnv((void**) &env,JNI_VERSION_1_6) != JNI_OK){
  85. return -1;
  86. }
  87. assert(env != NULL);
  88.  
  89. if (!registerNativeMethods(env)) {
  90. LOGE("registerNativeMethods failed");
  91. return -1;
  92. }
  93.  
  94. /* success -- return valid version number */
  95. result = JNI_VERSION_1_6;
  96.  
  97. return result;
  98. }

这里仅仅导出一个msg函数打印传递进来的字符串,仅作測试。再在jni文件夹下新建一个empty.cpp文件,内容为空,这个是为了解决NDK的bug所作的,以防编译出错。


打开local.properties,设置正确的SDK路径和NDK路径:
  1. sdk.dir=D\:/adt20131030/sdk
  2. ndk.dir=D\:/ndk
打开项目gradle/wrapper文件夹下的gradle-wrapper.properties文件,改动:
  1. #Wed Apr 10 15:27:10 PDT 2013
  2. distributionBase=GRADLE_USER_HOME
  3. distributionPath=wrapper/dists
  4. zipStoreBase=GRADLE_USER_HOME
  5. zipStorePath=wrapper/dists
  6. distributionUrl=http\://services.gradle.org/distributions/gradle-1.9-all.zip

为:

  1. #Wed Apr 10 15:27:10 PDT 2013
  2. distributionBase=GRADLE_USER_HOME
  3. distributionPath=wrapper/dists
  4. zipStoreBase=GRADLE_USER_HOME
  5. zipStorePath=wrapper/dists
  6. distributionUrl=http\://services.gradle.org/distributions/gradle-1.10-all.zip

并打开项目根文件夹下的build.gradle文件,改动:

  1. // Top-level build file where you can add configuration options common to all sub-projects/modules.
  2. buildscript {
  3. repositories {
  4. mavenCentral()
  5. }
  6. dependencies {
  7. classpath 'com.android.tools.build:gradle:0.7.+'
  8. }
  9. }
  10.  
  11. allprojects {
  12. repositories {
  13. mavenCentral()
  14. }
  15. }

为(指定使用gradle1.10则改动为0.9.+,指定使用gradle1.11则改动为0.9.2):

  1. // Top-level build file where you can add configuration options common to all sub-projects/modules.
  2. buildscript {
  3. repositories {
  4. mavenCentral()
  5. }
  6. dependencies {
  7. classpath 'com.android.tools.build:gradle:0.9.+'
  8. }
  9. }
  10.  
  11. allprojects {
  12. repositories {
  13. mavenCentral()
  14. }
  15. }

解释:參考http://tools.android.com/tech-docs/new-build-system知道

  1. 0.7.0
  2. Requires Gradle 1.9
  3. Requires Studio 0.4.0

  1. 0.9.0
  2. Compatible with Gradle 1.10 and 1.11
  3. Using Gradle 1.11 requires Android Studio 0.5.0

假设配置的是0.7.+则默认使用gradle1.9,假设设置为0.9.+则默认使用gradle1.10。


另外还须要注意的是gradle1.9下没有buildTypes标签,须要将debug、release标签直接放在android标签内,在gradle1.10下debug、release须要放在buildTypes标签内,buildTypes在android内。这里hellojni配置的build.gradle文件内容例如以下:
  1. assert gradle.gradleVersion >= "1.10"
  2.  
  3. apply plugin: 'android-library'
  4.  
  5. android {
  6. compileSdkVersion 19
  7. buildToolsVersion "19.0.3"
  8.  
  9. defaultConfig {
  10. minSdkVersion 8
  11. targetSdkVersion 16
  12. versionCode 1
  13. versionName "1.0"
  14. }
  15.  
  16. buildTypes {
  17. release {
  18. runProguard false
  19. proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
  20. ndk {
  21. moduleName "hellojni"
  22. abiFilters "armeabi", "armeabi-v7a", "x86"
  23. }
  24. }
  25.  
  26. debug {
  27. ndk {
  28. moduleName "hellojni"
  29. //stl "stlport_shared"
  30. ldLibs "log", "z", "m"
  31. //cFlags "-Wall -Wextra -I " + projectDir + "/src/main/jni/include"
  32. abiFilters "armeabi", "armeabi-v7a", "x86"
  33. }
  34. }
  35. }
  36.  
  37. productFlavors {
  38. x86 {
  39. versionCode Integer.parseInt("6" + defaultConfig.versionCode)
  40. ndk {
  41. abiFilter "x86"
  42. }
  43. }
  44. mips {
  45. versionCode Integer.parseInt("4" + defaultConfig.versionCode)
  46. ndk {
  47. abiFilter "mips"
  48. }
  49. }
  50. armv7 {
  51. versionCode Integer.parseInt("2" + defaultConfig.versionCode)
  52. ndk {
  53. abiFilter "armeabi-v7a"
  54. }
  55. }
  56. arm {
  57. versionCode Integer.parseInt("1" + defaultConfig.versionCode)
  58. ndk {
  59. abiFilters "armeabi", "armeabi-v7a"
  60. }
  61. }
  62. fat
  63. }
  64. }
  65.  
  66. dependencies {
  67. compile 'com.android.support:appcompat-v7:19.+'
  68. compile fileTree(dir: 'libs', include: ['*.jar'])
  69. }

然后选择hellojni项目右键“Make Module hellojni”,等待一段时间后会在项目下生成build-ndk文件夹,文件夹下会有一些不同版本号的so库文件生成,如图:

注意这里的Android.mk文件每次编译都会又一次由工具自己主动生成,而非手动编辑的,我认为这一点设计就比較差劲。比如假设想要使用log输出函数__android_log_print,须要加入“LOCAL_LDLIBS :=  -llog”,则在build.gradle文件里加入例如以下的配置:
  1. debug {
  2. ndk {
  3. ldLibs "log"
  4. }
  5. }

由gradle依据配置再去生成Android.mk文件,最后再调用ndk进行编译。



右键project选择Open Module Settings,选择Modules-app,打开Dependencies选项卡点击“+”号,选择Module dependency,在打开的对话框中选择hellojni。
可是測试发现设置依赖没有效果,假设直接编译app,hellojni并没有编译,仍须要手动编译hellojni。


调用native函数:

app项目中,在MainActivity类中声明native函数:
  1. public native void msg(String str);

并加入静态代码载入hellojni库:

  1. static {
  2. System.loadLibrary("hellojni");
  3. }
在MainActivity::onCreate中调用native函数打印一句log:
  1. @Override
  2. protected void onCreate(Bundle savedInstanceState) {
  3. super.onCreate(savedInstanceState);
  4. setContentView(R.layout.activity_main);
  5. msg("MainActivity onCreate");
  6. }

还须要将hellojni生成的so库文件打包进apk,仍须要配置build.gradle文件,加入:
  1. task copyNativeLibs(type: Copy) {
  2. from fileTree(dir: '../hellojni/build/ndk/arm/debug/lib', include: 'armeabi/*.so') into 'build/lib'
  3. }
  4. tasks.withType(Compile) {
  5. compileTask -> compileTask.dependsOn copyNativeLibs
  6. }
  7. clean.dependsOn 'cleanCopyNativeLibs'
  8. tasks.withType(com.android.build.gradle.tasks.PackageApplication) { pkgTask ->
  9. pkgTask.jniFolders = [new File(buildDir, 'lib')]
  10. }
參考:“Android Studio加入so库”http://blog.csdn.net/caesardadi/article/details/18264399

当中copyNativeLibs任务是从相对app的项目路径'../hellojni/build/ndk/arm/debug/lib'下复制全部armeabi子文件夹的so文件到本项目build文件夹下的lib文件夹中,运行效果:

这样最后打包生成的apk包才会包括有hellojni的so库文件。


測试:


编译执行app,apk安装完成执行时输出log信息:


后面列出了可能出现的gradle错误以及解决方式,以供參考。

错误:
  1. Execution failed for task ':hellojni:compileDebugNdk'.
  2. > com.android.ide.common.internal.LoggedErrorException: Failed to run command:
  3. D:\ndk\ndk-build.cmd NDK_PROJECT_PATH=null APP_BUILD_SCRIPT=F:\androidstudio\test\hellojni\build\ndk\debug\Android.mk APP_PLATFORM=android-19 NDK_OUT=F:\androidstudio\test\hellojni\build\ndk\debug\obj NDK_LIBS_OUT=F:\androidstudio\test\hellojni\build\ndk\debug\lib APP_ABI=armeabi,armeabi-v7a
  4. Error Code:
  5. 2
  6. Output:
  7. make.exe: *** No rule to make target `F:\androidstudio\test\hellojni\build\ndk\debug\obj/local/armeabi/objs/jnimain/F_\androidstudio\test\hellojni\src\main\jni', needed by `F:\androidstudio\test\hellojni\build\ndk\debug\obj/local/armeabi/objs/jnimain/F_\androidstudio\test\hellojni\src\main\jni\hellojni.o'. Stop.

解决方式:

这是NDK在Windows下一个bug,当仅仅编译一个文件时出现,解决方法就是再加入一个空的文件就可以。
  1. This may come from a current NDK bug on Windows, when there is only one source file to compile. You only need to add one empty source to make it work again.


错误:
  1. Could not determine the dependencies of task ':hellojni:compileArmDebugJava'.
  2. > failed to find Build Tools revision 19.0.3
解决方式:
这个Build Tools是指“Android SDK Build-tools”,打开SDK Manager勾选对应版本号(比如这里是19.0.3)安装就可以。







错误:
  1. FAILURE: Build failed with an exception.
  2.  
  3. * What went wrong:
  4. Task 'assembleArmDebug' not found in project ':hellojni'. Some candidates are: 'assembleDebug'.
  5.  
  6. * Try:
  7. Run gradle tasks to get a list of available tasks. Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.
解决方式
android { }中加入:
  1. productFlavors{
  2. arm {
  3. }
  4. }

若有类似错误能够參考增加对应的标签:

  1. productFlavors {
  2. x86 {
  3. versionCode Integer.parseInt("6" + defaultConfig.versionCode)
  4. ndk {
  5. abiFilter "x86"
  6. }
  7. }
  8. mips {
  9. versionCode Integer.parseInt("4" + defaultConfig.versionCode)
  10. ndk {
  11. abiFilter "mips"
  12. }
  13. }
  14. armv7 {
  15. versionCode Integer.parseInt("2" + defaultConfig.versionCode)
  16. ndk {
  17. abiFilter "armeabi-v7a"
  18. }
  19. }
  20. arm {
  21. versionCode Integer.parseInt("1" + defaultConfig.versionCode)
  22. ndk {
  23. abiFilter "armeabi"
  24. //abiFilters "armeabi", "armeabi-v7a"
  25. }
  26. }
  27. fat
  28. }


错误:
  1. Execution failed for task ':hellojni:compileDebugNdk'.
  2. > java.io.IOException: Cannot run program "D:\ndk\ndk-build": CreateProcess error=193, %1 ??????Ч?? Win32 ??ó

解决方式:

在使用gradle1.9版本号时遇到,使用gradle1.10版本号来解决。


错误:
  1. A problem occurred evaluating project ':app'.
  2. > Could not create plugin of type 'AppPlugin'.

解决方式:

Don’t use latest Gradle (version 1.10), downgrade to 1.9。參考:http://blog.vyvazil.eu/tag/android-studio/
可是假设我们使用gradle1.9版本号的话又会出现错误:
  1. Execution failed for task ':hellojni:compileDebugNdk'.
  2. > java.io.IOException: Cannot run program "D:\ndk\ndk-build": CreateProcess error=193, %1 ??????Ч?? Win32 ??ó
不管使用哪个版本号都有问题,后来细致查看了下'AppPlugin'这个错误是出如今‘app’模块上的而非‘hellojni’模块上,于是考虑新建project项目而且仅仅在该project下建立一个库模块,不再创建app模块,如图:
这里不勾选“Create custom launcher icon”和“Create activity”,直接finish完毕,其它配置參考前述,最后编译后能够生成so库文件:


错误:
这个错误忘记记录了囧

解决方式:
File-Settings-Gradle-Gradle VM options:-Xmx512m

使用AndroidStudio编译NDK的方法及错误解决方式的更多相关文章

  1. 使用AndroidStudio编译NDK的方法及错误解决方案

    参考资料: [android ndk]macos环境下Android Studio中利用gradle编译jni模块及配置:http://demo.netfoucs.com/ashqal/article ...

  2. VS2012 编译程序时报无法载入PDB文件错误解决方式

    VS2012 编译程序时报无法载入PDB文件错误解决方式 "ConsoleApplication1.exe"(Win32): 已载入"C:\Users\hp\Docume ...

  3. Delphi - 10.1编译OSX10.12程序遇到错误解决了!

    昨天,尝试Delphi的跨平台开发功能,在windows10下,做了一个控制台程序,发布目标平台是OSX10.12,中间配置过程都非常顺利,没有任何错误,但是当编译运行时候出现下面错误: [dccos ...

  4. 史上最详细 Python第三方库添加方法 and 错误解决方法

    (1):如何添加python第三方库(方法一): File ->> Settings... ->> Project Interpreter (2):如何添加python第三方库 ...

  5. Android加载图片OOM错误解决方式

    前几天做项目的时候,甲方要求是PAD (SAMSUNG P600 10.1寸 2560*1600)的PAD上显示高分辨率的大图片. SQLITE採用BOLD方式存储图片,这个存取过程就不说了哈,网上一 ...

  6. 8000401a错误解决方式(Excel)

    前一阵子做开发须要用到Excel和Word编程,本人用的是Vista系统,开发环境是VS2005和Office2007,測试无不论什么问题,但是到部署的时候出现了一些令人非常头痛的问题,老是会出现比如 ...

  7. redis 创建集群时 出现的错误解决方式

    1. 创建集群时报以下错误 (1)错误1 ./redis-trib.rb create --replicas 1 XXXXXX:5301 XXXXXX:5302 XXXXXX:5303 XXXXXX: ...

  8. apt-get install安装软件时出现依赖错误解决方式

    在使用apt-get install安装软件时,常常会遇到如上图所看到的错误.该错误的意思为缺少依赖软件.解决方式为: aptitude install golang-go

  9. VS编译duilib项目时候的错误解决方法整理(转载)

    转载自:http://blog.csdn.net/x356982611/article/details/30217473 @1:找不到Riched20.lib 用everything等软件搜索下磁盘, ...

随机推荐

  1. task16 表格增减笔记

    trim()方法会创建一个字符串副本,删除前置及后缀所有空格,然后返回结果(中间的空格符无法消除) match()方法可在字符串内检索指定的值,找到一个或多个正则表达式的匹配 正则表达式 匹配中文:[ ...

  2. clipChildren属性

    <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android=&quo ...

  3. linux 获取命令或配置文件的帮助信息 man、whatis、apropos、--help

    man /usr/bin/man man [命令或配置文件]获取帮助信息 man ls /-lman date/-d man services //不需要添加绝对路径/etc/services NAM ...

  4. Django settings介绍

    """ Django settings for macboy project. Generated by 'django-admin startproject' usin ...

  5. centos7 部署 汉化版 gitlab 10.0.2

    更新说明: 20171009:增加3.5的内容 20171008:整理出gitlab部署手册 =============================================== gitla ...

  6. scp远程传输文件和ssh远程连接

    ssh使用方法 如果从一台linux服务器通过ssh远程登录到另一台Linux机器, 这种情况通常会在多台服务器的时候用到. 如用root帐号连接一个IP为192.168.1.102的机器,输入:“  ...

  7. git下配置github sshkey

    教程看这里 http://xiaxveliang.blog.163.com/blog/static/29708034201341244759225/

  8. 在Windows2003下如何查看IIS站点中对应的PID值

    分享:查看IIS站点中对应的PID值 在Win2003下,提供了一个命令,可以方便的查看.cmd -> iisapp -a 显示W3WP.exe PID: 1264 AppPoolID: hxW ...

  9. Oracle EBS GL 创建会计科目

    SELECT ct.trx_number ,l.accounting_class_code ,l.entered_dr ,l.entered_cr ,fnd_flex_ext.get_segs('SQ ...

  10. UNIX高级环境编程(7)标准IO函数库 - 二进制文件IO,流定位,创建临时文件和内存流

    1 二进制IO(Binary IO) 在前一篇我们了解了逐字符读写和逐行读写函数. 如果我们在读写二进制文件,希望以此读写整个文件内容,这两个函数虽然可以实现,但是明显会很麻烦且多次循环明显效率很低. ...