JNI基本使用

JNI使用步骤

先看一下代码示例

public class MainActivity extends AppCompatActivity {

    //使用静态块加载.so库文件
    static {
        System.loadLibrary("hello");
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        RelativeLayout relativeLayout = new RelativeLayout(this);
        final TextView textView = new TextView(this);
        Button button = new Button(this);

        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                //在此调用native方法
                textView.setText(stringFromC());
            }
        });

        RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
        lp.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, RelativeLayout.TRUE);
        lp.addRule(RelativeLayout.ALIGN_PARENT_TOP, RelativeLayout.TRUE);

        relativeLayout.addView(textView);
        relativeLayout.addView(button,lp);


        setContentView(relativeLayout);
    }

    //第一步,声明本地方法
    public native String stringFromC();
}

来看一下使用的基本步骤,包括但不限于如下:

1、声明native修饰的本地方法

//这里无需实现,此方法在点击后返回一个【字符串数据】
public native String stringFromC();

2、添加C代码的实现,头文件和方法体。

2.1使用javah命令生成C语言要用的头文件(*.h)。
在此目录(java下,包名开始的位置)下使用javah命令,位于%JAVA_HOME%/bin目录下,可能需要配置环境变量后才能使用。这一步的目的是生成“Java_全包名_方法名“格式的方法。

H:_MY_ANDROID\AndroidProjects\1010_jni2\app\src\main\java>
javah -jni com.vincyan.a1010_jni2.MainActivity

2.2右键app-new-folder-JNI folder,在此文件夹编写 hello.c

// Created by vincyan on 2016/10/10.

#include<jni.h>
//引入自定义的库文件,使用双引号;
#include "com_vincyan_a1010_jni2_MainActivity.h"

/**为方法添加实现,此方法为我们返回一个字符串
此处为jni的规则。任意的jni方法,此处都必须有此两个参数,env表示结构体的二级指针,thiz表示调用native方法的Java对象
对于更多参数的方法,在后面添加,如jint,jboolean等。

JNIEXPORT和JNICALL为自动添加的关键字,忽略之。 
*/
JNIEXPORT jstring JNICALL Java_com_vincyan_a1010_1jni2_MainActivity_stringFromC
  (JNIEnv * env, jobject thiz){


    //char* cstr表示C语言中的字符串,传入下面的方法
    char* cstr = "hello in c";


    return (*env)->NewStringUTF(env,cstr);

  }

jni.h文件的路径
H:\android\android-ndk-r10\platforms\android-12\arch-arm\usr\include


//jni.h中的部分代码
typedef const struct JNINativeInterface* JNIEnv;

/**
JNIEnv是结构体struct JNINativeInterface的一级指针,那么JNIEnv* env就是该结构体的二级指针,(*env)就表示其一级指针,可以使用间接引用运算符,故可通过(*env)->NewStringUTF()来调用结构体的函数指针,从而调用其指向的函数。
结构体中定义的大量的函数指针对应着大量的函数实现,在jni开发中会用到这些定义的函数,故将JNIEnv* env作为形参传递进来。
*/

#if defined(__cplusplus)
typedef _JNIEnv JNIEnv;
typedef _JavaVM JavaVM;
#else
//C中的自定义类型
typedef const struct JNINativeInterface* JNIEnv;
typedef const struct JNIInvokeInterface* JavaVM;
#endif

/*
 * Table of interface function pointers.
 */
struct JNINativeInterface {
    //定义的大量函数指针...
    jstring     (*NewStringUTF)(JNIEnv*, const char*);
    ...
}

//*NewStringUTF的实现
jstring NewStringUTF(const char* bytes)
    { return functions->NewStringUTF(this, bytes); }

...

3、引入Android.mk和Application.mk文件

//Android.mk,linux下make file,此文件保存基本配置信息
LOCAL_PATH := $(call my-dir)

//清除上次配置的信息,变量
include $(CLEAR_VARS)

//指定了c源文件编译后生成动态链接库的名字
LOCAL_MODULE    := hello
//指定了c的源文件的名字,多个时使用空格隔开
LOCAL_SRC_FILES := hello.c

//指定生成动态链接库文件
include $(BUILD_SHARED_LIBRARY)

/**
Application.mk
指定支持的平台,会生成对应平台的库文件,all表示所有平台,多个使用空格隔开,mips armeabi(默认情况下为此,市面上80-90%的手机) x86(genemotion模拟器)
*/
APP_ABI := all

4、使用ndk-build命令生成.so文件。

4.1 进入工程下的jni路径,使用ndk-build命令,编译生成文件。

H:_MY_ANDROID\AndroidProjects\1010_jni2\app\src\main\java>
cd /d H:_MY_ANDROID\AndroidProjects\1010_jni2\app\src\main\jni

H:\_MY_ANDROID\AndroidProjects\1010_jni2\app\src\main\jni>ndk-build
[armeabi-v7a] Compile thumb  : hello <= hello.c
[armeabi-v7a] SharedLibrary  : libhello.so
[armeabi-v7a] Install        : libhello.so => libs/armeabi-v7a/libhello.so
[armeabi] Compile thumb  : hello <= hello.c
[armeabi] SharedLibrary  : libhello.so
[armeabi] Install        : libhello.so => libs/armeabi/libhello.so
[x86] Compile        : hello <= hello.c
[x86] SharedLibrary  : libhello.so
[x86] Install        : libhello.so => libs/x86/libhello.so
[mips] Compile        : hello <= hello.c
[mips] SharedLibrary  : libhello.so
[mips] Install        : libhello.so => libs/mips/libhello.so

4.2导入生成的so文件,将生成的.so文件,导入该该项目下的libs路径,H:_MY_ANDROID\AndroidProjects\1010_jni2\app\libs

5、配置加载的环境

5.1在build.gradle文件中配置jni

sourceSets{
        main{
            jniLibs.srcDirs "libs"
            //防止干扰(StackOverflow)
            jni.srcDirs = []
        }
    }

5.2使用静态代码块加载库文件

//hello文件为生成的libhello.so,lib与.so为编译器自动添加

static {
        System.loadLibrary("hello");
    }

5.3在Java代码中调用即可

【WARNING】

<0>配置环境变量,包括jdk/jdk-bin/ndk
这里写图片描述

最终项目结构
编译过程会生成obj文件夹,事实上jni和obj文件夹只是在编译过程中有用,不会打包到apk中。

这里写图片描述
若以上有问题,可能还需要添加。
<1> 在app下的build.gradle 中配置 defaultConfig{ndk{moduleName ‘hello’}}
<2>在gradle.properties 文件中配置允许使用过时的ndk:android.useDeprecatedNdk=true

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值