Android NDK开发(一)环境搭建及运行示例
2015-08-21 10:48
597 查看
转载:/article/1324878.html
/***************************************************
* TODO: description .
* @author: gao_chun
* @since: 2015-3-30
* @version: 1.0.0
*@remark: 转载请注明出处
**************************************************/
下载Android开发工具,这里使用Eclipse,若无法下载,可查看
Android官网无法下载eclipse-adt-bundle:/article/1476901.html
下载后若Android SDK无法正常更新,可查看
Android
SDK无法更新终极解决方式:[b]http://blog.csdn.net/gao_chun/article/details/37971461[/b]
在android ndk r7之后,已经不用下载安装Cygwin(模拟Linux环境),在以往的NDK开发中必须要下载,且需下载CDT(Eclipse
C/C++开发插件),还要配置编译器,环境变量,等等。太过于麻烦。
一、介绍下NDK是什么东西
1.NDK是一系列工具的集合
NDK提供了一系列的工具,帮助开发者快速开发C(或C++)的动态库,并能自动将so和java应用一起打包成apk。这些工具对开发者的帮助是巨大的。NDK集成了交叉编译器,并提供了相应的mk文件隔离CPU、平台、ABI等差异,开发人员只需要简单修改mk文件(指出“哪些文件需要编译”、“编译特性要求”等),就可以创建出so。NDK可以自动地将so和Java应用一起打包,极大地减轻了开发人员的打包工作。
2.NDK提供了一份稳定、功能有限的API头文件声明
Google明确声明该API是稳定的,在后续所有版本中都稳定支持当前发布的API。从该版本的NDK中看出,这些API支持的功能非常有限,包含有:C标准库(libc)、标准数学库(libm)、压缩库(libz)、Log库(liblog)。
二、为什么使用NDK
1.代码的保护。由于apk的java层代码很容易被反编译,而C/C++库反汇难度较大。
2.可以方便地使用现存的开源库。大部分现存的开源库都是用C/C++代码编写的。
3.提高程序的执行效率。将要求高性能的应用逻辑使用C开发,从而提高应用程序的执行效率。
4.便于移植。用C/C++写得库可以方便在其他的嵌入式平台上再次使用。
三、下载NDK之后,解压便可
![](http://img.blog.csdn.net/20150330165013655?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZ2FvX2NodW4=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
注:1.在android-ndk-r10c目录下有一个samples的目录,里面存放着例子,可供学习。
2.注意NDK的环境变量,如:
![](http://img.blog.csdn.net/20150330170030524?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZ2FvX2NodW4=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
四、在Eclipse的Window->Preferences->Android->NDK,设置NDK路径,例如:
![](http://img.blog.csdn.net/20150330165454406?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZ2FvX2NodW4=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
注:需检查ADT插件是否安装了Android Native Delelopment Tools(可在Eclipse - Help - Install new Software中检查)
五、新建一个Android工程后,在new出来的Project上右键点击Android Tools->Add Native Support...给库文件(.so)取个名字,如:hello
![](http://img.blog.csdn.net/20150330170404931?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZ2FvX2NodW4=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
这时你会发现工程会多一个jni的文件夹,jni下有Android.mk和hello.cpp文件。
Android.mk是NDK工程的Makefile,hello.cpp就是NDK的源文件。
有关Android.mk文件的介绍:http://blog.csdn.net/gao_chun/article/details/44656169
六、我们在hello.cpp中写下如下代码,可以参考samples目录中的hello-jni例子。
[cpp]
view plaincopyprint?
![](https://code.csdn.net/assets/CODE_ico.png)
![](https://code.csdn.net/assets/ico_fork.svg)
#include <jni.h>
extern "C" {
JNIEXPORT jstring JNICALL Java_com_hello_Main_stringFromJNI(JNIEnv *env,
jobject thiz) {
return env->NewStringUTF("Hello jni");
}
}
C代码中是:
return (*env)->NewStringUTF(env,"Hello jni!");
C++代码是:
return env->NewStringUTF("Hello jni!");
JNI接口的命名规范是:Java_
+ 调用该方法的包名(包名的点用_代替) +_ +调用该接口的类名
+_ +方法名,对于实例方法,有两个参数是必要的,一个JNI的环境指针
JNIEnv *,另一个是调用该方法的Java实例
jobject
这里需要注意一点,按照如下的方式写,在程序运行后是报错的(注:是程序运行后会报错,不是该文件有错,该文件有错是因为java编辑器没有安装支持C/C++的插件所导致,在该文件编写完成后可以colse项目从新打开便可,或者clean):
![](http://img.blog.csdn.net/20150330171338500?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZ2FvX2NodW4=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
报错信息如下:
![](http://img.blog.csdn.net/20150330171648755?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZ2FvX2NodW4=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
总结:使用extern "C"修饰,编译器会按C语言的方式编译和连接。在C语言中,函数编译之后函数名与C++函数编译之后不同,例如foo(int x, int y),C可能会编译成
_foo 的名字,而C++因为支持重载,所以会编译成像
_foo_int_int 这种带参数的函数名。如果是按照C语言的编译方式,调用foo函数是找不到_foo的函数名就会报出函数名找不到的错误。所以要添加extern "
C "修饰。
七、Main.java :
[java]
view plaincopyprint?
![](https://code.csdn.net/assets/CODE_ico.png)
![](https://code.csdn.net/assets/ico_fork.svg)
package com.hello;
import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;
public class Main
extends Activity {
//静态方法优先加载
static {
System.loadLibrary("hello");
}
//声明jni层的原生方法,使用native关键字
public native String stringFromJNI();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TextView tv = new TextView(this);
tv.setText(stringFromJNI());
setContentView(tv);
}
}
注:static代码块里面用System.loadLaibrary加载的是编译器编译完成后的.so库,并非hello.cpp文件。
八、完成,运行就ok。
![](http://img.blog.csdn.net/20150330174811931?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZ2FvX2NodW4=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
运行之前先编译NDK,然后在编译J***A代码。编译也许会遇到Unable to launch cygpath. Is Cygwin on the path?
错误,解决办法如下:
1.工程右键,点Properties->C/C++ Build的Building Settings 中去掉Use
default build command,然后输入${NDKROOT}/ndk-build.cmd
![](http://img.blog.csdn.net/20150330172903597?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZ2FvX2NodW4=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
2.在C/C++ Build中点击Environment,点Add...添加环境变量NDKROOT,值为NDK的根目录
![](http://img.blog.csdn.net/20150330174116078?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZ2FvX2NodW4=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
3.再编译就ok!
如果觉得文章对你有用,点个赞将是我最大的动力!
/***************************************************
* TODO: description .
* @author: gao_chun
* @since: 2015-3-30
* @version: 1.0.0
*@remark: 转载请注明出处
**************************************************/
下载Android开发工具,这里使用Eclipse,若无法下载,可查看
Android官网无法下载eclipse-adt-bundle:/article/1476901.html
下载后若Android SDK无法正常更新,可查看
Android
SDK无法更新终极解决方式:[b]http://blog.csdn.net/gao_chun/article/details/37971461[/b]
在android ndk r7之后,已经不用下载安装Cygwin(模拟Linux环境),在以往的NDK开发中必须要下载,且需下载CDT(Eclipse
C/C++开发插件),还要配置编译器,环境变量,等等。太过于麻烦。
一、介绍下NDK是什么东西
1.NDK是一系列工具的集合
NDK提供了一系列的工具,帮助开发者快速开发C(或C++)的动态库,并能自动将so和java应用一起打包成apk。这些工具对开发者的帮助是巨大的。NDK集成了交叉编译器,并提供了相应的mk文件隔离CPU、平台、ABI等差异,开发人员只需要简单修改mk文件(指出“哪些文件需要编译”、“编译特性要求”等),就可以创建出so。NDK可以自动地将so和Java应用一起打包,极大地减轻了开发人员的打包工作。
2.NDK提供了一份稳定、功能有限的API头文件声明
Google明确声明该API是稳定的,在后续所有版本中都稳定支持当前发布的API。从该版本的NDK中看出,这些API支持的功能非常有限,包含有:C标准库(libc)、标准数学库(libm)、压缩库(libz)、Log库(liblog)。
二、为什么使用NDK
1.代码的保护。由于apk的java层代码很容易被反编译,而C/C++库反汇难度较大。
2.可以方便地使用现存的开源库。大部分现存的开源库都是用C/C++代码编写的。
3.提高程序的执行效率。将要求高性能的应用逻辑使用C开发,从而提高应用程序的执行效率。
4.便于移植。用C/C++写得库可以方便在其他的嵌入式平台上再次使用。
三、下载NDK之后,解压便可
注:1.在android-ndk-r10c目录下有一个samples的目录,里面存放着例子,可供学习。
2.注意NDK的环境变量,如:
四、在Eclipse的Window->Preferences->Android->NDK,设置NDK路径,例如:
注:需检查ADT插件是否安装了Android Native Delelopment Tools(可在Eclipse - Help - Install new Software中检查)
五、新建一个Android工程后,在new出来的Project上右键点击Android Tools->Add Native Support...给库文件(.so)取个名字,如:hello
这时你会发现工程会多一个jni的文件夹,jni下有Android.mk和hello.cpp文件。
Android.mk是NDK工程的Makefile,hello.cpp就是NDK的源文件。
有关Android.mk文件的介绍:http://blog.csdn.net/gao_chun/article/details/44656169
六、我们在hello.cpp中写下如下代码,可以参考samples目录中的hello-jni例子。
[cpp]
view plaincopyprint?
![](https://code.csdn.net/assets/CODE_ico.png)
#include <jni.h>
extern "C" {
JNIEXPORT jstring JNICALL Java_com_hello_Main_stringFromJNI(JNIEnv *env,
jobject thiz) {
return env->NewStringUTF("Hello jni");
}
}
#include <jni.h> extern "C" { JNIEXPORT jstring JNICALL Java_com_hello_Main_stringFromJNI(JNIEnv *env, jobject thiz) { return env->NewStringUTF("Hello jni"); } }
C代码中是:
return (*env)->NewStringUTF(env,"Hello jni!");
C++代码是:
return env->NewStringUTF("Hello jni!");
JNI接口的命名规范是:Java_
+ 调用该方法的包名(包名的点用_代替) +_ +调用该接口的类名
+_ +方法名,对于实例方法,有两个参数是必要的,一个JNI的环境指针
JNIEnv *,另一个是调用该方法的Java实例
jobject
这里需要注意一点,按照如下的方式写,在程序运行后是报错的(注:是程序运行后会报错,不是该文件有错,该文件有错是因为java编辑器没有安装支持C/C++的插件所导致,在该文件编写完成后可以colse项目从新打开便可,或者clean):
报错信息如下:
总结:使用extern "C"修饰,编译器会按C语言的方式编译和连接。在C语言中,函数编译之后函数名与C++函数编译之后不同,例如foo(int x, int y),C可能会编译成
_foo 的名字,而C++因为支持重载,所以会编译成像
_foo_int_int 这种带参数的函数名。如果是按照C语言的编译方式,调用foo函数是找不到_foo的函数名就会报出函数名找不到的错误。所以要添加extern "
C "修饰。
七、Main.java :
[java]
view plaincopyprint?
![](https://code.csdn.net/assets/CODE_ico.png)
package com.hello;
import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;
public class Main
extends Activity {
//静态方法优先加载
static {
System.loadLibrary("hello");
}
//声明jni层的原生方法,使用native关键字
public native String stringFromJNI();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TextView tv = new TextView(this);
tv.setText(stringFromJNI());
setContentView(tv);
}
}
package com.hello; import android.app.Activity; import android.os.Bundle; import android.widget.TextView; public class Main extends Activity { //静态方法优先加载 static { System.loadLibrary("hello"); } //声明jni层的原生方法,使用native关键字 public native String stringFromJNI(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); TextView tv = new TextView(this); tv.setText(stringFromJNI()); setContentView(tv); } }
注:static代码块里面用System.loadLaibrary加载的是编译器编译完成后的.so库,并非hello.cpp文件。
八、完成,运行就ok。
运行之前先编译NDK,然后在编译J***A代码。编译也许会遇到Unable to launch cygpath. Is Cygwin on the path?
错误,解决办法如下:
1.工程右键,点Properties->C/C++ Build的Building Settings 中去掉Use
default build command,然后输入${NDKROOT}/ndk-build.cmd
2.在C/C++ Build中点击Environment,点Add...添加环境变量NDKROOT,值为NDK的根目录
3.再编译就ok!
如果觉得文章对你有用,点个赞将是我最大的动力!
相关文章推荐
- Android之使用ThumbnailUtils类来获取视频第一帧缩略图
- Android 看过的 不错的文章 嘎嘎
- Android布局的优化方案汇总
- Android布局的优化方案汇总
- Android Service浅谈
- android学习笔记 是用显示和隐式的Intent 跳转界面
- Android性能优化之数据库优化
- Android性能优化之数据库优化
- Android开发优化之——从代码角度进行优化
- Android开发优化之——从代码角度进行优化
- android 5.0开发环境搭建
- Android之ListView原理学习与优化总结
- Android之ListView原理学习与优化总结
- Android中Drawable分类汇总(上)
- android--textView添加html超链接响应
- 关于Android中fragment中创建popwindow全屏显示时手机状态遮挡popwindow的问题
- android:修改PagerTabStrip中的背景颜色,标题字体的样式、颜色和图标以及指示条的颜色
- android应用:startActivityForResult使用实例
- Android 开源框架Volley完全解析,Volley的基本用法。
- android EditText 有边框 透明样式