Android studio简单的JNI实现

来源:互联网 发布:报纸编辑排版软件 编辑:程序博客网 时间:2024/06/06 08:53
  JNI :java native interface  java本地接口,native一般指c/c++;

废话不多说,首先说明一下这篇博客总体大纲
1.生成.h头文件
2. 书写c/c++代码
3. 生成.so库
4. 实现java和c/c++互相通信

1.打开AS ,创建一个新的项目,记得要勾上 Include c++ support.(勾上后,生成的项目会有写好的jni调用实例)
这里写图片描述
创建完项目后,我们新建一个JniTest Java类, 代码如下:

public class JniTest {    public native String getStrFromC();}

getStrFromC函数需要用native修饰,表明是一个和本地通信函数.

然后开始使用 javah命令生成c/c++类,

接着点击小锤子图标,生成.class文件
这里写图片描述

.class文件可以在…\app\build\intermediates\classes\debug\com……\jnitest
路径下找到,
下一步我们需要用这个.class文件生成.h文件

点击AS下方的Terminal, 进入到main目录下输入指令
这里写图片描述

javah -d jni -jni -classpath D:\as\JNITest\app\build\intermediates\classes\debugcom.sakura.administrator.jnitest.JniTest

这个命令会在main目录下生成一个Jni目录,并在jni目录下创建一个头文件
这里写图片描述

分析一下这个 javah 命令

 javah -d jni -jni -classpath      在这个目录下生成一个jni目录,在这目录下生成一个头文件,后边跟.class文件

在-classpath 后添加:

......\app\build\intermediates\classes\debug

到debug就可以,
然后在debug后边接上包名,接上Jni 类名 ,就组成这个命令,注意格式!!!

到此,第一步生成.h头文件文件完成.

2.
有了.h文件,我们就接着书写c++代码.
在刚生成的jni目录下新建 c++类

注意: 命名要和.h文件名一致
jni里的函数是按”Java_完整的包名activity类名函数名”来命名的
extern “C” 语句是用于兼容C动态库使用的, 不加会发生执行出错.
c++代码如下:

#include <string>#include "com_sakura_administrator_jnitest_JniTest.h" jstring  Java_com_sakura_administrator_jnitest_JniTest_getStrFromC        (JNIEnv *env, jobject){     std::string hello = "Hello from C++";     return env->NewStringUTF(hello.c_str());}

注意要用#include 预编译指令编译刚生成的.h头文件
代码只是简单的测试代码
书写c/c++代码结束

3.
c/c++代码写完之后,开始生成.so库文件
生成so文件之前,需要先写Android.mk和Application.mk两个配置文件,并在build.gradle中进行其他配置

(1).在之前生成的jni目录下新建一个Android.mk文件,内容如下:

LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE := JNILOCAL_SRC_FILES := com_sakura_administrator_jnitest_JniTest.cppinclude $(BUILD_SHARED_LIBRARY)

lOCAL_MODULE 是生成的.so库文件名称
LOCAL_SRC_FILES 是你写的c++文件

(2).
在之前生成的jni目录下新建一个Application.mk文件,内容如下:

APP_ABI := allAPP_STL := stlport_static

APP_ABI := all 生成适合所有架构的.so库文件
APP_STL := stlport_static 是支持STL运行库,(不写这句话,在c++代码中使用string,使用ndk编译时会报错.)
(3).
配置build.gradle
打开build.gradle,在defaultConfig括号里添加
这里写图片描述

ndk{            moduleName "JNI"        }

然后在android括号下添加

这里写图片描述

  sourceSets {        main() {            jni.srcDirs = ['src/main/jni', 'src/main/jni/']            jniLibs.srcDirs = ['libs']        }    }

(4).
打开gradle.properties文件
添加

android.useDeprecatedNdk=true

这里写图片描述

配置完成,然后打开Terminal终端,
进入到刚生成的jni目录的父目录下
输入ndk-build 指令

这里写图片描述
然后适合各个架构的.so库文件就自动生成了

4.
java调c++方法
把.so库文件放到libs目录下,
修改jniTest类;

public class JniTest {    static{        System.loadLibrary("JNI");    }    public native String getStrFromC();}

动态加载so库(生成的so库文件名字是libJNI.so)

在MainActivity类:

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.sample_text);        String str=new JniTest().getStrFromC();        tv.setText(str);    }}

展示从c++返回的字符串

所有流程结束,我们来看下运行效果:

这里写图片描述

完美!
PS:
javah 命令,看具体需求
jni调用繁琐,但胜在能调用java不具备的特性
gradle 配置也不是很懂…有什么不对的地方请大家指正,多谢!

阅读全文
0 0