Android Studio下JNI调用与编译so包

  2个月前做一款IM软件的时候,手机录音的声音比较小,所以就找了一些声音的增益库,在网上找了一遍最后选择了webrtc的声音增益模块。webrtc源码是c,所以如果要在android中使用的话,就必须将该模块打包成so库文件然后用java调用这个库。
  这里就不得不说一下JNI是什么了。

  JNI是什么?

  JNI(Java Native Interface)意为JAVA本地调用,它允许Java代码和其他语言写的代码进行交互,简单的说,一种在Java虚拟机控制下执行代码的标准机制。

  NDK是什么?

  Android NDK(Native Development Kit )是一套工具集合,允许你用像C/C++语言那样实现应用程序的一部分。

  为什么要用NDK?

  1、安全性,java是半解释型语言,很容易被反汇编后拿到源代码文件,我们可以在重要的交互功能使用C语言代替。
  2、效率,C语言比起java来说效率要高出很多(该不该使用jni这个需要结合项目环境需求,并不一定使用jni效率就比java高)。

  JNI和NDK的区别?

  从工具上说,NDK其实多了一个把.so和.apk打包的工具,而JNI开发并没有打包,只是把.so文件放到文件系统的特定位置。从编译库说NDK开发C/C++只能能使用NDK自带的有限的头文件,而使用JNI则可以使用文件系统中带的头文件。从编写方式说,它们一样。

  JNI具体的介绍就不多说了,网上很多的,这里主要讲一下编译so库和调用。之前是在eclipse里边编译的so库,相对来说比较起android studio麻烦一些,因为编译过程中又使用到了cygwin。

  下面说说在android studio中编译so库,首先新建一个工程

新建一个类,并写一个native方法,用来调用so库中的方法

下一步就是清空工程,然后再编译工程

直到build目录下出现classes目录

接着使用命令生成c的头文件

使用命令进入到项目build目录下的debug目录


然后再使用javah -jni 类的包名加类名


如果java环境没错的话就会在debug目录下生产一个头文件


生产了头文件然后在src/main目录下新建一个jni的目录用来存放c的代码文件


将刚刚生成的c的头文件拷贝到jni目录下,文件的名字可以改


之后新建一个.c的文件,这个文件用来实现头文件中的方法,首先来看看生成的头文件的内容

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

#ifndef _Included_com_caidongdong_contentprovider_util_JniUtil
#define _Included_com_caidongdong_contentprovider_util_JniUtil
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_caidongdong_contentprovider_util_JniUtil
 * Method:    getStringFromC
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_caidongdong_contentprovider_util_JniUtil_getStringFromC
  (JNIEnv * env, jobject obj);

#ifdef __cplusplus
}
#endif
#endif
这个头文件是不用改的,下面贴上.c文件的内容

#include "mystring.h"
#include <string.h>
JNIEXPORT jstring JNICALL Java_com_caidongdong_contentprovider_util_JniUtil_getStringFromC
        (JNIEnv * env, jobject obj){
    return (*env)->NewStringUTF(env,"Hello from JNI !");
}
这个c文件的内容需要自己写的,首先引入头文件,使用#include 引入需要的头文件,这个跟java的import类似,但是有区别。拷贝生成的头文件中的方法到c文件中,注意要把行参补全


然后写上该方法的实现,当然这里只是简单的返回一个字符串,多说一句c和c++的方法有些是有区别的,所以写的时候注意选择。

c文件写好之后就可以配置编译环境,编译需要ndk我这里使用的ndk的版本是android-ndk-r11,下载好解压后在Android studio中配置ndk路径



选择ndk的路径


下一步,启用ndk编译,需要在gradle.properties中配置

android.useDeprecatedNdk=true




下一步,需要在app的build.gradle中的defaultConfig配置ndk生成的so库名称依据生成多个平台的包


下一步,在含有native方法的类中加载so库

public class JniUtil {
    static {
        System.loadLibrary("my_lib");
    }
    public  native String getStringFromC();
}

然后在activity中使用该类并调用其中的方法

        JniUtil jniUtil = new JniUtil();
        content.setText(jniUtil.getStringFromC());

最后的运行效果图


在工程目录下的lib并没有生成so库,因为gradle已经自动的帮我们生成好了,工程目录下就有,如果反编译apk的话,就会发现so库是存在于lib中的。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值