Android NDK 环境搭建

最近准备研究一下在android利用opencv进行开发,那么遇到的第一个问题就是NDK的环境搭建。

网上的很多用到的cygwin什么的,其实现在不用了,Android SDK已经自带了GCC

不过如果想体验下控制台编译的装逼感,还是可以下载个cygwin或者mingw什么的。

在windows下面不推荐cygwin,我之前就是用这个遇到了些乱七八糟的环境问题,使用mingw相对问题就不多。


正文

以我自己的经验,总结一下步骤。

1.安装JDK

2.安装Android SDK,(自带ADT)

3.下载安装NDK

4.配置ADT

5.编写一个hello world。


1~3这里就省略了,这里从ADT的配置开始说起。


配置ADT

配置ADT的主要工作就是让SDK和NDK可以一起工作。

首先我们要做的是,打开ADT

然后[Window]->[Preferences]->[Android]->[NDK] 然后选择你的NDK目录,如图


这里配置完基本上就差不多了,接下来通过一个hello world来更加详细的说明。


Hello NDK

1.首先,创建一个android工程。打开Activity主文件,写下如下代码

package com.example.hellondk;

import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.widget.TextView;

public class NDKActivity extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_ndk);
		
		TextView tv = (TextView)findViewById(R.id.hello);
		tv.setText(stringFromJni(this.getClass().getName()));
		
	}
	
	public native String stringFromJni(String name);
	
	static{
		System.loadLibrary("HelloNDK");
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.ndk, menu);
		return true;
	}

}

有过jni基础的着代码一看就懂。

native修饰的方法是需要用C来实现的,loadLibrary加载的就是最后编译成型的.so文件的名称。


2.然后右击你的工程项,[Android Tools] -> [Add Native Support] ,填入之前加载的那个库名


点击[Finish]后,会在工程目录下会出现一个jni的文件夹和两个文件


这时候HelloNDK.cpp里面什么都还没有,这时我们需要使用javah来生成可用的头文件。

3.生成头文件有两种方式,一种是控制台敲指令,另一种是通过ecplise直接生成 详情点击 

这里我们使用控制台来进行。

进入到工程的根目录,输入指令

javah -classpath src -o jni/HelloNDK.h -jni com.example.hellondk.HelloNDK

说明: classpath指源文件目录,因为在根目录的缘故,所以制定src即可,-o指输出文件,如果对文件名没有要求,-d jni也是可以的,-jni可以省略,后面的类需要类全名,且不加后缀。

生成的头文件大概是这样

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_example_hellondk_NDKActivity */

#ifndef _Included_com_example_hellondk_NDKActivity
#define _Included_com_example_hellondk_NDKActivity
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_example_hellondk_NDKActivity
 * Method:    stringFromJni
 * Signature: (Ljava/lang/String;)Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_example_hellondk_NDKActivity_stringFromJni
  (JNIEnv *, jobject, jstring);

#ifdef __cplusplus
}
#endif
#endif

这里我们在具体实现的时候,最好直接从这里复制方法声明,减少出错的机会。因为你的方法的参数返回值,是否是静态的都会影响到具体函数声明的形式。

生成头文件后,我们实际上只需要方法的申明,其他的可以不用。

4.编写HelloNDK.cpp文件,下面是我代码

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

//char* to jstring
jstring stoJstring(JNIEnv* env, const char* pat)
{
       jclass strClass = env->FindClass("java/lang/String");
       jmethodID ctorID = env->GetMethodID(strClass, "<init>", "([BLjava/lang/String;)V");
       jbyteArray bytes = env->NewByteArray(strlen(pat));
       env->SetByteArrayRegion(bytes, 0, strlen(pat), (jbyte*)pat);
       jstring encoding = env->NewStringUTF("utf-8");
       return (jstring)env->NewObject(strClass, ctorID, bytes, encoding);
}

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;
}

extern "C"
{
	JNIEXPORT jstring JNICALL Java_com_example_hellondk_NDKActivity_stringFromJni
	  (JNIEnv * env, jobject obj, jstring name)
	{
		char str[128];
		char* cname = jstringTostring(env, name);

		sprintf(str,"%s say hello NDK", cname);
		jstring js = stoJstring(env, str);
		return js;
	}
}

代码有点长,前面两个函数分别是jstring到char*的转换方法,需要调用jdk的方法, 详情可下载 


需要注意的是,如果我们实现的方法没有被extern "C" 包含的话就会出现如下的错误

E/AndroidRuntime(4029): java.lang.UnsatisfiedLinkError: Native method not found: 

com.example.hellondk.NDKActivity.stringFromJni:(Ljava/lang/String;)Ljava/lang/String;

这是因为编译的问题。由于我们的文件是.cpp文件,所以这里按照c++来编译的,这样对于c风格的代码就会出现问题,更多的说明

5.ndk-build编译

将NDK的根目录加入环境变量后,我们在工程的根目录输入 ndk-build指令后即可完成编译,但实际上并不需要。ADT可以帮我们做完这些事情,现在需要的之只要运行即可。

以下是运行截图。

囧...这截图好大。


还有很多被忽略的问题,比如Android.mk文件的描述等等。.mk文件应该就是类似makefile的东西,具体的还有待之后的研究。


1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看REAdMe.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看REAdMe.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看READme.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 、 1资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看READmE.文件(md如有),本项目仅用作交流学习参考,请切勿用于商业用途。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值