Android 下 JNI 开发简介

Android 下 JNI 开发

一、什么是 JNI
  • JNI java native interface native 本地 java 本地接口
  • 通过 JNI 可以实现 java 和本地代码之间相互调用
  • jni 可以看做是翻译,实际上就是一套协议
二、为什么要用 JNI
   Java 一处编译到处运行
  1. java 运行在虚拟机上,JNI 可以扩展 java 虚拟机的能力,让 java 代码可以调用驱动。
  2. java 是解释型语言,运行效率相对较低,C/C++的效率要高很多,通过 jni调用耗时操作方法 C/C++可以提高 java 运行效率。
  3. java 代码编译成的.class 文件安全性较差, 可以通过 jni 把重要的业务逻辑放到 c/c++去实现,c/c++反编译比较困难,安全性较高。
  4. C 历史悠久,1972 年 C 通过 JNI 可以调用优秀的 C 开源类库。
三、怎么用 JNI

  • 掌握 java 
  • 能看懂 c/c++ 会调用
  • NI 开发流程 NDK native develop ki

四、交叉编译
  • 在一个平台上去编译另一个平台上可以执行的本地代码
  • cpu 平台: arm  x86
  • 操作系统平台:windows linux  mac os
  • 原理:模拟不同平台的特性去编译代码
五、jni 开发工具
  • ndk native develop kit
  • ndk 目录
    1. docs 帮助文档
    2. platforms 好多平台版本文件夹,选择时选择项目支持的最小版本号对应的文件夹
    3. 每一个版本号的文件夹中放了不同 cpu 架构的资源文件
    4. include 文件夹:jni 开发中常用的 .h 头文件
    5. lib 文件夹:google 打包好的提供给开发者使用的 .so 文件
    6. Samples:google 官方提供的样例工程,可以参考进行开发
    7. android-ndk-r9d\build\tools:linux 系统下的批处理文件,在交叉编译时会自动调用
    8. ndk-build:交叉编译的命令
  • cdt  eclipse 的插件用于高亮显示 C 代码,C 的代码提示

六、Jni-Helloworld 开发

    jni 开发的步骤
  1. 写 java 代码,声明本地方法,用到 native 关键字,本地方法不用去实现。
  2. 项目根目录下创建 jni 文件夹
  3. 在 jni 文件夹下创建.c 文件
本地函数命名规则: Java 包名类名_本地方法名
JNIENV* env JNIEnv 是 JniNativeInterface 这个结构体的一级指针
JniNativeInterface 这个结构体定义了大量的函数指针
env 就是结构体 JniNativeInterface 这个结构体的二级指针
(*env)->调用结构体中的函数指针

第二个参数 jobject 调用本地函数的 Java 对象就是这个 jobject

   4.  导入<jni.h>

   5.  创建 Android.mk makefile 告诉编译器.c 的源文件在什么地方,要生成的编译对象的名字是什么

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCALMODULE := hello #指定了生成的动态链接库的名字
LOCALSRC_FILES := hello.c #指定了 C 的源文件叫什么名字

include $(BUILDSHAREDLIBRARY)

   6.  调 用 ndk-build 编 译 c 代 码 生 成 动 态 链 接 库 .so 文 件 , 文 件 的 位 置 :
        lib->armeabi->.so

   7.  在 java 代码中加载动态链接库:System.loadlibrary("动态链接库的名字"); Android.mk LOCAL_MODULE 所指定的名字


七、jni 开发中的常见错误
  • java.lang.UnsatisfiedLinkError: Native method not found: 本地方法没有找到
    1. 本地函数名写错
    2. 忘记加载.so 文件 没有调用 System.loadlibrary
  • findLibrary returned null
    1. System.loadLibrary("libhello"); 加载动态链接库时,动态链接库名字写错
    2. 平台类型错误:把只支持 arm 平台的.so 文件部署到了 x86cpu 的设备上,在 jni 目录下创建 Application.mk 在里面指定

APPABI := armeabi APPPLATFORM := android-14


八、jni 简便开发流程

  1. 写 java 代码 native 声明本地方法
  2. 添加本地支持 右键单击项目->andorid tools->add native surport如果发现 finish 不能点击,需要给工作空间配置 ndk 目录的位置。
window->preferences->左侧选择 android->ndk,把 ndk 解压的目录指定进来

   3.  如果写的是.c 的文件,先修改一下生成的.cpp 文件的扩展名,不要忘了相应修改 Android.mk 文件中 LOCALSRCFILES 的值
   4.  javah 生成头文件,在生成的头文件中拷贝 c 的函数名到.c 的文件
   5.  解决 CDT 插件报错的问题
        右键单击项目选择 properties 选测 c/c++ general->paths and
symbols->include 选项卡下->点击 add..->file system 选择 ndk 目录下
platforms 文件夹 对应平台下(项目支持的最小版本) usr 目录下 arch-arm ->
include 确定后 会解决代码提示和报错的问题
   6.  编写 C 函数:如果需要单独编译一下 c 代码就在 c/c++视图中找到小锤子,如果想直接运行到模拟器上,就不用锤子了

   7.  java 代码中不要忘了加载类库:system.loadlibrary();


九、C 代码中向 logcat 输出内容

Android.mk 文件增加以下内容:
LOCAL_LDLIBS += -llog
C 代码中增加以下内容
#include <android/log.h>
#define LOG_TAG "System.out"
#define
LOGD(...)
__android_log_print(ANDROID_LOG_DEBUG, LOG_TAG,
__android_log_print(ANDROID_LOG_INFO, LOG_TAG,
__VA_ARGS__)
#define
LOGI(...)
__VA_ARGS__)

  • define C 的 宏 定 义 起别名
        #define LOGTAG "System.out" 给"System.out"起别名 LOGTAG
  • #define
LOGI(...)
androidlogprint(ANDROID_LOGINFO,
LOGTAG,

  • _VAARGS)给androidlogprint 函数起别名 写死了前两个参数 第一个参数 优先级 第二个参数 TAG
  •  VAARGS_ 可变参数的固定写法
  •  LOGI(...)在调用的时候 用法跟 printf()一样


十、C 代码回调 java 方法

    1.  找到字节码对象

jclass (FindClass)(JNIEnv, const char*);
第二个参数 :要回调的 java 方法所在的类的路径

"com/itheima/callbackjava/JNI"

    2.  通过字节码对象找到方法对象
jmethodID (GetMethodID)(JNIEnv, jclass, const char, const char);
第二个参数 :字节码对象, 第三个参数:要反射调用的 java 方法名, 第四个
参数:要反射调用的 java 方法签名

javap -s 要获取方法签名的类的全类名 项目/bin/classes 运行 javap

    3.  通过字节码创建 java 对象(可选),如果本地方法和要回调的 java 方法在同一个类里可以直接用 jni 传过来的 java 对象调用创建的 Method

jobject obj =(*env)->AllocObject(env,claz);
当回调的方法跟本地方法不在一个类里, 需要通过刚创建的字节码对象手动创建 一个 java 对象,再通过这个对象来回调 java 的方法。

需要注意的是:如果创建的是一个 activity 对象,回调的方法还包含上下文时这个方法行不通!!!会报空指针异常。

    4.  反射调用 java 方法

void (CallVoidMethod)(JNIEnv, jobject, jmethodID, ...);
第二个参:调用 java 方法的对象,第三个参数:要调用的 jmethodID 对象,可 选的参数:调用方法时接收的参数
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值