JNI及Android JNI 开发基本知识和具体操作步骤
2012-11-12 16:52
441 查看
转自:http://doandroid.info/jni_and_android_jni_details/
目录:
1 JNI基础知识
2 Android中的JNI
3 我们在写JNI时候,一些容易出现的问题
4 Android中一个简单的例子
5 Android中交叉编译最新版libjpeg-8d的例子
6 C++编写JNI的不同之处
7 后记
8 参考文章
1 JNI基础知识
JNI是Java native interface的简写,可以译作Java原生接口。Java可以通过JNI调用C/C++的库,这对于那些对性能要求比较高的Java程序无疑是一个福音。
在Sun的官方提供了一个详细的文档,关于Java中JNI的基本对象方法以及使用说明。英文好的兄弟可以下载下来直接看。从开发的角度,基本差不多,问题的关键是语法、资源的释放、复杂对象的传递问题。
中文版相关下载地址:http://download.csdn.net/detail/ZFZF294990051/3477828
本文附上本地下载:
jni.doc.tar
JNI开发的基本步骤见下图(请单独点击打开):
2 Android中的JNI
Android中使用JNI,是Android NDK编程的一个媒介,在开发中,Android的版本必须高于1.5才可以使用JNI编程。当然,现在市面上的机器都满足。
其基本的使用方式为:
使用上面的定义后,我们就可一像使用本地的java类函数一样调用Hello了,这个函数返回String对象。
这里需要提到的一点就是在JNI里面,有两个很重要的函数
上面的函数是指如果我们需要在加载SO库或者释放SO库的时候,需要额外处理,可以加在这里。
在Android中,我们如果编译了一个APK,可以使用javah 自动生成相应的JNI的C实现头文件。但是,跟单独使用javac编译文件不同的时候,我们需要额外指定android.jar库的路径。否则会出现奇怪的错误。下面是两个典型的错误。
当我们编译完毕后,使用 javah com.jouhu.HelloWorld,会出现如下错误:
Error: Could not find class file for ‘com.jouhu.HelloWorld’.
解决办法:
javah -classpath /root/workspace/HelloWorld/bin/classes com.jouhu.HelloWorld
请注意,由于我们Android编译后,会将.class文件放到classes目录下面,如果我们在bin目录下,执行,还会报上面的错误的。这里非常关键。
当我们使用上面的方法编译后,出现如下错误:
Error: cannot access android.app.Activity
class file for android.app.Activity not found
解决方法,附加android.jar库的地址:
javah -classpath /opt/android-sdk-linux/platforms/android-8/android.jar:/root/workspace/HelloWorld/bin/classes com.jouhu.HelloWorld
至此,我们就会生成文件com_jouhu_HelloWorld.h
接下来,我们就可以根据定义,去实现printJNI函数了。
这里还有一个问题需要注意的就是:
我们使用NDK-Build生成的文件是libhelloworld.so,我们在使用System.loadLibrary的时候,参数只需要到helloworld,而不需要把lib和.so加上。
编写Android.mk文件
3 我们在写JNI时候,一些容易出现的问题,参考文章
内存释放,各种类型数据的转换
jbytearray转c++byte数组
jbyteArray 转 c++中的BYTE[]
char* 转jstring
jbyteArray 转 char *
更多的请参考原文,本文仅摘录部分用的比较多的。
4 Android中一个简单的例子
4.1 使用Eclipse创建一个HelloWorld的Activity的程序。
4.2 在虚拟机中运行一次,系统会在/root/workspace/HelloWorld/bin/classes/com/jouhu目录生成相应的class文件
4.3 进入命令行的/root/workspace/HelloWorld/bin目录
执行
javah -classpath /opt/android-sdk-linux/platforms/android-8/android.jar:/root/workspace/HelloWorld/bin/classes com.jouhu.HelloWorld
4.4 将会在/bin目录生成一个com_jouhu_HelloWorld.h文件
4.5 在/root/workspace/HelloWorld目录建立jni目录
4.6 将刚才生成的com_jouhu_HelloWorld.h拷贝到jni目录下
4.7 创建com_jouhu_HelloWorld.cpp文件
4.8 创建 Android.mk文件
4.9 打开命令行 进入目录/root/workspace/HelloWorld/jni
4.10 执行ndk-build
4.11 结果
4.12 adb install HelloWorld.apk 即可看到结果了。
5 Android中交叉编译libjpeg的例子
5.1 下载最新的jpeg-8d源代码
5.2 创建Android Project
5.3 编写native加载函数代码
5.4 虚拟机中执行程序(主要目的是为了生成class文件)
5.5 使用javah生成.h文件
javah -classpath /opt/android-sdk-linux/platforms/android-8/android.jar:/root/workspace/AndroidJpeg8D/bin/classes com.jouhu.AndroidJpeg8DActivity
5.6 拷贝生成的com_jouhu_AndroidJpeg8DActivity.h文件到项目的jni目录,并编写.cpp文件
5.7 编写Android.mk文件(在jni目录一个Android.mk以及jpeg-8d目录的Android.mk)
jni目录的Android.mk文件
jpeg-8d/Android.mk
注意上面LOCAL_SRC_FILES的所有文件从jpeg-8d目录下的Makefile中拷贝而来,不是自己敲上去的,这样可以保证不会又问题。
5.8 ndk-build编译
root@ubuntu:~/workspace/AndroidJpeg8D/jni# ndk-build
Compile arm : jpeg <= jaricom.c
Compile arm : jpeg <= jcapimin.c
Compile arm : jpeg <= jcapistd.c
Compile arm : jpeg <= jcarith.c
Compile arm : jpeg <= jccoefct.c
Compile arm : jpeg <= jccolor.c
Compile arm : jpeg <= jcdctmgr.c
Compile arm : jpeg <= jchuff.c
Compile arm : jpeg <= jcinit.c
Compile arm : jpeg <= jcmainct.c
Compile arm : jpeg <= jcmarker.c
Compile arm : jpeg <= jcmaster.c
Compile arm : jpeg <= jcomapi.c
Compile arm : jpeg <= jcparam.c
Compile arm : jpeg <= jcprepct.c
Compile arm : jpeg <= jcsample.c
Compile arm : jpeg <= jctrans.c
Compile arm : jpeg <= jdapimin.c
Compile arm : jpeg <= jdapistd.c
Compile arm : jpeg <= jdarith.c
Compile arm : jpeg <= jdatadst.c
Compile arm : jpeg <= jdatasrc.c
Compile arm : jpeg <= jdcoefct.c
Compile arm : jpeg <= jdcolor.c
Compile arm : jpeg <= jddctmgr.c
Compile arm : jpeg <= jdhuff.c
Compile arm : jpeg <= jdinput.c
Compile arm : jpeg <= jdmainct.c
Compile arm : jpeg <= jdmarker.c
Compile arm : jpeg <= jdmaster.c
Compile arm : jpeg <= jdmerge.c
Compile arm : jpeg <= jdpostct.c
Compile arm : jpeg <= jdsample.c
Compile arm : jpeg <= jdtrans.c
Compile arm : jpeg <= jerror.c
Compile arm : jpeg <= jfdctflt.c
Compile arm : jpeg <= jfdctfst.c
Compile arm : jpeg <= jfdctint.c
Compile arm : jpeg <= jidctflt.c
Compile arm : jpeg <= jidctfst.c
Compile arm : jpeg <= jidctint.c
Compile arm : jpeg <= jquant1.c
Compile arm : jpeg <= jquant2.c
Compile arm : jpeg <= jutils.c
Compile arm : jpeg <= jmemmgr.c
StaticLibrary : libjpeg.a
SharedLibrary : libjpegtest.so
Install : libjpegtest.so => libs/armeabi/libjpegtest.so
5.9 执行
5.10 可以使用libjpeg库了
6 C++编写JNI的不同之处
具体可以参考Simon的文章和这篇。
在Android自身的调用中,大都采用这种方式。
7 后记
很早就想写这篇文章,碍于一些事情,耽搁了很久,另外,本文也仅仅是涵盖了一些基本和简单的方面。很多深入的地方,还有待继续探讨,如果有什么更好的建议,欢迎提出。本文很多知识也是来自网络整理,这里需要特别感谢simon兄的文章。另外要说明的就是,在我们的ndk目录里面有一些例子,大家可以参考。本文对应的目录为/opt/android-ndk-r7b/samples
目录:
1 JNI基础知识
2 Android中的JNI
3 我们在写JNI时候,一些容易出现的问题
4 Android中一个简单的例子
5 Android中交叉编译最新版libjpeg-8d的例子
6 C++编写JNI的不同之处
7 后记
8 参考文章
1 JNI基础知识
JNI是Java native interface的简写,可以译作Java原生接口。Java可以通过JNI调用C/C++的库,这对于那些对性能要求比较高的Java程序无疑是一个福音。
在Sun的官方提供了一个详细的文档,关于Java中JNI的基本对象方法以及使用说明。英文好的兄弟可以下载下来直接看。从开发的角度,基本差不多,问题的关键是语法、资源的释放、复杂对象的传递问题。
中文版相关下载地址:http://download.csdn.net/detail/ZFZF294990051/3477828
本文附上本地下载:
jni.doc.tar
JNI开发的基本步骤见下图(请单独点击打开):
2 Android中的JNI
Android中使用JNI,是Android NDK编程的一个媒介,在开发中,Android的版本必须高于1.5才可以使用JNI编程。当然,现在市面上的机器都满足。
其基本的使用方式为:
1 2 3 4 5 6 | static { System.loadLibrary("HelloWorld"); } private native String Hello(); |
这里需要提到的一点就是在JNI里面,有两个很重要的函数
在Android中,我们如果编译了一个APK,可以使用javah 自动生成相应的JNI的C实现头文件。但是,跟单独使用javac编译文件不同的时候,我们需要额外指定android.jar库的路径。否则会出现奇怪的错误。下面是两个典型的错误。
当我们编译完毕后,使用 javah com.jouhu.HelloWorld,会出现如下错误:
Error: Could not find class file for ‘com.jouhu.HelloWorld’.
解决办法:
javah -classpath /root/workspace/HelloWorld/bin/classes com.jouhu.HelloWorld
请注意,由于我们Android编译后,会将.class文件放到classes目录下面,如果我们在bin目录下,执行,还会报上面的错误的。这里非常关键。
当我们使用上面的方法编译后,出现如下错误:
Error: cannot access android.app.Activity
class file for android.app.Activity not found
解决方法,附加android.jar库的地址:
javah -classpath /opt/android-sdk-linux/platforms/android-8/android.jar:/root/workspace/HelloWorld/bin/classes com.jouhu.HelloWorld
至此,我们就会生成文件com_jouhu_HelloWorld.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | /* DO NOT EDIT THIS FILE - it is machine generated */ #include /* Header for class com_jouhu_HelloWorld */ #ifndef _Included_com_jouhu_HelloWorld #define _Included_com_jouhu_HelloWorld #ifdef __cplusplus extern "C" { #endif #undef com_jouhu_HelloWorld_MODE_PRIVATE #define com_jouhu_HelloWorld_MODE_PRIVATE 0L #undef com_jouhu_HelloWorld_MODE_WORLD_READABLE #define com_jouhu_HelloWorld_MODE_WORLD_READABLE 1L #undef com_jouhu_HelloWorld_MODE_WORLD_WRITEABLE #define com_jouhu_HelloWorld_MODE_WORLD_WRITEABLE 2L #undef com_jouhu_HelloWorld_MODE_APPEND #define com_jouhu_HelloWorld_MODE_APPEND 32768L #undef com_jouhu_HelloWorld_BIND_AUTO_CREATE #define com_jouhu_HelloWorld_BIND_AUTO_CREATE 1L #undef com_jouhu_HelloWorld_BIND_DEBUG_UNBIND #define com_jouhu_HelloWorld_BIND_DEBUG_UNBIND 2L #undef com_jouhu_HelloWorld_BIND_NOT_FOREGROUND #define com_jouhu_HelloWorld_BIND_NOT_FOREGROUND 4L #undef com_jouhu_HelloWorld_CONTEXT_INCLUDE_CODE #define com_jouhu_HelloWorld_CONTEXT_INCLUDE_CODE 1L #undef com_jouhu_HelloWorld_CONTEXT_IGNORE_SECURITY #define com_jouhu_HelloWorld_CONTEXT_IGNORE_SECURITY 2L #undef com_jouhu_HelloWorld_CONTEXT_RESTRICTED #define com_jouhu_HelloWorld_CONTEXT_RESTRICTED 4L #undef com_jouhu_HelloWorld_RESULT_CANCELED #define com_jouhu_HelloWorld_RESULT_CANCELED 0L #undef com_jouhu_HelloWorld_RESULT_OK #define com_jouhu_HelloWorld_RESULT_OK -1L #undef com_jouhu_HelloWorld_RESULT_FIRST_USER #define com_jouhu_HelloWorld_RESULT_FIRST_USER 1L #undef com_jouhu_HelloWorld_DEFAULT_KEYS_DISABLE #define com_jouhu_HelloWorld_DEFAULT_KEYS_DISABLE 0L #undef com_jouhu_HelloWorld_DEFAULT_KEYS_DIALER #define com_jouhu_HelloWorld_DEFAULT_KEYS_DIALER 1L #undef com_jouhu_HelloWorld_DEFAULT_KEYS_SHORTCUT #define com_jouhu_HelloWorld_DEFAULT_KEYS_SHORTCUT 2L #undef com_jouhu_HelloWorld_DEFAULT_KEYS_SEARCH_LOCAL #define com_jouhu_HelloWorld_DEFAULT_KEYS_SEARCH_LOCAL 3L #undef com_jouhu_HelloWorld_DEFAULT_KEYS_SEARCH_GLOBAL #define com_jouhu_HelloWorld_DEFAULT_KEYS_SEARCH_GLOBAL 4L /* * Class: com_jouhu_HelloWorld * Method: printJNI * Signature: ()Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_com_jouhu_HelloWorld_printJNI (JNIEnv *, jobject); #ifdef __cplusplus } #endif #endif |
我们使用NDK-Build生成的文件是libhelloworld.so,我们在使用System.loadLibrary的时候,参数只需要到helloworld,而不需要把lib和.so加上。
编写Android.mk文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | //一般都是这行 LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) //代码文件 LOCAL_SRC_FILES:=com_jouhu_HelloWorld.c //包含的头文件 LOCAL_C_INCLUDES := $(JNI_H_INCLUDE) //生成的so库名称 LOCAL_MODULE := libhelloworld LOCAL_SHARED_LIBRARIES := libutils LOCAL_PRELINK_MODULE := false include $(BUILD_SHARED_LIBRARY) |
内存释放,各种类型数据的转换
jbytearray转c++byte数组
4 Android中一个简单的例子
4.1 使用Eclipse创建一个HelloWorld的Activity的程序。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | package com.jouhu; import android.app.Activity; import android.os.Bundle; import android.util.Log; public class HelloWorld extends Activity { private static final String TAG = "HelloWorld"; static { System.loadLibrary("helloworld"); } private native String printJNI(); /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); Log.d(TAG, "Activity call JNI: " + printJNI()); } } |
4.3 进入命令行的/root/workspace/HelloWorld/bin目录
执行
javah -classpath /opt/android-sdk-linux/platforms/android-8/android.jar:/root/workspace/HelloWorld/bin/classes com.jouhu.HelloWorld
4.4 将会在/bin目录生成一个com_jouhu_HelloWorld.h文件
4.5 在/root/workspace/HelloWorld目录建立jni目录
4.6 将刚才生成的com_jouhu_HelloWorld.h拷贝到jni目录下
4.7 创建com_jouhu_HelloWorld.cpp文件
1 2 3 4 5 6 7 8 9 10 11 12 | LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES:=com_jouhu_HelloWorld.cpp LOCAL_C_INCLUDES := $(JNI_H_INCLUDE) LOCAL_MODULE := libhelloworld LOCAL_SHARED_LIBRARIES := libutils LOCAL_PRELINK_MODULE := false include $(BUILD_SHARED_LIBRARY) |
4.10 执行ndk-build
4.11 结果
1 2 | root@ubuntu:~/workspace/HelloWorld/jni# ndk-build Compile++ thumb : helloworld libs/armeabi/libhelloworld.so |
5 Android中交叉编译libjpeg的例子
5.1 下载最新的jpeg-8d源代码
5.2 创建Android Project
5.3 编写native加载函数代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | package com.jouhu; import android.app.Activity; import android.os.Bundle; public class AndroidJpeg8DActivity extends Activity { static { System.loadLibrary("jpegtest"); } public native String jpegTest(); /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } } |
5.5 使用javah生成.h文件
javah -classpath /opt/android-sdk-linux/platforms/android-8/android.jar:/root/workspace/AndroidJpeg8D/bin/classes com.jouhu.AndroidJpeg8DActivity
5.6 拷贝生成的com_jouhu_AndroidJpeg8DActivity.h文件到项目的jni目录,并编写.cpp文件
jni目录的Android.mk文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | # Copyright (C) 2009 The Android Open Source Project # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES := com_jouhu_AndroidJpeg8DActivity.cpp LOCAL_C_INCLUDES := $(LOCAL_PATH)/jpeg8d LOCAL_STATIC_LIBRARIES := libjpeg LOCAL_MODULE := jpegtest #LOCAL_LDLIBS := -llog include $(BUILD_SHARED_LIBRARY) include $(LOCAL_PATH)/jpeg-8d/Android.mk |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_ARM_MODE := arm LOCAL_SRC_FILES := \ jaricom.c jcapimin.c jcapistd.c jcarith.c jccoefct.c jccolor.c \ jcdctmgr.c jchuff.c jcinit.c jcmainct.c jcmarker.c jcmaster.c \ jcomapi.c jcparam.c jcprepct.c jcsample.c jctrans.c jdapimin.c \ jdapistd.c jdarith.c jdatadst.c jdatasrc.c jdcoefct.c jdcolor.c \ jddctmgr.c jdhuff.c jdinput.c jdmainct.c jdmarker.c jdmaster.c \ jdmerge.c jdpostct.c jdsample.c jdtrans.c jerror.c jfdctflt.c \ jfdctfst.c jfdctint.c jidctflt.c jidctfst.c jidctint.c jquant1.c \ jquant2.c jutils.c jmemmgr.c # the assembler is only for the ARM version, don't break the Linux sim ifneq ($(TARGET_ARCH),arm) ANDROID_JPEG_NO_ASSEMBLER := true endif LOCAL_MODULE:= libjpeg include $(BUILD_STATIC_LIBRARY) |
5.8 ndk-build编译
root@ubuntu:~/workspace/AndroidJpeg8D/jni# ndk-build
Compile arm : jpeg <= jaricom.c
Compile arm : jpeg <= jcapimin.c
Compile arm : jpeg <= jcapistd.c
Compile arm : jpeg <= jcarith.c
Compile arm : jpeg <= jccoefct.c
Compile arm : jpeg <= jccolor.c
Compile arm : jpeg <= jcdctmgr.c
Compile arm : jpeg <= jchuff.c
Compile arm : jpeg <= jcinit.c
Compile arm : jpeg <= jcmainct.c
Compile arm : jpeg <= jcmarker.c
Compile arm : jpeg <= jcmaster.c
Compile arm : jpeg <= jcomapi.c
Compile arm : jpeg <= jcparam.c
Compile arm : jpeg <= jcprepct.c
Compile arm : jpeg <= jcsample.c
Compile arm : jpeg <= jctrans.c
Compile arm : jpeg <= jdapimin.c
Compile arm : jpeg <= jdapistd.c
Compile arm : jpeg <= jdarith.c
Compile arm : jpeg <= jdatadst.c
Compile arm : jpeg <= jdatasrc.c
Compile arm : jpeg <= jdcoefct.c
Compile arm : jpeg <= jdcolor.c
Compile arm : jpeg <= jddctmgr.c
Compile arm : jpeg <= jdhuff.c
Compile arm : jpeg <= jdinput.c
Compile arm : jpeg <= jdmainct.c
Compile arm : jpeg <= jdmarker.c
Compile arm : jpeg <= jdmaster.c
Compile arm : jpeg <= jdmerge.c
Compile arm : jpeg <= jdpostct.c
Compile arm : jpeg <= jdsample.c
Compile arm : jpeg <= jdtrans.c
Compile arm : jpeg <= jerror.c
Compile arm : jpeg <= jfdctflt.c
Compile arm : jpeg <= jfdctfst.c
Compile arm : jpeg <= jfdctint.c
Compile arm : jpeg <= jidctflt.c
Compile arm : jpeg <= jidctfst.c
Compile arm : jpeg <= jidctint.c
Compile arm : jpeg <= jquant1.c
Compile arm : jpeg <= jquant2.c
Compile arm : jpeg <= jutils.c
Compile arm : jpeg <= jmemmgr.c
StaticLibrary : libjpeg.a
SharedLibrary : libjpegtest.so
Install : libjpegtest.so => libs/armeabi/libjpegtest.so
5.9 执行
5.10 可以使用libjpeg库了
6 C++编写JNI的不同之处
具体可以参考Simon的文章和这篇。
在Android自身的调用中,大都采用这种方式。
7 后记
很早就想写这篇文章,碍于一些事情,耽搁了很久,另外,本文也仅仅是涵盖了一些基本和简单的方面。很多深入的地方,还有待继续探讨,如果有什么更好的建议,欢迎提出。本文很多知识也是来自网络整理,这里需要特别感谢simon兄的文章。另外要说明的就是,在我们的ndk目录里面有一些例子,大家可以参考。本文对应的目录为/opt/android-ndk-r7b/samples
相关文章推荐
- JNI及Android JNI 开发基本知识和具体操作步骤
- JNI及Android JNI 开发基本知识和具体操作步骤
- JNI及Android JNI 开发基本知识和具体操作步骤
- 最新基于高德地图的android进阶开发(5)地图的基本操作、事件监听、用户UI、图层选择等
- Android开发笔记(五十五)手机设备基本操作
- Ionic开发Android项目app基本步骤
- Android(java)学习笔记262:JNI之工具快速开发步骤
- 使用jni接口完成android本地程序的运行--具体的操作
- Android Bitmap开发之基本操作
- Android开发之极光推送基本步骤
- 开发android应用程序的基本步骤及RSS、SAX简介
- Android Bitmap开发之旅--基本操作
- Android JNI/NDK开发之基本姿势
- Android JNI/NDK开发之基本姿势<一>
- 使用jni接口完成android本地程序的运行--具体的操作
- android之JNI开发步骤总结
- android之JNI开发详细步骤
- android JNI 开发步骤
- 总结android项目的基本开发步骤(转帖)
- Android IOS WebRTC 音视频开发总结(十六)-- 音频设备操作之opensl与jni