jni是java native interface的缩写,java 本地接口。它提供了若干的API实现了Java和其他语言的通信(主要是C/C++)。从Java1.1开始,jni标准成为java平台的一部分,它允许Java代码和其他语言写的代码进行交互。

  ndk:Android NDK 是在SDK前面又加上了“原生”二字,即Native Development Kit,因此又被Google称为“NDK”。

  .so:共享函数库,在可执行程序启动的时候加载,所有程序重新运行时都可自动加载共享函数库中的函数。

  为何要使用ndk?

    1. 代码的保护,由于apk的java层代码很容易被反编译,而C/C++库反汇难度较大。     2. 在NDK中调用第三方C/C++库,因为大部分的开源库都是用C/C++代码编写的。     3. 便于移植,用C/C++写的库可以方便在其他的嵌入式平台上再次使用。

  通俗来说,jni提供一套标准,包括定义了一些数据类型,引用类型,对应于Java中的数据类型,引用类型。还有一些转换函数,这些都定义在jni.h中。

  例如,java传入的String参数,在c文件中被jni转换为jstring的数据类型,在c文件中声明char* test,然后test = (char*)(*env)->GetStringUTFChars(env, jstring, NULL);注意:test使用完后,需要释放指针变量:(*env)->ReleaseStringUTFChars(env, jstring, test);将char* test转换为jstring 用(*env)->NewStringUTF(env,const char* );(const 指啥意思?)

  Android 函数库是用c/c++写的,框架层不能直接调用它,而是通过jni调用的。我们也可以自己用jni调用native层。

  实战。

  1,配置NDK环境,需要下载NDK开发包并配置。

  2,在app build.gradle里面配置ndk属性。

  3,静态加载动态库,编写naive方法,和普通java方法基本没区别。

1 2 3 4 5 static { System.loadLibrary( "JniTest" ); } public native String getStringFromNative();

  4,生成头文件。在android studio 的命令行界面中,进入/app/src/main/java目录下,执行命令:

1 javah -d ../jni com.example.shengchanglu.test.MainActivity

  这样就在src/main/目录中新增了jni目录,以及jni/com_example_shengchanglu_test_MainActivity.h头文件。

  com_example_shengchanglu_test_MainActivity.h头文件内容如下:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 /* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class com_example_shengchanglu_test_MainActivity */ #ifndef _Included_com_example_shengchanglu_test_MainActivity #define _Included_com_example_shengchanglu_test_MainActivity #ifdef __cplusplus extern "C" { #endif /* * Class: com_example_shengchanglu_test_MainActivity * Method: getStringFromNative * Signature: ()Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_com_example_shengchanglu_test_MainActivity_getStringFromNative (JNIEnv *, jobject); #ifdef __cplusplus } #endif #endif

  看返回值jstring对应于java中得String。

  5,在jni目录中新增main.c文件,去实现com_example_shengchanglu_test_MainActivity.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 // // Created by shengchang lu on 15/9/2. // /* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> #include <android/log.h> #ifndef LOG_TAG #define LOG_TAG "ANDROID_LAB" #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__) #endif #ifndef _Included_com_example_shengchanglu_test_MainActivity #define _Included_com_example_shengchanglu_test_MainActivity #ifdef __cplusplus extern "C" { #endif /* * Class: com_example_shengchanglu_test_MainActivity * Method: getStringFromNative * Signature: ()Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_com_example_shengchanglu_test_MainActivity_getStringFromNative(JNIEnv * env , jobject j) { LOGE( "log string from ndk." ); return (*env)->NewStringUTF(env, "Hello From JNI!" ); } #ifdef __cplusplus } #endif #endif

  6,Android中调用native方法。

  7,编译,运行。在app/build/intermediates/下出现ndk目录,生成了动态库so文件和mk文件。

  上面讲的只是ndk开发最基本的。Java不仅可以调用jni方法,jni也可以调用Java中属性(静态和非静态),方法(静态和非静态)。

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 void AppAction::setUndoRedoState(bool undo, bool redo) { JNIEnv* jniEnv = EnvManager::shareInstance()->getEnv(); if (jniEnv == NULL) { return ; } jclass jclz = NULL; jclz = jniEnv->FindClass( "com/fotoable/fotoproedit/activity/ProEditLightPenActivity" ); if (jniEnv->ExceptionCheck() == JNI_TRUE) { jniEnv->ExceptionClear(); jniEnv->DeleteLocalRef(jclz); return ; } jmethodID checkUndoRedoState = jniEnv->GetStaticMethodID(jclz, "checkUndoRedoState" , "(ZZ)V" ); if (checkUndoRedoState == NULL) { jniEnv->DeleteLocalRef(jclz); return ; } jniEnv->CallStaticVoidMethod(jclz, checkUndoRedoState, undo,redo); if (jniEnv->ExceptionCheck() == JNI_TRUE) { jniEnv->ExceptionClear(); } jniEnv->DeleteLocalRef(jclz); }

  根据上面的jni代码,我们可以反推出在当前项目中有且只有一个类中有这个方法。

   类名:com.fotoable.fotoproedit.activity.ProEditLightPenActivity

   方法:public void static checkUndoRedoState(boolean b1,boolean b1);

  调用方法完毕后,指针变量应该释放,要不然会引起内存泄露,程序崩溃。难点是异常捕获,ExceptionCheck只能捕获上一行代码引发的异常,且不能向Android层抛出,所以必须多加小心。

  关于保存jni环境:EnvManager::shareInstance():

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 /* * UtilManager.h * * Created on: 2013-12-31 * Author: Administrator */ #ifndef UTILMANAGER_H_ #define UTILMANAGER_H_ #include <jni.h> class EnvManager { public : EnvManager(); virtual ~EnvManager(); static EnvManager* shareInstance(); static void destroy(); JNIEnv* getEnv(); void setEnv(JNIEnv* jniEnv); private : JNIEnv* env; }; #endif /* UTILMANAGER_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 /* * UtilManager.cpp * * Created on: 2013-12-31 * Author: Administrator */ #include <stdio.h> #include <stdlib.h> #include "EnvManager.h" static EnvManager * sEnvManager = NULL; EnvManager * EnvManager::shareInstance() { if (!sEnvManager) { sEnvManager = new EnvManager(); } return sEnvManager; } void EnvManager::destroy() { delete sEnvManager; sEnvManager = NULL; } JNIEnv* EnvManager::getEnv(){ return env; } void EnvManager::setEnv(JNIEnv* jniEnv){ env = jniEnv; } EnvManager::EnvManager() { env = NULL; } EnvManager::~EnvManager() { delete env; }

更多相关文章

  1. Android(安卓)游戏开发中横竖屏切换问题
  2. Android中的消息机制-源码分析
  3. LoganSquare——快速解析和序列化JSON对象的Android类库
  4. [置顶] Android点击Button实现功能的几种方法
  5. Android架构实例分析之注册hello HAL的JNI方法表
  6. Android(安卓)MonkeyRunner测试NotePad例子(SDK中的源码实例)
  7. 经典Android试题及答案
  8. android中apk反编译
  9. android 程序中运行main方法

随机推荐

  1. 什么是Android-Android中文SDK
  2. Android学习笔记(33):Android对话框
  3. android工具之TraceView学习笔记
  4. Android4.1 关于Rotation相关的Configura
  5. Android上通过gcc编译普通的C程序
  6. android 版本更新
  7. Android之Room
  8. android 屏幕上面画线
  9. [置顶] Android中的dispatchTouchEvent()
  10. Android(安卓)SDK安装失败处理办法