參考资料:
【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+版本号的,否则编译时会出现例如以下错误:
Execution failed for task ':hellojni:compileDebugNdk'.
> com.android.ide.common.internal.LoggedErrorException: Failed to run command:
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
Error Code:
2
Output:
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,代码例如以下:
#include <stdio.h>
#include <stdlib.h>
#include <jni.h>
#include <assert.h>
#include <sys/types.h>
#include <android/log.h> #define LOG_TAG "Hellojni"
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__) //注冊native api的类#define JNIREG_CLASS "com/example/test9/app/MainActivity" extern "C" {
JNIEXPORT void msg(JNIEnv *env, jobject clazz, jstring str);
}; //jstring to char* char* jstringTostring(JNIEnv* env, jstring jstr)
{
char* rtn = NULL;
jclass clsstring = env->FindClass("java/lang/String");
jstring strencode = env->NewStringUTF("utf-8");
jmethodID mid = env->GetMethodID(clsstring, "getBytes", "(Ljava/lang/String;)[B");
jbyteArray barr= (jbyteArray)env->CallObjectMethod(jstr, mid, strencode);
jsize alen = env->GetArrayLength(barr);
jbyte* ba = env->GetByteArrayElements(barr, JNI_FALSE);
if (alen > 0)
{
rtn = (char*)malloc(alen + 1);
memcpy(rtn, ba, alen);
rtn[alen] = 0;
}
env->ReleaseByteArrayElements(barr, ba, 0);
return rtn;
} JNIEXPORT void msg(JNIEnv *env, jobject clazz, jstring str)
{
char *pszstr = NULL; pszstr = jstringTostring(env, str);
LOGI("%s", pszstr);
free(pszstr);
} /**
* Table of methods associated with a single class.
*/static JNINativeMethod gMethods[] = {
{ "msg", "(Ljava/lang/String;)V", (void*)msg},
}; /*
* Register native methods for all classes we know about.
*/static int registerNativeMethods(JNIEnv* env)
{
int nError = 0;
jclass clazz = NULL; clazz = env->FindClass(JNIREG_CLASS);
if (clazz == NULL) {
LOGE("clazz is null");
return JNI_FALSE;
} nError = env->RegisterNatives(clazz, gMethods, sizeof(gMethods) / sizeof(gMethods[0]) );
if ( nError < 0 ) {
LOGE("RegisterNatives error: %d num: %d",nError, sizeof(gMethods) / sizeof(gMethods[0]) );
return JNI_FALSE;
} return JNI_TRUE;
} /*
* Set some test stuff up.
*
* Returns the JNI version on success, -1 on failure.
*/
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved)
{
JNIEnv* env = NULL;
jint result = -1; if(vm->GetEnv((void**) &env,JNI_VERSION_1_6) != JNI_OK){
return -1;
}
assert(env != NULL); if (!registerNativeMethods(env)) {
LOGE("registerNativeMethods failed");
return -1;
} /* success -- return valid version number */
result = JNI_VERSION_1_6; return result;
}

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


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

为:

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

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

// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:0.7.+'
}
} allprojects {
repositories {
mavenCentral()
}
}

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

// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:0.9.+'
}
} allprojects {
repositories {
mavenCentral()
}
}

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

0.7.0
Requires Gradle 1.9
Requires Studio 0.4.0

0.9.0
Compatible with Gradle 1.10 and 1.11
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文件内容例如以下:
assert gradle.gradleVersion >= "1.10"

apply plugin: 'android-library'

android {
compileSdkVersion 19
buildToolsVersion "19.0.3" defaultConfig {
minSdkVersion 8
targetSdkVersion 16
versionCode 1
versionName "1.0"
} buildTypes {
release {
runProguard false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
ndk {
moduleName "hellojni"
abiFilters "armeabi", "armeabi-v7a", "x86"
}
} debug {
ndk {
moduleName "hellojni"
//stl "stlport_shared"
ldLibs "log", "z", "m"
//cFlags "-Wall -Wextra -I " + projectDir + "/src/main/jni/include"
abiFilters "armeabi", "armeabi-v7a", "x86"
}
}
} productFlavors {
x86 {
versionCode Integer.parseInt("6" + defaultConfig.versionCode)
ndk {
abiFilter "x86"
}
}
mips {
versionCode Integer.parseInt("4" + defaultConfig.versionCode)
ndk {
abiFilter "mips"
}
}
armv7 {
versionCode Integer.parseInt("2" + defaultConfig.versionCode)
ndk {
abiFilter "armeabi-v7a"
}
}
arm {
versionCode Integer.parseInt("1" + defaultConfig.versionCode)
ndk {
abiFilters "armeabi", "armeabi-v7a"
}
}
fat
}
} dependencies {
compile 'com.android.support:appcompat-v7:19.+'
compile fileTree(dir: 'libs', include: ['*.jar'])
}

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

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

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



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


