JNI和NDK编程
来源:互联网 发布:企业app建站源码 编辑:程序博客网 时间:2024/06/06 05:21
(一) JNI
1.创建JniTest.java类
public class JniTest {static {System.loadLibrary("jnidemo");}public static void main(String[] args) {JniTest jt = new JniTest();System.out.println(jt.get());jt.set("hello world!!!");}public native void set(String string);public native String get();}2.依次执行:
javac JniTest.javajavah JniTest分别完成编译,以及生成头文件。
3.实现头文件JniTest.h中声明的方法,保存为test.cpp
#include "JniTest.h"#include <stdio.h>JNIEXPORT jstring JNICALL Java_JniTest_get (JNIEnv *env, jobject thiz){printf("invoke get in cpp \n");return env->NewStringUTF("Hello from JNI~");} JNIEXPORT void JNICALL Java_JniTest_set (JNIEnv *env, jobject thiz, jstring string){ printf("invoke set from cpp\n"); char* str = (char*)env->GetStringUTFChars(string, NULL); printf("%s\n", str); env->ReleaseStringUTFChars(string, str);}4.执行以下命令
Mac OS:
g++ -dynamiclib -I /Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/include -I /Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/include/darwin test.cpp -o libjnidemo.jnilib
Linux/Windows:
gcc -shared -I /Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/include -I /Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/include/darwin -fPIC test.cpp -o libjnidemo.so
生成对应的动态库文件,-I /Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/include用于指定jni.h的路径,-I /Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/include/darwin指定jni_md.h的路径。
5.运行
java -Djava.library.path=. JniTest-Djava.library.path用于指定动态库的路径。
运行结果:
invoke get in cpp Hello from JNI~invoke set from cpphello world!!!
(二) NDK
1.创建一个Android项目,声明所需要的native方法
public class MainActivity extends Activity { static { System.loadLibrary("jni-test"); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Log.e("weilei", get()); set("Hello world from Demo---"); } public native String get(); public native void set(String string);}2.实现Android项目中的native方法
在外部创建一个名为jni的目录(这里的目录名必须为jni),然后在jni目录下创建3个文件:test.cpp、Android.mk、Application.mk,它们的实现如下。
test.cpp
#include <jni.h>#include <stdio.h>#ifdef __cplusplusextern "C" {#endifvoid Java_com_example_weilei_demoapp_activities_MainActivity_set(JNIEnv *env, jobject thiz, jstring string) {printf("invoke set from cpp\n"); char* str = (char*)env->GetStringUTFChars(string, NULL); printf("%s\n", str); env->ReleaseStringUTFChars(string, str);}jstring Java_com_example_weilei_demoapp_activities_MainActivity_get(JNIEnv *env, jobject thiz) {printf("invoke get in cpp \n"); return env->NewStringUTF("Hello from JNI~"); }#ifdef __cplusplus}#endif
Android.mk
LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE := jni-testLOCAL_SRC_FILES := test.cppinclude $(BUILD_SHARED_LIBRARY)
Application.mk
APP_ABI := ARMEABILOCAL_MODULE代表模块的名称,LOCAL_SRC_FILES表示需要参与编译的源文件。APP_ABI表示CPU的架构平台类型。
4.切换到jni的父目录,执行ndk-build生成so库
这个时候NDK会创建一个与jni目录平级的目录libs,里面放的就是生成的so库。
5.然后在app/src/main中创建一个名为jniLibs的目录,将lib下的armeabi目录连同armeabi里的so库一起复制到jniLibs目录中,然后运行即可。
运行效果:
07-07 22:19:34.867 9057-9057/com.example.weilei.demoapp E/weilei: Hello from JNI~说明连接成功。
在上面的步骤中需要将NDK编译的so库放置到jniLib中,如果想放到其他目录,可以按照如下方式修改App的build.gradle文件。
android { ... sourceSets.main { jniLibs.srcDir 'libs' }}这样的话,就将DemoApp/app/libs/指定为新的存放so库的目录。
除了手动使用ndk-build创建so库,还可以通过AndroidStudio来自动编译产生so库。首先在App的build.gradle的defaultConfig中添加NDK选项,其中moduleName指定了模块的名称,即so库的名称。
android { compileSdkVersion 22 buildToolsVersion "22.0.1" defaultConfig { applicationId "com.example.weilei.demoapp" minSdkVersion 15 targetSdkVersion 22 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" ndk { moduleName "jni-test" } }}接着讲JNI代码放到app/src/main/jni目录下(目录必须为jni),如果不想采用jni这个名字,可以通过如下方式指定:
android { ... sourceSets.main { jni.srcDirs 'src/main/jni_test' }}
最后在gradle.properties中添加android.useDeprecatedNdk=true
经过上面的步骤,AndroidStudio就可以自动编译JNI代码了,但是这个时候AndroidStudio会把所有CPU平台的so库都打包到apk中。按照如下方式修改build.gradle的位置,然后在执行gradle assembleArmDebug编译即可。android { ... productFlavors { arm { ndk { abiFilter "armeabi" } } x86 { ndk { abiFilter "x86" } } }}
(三) JNI调用Java的方法
1.接着NDK的这个例子,在MainActivity中创建一个方法,如下:
public static void printLog(String string) { Log.e("MainActivity", string); }2.然后在test.cpp中创建一个调用这个方法的方法:
void CallJavaMethod(JNIEnv *env, jobject thiz) { jclass clazz = env->FindClass("com/example/weilei/demoapp/activities/MainActivity"); if (clazz == NULL) { printf("Find class MainActivity error!"); return; } jmethodID id = env->GetStaticMethodID(clazz, "printLog", "(Ljava/lang/String;)V"); if (id == NULL) { printf("find method error!"); } jstring msg = env->NewStringUTF("msg from JNI~~~"); env->CallStaticVoidMethod(clazz, id, msg);}这个过程首先根据完整的类名获取MainActivity的jclass对象,然后获取方法id,最后调用env.CallStaticMethod()方法来调用java中的方法。
3.为了查看是否调用成功,我们在test.cpp的get方法中添加对CallJavaMethod()的调用:
jstring Java_com_example_weilei_demoapp_activities_MainActivity_get(JNIEnv *env, jobject thiz) {printf("invoke get in cpp \n"); CallJavaMethod(env, thiz); return env->NewStringUTF("Hello from JNI~"); }
运行查看结果:
07-08 11:02:25.270 2732-2732/com.example.weilei.demoapp E/MainActivity: msg from JNI~~~说明调用成功。
- JNI和NDK编程
- JNI和NDK编程
- JNI和NDK编程
- JNI和NDK编程
- JNI和NDK编程
- JNI和NDK编程入门
- JNI和NDK编程-JNI入门
- Android-JNI和NDK编程【占坑中】
- Android中的JNI和NDK编程实践
- JNI和NDK编程的简单了解
- JNI和NDK编程(二)NDK的开发流程
- JNI和NDK编程-使用AndroidStudio进行NDK开发
- JNI和NDK编程(一)JNI的开发流程
- 初学JNI-NDK编程
- Android JNI + NDK 编程
- jni和ndk详解
- NDK 和 JNI 总结
- Android NDK和Jni
- 【笔记】WebService CXF与SSM整合,模拟实名认证功能
- C++基本语法
- DPDK 使用网卡ip/tcp/udp checksum offload
- jenkins保持持续登录后,立即构建报错
- DOC下运行java工程报错:找不到或无法加载主类 xxx
- JNI和NDK编程
- easyui的combotree组件undefined问题
- Oracle索引详细介绍和使用
- 【Caffe】ubuntu14.04+caffe+gpu
- CRF条件随机场简介
- 锁开销和上下文切换开销
- SQLITE3使用总结
- varchar类型的字段存储纯数字的排序
- VS2013下socket新函数代替旧函数引起的编译错误