android studio 编译C生成.so文件

作者: android00 发布时间: 2017-08-22 浏览: 3850 次 编辑

一、前言

前段时间有个同事离职了,用C编译的.SO文件需要更改,结果C文件是他写的,无赖啊,自己又是一个小白,不会啊,所以自己又好好钻研了一天,不会,看什么都难啊,痛苦啊,网上找了好多,才找到的,而且感觉都不怎么详细,步骤说的不是很清楚,所以自己整理了一下,谁便记录一下,好了,废话不多说,开始正题。

二、编译过程

1、编译环境的搭建

正所谓:“工欲善其事必先利其器”嘛,所以先把改准备工具准备一下,因为是在studio下编译的,所以啊,什么studio、什么sdk、什么jdk,这些都自己去弄吧,这里说一下ndk这个编译C文件工具怎么下载安装;

下载链接:https://developer.android.com/ndk/downloads/index.html(一般需要翻墙,至于原因嘛,你懂得)进去之后下载自己相对应的ndk平台版本;

下载完了之后直接是一个zip的压缩包,解压即可;

然后如下图所示的配置ndk:

\

然后你会在local.properties文件中看到:

\

不要急,还没有完,ndk环境搭建还有最后一步,在gradle.properties的文件末尾加上android.useDeprecatedNdk=true这段代码,文字看不懂吧直接上图:

\

好了,到此处环境就搭建完毕了。

2、java代码和C代码的编写步骤及过程

首先新建一个java类JNIUtils.java

public class JNIUtils {
    static {
        System.loadLibrary("huazict");
    }
 
    //java调C中的方法都需要用native声明且方法名必须和c的方法名一样
    public native String getString();
}

然后如下图所示重新Make Project一下工程:

\

会在工程目录E:\work\MyApplication\stujni\build\intermediates\classes\debug\com\huazi\stujni\jni中看到自己编译后的class文件JNIUtils.class如下图所示:

\

其次就是生成.h文件了

在studio打开Terminal命令行工具,打开步骤是View->Tool Windows->Terminal (或直接按Alt+F12),如下图所示:

\

然后在命令行中先进入到工程的main目录下

输入命令:javah -d jni -classpath 自己编译后的class文件的绝对路径

例如:javah -d jni -classpath E:\work\MyApplication\stujni\build\intermediates\classes\debug com.huazi.stujni.jni.JNIUtils(注意debug后的空格)

\

看到上图,图中命令行中是直接进入到了工程的main目录下(在哪个目录下运行就会在哪个目录下自动生成jni文件夹),按回车之后就会在main目录下生成jni文件夹,同时生成.h文件,如下图:

\

这个文件.h文件不需要做任何修改,默认即可。

现在我们来写一个test的C文件huazict.c同.h文件一样放到jni文件夹下,代码如下:

#include "com_huazi_stujni_jni_JNIUtils.h"
/**
 * 上边的引用标签一定是.h的文件名家后缀,方法名一定要和.h文件中的方法名称一样
 */
JNIEXPORT jstring JNICALL Java_com_huazi_stujni_jni_JNIUtils_getString
        (JNIEnv *env, jobject obj) {
    return (*env)->NewStringUTF(env, "这是我测试的jni");
}

如图所示:

最后在构建文件中的默认配置中加上:

//ndk编译生成.so文件
ndk {
   moduleName "huazict"         //生成的so名字
   abiFilters "armeabi", "armeabi-v7a", "x86"  //输出指定三种abi体系结构下的so库。
}

如图:

\

到这里,通过jni调C就完成了,现在我们来测试一下,写个TextView显示一下调用的C:

public class MainActivity extends AppCompatActivity {
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        TextView tv = (TextView)findViewById(R.id.tv);
 
        tv.setText(new JNIUtils().getString());
    }
}

看效果,直接上图:

\

ok,没问题,可以调用,其实也没有想象中的那么难,是吧!

三、调用编译过的.so库

上边编译完成了,有人会问:我要的是编译后的.so库,别人用的时候直接拿来用就可以了,那编译后的.so库在哪呢?不要着急请看下图:

\

根据这个路径就可以找到指定输出的三种体系结构下的.so库文件,然后把.so文件复制出来,如下图所示的放到相应的文件夹下就ok了:

\

再次运行,结果还是一样的,跟上边贴的那张图的显示效果是是一样的,同样能调用到,代码我就不上传了,都在上边贴上去了,而且也上传不了,公司的所有文件都是加密的,想上传都上传不了。

到这里,整个jni的调用过程就结束了,包括调用jni需要的环境以及调用的过程,最后.so文件的导出,都在上边了,如果上边的jni调用过程有什么问题,欢迎留言,谢谢。

文章来源:http://www.2cto.com/kf/201607/526887.html