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 <jni.h>
/* 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)應該就可以了。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章