NDK编程入门笔记
来源:互联网 发布:线切割编程软件win7 编辑:程序博客网 时间:2024/06/06 07:04
今天研究了一下NDK 的使用,以为写个hello world还是很简单的,竟然被一堆bug弄了几个小时。所以就详细的研究了一下,先摘一段NDK简介:
一、NDK简介
1.NDK是一系列工具的集合
NDK提供了一系列的工具,帮助开发者快速开发C(或C++)的动态库,并能自动将so和java应用一起打包成apk。这些工具对开发者的帮助是巨大的。
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++写得库可以方便在其他的嵌入式平台上再次使用。
至于开发环境搭建,这里就不说了。下面开始
1.创建一个android工程,名字随意,比如 hellondk
2. 在MainActivity中定义被调用方法,用native修饰
package com.example.hellondk;import android.app.Activity;import android.os.Bundle;import android.view.Menu;import android.view.MenuItem;import android.widget.TextView;public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); TextView tv = new TextView(this); int a = 1; int b = 3; tv.setText(getStringFromC()+"\na + b = "+add(a,b)); setContentView(tv); } //这里定义了两个方法,getStringFromC()和add(int,int) public static native int add(int a, int b); public static native String getStringFromC(); //这里被static修饰的静态代码块,在类加载时加载,会加载对应的so文 //件,上面声明的两个函数就是在这个so文件中 static { System.loadLibrary("helloc"); }}
3.项目,右键,新建jni文件夹,然后在jni中新建一个helloc.c文件
#include <string.h>#include <jni.h>/*这些函数可以用javah命令生成,这里先不讲,这个函数名很长,但是却是有 *规律的,包名com.example.hellondk,类名MainActivity,*方法名getStringFromC,以下划线分割*com.example.hellondk.MainActivity.getStringFromC*/jstringJava_com_example_hellondk_MainActivity_getStringFromC( JNIEnv* env, jobject thiz ){ return (*env)->NewStringUTF(env, "Hello C from JNI !");}jintJava_com_example_hellondk_MainActivity_add( JNIEnv* env, jobject thiz, jint a, jint b){ return a+b;}
4.项目,右键,android tools -> add native support
在jni目录下会自动新建一个Android.mk文件,内容如下:格式不用记,copy就行。helloc.c是同目录的helloc.c,helloc同System.loadLibrary(“helloc”);,这两个要保持一致
LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE := hellocLOCAL_SRC_FILES := helloc.cinclude $(BUILD_SHARED_LIBRARY)
5. 构建安装运行
我用的IDE是adt bundle加NDK,如果环境搭建正确,这个时候,就应该能 项目右键 -> build project了,我测试的,没问题,但是c/c++文件有错误,无法通过eclipse安装。貌似是bug,以为编译生成都ok了,说明没有编译错误。项目根目录下面有个bin目录,里面有刚生成的apk文件,adb install hellondk.apk,安装到手机,运行OK
到这,已经手动完成了一个简单的NDK 函数调用。
如果是C++文件呢,则有点儿小不同,具体参见这篇博客,讲的很详细
http://blog.sina.com.cn/s/blog_72a98b310100x4r6.html
为防止外部链接失效,还是把代码贴出来吧
两处差异,
- 函数块被 extern “C”{}包裹
- jstring 类型 变成 JNIEXPORT jstring JNICALL
同理jint变成JNIEXPORT jint JNICALL,等等
#include <string.h>#include <jni.h>extern "C"{ JNIEXPORT jstring JNICALL Java_com_example_hellondk_MainActivity_getStringFromC( JNIEnv* env, jobject thiz ){ return env->NewStringUTF("Hello C++ from JNI !"); } JNIEXPORT jint JNICALL Java_com_example_hellondk_MainActivity_add( JNIEnv* env, jobject thiz, jint a, jint b){ return a+b; }}
下面是另一种方式:
1. 第一步一样,在activity中声明native 方法,代码和上面第一步一样
2. 第二步,用javah生成头文件
命令格式
javah -classpath bin/classes;E:\androidsdk\platforms\android-15\android.jar -d jni com.example.hellondk.MainActivity
-classpath 指定了类路径,在这里,指定的是MainActivity的类的路径:
*.class文件就在hellondk/bin/classes/com/example/hellondk/…下面
-d 指定了自动生成的 .h文件的存放目录,最后面跟的是类的全名,即包名加类名
javah 能根据Mactivity的类文件,识别出里面声明的native方法,自动生成上面提到的超长方法名如
Java_com_example_hellondk_MainActivity_getStringFromC 和
Java_com_example_hellondk_MainActivity_add
下面看一下生成代码
/* DO NOT EDIT THIS FILE - it is machine generated */#include <jni.h>/* Header for class com_example_hellondk_MainActivity */#ifndef _Included_com_example_hellondk_MainActivity#define _Included_com_example_hellondk_MainActivity#ifdef __cplusplusextern "C" {#endif#undef com_example_hellondk_MainActivity_MODE_PRIVATE#define com_example_hellondk_MainActivity_MODE_PRIVATE 0L#undef com_example_hellondk_MainActivity_MODE_WORLD_READABLE#define com_example_hellondk_MainActivity_MODE_WORLD_READABLE 1L#undef com_example_hellondk_MainActivity_MODE_WORLD_WRITEABLE#define com_example_hellondk_MainActivity_MODE_WORLD_WRITEABLE 2L#undef com_example_hellondk_MainActivity_MODE_APPEND#define com_example_hellondk_MainActivity_MODE_APPEND 32768L#undef com_example_hellondk_MainActivity_MODE_MULTI_PROCESS#define com_example_hellondk_MainActivity_MODE_MULTI_PROCESS 4L#undef com_example_hellondk_MainActivity_BIND_AUTO_CREATE#define com_example_hellondk_MainActivity_BIND_AUTO_CREATE 1L#undef com_example_hellondk_MainActivity_BIND_DEBUG_UNBIND#define com_example_hellondk_MainActivity_BIND_DEBUG_UNBIND 2L#undef com_example_hellondk_MainActivity_BIND_NOT_FOREGROUND#define com_example_hellondk_MainActivity_BIND_NOT_FOREGROUND 4L#undef com_example_hellondk_MainActivity_BIND_ABOVE_CLIENT#define com_example_hellondk_MainActivity_BIND_ABOVE_CLIENT 8L#undef com_example_hellondk_MainActivity_BIND_ALLOW_OOM_MANAGEMENT#define com_example_hellondk_MainActivity_BIND_ALLOW_OOM_MANAGEMENT 16L#undef com_example_hellondk_MainActivity_BIND_WAIVE_PRIORITY#define com_example_hellondk_MainActivity_BIND_WAIVE_PRIORITY 32L#undef com_example_hellondk_MainActivity_BIND_IMPORTANT#define com_example_hellondk_MainActivity_BIND_IMPORTANT 64L#undef com_example_hellondk_MainActivity_BIND_ADJUST_WITH_ACTIVITY#define com_example_hellondk_MainActivity_BIND_ADJUST_WITH_ACTIVITY 128L#undef com_example_hellondk_MainActivity_CONTEXT_INCLUDE_CODE#define com_example_hellondk_MainActivity_CONTEXT_INCLUDE_CODE 1L#undef com_example_hellondk_MainActivity_CONTEXT_IGNORE_SECURITY#define com_example_hellondk_MainActivity_CONTEXT_IGNORE_SECURITY 2L#undef com_example_hellondk_MainActivity_CONTEXT_RESTRICTED#define com_example_hellondk_MainActivity_CONTEXT_RESTRICTED 4L#undef com_example_hellondk_MainActivity_RESULT_CANCELED#define com_example_hellondk_MainActivity_RESULT_CANCELED 0L#undef com_example_hellondk_MainActivity_RESULT_OK#define com_example_hellondk_MainActivity_RESULT_OK -1L#undef com_example_hellondk_MainActivity_RESULT_FIRST_USER#define com_example_hellondk_MainActivity_RESULT_FIRST_USER 1L#undef com_example_hellondk_MainActivity_DEFAULT_KEYS_DISABLE#define com_example_hellondk_MainActivity_DEFAULT_KEYS_DISABLE 0L#undef com_example_hellondk_MainActivity_DEFAULT_KEYS_DIALER#define com_example_hellondk_MainActivity_DEFAULT_KEYS_DIALER 1L#undef com_example_hellondk_MainActivity_DEFAULT_KEYS_SHORTCUT#define com_example_hellondk_MainActivity_DEFAULT_KEYS_SHORTCUT 2L#undef com_example_hellondk_MainActivity_DEFAULT_KEYS_SEARCH_LOCAL#define com_example_hellondk_MainActivity_DEFAULT_KEYS_SEARCH_LOCAL 3L#undef com_example_hellondk_MainActivity_DEFAULT_KEYS_SEARCH_GLOBAL#define com_example_hellondk_MainActivity_DEFAULT_KEYS_SEARCH_GLOBAL 4L/* * Class: com_example_hellondk_MainActivity * Method: add * Signature: (II)I */JNIEXPORT jint JNICALL Java_com_example_hellondk_MainActivity_add (JNIEnv *, jclass, jint, jint);#ifdef __cplusplus}#endif#endif
上面的大量的宏,忽视它们,重点是最后几行那个函数,很眼熟对不对。
是的,他就是自动生成的,上文中我们手动拼写的那个函数。
有了它,我们就不用在手动拼写,避免错误。
然后,在同目录(jni)下面新建文件helloc.c,记得include这个头文件
helloc.c的内容上文已经贴出,除了引用头文件,其他一样。
3.ndk-build编译c/c++文件
Android.mk文件和上面一样
cmd进入项目根目录,ndk-build开始编译C/C++文件。如果成功,项目会多出一个文件夹obj,里面就是so文件libhelloc.so,lib + helloc+.so
4.构建安装运行
项目右键,run as Android Applecation
如果还是build正常,但是运行app时显示C/C++有错误,还是手动命令行安装吧,这些bug太头大
因为捉bug弄了一下午,有些问题估计是确实ndk本身的问题,就先搁置了。以后在研究:
- 不知道为什么,有时用javah 生成的.h头文件会不一样。比如下面这个
为节省控件,我把宏和一些注释删除了
/* DO NOT EDIT THIS FILE - it is machine generated */#include <jni.h>#ifdef __cplusplusextern "C" {#endifJNIEXPORT jstring JNICALL Java_com_example_hellondk3_MainActivity_getStringFromC (JNIEnv *, jobject);#ifdef __cplusplus}#endif
2.项目编译生成OK,手动安装到手机运行演示OK,但是C/C++文件在IDE报错误,是bug,还是环境配置问题
代码下载
- NDK编程入门笔记
- NDK编程入门笔记
- NDK编程入门笔记
- NDK编程入门笔记
- Android: NDK编程入门笔记
- Android: NDK编程入门笔记
- Android NDK编程入门笔记
- Android: NDK编程入门笔记
- Android NDK编程入门笔记
- Android: NDK编程入门笔记
- Android: NDK编程入门笔记
- Android: NDK编程入门笔记
- Android: NDK编程入门笔记
- Android: NDK编程入门笔记
- Android: NDK编程入门笔记
- Android: NDK编程入门笔记
- Android: NDK编程入门笔记
- Android-NDK编程入门笔记
- 扔鸡蛋问题(Egg Dropping Puzzle)
- 最流行框架---viewpager,fragment完美结合
- 简单的菜单,进行修改menu4
- mysql误删除恢复
- 黑马程序员——【学习笔记】集合——String、StringBuffer 以及集合
- NDK编程入门笔记
- JS仿IOS风格对话框源码范例
- Hibernate使用中sessionFactory的获取以及问题解决
- 对当前主流hybrid app、web app与native app工具的初步比较与分析
- jquery特效(3)—轮播图①(手动点击轮播)
- KVO入门介绍
- Android 学习之路一:Activity之间传递数据的四种方式
- 将java程序作为Windows服务
- 每天一个linux命令(11):nl命令