Android中JNI的使用方法

Android通过Jni实现Java对C/C++函数的调用示例说明:

A.第一步

使用Java编写Android应用程序,以HelloWorld为例:

 

<pre name="code" class="objc">package com.lucy;

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

public class HelloWorld extends Activity {
   @Override
   public void onCreate(Bundle savedInstanceState){
     super.onCreate(savedInstanceState);
     setContentView(R.layout.main);
     Log.v("dufresne", printJNI("I am HelloWorld Activity"));
   }
  static{
    //加载库文件
    System.loadLibrary("HelloWorldJni");
  }
   //声明原生函数 参数为String类型 返回类型为String
  private native String printJNI(String inputStr);
}
编写完成之后,用eclipse编译Java应用程序。

 

 

 

B.第二步

生成共享库的头文件:

  进入到eclipse对应的AndroidProject中 :/HelloWorld/bin/classes/com/lucy/下:

  可以看到里面有很多后缀为.class的文件,就是eclipse为我们自动编译好了的java文件,其中就有:HelloWorld.class文件。

  退回到classes一级目录:/HelloWorld/bin/classes/执行如下命令:

  javah com.lucy.HelloWorld

  生成文件:com_lucy_HelloWorld.h

 

#include <jni.h>
#ifndef _Included_com_lucy_HelloWorld
#define _Included_com_lucy_HelloWorld
#ifdef __cplusplus
extern "C" {
#endif

JNIEXPORT jstring JNICALL Java_com_lucy_HelloWorld_printJNI(JNIEnv *, jobject, jstring);

#ifdef __cplusplus
}
#endif
#endif

 

 

可以看到自动生成对应的函数:Java_com_lucy_HelloWorld_printJNI

 

  Java_ + 包名(com.lucy) + 类名(HelloWorld) + 接口名(printJNI):必须要按此JNI规范来操作。

  当然函数名太长,可以在.c文件中通过函数名映射表来实现简化。

 

C.第三步

实现JNI原生函数源文件:

新建com_lucy_HelloWorld.c文件:

 

#include <jni.h>
#define LOG_TAG "HelloWorld"
#include <utils/Log.h>
/* Native interface, it will be call in java code */
JNIEXPORT jstring JNICALL Java_com_lucy_HelloWorld_printJNI(JNIEnv *env, jobject obj,jstring inputStr)
{
  LOGI("dufresne Hello World From libhelloworld.so!");
  const char *str = (const char *)(*env)->GetStringUTFChars( env,inputStr, JNI_FALSE );
  LOGI("dufresne--->%s",(const char *)str);
  (*env)->ReleaseStringUTFChars(env, inputStr, (const char *)str );
  return (*env)->NewStringUTF(env, "Hello World! I am Native interface");
}

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

 

OnLoad  Java_com_lucy_HelloWorld_printJNI

函数里面做一些log输出,注意JNI中的log输出的不同。

  JNI_OnLoad函数JNI规范定义的,当共享库第一次被加载的时候会被回调,

这个函数里面可以进行一些初始化工作,比如注册函数映射表,缓存一些变量等,

最后返回当前环境所支持的JNI环境。本例只是简单的返回当前JNI环境。

D.第四步

编译生成so库

  编译com_lucy_HelloWorld.c生成so库可以和app一起编译,也可以都单独编译。

        在当前目录下建立jni文件夹:HelloWorld/jni/下建立Android.mk ,并将com_lucy_HelloWorld.c和 com_lucy_HelloWorld.h 拷贝到进去

编写编译生成so库的Android.mk文件:

 

LOCAL_PATH:= $(call my-dir)
# 一个完整模块编译
include $(CLEAR_VARS)
LOCAL_SRC_FILES:=com_lucy_HelloWorld.c
LOCAL_C_INCLUDES := $(JNI_H_INCLUDE)
LOCAL_MODULE := libHelloWorldJni
LOCAL_SHARED_LIBRARIES := libutils
LOCAL_PRELINK_MODULE := false
LOCAL_MODULE_TAGS :=optional
include $(BUILD_SHARED_LIBRARY)

 

系统变量解析:

  LOCAL_PATH - 编译时的目录
  $(call目录,目录….)目录引入操作符

  include$(CLEAR_VARS) -清除之前的一些系统变量
  LOCAL_MODULE-编译生成的目标对象
  LOCAL_SRC_FILES-编译的源文件
  LOCAL_C_INCLUDES-需要包含的头文件目录
  LOCAL_SHARED_LIBRARIES-链接时需要的外部库
  LOCAL_PRELINK_MODULE-是否需要prelink处理
  include$(BUILD_SHARED_LIBRARY)-指明要编译成动态库

  android.mk编译模块添加具体方法参考:http://blog.csdn.net/yili_xie/article/details/4906865

 

编译此模块:输入编译命令

  ./make Mtkmm packages/apps/HelloWorld/jni/

  上面是我的工程根目录编译命令。具体编译方式根据自己系统要求执行。

        编译输出:libHelloWorldJni.so (system/lib中视具体而定)

  此时库文件编译好了可以使用,如果在eclipse中模拟器上使用,需要将libHelloWorldJni.so导入到system/lib下,

  或者对应app的data/data/com.lucy/lib/下;

        直接在真机上弄,看一下HelloWorld中Android.mk文件的配置:

  其中存在:

    include$(LOCAL_PATH)/jni/Android.mk 表示编译库文件

    LOCAL_JNI_SHARED_LIBRARIES:= libHelloWorldJni 表示app依赖库,打包的时候会一起打包。

E.第五步

验证执行

  将编译好的apk安装到手机上

  使用adbpush到手机上去需要自己去导入库文件libHelloWorldJni.so到data/data/com.lucy/lib/

  使用adbinstall方式安装则会自动导入。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值