调用native函数:

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

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

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

还须要将hellojni生成的so库文件打包进apk,仍须要配置build.gradle文件,加入:
task copyNativeLibs(type: Copy) {
from fileTree(dir: '../hellojni/build/ndk/arm/debug/lib', include: 'armeabi/*.so') into 'build/lib'
}
tasks.withType(Compile) {
compileTask -> compileTask.dependsOn copyNativeLibs
}
clean.dependsOn 'cleanCopyNativeLibs'
tasks.withType(com.android.build.gradle.tasks.PackageApplication) { pkgTask ->
pkgTask.jniFolders = [new File(buildDir, 'lib')]
}
參考:“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错误以及解决方式,以供參考。

错误:
Execution failed for task ':hellojni:compileDebugNdk'.
> com.android.ide.common.internal.LoggedErrorException: Failed to run command:
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
Error Code:
2
Output:
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,当仅仅编译一个文件时出现,解决方法就是再加入一个空的文件就可以。
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.


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







错误:
FAILURE: Build failed with an exception.

* What went wrong:
Task 'assembleArmDebug' not found in project ':hellojni'. Some candidates are: 'assembleDebug'. * Try:
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 { }中加入:
    productFlavors{
arm {
}
}

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

    productFlavors {
x86 {
versionCode Integer.parseInt("6" + defaultConfig.versionCode)
ndk {
abiFilter "x86"
}
}
mips {
versionCode Integer.parseInt("4" + defaultConfig.versionCode)
ndk {
abiFilter "mips"
}
}
armv7 {
versionCode Integer.parseInt("2" + defaultConfig.versionCode)
ndk {
abiFilter "armeabi-v7a"
}
}
arm {
versionCode Integer.parseInt("1" + defaultConfig.versionCode)
ndk {
abiFilter "armeabi"
//abiFilters "armeabi", "armeabi-v7a"
}
}
fat
}


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

解决方式:

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


错误:
A problem occurred evaluating project ':app'.
> 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版本号的话又会出现错误:
Execution failed for task ':hellojni:compileDebugNdk'.
> 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. 纯web实现游记类手机端应用

    初衷 当初的一个学习框架项目,采用sui框架实现的一套手机端页面.今天清理github的时候重新整理了一下,因为设计的确实不错嘛,拿出来大家一起学习...哈哈 说明 采用sui框架 纯html/css ...

  2. pom.xml配置文件内容记录

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/20 ...

  3. IOS下 input 被软键盘方案遮盖问题解决

    前言: 并没有完美解决 ! 场景: 最近在做企业微信H5的一个项目,里面有个动态列表页,开始输入框是隐藏的,点击评论才会出现并让 input 聚焦.经过测试在安卓上面应该没什么问题,但是iOS上面会出 ...

  4. Xcode 7安装KSImageNamed 不启作用

    1. 到 ~/Library/Developer/Xcode/Plug-ins  删除KSImageNamed.xcplugin 2. 在~/Library/Developer/Xcode/Plug- ...

  5. Java并发编程指南

    多线程是实现并发机制的一种有效手段.在 Java 中实现多线程有两种手段,一种是继承 Thread 类,另一种就是实现 Runnable/Callable 接口. java.util.concurre ...

  6. js匹配日期和时间的正则表达式

    自己写比较头疼,copy下来留着以后用 //日期的正则表达式 -]\d{}-([-]|[-])-([-]|[-][-]|[-])$/; var regExp = new RegExp(reg); if ...

  7. Django 模板语言 标签

    前言:django的模板语法基本和flask的jinja2基本一样.下面比较一下两个模板语法的区别. ------深度变量的查找(万能的句点号) 在 Django 模板中遍历复杂数据结构的关键是句点字 ...

  8. 回归JavaScript基础(一)

    主题:JavaScript简介. 一.JavaScript的起源 JavaScript诞生于1995年.当时,它的主要作用是处理一些输入验证操作.之前的话,都是把表单数据发送到服务器端,然后再去判断有 ...

  9. aws rhel 7 安装GUI ,配置VNC

    预计阅读时间:15分钟 预计配置时间:30分钟  (前提是已经申请AWS的EC2的rhel7 云主机并且成功运行) 目前AWS 亚马逊云免费试用一年,申请一个学习使用 痛点:没有GUI,无法搭建Jen ...

  10. 使用UICollectionView

    使用UICollectionView 使用UICollectionView的流程: 1. 设定一个UICollectionViewFlowLayout 2. 使用这个设定的UICollectionVi ...