关于jni有两种方法注册 分别为 静态注册和动态注册
首先 来看看静态注册 所谓的静态注册 就是直接在Java文件里写个native方法 然后再c/c++文件中实现这个方法就行了!来看看代码:
package com.example.ndk_test;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
public class MainActivity extends ActionBarActivity {
//调用加载LIB库
static{
System.loadLibrary("ndk_test");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//调用方法 该方法是c或者c++实现
testJni();
}
//声明为本地方法
public native void testJni();
}
看看本地方法的实现 这里为了测试 直接打印一个 “hello”
#include
#include
#include//包含Android log打印 需要再make文件中添加 LOCAL_LDLIBS := -llog
#include"com_example_ndk_test_MainActivity.h"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, "NDK_TEST", __VA_ARGS__)//为了使用方便 直接定义一个宏
/*
* Class: com_example_ndk_test_MainActivity 类名
* Method: testJni 方法名
* Signature: ()V 方法签名
*/
JNIEXPORT void JNICALL Java_com_example_ndk_1test_MainActivity_testJni
(JNIEnv * env, jobject clazz){
//直接打印hello
LOGD("hello");
}
再来看看make文件
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := ndk_test
LOCAL_SRC_FILES := ndk_test.cpp
LOCAL_LDLIBS := -llog
include $(BUILD_SHARED_LIBRARY)
是不是很简单
然后我们再看看怎么用c/c++代码调用Java代码呢 :
再原有的代码上继续
package com.example.ndk_test;
import android.support.v7.app.ActionBarActivity;
import android.util.Log;
import android.os.Bundle;
public class MainActivity extends ActionBarActivity {
private static final String LOG ="NDK_TEST";
//调用加载LIB库
static{
System.loadLibrary("ndk_test");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//调用方法 该方法是c或者c++实现
testJni();
}
//声明为本地方法
public native void testJni();
//声明一个Java方法 用本地方法来调用
public void getName(){
Log.i(LOG, "调用了getName()");
}
}
#include
#include
#include//包含Android log打印 需要再make文件中添加 LOCAL_LDLIBS := -llog
#include"com_example_ndk_test_MainActivity.h"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, "NDK_TEST", __VA_ARGS__)//为了使用方便 直接定义一个宏
jmethodID getNameID;
jclass mainActivity;
void callJava(JNIEnv *env,jobject obj){
mainActivity= env->FindClass("com/example/ndk_test/MainActivity");
getNameID=env->GetMethodID(mainActivity,"getName","()V");
env->CallVoidMethod(obj,getNameID);
}
/*
* Class: com_example_ndk_test_MainActivity 类名
* Method: testJni 方法名
* Signature: ()V 方法签名
*/
JNIEXPORT void JNICALL Java_com_example_ndk_1test_MainActivity_testJni
(JNIEnv * env, jobject obj){
//直接打印hello
LOGD("hello");
callJava(env,obj);
}
这样的话 本地代码和Java就可以相互调用了!
那如果我现在要调用Java的静态方法呢 ?
直接使用 void CallStaticVoidMethod(jclass clazz, jmethodID methodID)
如果调用有返回值的方法呢?
好了直接看这里:CallXXXMethod 函数和CallStaticXXXMethod函数,XXX表明了方法的返回值类型。这些函数的变体允许传递数组参数 (CallXXXMethodA and CallStaticXXXMethodA)或者传递一个可变大小的列表(CallXXXMethodV and CallStaticXXXMethodV)。
那怎么获取/设置Java代码里面的全局变量呢?
//获取Java全局变量
void getFild(JNIEnv *env,jobject obj){
ifild= env->GetFieldID(mainActivity,"ifiled","I");
jint fid=env->GetIntField(obj,ifild);//获取
LOGI("%d",fid);
env->SetIntField(obj,ifild,10);//修改变量的值
}
现在来看看动态注册jni
动态注册好处是不要写很长的方法名,用jni_onload方法实现预注册 即当执行system.loadLibrary()方法时候就把需要调用的方法给注册了,效率要高 Android就是采用此方法;
那么首先得重写jni_onload方法了
//实现jni_onload 动态注册方法
jint JNI_OnLoad(JavaVM* vm, void* reserved) {
JNIEnv* env = NULL;
if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
return -1;
}
if(registerNativeMeth(env)!=JNI_OK){//注册方法
return -1;
}
return JNI_VERSION_1_4;//必须返回这个值
}
//注册Java端的方法 以及本地相对应的方法
JNINativeMethod method[]={{"test2","()V",(void*)native_test2},{"test3","()I",(int*)native_test3}};
//注册相应的类以及方法
jint registerNativeMeth(JNIEnv *env){
jclass cl=env->FindClass("com/example/ndk_test/MainActivity");
if((env->RegisterNatives(cl,method,sizeof(method)/sizeof(method[0])))<0){
return -1;
}
return 0;
}
这样的话就是当 Java端调用test2的时候就会调用到本地方法的 native_test2方法了 同理 test3也是一样的,注册方法主要是调用虚拟机的 RegisterNatives方法
现在来看看 完整的代码:
首先是Java端:
package com.example.ndk_test;
import android.support.v7.app.ActionBarActivity;
import android.util.Log;
import android.os.Bundle;
public class MainActivity extends ActionBarActivity {
private static final String LOG ="NDK_TEST";
private int ifiled=3;
private String name;
//调用加载LIB库
static{
System.loadLibrary("ndk_test");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//调用方法 该方法是c或者c++实现
testJni();
Log.i(LOG,"java變量--"+ifiled);
Log.i(LOG,"test3执行="+test3());
}
//声明为本地方法
public native void testJni();
//声明一个Java方法 用本地方法来调用
public void getName(){
Log.i(LOG, "调用了getName()");
test2();
}
//声明为本地方法
public native void test2();
public native int test3();
}
#include
#include
#include
#include//包含Android log打印 需要再make文件中添加 LOCAL_LDLIBS := -llog
#include"com_example_ndk_test_MainActivity.h"
#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, "ndk_test", __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO , "ndk_test", __VA_ARGS__)
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN , "ndk_test", __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR , "ndk_test", __VA_ARGS__)
jmethodID getNameID;
jfieldID ifild;
jclass mainActivity;
//調用Java方法
void callJava(JNIEnv *env, jobject obj) {
mainActivity = env->GetObjectClass(obj); //("com/example/ndk_test/MainActivity");
getNameID = env->GetMethodID(mainActivity, "getName", "()V");
env->CallVoidMethod(obj, getNameID);
}
//获取Java全局变量
void getFild(JNIEnv *env, jobject obj) {
ifild = env->GetFieldID(mainActivity, "ifiled", "I");
jint fid = env->GetIntField(obj, ifild);
LOGI("%d", fid);
env->SetIntField(obj, ifild, 10); //修改变量的值
}
/*
* Class: com_example_ndk_test_MainActivity 类名
* Method: testJni 方法名
* Signature: ()V 方法签名
*/JNIEXPORT void JNICALL Java_com_example_ndk_1test_MainActivity_testJni(
JNIEnv * env, jobject obj) {
//直接打印hello
LOGI("hello");
callJava(env, obj);
getFild(env, obj);
}
//替换java端的test2
void native_test2(){
LOGI("native_test2");
}
//替换java端的test3
int native_test3(){
return 190;
}
//注册Java端的方法 以及本地相对应的方法
JNINativeMethod method[]={{"test2","()V",(void*)native_test2},{"test3","()I",(int*)native_test3}};
//注册相应的类以及方法
jint registerNativeMeth(JNIEnv *env){
jclass cl=env->FindClass("com/example/ndk_test/MainActivity");
if((env->RegisterNatives(cl,method,sizeof(method)/sizeof(method[0])))<0){
return -1;
}
return 0;
}
//实现jni_onload 动态注册方法
jint JNI_OnLoad(JavaVM* vm, void* reserved) {
JNIEnv* env = NULL;
if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
return -1;
}
if(registerNativeMeth(env)!=JNI_OK){//注册方法
return -1;
}
return JNI_VERSION_1_4;//必须返回这个值
}