JNI在Android系统中有着广泛的应用。Android系统底层都是C/C++实现的,上层提供的API都是Java的,Java通过JNI调用底 层的实现。比如:Android API多媒体接口MediaPlayer类,其实底层通过JNI调用libmedia库。由于JNI的存在可以让我们重用很多已经存在C/C++的库,省 去了重复开发的麻烦,并且可以利用很多开源的库(Android库中就有很多开源库,比如libjpeg,libpng等等),并且让我们开发的程序更有 效率(C/C++代码发挥硬件最佳性能)。如果你对标准JNI不熟悉的话,可以先参考我的博文《Linux下JNI实现》,文中介绍了怎样用标准JNI在Linux系统中实现一个Helloworld程序,可以让你对JNI有一个初步的认识。本文简单介绍一下怎样在Android下面怎样用JNI开发程序,并开发一个经典Helloworld应用程序。

交叉编译环境

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

我们首先编译一个Native C的helloworld程序,一个学习怎样在Android中增加一个程序,另外也可以验证我们的交叉编译环境是否正确,可以参考《Android编译环境(1) – 编译Native C的helloworld模块》。如果这个步没有问题说明你的交叉编译环境是没有问题的,可以继续往下面进行。

Java编写的Android应用程序

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

package com.simon;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. */@Overridepublic 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代码的头文件(可以参考我的博文《Linux下JNI实现》)。如果你是在Eclipse中开发apk的话,可以在打开终端进入bin目录,然后执行:

javah com.simon.HelloWorld

你将会得到,一个头文件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.cLOCAL_C_INCLUDES := $(JNI_H_INCLUDE)LOCAL_MODULE := libhelloworldLOCAL_SHARED_LIBRARIES := libutilsLOCAL_PRELINK_MODULE := falseinclude $(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。

编译这个模块,根据你的环境不同,选择不同的编译途径。然后安装apk,然后运行他们,通过logcat工具将会看到相应的输出。

原文

转载于:https://www.cnblogs.com/xiaoxiaoboke/archive/2012/02/13/2349651.html

Android JNI开发入门之一相关推荐

  1. Android JNI开发入门之二

    在上一篇文章<Android JNI开发入门之一>中,我介绍了Android应用程序(APK)怎样通过JNI调用Native C实现的共享库.本文将进一步介绍Android应用程序通过JN ...

  2. Android JNI开发入门与实战

    简介: 涉及到一些算法或者底层驱动的时候,往往需要使用jni来开发.现在官方推荐使用CMake工具来开发jni. 使用CMake开发Jni其实挺简单的,要求不高的话只需要简单配置一下就可以使用了. 配 ...

  3. Android APP开发入门

    Android APP开发入门 目录 android_studio很好用的一个就是debug 1 1导入demo编译出错 1 4使用as运行安装不了apk安装adb 2 5SeekBar组件使用 2 ...

  4. AndroidStudio jni开发入门及打包so库和jar包

    AndroidStudio jni开发入门及打包so库和jar包 配置ndk开发环境 下载NDK,LLDB,CMake工具包 配置系统环境变量 在原有项目中进行jni开发环境配置 Androidstu ...

  5. Android JNI开发

    1. 在Android Studio开发JNI Android Studio第一个JNI开发入门(整理一)_sevenjoin的博客-CSDN博客_androidstudio jni开发 Androi ...

  6. 5G 时代的 Android App 开发入门与项目实战

    随着移动互联网的持续发展,Android系统从智能手机逐步拓展到平板电脑.智能电视.车载大屏.智能家居.智能手表等诸多设备,Android开发依然是前景可期的IT岗位. 当然,整个社会正在迈向5G时代 ...

  7. 《Android应用开发入门经典(第3版)》——第6.1节创建演示应用

    本节书摘来自异步社区<Android应用开发入门经典(第3版)>一书中的第6章,第6.1节创建演示应用,作者 [美]Carmen Delessio , Lauren Darcey , Sh ...

  8. 《Android应用开发入门经典(第3版)》——导读

    本节书摘来自异步社区<Android应用开发入门经典(第3版)>一书中的目录,作者 [美]Carmen Delessio , Lauren Darcey , Shane Conder,更多 ...

  9. Android 游戏开发入门

    Android 游戏开发入门 图书描述: Android系统已经红遍了大江南北,持有Android设备的人也在不断增长.看着大街上用手指划着手机玩游戏的人,你有没有一种自己做一个游戏的想法呢?然而,入 ...

最新文章

  1. 今年1篇Science,2篇NBT,2篇MP,1篇PNAS等11篇文章,遗传发育所白洋组在植物微生物组取得系列进展!
  2. [Head First设计模式]餐馆中的设计模式——命令模式
  3. 索赔 100 万!只是因为一个开源插件?
  4. python第三方库安装-python第三方库安装在哪
  5. java web netty_基于Netty的非Servlet规范 JavaWeb框架及高性能 Java服务器
  6. MySQL——修改root密码的4种方法(以windows为例)
  7. Gitlab7.0通知邮箱的配置(smtp)
  8. requestmapping注解访问404_【框架】127:几个非常重要的注解
  9. UVA - 202 Repeating Decimals
  10. django-模板语言
  11. Python 学习入门(22)—— 线程同步
  12. Microsoft visio 2013 professional破解软件
  13. uml点餐系统活动图_大学生网上订餐系统--UML建模
  14. 从一到无穷大--读后感
  15. 立创EDA---PCB
  16. 武汉科技大学计算机学院温文,第五届华中地区计算机类院校学生领袖峰会成功举行...
  17. PQ节点-PV节点-平衡节点
  18. 过去两三年 互联网科技公司的掌舵人这样看区块链
  19. 面试官:什么是虚拟DOM?如何实现一个虚拟DOM?
  20. 全国计算机二级考试设置地点,黑龙江2020年3月全国计算机等级考试考点设置

热门文章

  1. 用链栈实现简易四则运算计算器(php版)
  2. css案例学习之全局声明*{} 与body{}的区别
  3. Integer 和 int的种种比较
  4. 过河问题 还是不会 去学请教一下 数学老师 -----
  5. 虚拟存储:迈向私有云的关键一步
  6. 2016年十大存储预测
  7. S5700三层交换机 复杂网络环境设置默认路优先级实战
  8. Hibernate(2)——Hibernate的实现原理总结和对其模仿的demo
  9. CSS代码重构与优化之路
  10. 29个月过去了,CSDN排名前200了:排名不断靠前的过程中,自己的技术水平和竞争力一定会不断向上...