Android JNI开发二:实战开发详解

调用原理

java代码编译后,运行时会去某个目录寻找so文件、并load,然后调用so文件中的方法,要保证这个流程准确无误,就必须约定好如下条件:

  • java代码运行时,知道去哪里加载so库 —— so库存放目录;
  • java代码运行时,知道加载哪个so文件 —— so库名称;
  • java代码运行时,知道如何正确调用某个方法 —— so库的方法名、参数、返回值;

第1个条件是android系统帮我们完成的,apk安装时,会把so库解压到/data/app/com.example.test/lib/ABI/目录下,运行时也会自动去这个目录下加载so库;

第2、3个条件则是我们自己开发时需要约定好的。具体如何约定,后面会讲到。

实现步骤

知道了调用原理后,开发步骤就很容易了,大致分为如下几步:

  • java代码加载so文件(约定so文件名),声明native方法(约定方法名、参数和返回值);
  • 生成C/C++头文件,声明方法(方法名、参数和返回值与java代码约定的一致);
  • 实现C/C++头文件中声明的方法;
  • 将C/C++文件编译成Android平台下的so文件(so文件名与java代码约定的一致);
  • 将编译好的so文件放入对应的jniLib目录下

java代码加载so文件

package com.example.mytest;

public class JniTest {
    static {
        // load名称为useffmpeg的so文件。最终so文件名会在前面加上lib、后面加上.so,即libuseffmptg.so
        System.loadLibrary("useffmpeg");
    }

    // 声明本地方法名称、参数、返回值
    public native String getFFMpegInfo();
}

生成C/C++头文件

通过javah命令,可以生成JniTest.java对应的C/C++头文件,不过我觉得用代码写还方便一点。

头文件命名为com_example_mytest_JniTest.h,命名规则就是包名+类名,用下划线代替.号,代码如下:

/* 引用jni库*/
#include <jni.h>

extern "C" {
#endif
/*
 * 1.jstring是方法返回值,对应java代码中native方法的返回值String;
 * 2.Java_com_example_mytest_JniTest_getFFMpegInfo就是声明的方法名,对应java代码中的包名、类名和方法名;
 * 3.JNIEnv *, jobject是必带的参数,没有其它参数对应的就是java代码中的native方法没有参数;
 */
JNIEXPORT jstring JNICALL Java_com_example_mytest_JniTest_getFFMpegInfo (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

实现C/C++头文件中的方法

具体实现类命名com_example_mytest_JniText.c,实现代码如下:

/* 引入上面的.h文件 */
#include "com_example_mytest_JniTest.h"
/**
 * 实现上面头文件声明的方法
 */
JNIEXPORT jstring JNICALL Java_com_example_mytest_JniTest_getFFMpegInfo (JNIEnv *env, jobject obj) {
    /* NewStringUTF是jni.h库中的方法。*/
    /*至于本地方法如何用C代码实现,那就要有一定C语言功底了,这里只是简单地返回一个字符串 */ 
    return (*env)->NewStringUTF(env, "jni测试");
}

编译so文件

编译Android平台的so文件需要四个文件:

  • C/C++头文件。作用是约定方法名、参数和返回值;
  • 上面声明的方法的具体实现类。用来编译成具有实际功能的二进制文件;
  • Android.mk文件。作用是约定so文件名称,以及一些其它配置;
  • Application.mk文件。作用是配置编译的ABI;

Android.mk文件如下:

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

// 约定so文件的名称
LOCAL_MODULE := useffmpeg   
// so文件的实现类
LOCAL_SRC_FILES := com_example_mytest_JniText.c  

// 编译so的时候,记得把注释、中文、空行全删掉,有些情况下可能会编译不过

include $(BUILD_SHARED_LIBRARY)

Application.mk文件如下:

// 编译所有ABI的so库
APP_ABI := all

将这4个文件放在同一个目录下,打开命令行,进入到该目录下,使用命令“ndk-build”命令即可编译出各个ABI的so库。

使用so文件

将so文件放入jniLIbs目录下,在gradle文件中指定jniLibs目录即可。
这里写图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值