JNI和NDK编程
2017-07-07 10:21
162 查看
(一) JNI
1.创建JniTest.java类
3.实现头文件JniTest.h中声明的方法,保存为test.cpp
Mac OS:
Linux/Windows:
生成对应的动态库文件,-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.运行
运行结果:
(二) NDK
1.创建一个Android项目,声明所需要的native方法
在外部创建一个名为jni的目录(这里的目录名必须为jni),然后在jni目录下创建3个文件:test.cpp、Android.mk、Application.mk,它们的实现如下。
test.cpp
Android.mk
Application.mk
4.切换到jni的父目录,执行ndk-build生成so库
这个时候NDK会创建一个与jni目录平级的目录libs,里面放的就是生成的so库。
5.然后在app/src/main中创建一个名为jniLibs的目录,将lib下的armeabi目录连同armeabi里的so库一起复制到jniLibs目录中,然后运行即可。
运行效果:
在上面的步骤中需要将NDK编译的so库放置到jniLib中,如果想放到其他目录,可以按照如下方式修改App的build.gradle文件。
除了手动使用ndk-build创建so库,还可以通过AndroidStudio来自动编译产生so库。首先在App的build.gradle的defaultConfig中添加NDK选项,其中moduleName指定了模块的名称,即so库的名称。
最后在gradle.properties中添加android.useDeprecatedNdk=true
经过上面的步骤,AndroidStudio就可以自动编译JNI代码了,但是这个时候AndroidStudio会把所有CPU平台的so库都打包到apk中。按照如下方式修改build.gradle的位置,然后在执行gradle assembleArmDebug编译即可。
(三) JNI调用Java的方法
1.接着NDK的这个例子,在MainActivity中创建一个方法,如下:
3.为了查看是否调用成功,我们在test.cpp的get方法中添加对CallJavaMethod()的调用:
运行查看结果:
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.java javah 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 cpp hello 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 __cplusplus extern "C" { #endif void 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-test LOCAL_SRC_FILES := test.cpp include $(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~~~说明调用成功。
相关文章推荐
- Android jni/ndk编程二:jni数据类型转换(primitive,String,array)
- android studio中使用ndk编译.so文件,调用C/C++代码(jni编程)
- JNI和NDK编程(二)NDK的开发流程
- 串口编程前瞻-熟悉JNI、NDK以及SO库的开发
- 关于Android下的JNI编程、SO库以及NDK的一些问题
- Andoid NDK编程 2 - JNI签名规则
- JNI和NDK编程
- JNI和NDK编程(三)JNI的数据类型和类型签名
- android ndk jni 编程入门例子
- android ndk jni 编程入门例子
- Android Studio JNI/NDK 编程(二) Windows 下环境搭建 demo 开发
- JNI和NDK编程
- JNI和NDK编程-使用AndroidStudio进行NDK开发
- Android-JNI和NDK编程【占坑中】
- JNI和NDK编程(四)JNI调用Java方法的流程
- Android开发艺术探索读书笔记(第14章 JNI和NDK编程)
- JNI编程 ndk-build报错:unkown escape sequence ‘h’ 解决
- Android JNI编程和NDK学习 --静态、动态两种方式实现JNI
- Android中的JNI和NDK编程实践
- JNI和NDK编程的简单了解