JNI调用

原创 2015年11月18日 14:17:41

参考:http://www.cnblogs.com/bastard/archive/2012/05/19/2508913.html

        http://blog.csdn.net/cghs123/article/details/7044826

1.新建Android工程 JNITest


在HelloWorld的Activity中添加加载c库的代码,系统运行后自动执行该段
    static {
        //加载库文件
        System.loadLibrary("HelloWorldJni");
    }

声明c库中需要自定义的原生函数
private native String printJNI(String inputStr);
HelloWorld整段代码如下:

package com.sirc.jni;

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

public class HelloWorld extends Activity {

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

        String jniStr=printJNI("I am HelloWorld Activity");
        Log.v("android", jniStr);
        
    }
    static
    {
        //加载库文件
        System.loadLibrary("HelloWorldJni");
    }
    //声明原生函数 参数为String类型 返回类型为String
    private native String printJNI(String inputStr);

}

2.生成共享库的头文件

我们都知道在Eclipse中新建类后,eclipse会帮助我们在项目下自动建立去对应的class文件,位于项目目录下的\bin\classes中。共享库的头文件可以根据class文件通过javah编译生成。

通过命令进入项目根目录

再输入命令:javah -classpath bin\classes -d jni com.sirc.jni.HelloWorld 

可以得到头文件com_sirc_jni_HelloWorld.h,位于跟目录/jni/下面

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

#ifndef _Included_com_sirc_jni_HelloWorld
#define _Included_com_sirc_jni_HelloWorld
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_sirc_jni_HelloWorld
 * Method:    printJNI
 * Signature: (Ljava/lang/String;)Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_sirc_jni_HelloWorld_printJNI
  (JNIEnv *, jobject, jstring);

#ifdef __cplusplus
}
#endif
#endif

头文件中定义了与上层的访问接口Java_com_sirc_jni_HelloWorld_printJNI,方法名是按照”Java_包名_类名_方法名“来命名的。

3.实现JNI原生函数源文件

在jni文件夹下面新建com_sirc_jni_HelloWorld.c文件,文件代码如下:
#include <jni.h>
/* Native interface, it will be call in java code */
JNIEXPORT jstring JNICALL Java_com_sirc_jni_HelloWorld_printJNI(JNIEnv *env,
        jobject obj, jstring inputStr) {
    // 从 instring 字符串取得指向字符串 UTF 编码的指针
    const char *str = (const char *) (*env)->GetStringUTFChars(env, inputStr,
            JNI_FALSE);
    // 通知虚拟机本地代码不再需要通过 str 访问 Java 字符串。
    (*env)->ReleaseStringUTFChars(env, inputStr, (const char *) str);
    return (*env)->NewStringUTF(env, "Hello World! I am Native interface");
}


/* This function will be call when the library first be load.
 * You can do some init in the libray. return which version jni it support.
 */
jint JNI_OnLoad(JavaVM* vm, void* reserved) {
    void *venv;
    if ((*vm)->GetEnv(vm, (void**) &venv, JNI_VERSION_1_4) != JNI_OK) {
        return -1;
    }
    return JNI_VERSION_1_4;
}

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

Java_com_sirc_jni_HelloWorld_printJNI是头文件中方法的实现,可以通过这里获取上层传过来的参数,并在这里返回数据给上层框架使用。

注:这段代码是从其他网站上copy过来的,运行时如果出现错误stray '/241' in program 该错误是指源程序中有非法字符,需要去掉非法字符。

解决方法:来源于http://blog.sina.com.cn/s/blog_6bc5571a0100zmft.html

(1)把所粘的文字放到记事本里就行了 

(2)把出错行的空格删掉重新打一下试试。

4.编译生成so

4.1在jni文件夹下面新建Android.mk文件,文件内容如下:

LOCAL_PATH:= $(call my-dir)
# 一个完整模块编译
include $(CLEAR_VARS)
LOCAL_SRC_FILES:=com_sirc_jni_HelloWorld.c
LOCAL_C_INCLUDES := $(JNI_H_INCLUDE)
LOCAL_MODULE := libHelloWorldJni
LOCAL_SHARED_LIBRARIES := libutils
LOCAL_PRELINK_MODULE := false
LOCAL_MODULE_TAGS :=optional
LOCAL_LDLIBS += -L$(SYSROOT)/usr/lib -llog
include $(BUILD_SHARED_LIBRARY)

系统变量解析:

  LOCAL_PATH - 编译时的目录
  
$(call 
目录,目录….) 目录引入操作符
    
如该目录下有个文件夹名称 src,则可以这样写 $(call src),那么就会得到 src 目录的完整路径

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

4.2编译

我这里使用NDK来进行编译,首先要下载安装NDK。

Android NDK安装很简单,直接到http://developer.android.com/tools/sdk/ndk/index.html 下载android-ndk-r8e-windows-x86.zip 解压即可,接着设置环境变量。右击我的电脑属性,切换到高级选项卡,单击环境变量,在系统变量下单击编辑在Path变量名下直接变量值;D:\Android\android-ndk-r8e-windows-x86\android-ndk-r8e\ ,也就是你的解压路径,其中有个封号与前面的变量值分割。单击确定NDK就安装好了。

在命令行中使用ndk-build编译,过程如下




编译成功后会自动生成libs/armeabi/libHelloWorldJni.so文件。

5.运行测试

运行JNITest项目,在logcat中查看运行结果。可以看到

上层打印情况:



End!





版权声明:本文为博主原创文章,未经博主允许不得转载。

Android调用JNI的简单实例(附详细步骤)

最近想调用FFmepg库来做编解码的东西,首先就得学会使用JNI(JAVA Native Interface)调用。 下面做个简单的JNI调用实例,中间遇到的问题及解决过程省略一万字,查找到的资料也都...
  • EricFantastic
  • EricFantastic
  • 2015年10月21日 09:45
  • 4499

JNI/NDK开发指南(六)——C/C++访问Java实例方法和静态方法

通过前面5章的学习,我们知道了如何通过JNI函数来访问JVM中的基本数据类型、字符串和数组这些数据类型。下一步我们来学习本地代码如何与JVM中任意对象的属性和方法进行交互。比如本地代码调用Java层某...
  • xyang81
  • xyang81
  • 2015年01月11日 01:29
  • 18482

JNI_最简单的Java调用C/C++代码

JNI_最简单的Java调用C/C++代码 JNI,是Java Native Interface的简称,中文是“Java本地调用”。通过这种技术可以做到以下两点:Java程序中的函数可以调用Nativ...
  • wwj_748
  • wwj_748
  • 2014年06月02日 21:34
  • 22770

Android studio Jni调用第三方库(CMakelist)

  • 2017年11月29日 17:48
  • 20.21MB
  • 下载

JNI调用第三方dll实例

  • 2014年09月26日 09:56
  • 26.01MB
  • 下载

android-jni&amp;底层调用开发讲解

  • 2015年01月17日 09:40
  • 2.16MB
  • 下载

JNI编程示例(Java调用C-C++)

  • 2007年09月26日 17:26
  • 39KB
  • 下载

delphi通过JNI调用JAVA函数

  • 2011年10月20日 16:00
  • 6KB
  • 下载

jni调用第三方dll最简单的实例

  • 2012年08月26日 20:57
  • 14.63MB
  • 下载

linux调用jni生成的so

  • 2015年08月04日 11:29
  • 11KB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:JNI调用
举报原因:
原因补充:

(最多只允许输入30个字)