Android JNI C/C++编译生成库文件并调用

1、方法声明

public class MyJni {
    static {
        System.loadLibrary("MyJni");
    }

    public native static String getString();
}

2、实现在Android中声明的Native方法

 

a、使用javah工具生成头文件

我们的NDK模块源代码由C/C++的头/源文件和make文件组成,这些文件必须放在jni目录下

理论上,jni目录可以放在任何地方,例如我们放在xx/jni/下,在xx/jni/下执行ndk-build之后会在xx/下(即jni同级目录下)产生编译结果(即libs和obj文件)在Android Studio项目里,我们一般把jni目录放在main目录下(即java同级目录),这样我们编译出来的libs和obj将会在main目录下。

打开Terminal终端,输入以下命令:

//此种情况此刻进入main目录下,jni是jni的相对目录,java是MyJni .java的相对目录
//终端在运行命令前需配置
如下:
#sdk
export ANDROID_SDK_HOME=/opt/android/android-sdk-linux
export PATH=$PATH:${ANDROID_SDK_HOME}/tools
export PATH=$PATH:${ANDROID_SDK_HOME}/platform-tools
#android-ndk
export ANDROID_NDK=/opt/android/android-sdk-linux/ndk-bundle
export PATH=$ANDROID_NDK:$PATH
#android-jdk
export JAVA_HOME=/opt/android/android-studio/jre
export JRE_HOME=/$JAVA_HOME/jre
export PATH=$PATH:$JAVA_HOME/bin:$JRE_HOME/bin
export CLASSPATH=.:$JRE_HOME/lib:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
export JAVA_BIN=$JAVA_HOME/bin
然后在终端下输入命令 source profile   //profile是保存配置的文件
配置成功后方可在终端下输入如下命令:
javah -d jni -classpath java com.sercomm.jnihelloworld.MyJni
运行后会在jni目录下生成com_sercomm_jnihelloworld_MyJni .h,内容如下:

#include
/* Header for class com_sercomm_jnihelloworld_MyJni */

#ifndef _Included_com_sercomm_jnihelloworld_MyJni
#define _Included_com_sercomm_jnihelloworld_MyJni
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_sercomm_jnihelloworld_MyJni
 * Method:    getString
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_sercomm_jnihelloworld_MyJni_getString
  (JNIEnv *, jclass);

#ifdef __cplusplus
}
#endif
#endif


b、创建本地代码文件

在jni目录下创建hello.c文件,内容如下:

#include "jni.h"
#include "com_sercomm_jnihelloworld_MyJni.h"

JNIEXPORT jstring JNICALL Java_com_sercomm_jnihelloworld_MyJni_getString
  (JNIEnv *env, jclass jz){
    // 1. JNIEnv:代表了VM里面的环境,本地的代码可以通过该参数与Java代码进行操作
    // 2. jobject:定义JNI方法的类的一个本地引用(this)
  return (*env)->NewStringUTF(env,"this is the first time for me to use jni");

  }

注:
    方法名的格式:Java_包名_类名_Java需要调用的方法名,对于包名,包名中的 . 要改成 _ ,_ 要改成 _1


3、创建Android.mk文件和Application.mk文件

Android.mk文件是一个负责向NDK构建系统描述NDK项目的GNU Makefile片段,是每一个NDK项目的必备组件,根据GNU Make的命名规则,变量名要大写:
LOCAL_PATH :=$(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE :=MyJni
LOCAL_SRC_FILES :=hello.c
include $(BUILD_SHARED_LIBRARY)

Application.mk文件配置编译平台相关的内容
APP_ABI := all

编译上述文件,生成.so库文件
经过上述步骤,在main/jni文件夹中已经有4个文件(hello.c、Android.mk、Application.mk,com_sercomm_jnihelloworld_MyJni.h)

打开终端,进入src/main/jni目录,输入以下命令
     ndk-build
编译成功后,会在jni的同级目录中生成libs和obj两个文件夹,其中libs下存放的是.so库文件

此时,我们已经将本地代码文件编译成.so库文件。

在app的bulid文件中加入如下代码,然后build project

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

在MainActivity中调用
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        TextView  hello = findViewById(R.id.hello);
        hello.setText(MyJni.getString());
        
    }
}

到此项目已经可以运行了,由版本不同,具体执行的命令目录也需要改变一下,但过程是相同的。如果执行命令的过程找不到javah或ndk-build命令,这是由于环境没配置的问题,参考2(a)应该就可以了。

 

你可能感兴趣的:(Android,JNI)