Android JNI实现步骤

1、在eclipse下编写java应用程序
package com.zhang.jni.test;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;

public class JNITESTActivity extends Activity {
	private static final String Tag = "ZhangFang_JNITEST";
	private native void nativeMethod();
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        callNativeMathod();
    }
    /**
     * 
     */
    private void callNativeMathod()
    {
    	Log.v(Tag,"Activity call Native Mehotd:");
    	nativeMethod();
    }
    
    /**
     * 
     */
    private void callBack()
    {
    	Log.v(Tag,"Native method call the Activity methods");
    	Log.v(Tag,"****************Native Method call back successfully!********");
    }
    
    static {
    	System.loadLibrary("InstanceMethodCall");
    }
}



2、把java源码复制到$(Android)/external/路径下

 cp -Rf JNI ../Android/source/external/

3、进入$(Android)/external/JNI/bin目录,执行javah com.zhang.Android.JNI.JNIActivity,在bin目录下得到native头文件,这里包含有nativeMethod()接口的C/C++声明

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_zhang_jni_test_JNITESTActivity */

#ifndef _Included_com_zhang_jni_test_JNITESTActivity
#define _Included_com_zhang_jni_test_JNITESTActivity
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_zhang_jni_test_JNITESTActivity
 * Method:    nativeMethod
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_com_zhang_jni_test_JNITESTActivity_nativeMethod
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

注意:在2.3.4源码下,javah在/external/JNITEST/bin/classes目录下执行,本例中得到com_zhang_jni_test_JNITESTActivity.h头文件,如上所示。javah执行的文件要用.号隔开,而不是/隔开。



4、新建jni目录,把生成好的com_zhang_jni_test_JNITESTActivity.h复制到该目录下,并编写编写native C程序 com_zhang_jni_test_JNITESTActivity.c

