您的位置:首页 > 移动开发 > Android开发

android jni的使用,java中代码在native层实现

2016-01-29 10:37 447 查看
这里主要是依据jni规范来实现java跟native的交互,在android环境下过程是类似的,只是native方法的名字要简洁很多,可以参见:http://blog.csdn.net/lin20044140410/article/details/50629836

android应用层几乎都是java语言写的,application framework层多数也都是java代码,一些底层的系统库是用C,C++写的,所以上层的java代码要使用底层的lib库就要使用jni来实现,下面以HelloNativeDemo为例,来学习如何通过jni让java调用C、C++的代码,完成jni的大致有这几步:

       1)写一个jave类,用来声明带有native的方法,同时也要加载动态库

      2)获得这个jave类的.class文件,可以使用javac命令,也可以从app的bin目录获取

      3)依据上一步的.class文件,使用javah -jni java类名,生成扩展名为h的头文件,其实这一步不是必须的,生成这个.h的头文件,多半是为了书写native函数方便,因为这个函数名字可以直接从.h文件复制,在C文件中写的native函数,一定要符合jni的规范

      4)编写实现natvie方法的C 或者C++文件

      5)把C/C++编写的文件生成动态连接库

      

1,首先通过eclipse新建一个app,取名:HelloNativeDemo,其中包含2个类文件:

一个是app的显示类MainActivity :
package com.nativedemo.hellonativedemo;

import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.util.Log;

public class MainActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

JniDemo mJniDemo =new JniDemo();
mJniDemo.displayHelloJniStr();
Log.d("Hellojni","hello jni" +mJniDemo.getHelloJniStr());
}
。。。。。。
}


一个是负责声明本地方法的java类:
package com.nativedemo.hellonativedemo;
public class JniDemo{
//加载库文件
static {
System.loadLibrary("helloworldjni");
}
//声明要在native层实现的函数
public native void displayHelloJniStr();
public native String getHelloJniStr();
public native void noNativeFun();
}


2,然后到app的根目录,我是把app的代码放在linux的服务器上执行的。

首先进到code\LINUX\android\packages\apps\HelloNativeDemo\src\com\nativedemo\hellonativedemo这个目录,执行 javac JniDemo.java 生成JniDemo.class,然后退到目录code\LINUX\android\packages\apps\HelloNativeDemo\src这里,执行javah -jni com.nativedemo.hellonativedemo.JniDemo,生成com_nativedemo_hellonativedemo_JniDemo.h,这里执行javah命令一定要在源码的根目
4000
录,在JniDemo.java的同级目录执行javah会报错。

com_nativedemo_hellonativedemo_JniDemo.h内容如下:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_nativedemo_hellonativedemo_JniDemo */

#ifndef _Included_com_nativedemo_hellonativedemo_JniDemo
#define _Included_com_nativedemo_hellonativedemo_JniDemo
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class:     com_nativedemo_hellonativedemo_JniDemo
* Method:    displayHelloJniStr
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_com_nativedemo_hellonativedemo_JniDemo_displayHelloJniStr
(JNIEnv *, jobject);

/*
* Class:     com_nativedemo_hellonativedemo_JniDemo
* Method:    getHelloJniStr
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_nativedemo_hellonativedemo_JniDemo_getHelloJniStr
(JNIEnv *, jobject);

/*
* Class:     com_nativedemo_hellonativedemo_JniDemo
* Method:    noNativeFun
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_com_nativedemo_hellonativedemo_JniDemo_noNativeFun
(JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif


3,在app所在根目录新建一个helloWorldJni的文件夹,即是目录:\code\LINUX\android\packages\apps\HelloNativeDemo\helloWorldJni在这里放置文件前面步骤提到的文件:JniDemo.java,JniDemo.class,com_nativedemo_hellonativedemo_JniDemo.h,然后编写本地实现的JniDemoImpl.c文件,这个文件就是去实现com_nativedemo_hellonativedemo_JniDemo.h里面声明的方法,JniDemoImpl.c内容如下:
include <jni.h>
include "JNIHelp.h"
include <com_nativedemo_hellonativedemo_JniDemo.h>
include <android/log.h>

#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, "JniDemo", __VA_ARGS__)
/*
* Class:     HelloJniDemo
* Method:    displayHelloJniStr
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_com_nativedemo_hellonativedemo_JniDemo_displayHelloJniStr
(JNIEnv* jniEnv, jobject obj){
LOGD("helloJniDemo display string \n");
}

/*
* Class:     HelloJniDemo
* Method:    getHelloJniStr
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_nativedemo_hellonativedemo_JniDemo_getHelloJniStr
(JNIEnv* jniEnv, jobject obj){
//const char* str= "from jin string";
char str[32]="from jin string";
/*获取string类型,要借助于这个函数:NewStringUTF,并且这个函数的使用在c和c++里面是不一样的,这里是c语言的实现方式,如果是c++文件,要这么写:jstring jStr = jniEnv->NewStringUTF(str);
*/
jstring jStr = (*jniEnv)->NewStringUTF(jniEnv,str);
return jStr;
}

/*
* Class:     HelloJniDemo
* Method:    noNativeFun
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_com_nativedemo_hellonativedemo_JniDemo_noNativeFun
(JNIEnv* jniEnv, jobject obj){
LOGD("Hello jni demo LIB,no native !/n");
}


4,编写Android.mk文件,生成动态连接库,
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)

LOCAL_LDLIBS := -llog

LOCAL_SRC_FILES := \
JniDemoImpl.c \
JniCppDemoImple.cpp

LOCAL_C_INCLUDES := \
$(JNI_H_INCLUDE)

LOCAL_SHARED_LIBRARIES := \
libutils \
libcutils

LOCAL_PRELINK_MODULE := false

#LOCAL_MULTILIB := 64
LOCAL_MODULE:= libhelloworldjni

include $(BUILD_SHARED_LIBRARY)

该文件的一些全局变量的含义:
LOCAL_PATH的定义必须要放到所有的include $(CLEAR_VARS)之前,
LOCAL_PATH通过调用my-dir函数来获取当前的路径,
LOCAL_SRC_FILES  编译的源文件
LOCAL_C_INCLUDES  需要包含的头文件目录
LOCAL_SHARED_LIBRARIES  链接时需要的外部库
LOCAL_PRELINK_MODULE  是否需要 prelink 处理
LOCAL_MODULE  编译的目标对象
BUILD_SHARED_LIBRARY  指明要编译成动态库


5,添加应用app的Android.mk 内容如下:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional

#LOCAL_STATIC_JAVA_LIBRARIES := libarity android-support-v4 guava ejml \
#        android-support-v7-recyclerview
LOCAL_JNI_SHARED_LIBRARIES := libhelloworldjni

LOCAL_SRC_FILES := $(call all-java-files-under, src)

LOCAL_SDK_VERSION := current

LOCAL_PACKAGE_NAME := HelloNativeDemo

#LOCAL_PROGUARD_ENABLED := full
#LOCAL_PROGUARD_FLAG_FILES := proguard.flags

include $(BUILD_PACKAGE)

# Use the following include to make our test apk.
include $(call all-makefiles-under,$(LOCAL_PATH))

主要是添加 LOCAL_JNI_SHARED_LIBRARIES := libhelloworldjni 这句


6,执行./make mmma ./packages/apps/HelloNativeDemo 这个编译命令是在高通项目中的方式,其他平台可能会有差异。编译完成生成了:

\system\app\HelloNativeDemo\HelloNativeDemo.apk

\system\lib\libhelloworldjni.so

分别push到手机中的对应目录即可。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: