android jni的使用,java中代码在native层实现
2016-01-29 10:37
447 查看
这里主要是依据jni规范来实现java跟native的交互,在android环境下过程是类似的,只是native方法的名字要简洁很多,可以参见:http://blog.csdn.net/lin20044140410/article/details/50629836
android应用层几乎都是java语言写的,application framework层多数也都是java代码,一些底层的系统库是用C,C++写的,所以上层的java代码要使用底层的lib库就要使用jni来实现,下面以HelloNativeDemo为例,来学习如何通过jni让java调用C、C++的代码,完成jni的大致有这几步:
1)写一个jave类,用来声明带有native的方法,同时也要加载动态库
2)获得这个jave类的.class文件,可以使用javac命令,也可以从app的bin目录获取
3)依据上一步的.class文件,使用javah -jni java类名,生成扩展名为h的头文件,其实这一步不是必须的,生成这个.h的头文件,多半是为了书写native函数方便,因为这个函数名字可以直接从.h文件复制,在C文件中写的native函数,一定要符合jni的规范
4)编写实现natvie方法的C 或者C++文件
5)把C/C++编写的文件生成动态连接库
1,首先通过eclipse新建一个app,取名:HelloNativeDemo,其中包含2个类文件:
一个是app的显示类MainActivity :
一个是负责声明本地方法的java类:
2,然后到app的根目录,我是把app的代码放在linux的服务器上执行的。
首先进到code\LINUX\android\packages\apps\HelloNativeDemo\src\com\nativedemo\hellonativedemo这个目录,执行 javac JniDemo.java 生成JniDemo.class,然后退到目录code\LINUX\android\packages\apps\HelloNativeDemo\src这里,执行javah -jni com.nativedemo.hellonativedemo.JniDemo,生成com_nativedemo_hellonativedemo_JniDemo.h,这里执行javah命令一定要在源码的根目
4000
录,在JniDemo.java的同级目录执行javah会报错。
com_nativedemo_hellonativedemo_JniDemo.h内容如下:
3,在app所在根目录新建一个helloWorldJni的文件夹,即是目录:\code\LINUX\android\packages\apps\HelloNativeDemo\helloWorldJni在这里放置文件前面步骤提到的文件:JniDemo.java,JniDemo.class,com_nativedemo_hellonativedemo_JniDemo.h,然后编写本地实现的JniDemoImpl.c文件,这个文件就是去实现com_nativedemo_hellonativedemo_JniDemo.h里面声明的方法,JniDemoImpl.c内容如下:
4,编写Android.mk文件,生成动态连接库,
5,添加应用app的Android.mk 内容如下:
6,执行./make mmma ./packages/apps/HelloNativeDemo 这个编译命令是在高通项目中的方式,其他平台可能会有差异。编译完成生成了:
\system\app\HelloNativeDemo\HelloNativeDemo.apk
\system\lib\libhelloworldjni.so
分别push到手机中的对应目录即可。
android应用层几乎都是java语言写的,application framework层多数也都是java代码,一些底层的系统库是用C,C++写的,所以上层的java代码要使用底层的lib库就要使用jni来实现,下面以HelloNativeDemo为例,来学习如何通过jni让java调用C、C++的代码,完成jni的大致有这几步:
1)写一个jave类,用来声明带有native的方法,同时也要加载动态库
2)获得这个jave类的.class文件,可以使用javac命令,也可以从app的bin目录获取
3)依据上一步的.class文件,使用javah -jni java类名,生成扩展名为h的头文件,其实这一步不是必须的,生成这个.h的头文件,多半是为了书写native函数方便,因为这个函数名字可以直接从.h文件复制,在C文件中写的native函数,一定要符合jni的规范
4)编写实现natvie方法的C 或者C++文件
5)把C/C++编写的文件生成动态连接库
1,首先通过eclipse新建一个app,取名:HelloNativeDemo,其中包含2个类文件:
一个是app的显示类MainActivity :
package com.nativedemo.hellonativedemo; import android.app.Activity; import android.os.Bundle; import android.view.Menu; import android.view.MenuItem; import android.util.Log; public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); JniDemo mJniDemo =new JniDemo(); mJniDemo.displayHelloJniStr(); Log.d("Hellojni","hello jni" +mJniDemo.getHelloJniStr()); } 。。。。。。 }
一个是负责声明本地方法的java类:
package com.nativedemo.hellonativedemo; public class JniDemo{ //加载库文件 static { System.loadLibrary("helloworldjni"); } //声明要在native层实现的函数 public native void displayHelloJniStr(); public native String getHelloJniStr(); public native void noNativeFun(); }
2,然后到app的根目录,我是把app的代码放在linux的服务器上执行的。
首先进到code\LINUX\android\packages\apps\HelloNativeDemo\src\com\nativedemo\hellonativedemo这个目录,执行 javac JniDemo.java 生成JniDemo.class,然后退到目录code\LINUX\android\packages\apps\HelloNativeDemo\src这里,执行javah -jni com.nativedemo.hellonativedemo.JniDemo,生成com_nativedemo_hellonativedemo_JniDemo.h,这里执行javah命令一定要在源码的根目
4000
录,在JniDemo.java的同级目录执行javah会报错。
com_nativedemo_hellonativedemo_JniDemo.h内容如下:
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class com_nativedemo_hellonativedemo_JniDemo */ #ifndef _Included_com_nativedemo_hellonativedemo_JniDemo #define _Included_com_nativedemo_hellonativedemo_JniDemo #ifdef __cplusplus extern "C" { #endif /* * Class: com_nativedemo_hellonativedemo_JniDemo * Method: displayHelloJniStr * Signature: ()V */ JNIEXPORT void JNICALL Java_com_nativedemo_hellonativedemo_JniDemo_displayHelloJniStr (JNIEnv *, jobject); /* * Class: com_nativedemo_hellonativedemo_JniDemo * Method: getHelloJniStr * Signature: ()Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_com_nativedemo_hellonativedemo_JniDemo_getHelloJniStr (JNIEnv *, jobject); /* * Class: com_nativedemo_hellonativedemo_JniDemo * Method: noNativeFun * Signature: ()V */ JNIEXPORT void JNICALL Java_com_nativedemo_hellonativedemo_JniDemo_noNativeFun (JNIEnv *, jobject); #ifdef __cplusplus } #endif #endif
3,在app所在根目录新建一个helloWorldJni的文件夹,即是目录:\code\LINUX\android\packages\apps\HelloNativeDemo\helloWorldJni在这里放置文件前面步骤提到的文件:JniDemo.java,JniDemo.class,com_nativedemo_hellonativedemo_JniDemo.h,然后编写本地实现的JniDemoImpl.c文件,这个文件就是去实现com_nativedemo_hellonativedemo_JniDemo.h里面声明的方法,JniDemoImpl.c内容如下:
include <jni.h> include "JNIHelp.h" include <com_nativedemo_hellonativedemo_JniDemo.h> include <android/log.h> #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, "JniDemo", __VA_ARGS__) /* * Class: HelloJniDemo * Method: displayHelloJniStr * Signature: ()V */ JNIEXPORT void JNICALL Java_com_nativedemo_hellonativedemo_JniDemo_displayHelloJniStr (JNIEnv* jniEnv, jobject obj){ LOGD("helloJniDemo display string \n"); } /* * Class: HelloJniDemo * Method: getHelloJniStr * Signature: ()Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_com_nativedemo_hellonativedemo_JniDemo_getHelloJniStr (JNIEnv* jniEnv, jobject obj){ //const char* str= "from jin string"; char str[32]="from jin string"; /*获取string类型,要借助于这个函数:NewStringUTF,并且这个函数的使用在c和c++里面是不一样的,这里是c语言的实现方式,如果是c++文件,要这么写:jstring jStr = jniEnv->NewStringUTF(str); */ jstring jStr = (*jniEnv)->NewStringUTF(jniEnv,str); return jStr; } /* * Class: HelloJniDemo * Method: noNativeFun * Signature: ()V */ JNIEXPORT void JNICALL Java_com_nativedemo_hellonativedemo_JniDemo_noNativeFun (JNIEnv* jniEnv, jobject obj){ LOGD("Hello jni demo LIB,no native !/n"); }
4,编写Android.mk文件,生成动态连接库,
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_LDLIBS := -llog LOCAL_SRC_FILES := \ JniDemoImpl.c \ JniCppDemoImple.cpp LOCAL_C_INCLUDES := \ $(JNI_H_INCLUDE) LOCAL_SHARED_LIBRARIES := \ libutils \ libcutils LOCAL_PRELINK_MODULE := false #LOCAL_MULTILIB := 64 LOCAL_MODULE:= libhelloworldjni include $(BUILD_SHARED_LIBRARY) 该文件的一些全局变量的含义: LOCAL_PATH的定义必须要放到所有的include $(CLEAR_VARS)之前, LOCAL_PATH通过调用my-dir函数来获取当前的路径, LOCAL_SRC_FILES 编译的源文件 LOCAL_C_INCLUDES 需要包含的头文件目录 LOCAL_SHARED_LIBRARIES 链接时需要的外部库 LOCAL_PRELINK_MODULE 是否需要 prelink 处理 LOCAL_MODULE 编译的目标对象 BUILD_SHARED_LIBRARY 指明要编译成动态库
5,添加应用app的Android.mk 内容如下:
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE_TAGS := optional #LOCAL_STATIC_JAVA_LIBRARIES := libarity android-support-v4 guava ejml \ # android-support-v7-recyclerview LOCAL_JNI_SHARED_LIBRARIES := libhelloworldjni LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_SDK_VERSION := current LOCAL_PACKAGE_NAME := HelloNativeDemo #LOCAL_PROGUARD_ENABLED := full #LOCAL_PROGUARD_FLAG_FILES := proguard.flags include $(BUILD_PACKAGE) # Use the following include to make our test apk. include $(call all-makefiles-under,$(LOCAL_PATH)) 主要是添加 LOCAL_JNI_SHARED_LIBRARIES := libhelloworldjni 这句
6,执行./make mmma ./packages/apps/HelloNativeDemo 这个编译命令是在高通项目中的方式,其他平台可能会有差异。编译完成生成了:
\system\app\HelloNativeDemo\HelloNativeDemo.apk
\system\lib\libhelloworldjni.so
分别push到手机中的对应目录即可。
相关文章推荐
- Android WiFi
- android notification
- android中生成excel
- Xamarin开发Android之VisualStudio设置
- Android Bitmap太大导致ImageView不显示的问题
- Android源码下载同步指导
- android Java heap space
- android程序的完美退出
- Android倒计时原理的实现
- Android相机开发那些坑
- Android 三种方式实现圆形ImageView
- 【团队分享】刀锋铁骑:常见Android Native崩溃及错误原因
- android studio创建桌面插件widget
- Android 开发绕不过的坑:你的 Bitmap 究竟占多大内存?
- AndroidStudio快捷键汇总
- Android项目中引用本地aar文件的方法
- Android使用BroadcastReceiver实现手机开机之后显示画面的功能
- Android 第四天(上午)
- android中双向滑动listview
- Android开发笔记-Android Studio中安装Genymotion插件解决方案