`
abc20899
  • 浏览: 909184 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

jni开发之一

 
阅读更多
JNI在Android系统中有着广泛的应用。Android系统底层都是C/C++实现的,上层提供的API都是Java的,Java通过JNI调用底层的实现。比如:Android API多媒体接口MediaPlayer类,其实底层通过JNI调用libmedia库。由于JNI的存在可以让我们重用很多已经存在C/C++的库,省去了重复开发的麻烦,并且可以利用很多开源的库(Android库中就有很多开源库,比如libjpeg,libpng等等),并且让我们开发的程序更有效率(C/C++代码发挥硬件最佳性能)。

交叉编译环境
    首先是要搭建交叉编译环境,因为Java层的应用程序是和硬件无关的,JDK编译即可;但是Native C/C++代码是和硬件相关的,必须要用交叉编译器编译成特定硬件可执行代码。请根据你的硬件平台搭建你的交叉编译环境,我的MIPS平台,当然选择的是MIPS的交叉编译器,如果你是Arm的请配置自己的交叉编译器。

    我们首先编译一个Native C的helloworld程序,

Java编写的Android应用程序
    我们首先用java编写helloworld应用程序(APK),这个代码很简单创建一个HelloWorld activity。代码如下:

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

public class HelloWorld extends Activity {
    private static final String TAG = "HelloWorld";
	static {
		System.loadLibrary("helloworld");
	}

	private native String printJNI();

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        Log.d(TAG, "Activity call JNI: " + printJNI());
    }
}


这个HelloWorld Activity非常简单,只是调用JNI接口printJNI()打印一些信息到Android logger上面。我们需要关注一下的是printJNI()的声明,有一个native的关键字,说明他是一个用native代码实现的函数,需要用JNI调用Native代码。另外注意static代码段,这段代码意思是当类HelloWorld第一次被加载的时候,加载libhelloworld.so(请注意这里写的是库名称,在Linux中共享库名为xxx共享库,文件存在形式为libxxx.so。所以loadLibrary的参数不是libhelloworld.so,而是helloworld。如果写错误了将会加载库失败,将会收到异常)。


C语言实现helloworld共享库
     接下来我们需要来完成Native 代码部分了,这里需要强调一下,Android JNI实现中为C/C++提供了两套不同的API,调用的时候需要注意,否则非常有可能你会受到一些libc库的崩溃信息,没准儿会把你整“崩溃”,呵呵!下面先实现Native C来实现helloworld库。

     如果你对Java标准JNI熟悉的话,肯定知道javah工具,可以根据java源程序,生成Native代码的头文件,如果你是在Eclipse中开发apk的话,可以在打开终端进入bin目录,然后执行:

javah com.simon.HelloWorld  javah 包名类名

你将会得到,一个头文件com_simon_Helloworld.h,这里包含有printJNI接口的C/C++声明。这个声明肯定正确,如果你把printJNI接口声明写错了,HelloWorld将找不到printJNI接口,然后产生崩溃。

     我们创建com_simon_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_simon_HelloWorld_printJNI(JNIEnv *env, jobject obj)
{
    LOGI("Hello World From libhelloworld.so!");

    return (*env)->NewStringUTF(env, "Hello World!");
}

/* 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;
    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_com_simon_HelloWorld_printJNI函数的名字,这个名字是符合JNI规范的,Java_开头,后面紧跟着调用他类名(包含包名和类名,com_simon_HelloWorld),然后才是接口的名字printJNI。这样java虚拟机就可以在com.simon.HelloWorld类调用printJNI接口的时候自动找到这个C实现的Native函数调用。你可能注意到这个名字非常的长,作为一个函数名它非常有可能不是一个好的选择。JNI API允许你提供一个函数映射表,注册给Jave虚拟机,这样Java虚拟机就可以用函数映射表来调用相应的函数,就可以不必通过函数名来查找需要调用的函数了。这样你的函数名也可以随便定义了(可以定义最能表现函数功能的函数名),这个将会在helloworld共享库的C++实现中演示。但是Android系统中,还是推荐用JNI标准的函数名定义的。

    JNI_OnLoad函数JNI规范定义的,当共享库第一次被加载的时候会被回调,这个函数里面可以进行一些初始化工作,比如注册函数映射表,缓存一些变量等,最后返回当前环境所支持的JNI环境。本例只是简单的返回当前JNI环境。

注意网上很多例子都说可以不实现JNI_OnLoad,我发现如果不是实现的话,printJNI只可以返回整型类型的值,如果返回其他类型的值都会崩溃。并且GetEnv的调用也是必须的,否则也是崩溃,但是GetEnv的返回值我并没有用到,这些地方使我非常迷惑,期待达人解惑。

接下来编写Android.mk文件,创建之,并输入:

LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)

LOCAL_SRC_FILES:=com_simon_Helloworld.c

LOCAL_C_INCLUDES := $(JNI_H_INCLUDE)

LOCAL_MODULE := libhelloworld

LOCAL_SHARED_LIBRARIES := libutils

LOCAL_PRELINK_MODULE := false

include $(BUILD_SHARED_LIBRARY)


这里面有几个标签需要说明:

1、LOCAL_C_INCLUDES说明包含的头文件,这里需要包含JNI的头文件。

2、LOCAL_MODULE当前模块的名称

3、LOCAL_SHARED_LIBRARIES当前模块需要依赖的共享库,因为在hellowold中我们调用Android打印系统输出到logger,所以我们必须要依赖libutils库。

4、LOCAL_PRELINK_MODULE指明该模块是否被启动就加载,可以参考《动态库优化——Prelink(预连接)技术》。我们的helloworld库不需要prelink,所以置为false。


LOCAL_SRC_FILES -  编译的源文件
LOCAL_C_INCLUDES -  需要包含的头文件目录
LOCAL_SHARED_LIBRARIES - 链接时需要的外部库
LOCAL_PRELINK_MODULE -
是否需要prelink处理(参考prelink的详细介绍:《动态库优化——Prelink(预连接)技术》,Android的Toolchain, prelink工具:《Android Toolchain与Bionic Libc》)
LOCAL_MODULE -    编译的目标对象
BUILD_SHARED_LIBRARY -  指明要编译成动态库。

接下来回到Android顶层目录,并执行make libhello来编译:
# cd $(YOUR_ANDROID) && make libhello
target thumb C: libhello <= development/hellolib/hellolib.c
target SharedLib: libhello (out/target/product/generic/obj/SHARED_LIBRARIES/libhello_intermediates/LINKED/libhello.so)
target Non-prelinked: libhello (out/target/product/generic/symbols/system/lib/libhello.so)
target Strip: libhello (out/target/product/generic/obj/lib/libhello.so)
Install: out/target/product/generic/system/lib/libhello.so


编译结果可得到位于out/target/product/generic/system/lib/目录的动态共享库libhello.so






使用ndk编译:
在android项目中建立一个jni目录,
把*.h与*.c两个文件拷贝到jni目录
把android项目拷贝到NDK的sample目录
然后进入jni目录,ndk-build
分享到:
评论

相关推荐

    android-JNI开发

    一个简单的android JNI 开发范例. 可以做入门学习之用

    JNI开发之NDK下载

    资源是个TXT文件,里面是百度云盘链接跟提取码 一共两个文件,一个32位的一个64的,每个450M左右

    尚硅谷Android高级开发技术之JNI和NDK开发

    这算是尚硅谷培训学校推出的Android视频教程的高级教程了吧,而本套教程正是在Android开发中的核心重点开发技术(JNI/NDK...本教程照顾了不会C/C++的同学,会讲一些C/C++的基本知识,是一个JNI/NDK开发不可多得的教程。

    android jni调用demo

    这是Android的NDK开发之Android JNI调用流程程一个demo。下载下来可以直接在android studio上运行。

    JNI介绍及开发i教程.rar

    JNA(JavaNativeAccess)框架是一个开源的Java框架,是SUN公司主导开发的,建立在经典的JNI的基础之上的一个框架。 JNA项目地址:https://jna.dev.java.net/ JNA使Java调用原生函数就像.NET上的P/Invoke一样方便、快捷...

    Android 入门JNI的函数统计

    以前开发JNI是整理的一个JNI表格,都是常用的JNI函数,并且是个excel表格,方便查询,里面有各个函数的用法,挺好的资料,分享给大家参考

    android串口开发入门之搭建ndk开发环境及第一个jni调用程序

    主要给大家介绍了关于android串口开发入门之搭建ndk开发环境及第一个jni调用程序的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习...

    Android串口开发之使用JNI实现ANDROID和串口通信详解

    如果未配置ndk配置的朋友,或者对jni不熟悉的朋友,请查看上一篇文章,android 串口开发第一篇:搭建ndk开发环境以及第一个jni调用程序 ,串口通信和java操作io类似,先打开串口,然后向串口发送或者读取数据,最后关闭...

    JNI技术手册 c/c++调用java

    II. java c/cpp互相调用实例(姊妹篇之一)——java调用c/cpp 4 一 先制作一个系统中有的DLL文件(cpp给出的sdk接口) 4 二 JNI 7 1、 编写java文件 7 2、 生成.h头文件 8 3、 用c/cpp实现这个头文件 9 三 测试 10 ...

    Android代码-安卓串口打开、接收与发送

    AndroidSerialPort ...涉及到的 jni 开发可以参考:【Android 应用开发】Android 开发 之 JNI入门 - NDK从入门到精通 jni 开发遇到的坑:https://github.com/jp1017/Android-Collection/issues/10

    JNI技术在网络交互中的应用

    Android是一款运行在开放的Linux内核之上的操作系统,其上层应用程序采用Java开发语言,底层核心类库采用C/C++语言编写,开发者能够非常便捷的使用Android SDK调用丰富的API,实现各种功能。不仅如此,Android还支持...

    《Android应用开发揭秘》源码

     16.3.1 JNI接口设计  16.3.2 使用C\C++实现本地方法  16.3 编译C\C++代码  16.4 AndroidNDK中使用0penGL  16.5小结  第17章 Android脚本环境  17.1 Android脚本环境简介  17.2 Android脚本环境安装  17.3...

    《Android应用开发揭秘》附带光盘代码.

     16.3.1 JNI接口设计  16.3.2 使用C\C++实现本地  方法  16.3 编译C\C++代码  16.4 AndroidNDK中使用0penGL  16.5小结  第17章 Android脚本环境  17.1 Android脚本环境简介  17.2 Android脚本环境安装  ...

    《深入理解Android》卷Ⅰ

    1.2 搭建开发环境 1.2.1 下载源码 1.2.2 编译源码 1.3 工具介绍 1.3.1 Source Insight介绍 1.3.3 Busybox的使用 1.4 本章小结 第2章 深入理解JNI 2.1 JNI概述 2.2 学习JNI的实例:MediaScanner 2.3 Java层的...

    Android应用开发揭秘pdf高清版

    C++(NDK)和Python、Lua等脚本语言(AndroidScriptingEnvironment)来开发Android应用,《Android应用开发揭秘》实战性强,书中的每个知识点都有配精心设计的示例,尤为值得一提的是,它还以迭代的方式重现了各种...

    JNA最新源文件jar包

    JNA(Java Native Access)框架是一个开源的Java框架,是SUN公司主导开发的,建立在经典的JNI的基础之上的一个框架。使用JNI调用共享类库(.dll/.so文件)是非常麻烦的事情,既需要编写java代码,又要编写C语言的代理...

    android开发艺术探索高清完整版PDF

    《Android开发艺术探索》是一本Android进阶类书籍,采用理论、源码和实践相结合的方式来阐述高水准的Android应用开发要点。《Android开发艺术探索》从三个方面来组织内容。第一,介绍Android开发者不容易掌握的一些...

Global site tag (gtag.js) - Google Analytics