Android NDK 环境搭建 之 起始篇NDK HelloWorld
ADT插件:管理Android SDK和相关的开发工具的
NDK插件:用于开发Android NDK的插件,ADT版本在20以上,就能安装NDK插件,另外NDK集成了CDT插件(所以本文直接针对ADT 20以上版本进行说明)
到Android官网下载最新的NDK,注:NDK版本在r7以上之后就集成了Cygwin,而且还是十分精简版。比起下载Cygwin要方便多啦(Cygwin以前需要单独安装和配置,现在已被集成)!
下载链接见:http://developer.android.com/tools/sdk/ndk/index.html
下载完成之后,解压搞定。
解压后的目录结构如下图所示:
打开Eclipse,点Window->Preferences->Android->NDK,设置NDK路径,例如我的是:D:\Android\android-ndk_r10-windows
新建一个Android工程,在工程上右键点击Android Tools->Add Native Support… ,然后给我们的.so文件取个名字,例如我的是:XS_NDK_01
这时候工程就会多一个jni的文件夹,jni下有Android.mk和XS_NDK_01.cpp文件。Android.mk是NDK工程的Makefile,XS_NDK_01.cpp就是NDK的源文件。
(关于 Android.mk 的说明可以参考资料:http://www.cnblogs.com/luxiaofeng54/archive/2011/08/13/2137577.html)
JNI接口的命名规范是:Java_ + 调用该方法的包名(包名的点用代替) + + 调用该接口的类名 + _ + 方法名,对于实例方法,有两个参数是必要的,一个JNI的环境指针JNIEnv *,另一个是调用该方法的Java实例jobject
接下来编辑XS_NDK_01.cpp文件,写一个HelloWorld的demo,代码如下:
#include <string.h>
#include <jni.h>
extern "C"{
jstring
Java_com_shanhy_example_ndk01_MainActivity_getStringFromJNI(JNIEnv* env, jobject thiz)
{
//返回一个字符串给Java层
return env->NewStringUTF("小单 的 JNI HellWorld 程序.");
}
}
完成了,然后运行。运行之前先编译NDK,然后在编译JAVA代码。编译也许会遇到Unable to launch cygpath. Is Cygwin on the path?如何解决?
Eclipse -> Window -> Preperences -> C/C++ -> Build -> Environment 添加一个环境变量NDKROOT,如下图:
再工程右键,点Properties->C/C++ Build的Building Settings中去掉Use default build command,然后输入${NDKROOT}/ndk-build.cmd,如下图:
然后创建一个Activity调用我们刚刚编写的HelloWorld,代码如下:
package com.shanhy.example.ndk01;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
/**
* HelloWorld NDK 开发
*
* @author SHANHY(aaa@qq.com)
* @date 2015年11月19日
*/
public class MainActivity extends Activity {
//也就是你mk配置文件中的 LOCAL_MODULE := XS_NDK_01
private static final String libSoName = "XS_NDK_01";
private Context mContext = null;
private Button btnClick = null;
private String mStrMSG = null;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mContext = this;
btnClick = (Button) findViewById(R.id.btn_click);
btnClick.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
//调用 JNI 层实现的方法
mStrMSG = getStringFromJNI();
if(mStrMSG == null) {
mStrMSG = "调用JNI失败";
}
LogUtils.toastMessage(mContext, mStrMSG);
}
});
}
/**
* 声明本地方法
*
* 该方法为native方法.由C实现
*
* @return JNI 给出的信息
*/
public native String getStringFromJNI();
/**
* 载入JNI生成的so库文件
*/
static {
System.loadLibrary(libSoName);
}
}
至此,我们就完成了一个简单的例子,如需更进一步对NDK进行开发,请查阅相关资料。
=====================================
下面几种可能出现的错误的解决方案(如果直接按我上面的例子,是不会出现下面的错误的):
1、Method ‘NewStringUTF’ could not be resolved 问题(方法“NewStringUTF”无法被解析)
原因:
I had this issue. Based on my "solution," it seems to be something funny going on in Eclipse, since I had another project open with (as far as I was able to tell) the exact some properties, paths, etc., besides for being labeled a Library Project.
Just by observing the corresponding struct in jhi.h, the callback prototypes are all there! Ctrl-click the include statement and Eclipse will even link you the reference!
Go to the project's Properties -> C/C++ General -> Code Analysis. Click the "Use project settings" radio button (or "Configure Workspace Settings..." button). Disable (uncheck) the "Method cannot be resolved" checkbox. Click "Apply," "OK." Then for your project, refresh, clean, refresh, build.
There must have been something I did differently in creating the new project. Or maybe it was because of the locations of the projects, or the fact that the previous was a Library. Maybe it really is an Eclipse bug? For reference, I'm using ADT v21.1.0-569685 and NDK r8e for Windows。
项目右键->Properties->C/C++General->Code Analysis,选择”Use project settings或者Use workspace settings” 中的 Method cannot be resolved(方法无法被解析)取消选择,应用->保存,然后刷新、清理、刷新、build项目。
2、jni/hellocpp/main.cpp:16:18: error: base operand of ‘->’ has non-pointer type ‘JNIEnv {aka _JNIEnv}’ 问题
这是 android java 调用c++程序时报的错误
文件 XS_NDK_01.cpp 文件代码,按如下方式编写出现的错误:
#include <string.h>
#include <jni.h>
jstring
Java_com_duicky_MainActivity_getStringFromJNI( JNIEnv* env,jobject thiz )
{
// 返回一个字符串给Java层
return (*env)->NewStringUTF(env, "HelloWorld from JNI !!");
// return env->NewStringUTF("小单 的 JNI HellWorld 程序.");
}
错误在于:
我开始是 (*env)->NewStringUTF(env, “小单 的 JNI HellWorld 程序.”); 这样写的,这是c的写法(文件应该是.c扩展名),而我的是cpp程序(.cpp扩展名),需要改写成:
env->NewStringUTF( “小单 的 JNI HellWorld 程序.”);
3、 java.lang.UnsatisfiedLinkError: Native method not found: com.shanhy.example.ndk01.MainActivity.getStringFromJNI:()Ljava/lang/String; 错误
有可能是:
1、c++中的方法Java_xxx_xxx 中的Java 首字母一定要大写
2、如果是 .cpp 文件 则用 extern “C” {“您的方法在这里”},大括号里是您的本地方法(如我上面的例子中那样写)。