#include "com_zhang_jni_test_JNITESTActivity.h"
#include <utils/Log.h>
#define LOG_TAG "JNI_C"
/*
 * Class:     com_zhang_jni_test_JNITESTActivity
 * Method:    nativeMethod
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_com_zhang_jni_test_JNITESTActivity_nativeMethod
  (JNIEnv *env, jobject obj)
{
        LOGI("JNI IN nativeMethod");

        jclass cls=(*env)->GetObjectClass(env,obj);
        static jmethodID mid = NULL;
        if(mid == NULL){
                mid=(*env)->GetMethodID(env,cls,"callBack","()V");
                if(mid == NULL){
                        return;
                }
        }
        (*env)->CallVoidMethod(env,obj,mid);

}

jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
    void *venv;
    LOGI("JNI_OnLoad!");

    if ((*vm)->GetEnv(vm, (void**)&venv, JNI_VERSION_1_4) != JNI_OK) {
        LOGE("ERROR: GetEnv failed");
        return -1;
    }

     return JNI_VERSION_1_4;
}

当java层调用System.loadLibrary加载完JNI动态库之后,紧接着就会查找该库中一个叫JNI_OnLoad函数。如果存在,就调用它,动态注册的工作在这里完成。本文使用的是静态注册,但是好像也必须把该方法加上。就算静态注册没有要求写JNI_OnLoad函数,但是建议最好还是写上,因为有一些初始化工作是可以在这个函数里面完成的。

jmethodID (JNICALL *GetMethodID)
      (JNIEnv *env, jclass clazz, const char *name, const char *sig);

clazz代表java类,name表示成员函数的名字,sig表示函数的返回值。


5、在此jni目录下编写Android.mk
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)

LOCAL_MODULE_TAGS := optional

LOCAL_SRC_FILES:= com_zhang_jni_test_JNITESTActivity.c

LOCAL_C_INCLUDES := $(JNI_H_INCLUDE)

LOCAL_MODULE := libInstanceMethodCall

LOCAL_SHARED_LIBRARIES := libutils

LOCAL_PRELINK_MODULE := false

include $(BUILD_SHARED_LIBRARY)

注意 LOCAL_MODULE_TAGS := optional必须添加,否则会报错。 LOCAL_MODULE := libInstanceMethodCall. 如果不加lib,则会生成InstanceMethodCall.so,编译信息如下所示。

system/core/include/cutils/log.h:68:1: warning: this is the location of the previous definition
target SharedLib: InstanceMethodCall (out/target/product/omap3evm/obj/SHARED_LIBRARIES/InstanceMethodCall_intermediates/LINKED/InstanceMethodCall.so)
target Non-prelinked: InstanceMethodCall (out/target/product/omap3evm/symbols/system/lib/InstanceMethodCall.so)
target Strip: InstanceMethodCall (out/target/product/omap3evm/obj/lib/InstanceMethodCall.so)
Install: out/target/product/omap3evm/system/lib/InstanceMethodCall.so
但是我们需要的是libInstanceMethodCall.so,所以必须写成 LOCAL_MODULE := libInstanceMethodCall

target SharedLib: libInstanceMethodCall (out/target/product/omap3evm/obj/SHARED_LIBRARIES/libInstanceMethodCall_intermediates/LINKED/libInstanceMethodCall.so)
target Non-prelinked: libInstanceMethodCall (out/target/product/omap3evm/symbols/system/lib/libInstanceMethodCall.so)
target Strip: libInstanceMethodCall (out/target/product/omap3evm/obj/lib/libInstanceMethodCall.so)
Install: out/target/product/omap3evm/system/lib/libInstanceMethodCall.so
make:离开目录“/home/zhangfang/zf/DM3730/source/android_source/TI_Android_GingerBread_2_3_4Sources”



6、编译

进入$(Anroid/source)

mmm external/JNITEST/jni/

编译信息如上所示。

如果需重新打包系统文件,则执行 make snod.

如果不需要,则把生成的libInstanceMethodCall.so 复制到开发板/system/lib目录下,这样当程序启动需要加载库的时候,就会在此目录下寻找。

 


7、安装程序
adb install JNITEST.apk


8、adb shell
logcat查看日志
调用成功

I/ActivityManager( 1228): Start proc com.zhang.jni.test for activity com.zhang.jni.test/.JNITESTActivity: pid=1931 uid=10032 gids={}
D/dalvikvm( 1931): Debugger has detached; object registry had 1 entries
I/JNI_C   ( 1931): JNI_OnLoad!
V/ZhangFang_JNITEST( 1931): Activity call Native Mehotd:
I/JNI_C   ( 1931): JNI IN nativeMethod
V/ZhangFang_JNITEST( 1931): Native method call the Activity methods
V/ZhangFang_JNITEST( 1931): ****************Native Method call back successfully!********
I/ActivityManager( 1228): Displayed com.zhang.jni.test/.JNITESTActivity: +145ms
D/dalvikvm( 1311): GC_EXPLICIT freed 14K, 47% free 3078K/5767K, external 3115K/3867K, paused 25ms

9、实现JNI的动态注册

因为静态注册具有以下缺点:

(1)需要编译所有声明的native函数的java类,每个生成的class文件都的用javah生成头文件,麻烦。

(2)javah生成的头文件特别长,书写不方便。

(3)初次调用native函数时要根据函数名字搜索对应JNI层函数来建立关联关系,运行效率较低。

所以下面尝试动态加载。Android.mk文件不变,只替换原理jni目录下的.h和.c文件。

#include "jni.h"
#include "JNIHelp.h"
#include <utils/Log.h>

const char* className = "com/zhang/jni/test/JNITESTActivity";
void JNI_nativeMethod(JNIEnv *env,jobject obj)
{
        LOGI("JNI IN nativeMethod");

        jclass cls=(*env)->GetObjectClass(env,obj);
        static jmethodID mid = NULL;
        if(mid == NULL){
                mid=(*env)->GetMethodID(env,cls,"callBack","()V");
                if(mid == NULL){
                        return;
                }
        }
        (*env)->CallVoidMethod(env,obj,mid);
}

static JNINativeMethod gMethods[] = {
        {"nativeMethod","()V",(void *)JNI_nativeMethod},
};
static int registerNativeMethods(JNIEnv* env,const char* className,JNINativeMethod* gMethods,int numMethods)
{
        jclass clazz;
        clazz = (*env)->FindClass(env,className);
        if(clazz == NULL){
                return JNI_FALSE;
        }
        if((*env)->RegisterNatives(env,clazz,gMethods,numMethods)<0){
                return JNI_FALSE;
        }
        return JNI_TRUE;
}
static int register_android_methods(JNIEnv *env)
{
        return registerNativeMethods(env,className,gMethods,sizeof(gMethods)/sizeof(gMethods[0]));
}

jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
    JNIEnv* env = NULL;
    LOGI("JNI_OnLoad!");

    if ((*vm)->GetEnv(vm, (void**)&env, JNI_VERSION_1_4) != JNI_OK) {
        LOGE("ERROR: GetEnv failed");
        return -1;
    }

    if(register_android_methods(env)<0){
        LOGE("register_android_methods error.\n");
        return -1;
    }
     return JNI_VERSION_1_4;
}



10、c++ JNI的使用

和JNI调用本地C不同,C++的JNI函数与C 有些不一样,需要查看JNI.h头文件去查看参数。Android.mk中的LOCAL_SRC_FILES 也必须为.cpp文件。

删除安装的程序 adb -s emulator-5554 uninstall com.zhang.Android.JNICPP


#include "com_zhang_Android_JNICPP_JNICPP.h"
#define TAG "_JNICPP_"
#include <utils/Log.h>

jmethodID mid;
JNIEXPORT void JNICALL Java_com_zhang_Android_JNICPP_JNICPP_nativeCppMethod
  (JNIEnv *env, jobject obj)
{
        LOGI("In C\n");
        env->CallVoidMethod(obj,mid);
}

JNIEXPORT void JNICALL Java_com_zhang_Android_JNICPP_JNICPP_initIDs
  (JNIEnv *env, jclass cls)
{
        mid=env->GetMethodID(cls,"callback","()V");
}

static const char *classPathName="com/zhang/Android/JNICPP/JNICPP";

static JNINativeMethod methods[]={
        {"nativeCppMethod","()V",(void *)Java_com_zhang_Android_JNICPP_JNICPP_nativeCppMethod},
tiveCppMethod},
};

static int registerNativeMethods(JNIEnv *env,const char *className,JNINativeMethod* gMethods,int numMethods)
{
        jclass clazz;
        clazz=env->FindClass(className);
        if(clazz==NULL){
                LOGE("Native registeration unable to find class %s",className);
                return JNI_FALSE;
        }
        if(env->RegisterNatives(clazz,gMethods,numMethods)<0){
                LOGE("RegisterNatives failed for %s",className);
                return JNI_FALSE;
        }
        return JNI_TRUE;

}
static int registerNatives(JNIEnv *env)
{
        if(!registerNativeMethods(env,classPathName,methods,sizeof(methods)/sizeof(methods[0]))){
                return JNI_FALSE;
        }
        return JNI_TRUE;
}

typedef union{
        JNIEnv *env;
        void * venv;
}UnionJNIEnvToVoid;

/* This function will be call when the library first be loaded */
jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
    UnionJNIEnvToVoid uenv;
    JNIEnv* env = NULL;
    LOGI("JNI_OnLoad!");

    if (vm->GetEnv((void**)&uenv.venv, JNI_VERSION_1_4) != JNI_OK) {
        LOGE("ERROR: GetEnv failed");
        return -1;
    }

    env = uenv.env;;

    if (registerNatives(env) != JNI_TRUE) {
        LOGE("ERROR: registerNatives failed");
        return -1;
    }

     return JNI_VERSION_1_4;
}













  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值