【Android学习】NDK编程——JNI(Java Native Interface,java本地接口)编程

1,NDK(Native Development Kit,原生开发套件)

1)概念

NDK是在Android1.5引入,是SDK的辅助工具,可以用它把Android应用的一部分或全部用本地代码实现。

在Android开发中,通常使用SDK(Software Development Kit)开发java程序。对于性能要求较高的,通常使用NDK开发基于C/C++的本地库。

2)组成部分

所有文件放在一个单独的目录中。

①目录

build
docs
platforms
samples
sources
tests
toolchains
documentation.html
GNUmakefile
ndk-build
ndk-gdb
ndk-stack
README.txt
RELEASE.txt

②包含组件

文档
头文件
C/C++文件
预编译库
编译、链接、分析和调试代码的工具
示例应用程序

③针对不同平台有不同版本的预编译库

armeabi

ARM芯片。

armeabi-v7a

ARM芯片。

x86

表示Intel架构

2,JNI(Java Native Interface,java本地接口)

1)概念

在Android Framework中,JNI将java层(上层)与C/C++层(底层)联系起来,让java能够找到对应的本地实现方法。
JNI提供了一系列接口,允许java类与本地语言编写的应用程序、模块、库进行交互操作。

2)场景

①注重处理速度

②硬件控制

硬件控制代码通常用C语言编写。

③已有C/C++代码的复用

已经有写好的确认安全高效的C代码。

④用C/C++调用现有jar包

我见过有人这样做,低层调用高层一般不合适,这是标准懒人做法。
但是对于效率要求不高的项目,直接调用完成度比较高的jar包可能更安全吧,我可以包容这种做法,但不推荐。

3)JNI调用过程

安装和下载Cygwin下载Android NDK
在ndk项目中JNI接口的设计
使用C/C++实现本地方法
JNI生成动态链接库.so文件
将动态链接库复制到java工程在java工程中调用运行java工程即可。

3,实现

1)Java调用C++

①在Java中声明Native方法(即需要调用的本地方法)
②编译上述 Java源文件javac(得到 .class文件)
③通过 javah 命令导出JNI的头文件(.h文件)
④使用 Java需要交互的本地代码 实现在 Java中声明的Native方法
⑤通过NDK将.c编译为.so库文件(.so动态链接库)
⑥导入项目:libs/armeabi;通过Java命令执行 Java程序,最终实现Java调用本地代码

2)C++调用Java

①从classpath路径下搜索ClassMethod这个类,并返回该类的Class对象。
②获取类的默认构造方法ID。
③查找实例方法的ID。
④创建该类的实例。
⑤调用对象的实例方法。

4,java和C/C++混用

首先,建立java工程从helloworld开始。Android工程一样。

1)编写java代码

用native关键字 声明本地方法,不需要实现。
本地方法可以是public、protected、private、friendly。

package com.jnitest;

public class HelloJNI {
    //本地方法声明
    native void printHello();

    //加载库(dll文件,由VS生成)
    static{System.loadLibrary("HelloJNI");}

    public static void main(String[] args) {
        HelloJNI myJNI = new HelloJNI();

        //调用本地方法(实际上是用C语言编写的JNI本地函数)
        myJNI.printHello();
    }
}

2)编译java代码

通过javac命令编译java代码,生成.class文件。
class文件生成
刚开始出现了错误,根据提示把java文件的Text file encoding编码方式改为GBK就可以了。
运行成功后在当前目录生成.class文件。
生成的文件
(Android编译后的文件放在bin/classes目录下)。

3)生成C语言头文件

用javah命令生成头文件(.h)。
头文件

-classpath <路径> 用于装入类的路径  
(对于Android,后面的路径是指包”com.example.myclass”.class文件所在的根路径。
对于Java,后面的路径是.class文件所在路径)
-d <目录> 输出目录  (头文件输出的路径)
-jni 生成 JNI样式的头文件(默认) (后面的路径是包名+类名)

生成成功,我们可在刚才指定的目录src下看到对应头文件。

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

#ifndef _Included_com_jnitest_HelloJNI
#define _Included_com_jnitest_HelloJNI
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_jnitest_HelloJNI
 * Method:    printHello
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_com_jnitest_HelloJNI_printHello
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

内容不要修改。

我们 需要看一下这个函数原型。

JNIEXPORT void JNICALL Java_com_jnitest_HelloJNI_printHello
  (JNIEnv *, jobject);

有2个默认的参数,JNIEnv *是JNI接口的指针,用来调用JNI表中的各种JNI函数;参数类型jobject也是JNI提供的Java本地类型,用来再C代码中访问Java对象,此参数中保存着调用本地方法对象的一个引用。

4)编写C代码

在.h中拿到C函数原型,写C代码(.cpp)。

/* DO NOT EDIT THIS FILE - it is machine generated */
#include "HelloJNI.h"
#include <stdio.h>

JNIEXPORT void JNICALL Java_com_jnitest_HelloJNI_printHello(JNIEnv *, jobject)
  {

    printf("Hello World!\n");
    return;
  }

5)生成C共享库

用VS2013,用已经写好的.h和 .cpp生成dll文件。

新建项目:
新建项目

应用程序配置选择dll:
dll新建

删除初始的.h和.cpp文件,导入之前写好的.h和.cpp文件。
删除文件

导入后,cpp文件中有JNIEXPORT 报错:此声明没有存储类或类型说明符。
解决办法是:将 Java\jdk1.8.0_40\include\ jni.h Java\jdk1.8.0_40\include\win32\jni_md.h Java\jdk1.8.0_40\include\win32\jawt_md.h 这个3个文件拷贝到 Microsoft Visual Studio 10.0\VC\include 目录下即可。

修改项目名称为想要生成的dll文件名。
在.cpp文件右击,选择不使用预编译头。如图所示:
不使用预编译头

如果VS生成平台是32位,而java平台是64位则会报错。

Can't load IA 32-bit .dll on a AMD 64-bit platform

我们需要检查一下。
64-32位平台切换
新建并选择x64。
选择x64

项目名称右击生成。在 debug目录可以看到生成的dll文件。

为了方便 日后修改,我们不需要移动dll文件,这样 以后VS平台开发生成后可以直接再java平台使用。

6)运行java程序

接下来就是把刚才的dll文件导入java项目中。
双击Native library location:…,选择dll路径。
关联dll

运行java,成功。我们可以看到控制台输出了Hello World!
hello world

5,应用

1)Android

再Android系统 中,有大量代码使用了JNI函数,这些代码存在于Android源码的相关目录中:
framworks\base\core\jni
framworks\base\services\jni
framworks\base\media\jni
有时间翻阅一下源码。

2)eclipse-failed to load the JNI shared library问题

问题:
很久没有用eclipse,刚才打开,提示:failed to load the jni shared library。这个问题一般是eclipse和JDK位数不一样。

解决方案:
1,在cmd中输入【Java -version】
问题解决
在这里,画线部分是Client VM表示是32位的jdk。若是64-bit Server,表示64位jdk。
2,打开eclipse安装目录
问题解决
记事本方式打开eclipse.ini。我用sublime打开的。如下图。划红线处,是win32.x86表示32位。win32.x86_64,是根据你电脑的环境来安装,我电脑是64位机,所以eclipse是64位。所以jdk和eclipse版本不同。
问题解决

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值