概要
作者上一文通過Cmake的編譯方式對Android開發NDK調用三方so庫進行了演示,這里主要講一下在NDK開發中,怎么樣去動態的注冊C++里面的native方法,主要步驟如下:
java中定義Native方法
編寫C++文件,實現jni接口方法,以及JNI_OnLoad方法
編譯生成so
java加載so庫,調用native方法
1.創建加載native方法的java類
package com.example.testndk2;
public class NativeApi {
static {
System.loadLibrary("nativelib");
}
public static native String getHello();
}
2.編寫C++代碼
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <jni.h>
extern "C" { //因為是jni默認是調用C的代碼,這里由于開發語言是C++,為了兼容C,一定要用到 extern “C”
JNIEXPORT jstring JNICALL get_hello(JNIEnv *env, jclass clazz) {
return env->NewStringUTF("hello jni");
}
static JNINativeMethod g_methods[] = {
{ "getHello", "()Ljava/lang/String;", (void*)get_hello}
};
JNIEXPORT int JNICALL JNI_OnLoad(JavaVM *vm,void *reserved) {
JNIEnv *env;
if (vm->GetEnv((void **) &env,JNI_VERSION_1_6) != JNI_OK) {
return JNI_ERR;
}
const char* class_path = "com/example/testndk2/NativeApi";//這里對應native的java類
jclass javaClass = env->FindClass(class_path);
if (javaClass == NULL){
return JNI_ERR;
}
int method_count = sizeof(g_methods) / sizeof(g_methods[0]);
if (env->RegisterNatives(javaClass, g_methods, method_count) < 0) {
return JNI_ERR;
}
return JNI_VERSION_1_6;
}
}
3.編譯生成so庫
這里采用上一篇文章的方式,分別創建Android.mk、Application.mk,這里還是貼一下相應的代碼:
Android.mk
#Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := nativelib
LOCAL_SRC_FILES := NativeApi.cpp
NDK_APP_DST_DIR := ../../libs/$(TARGET_ARCH_ABI)
include $(BUILD_SHARED_LIBRARY)
Application.mk
#Application.mk
APP_STL:=c++_shared
APP_PLATFORM := android-16
APP_CPPFLAGS:=-frtti -fexceptions
APP_ABI := all
4.加載so庫,并調用方法
在模塊級的build.gradle
文件中配置lib庫目錄
sourceSets{
main{
jniLibs.srcDirs = ['libs']
}
}
在MainActivity里面調用native方法,拿到數據,顯示到TextView上
package com.example.testndk2;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView tv = findViewById(R.id.tv);
tv.setText(NativeApi.getHello());
}
}
注意
- 如果是用
C++
代碼編寫so庫,一定要記得加extern 'C'
-
C++
代碼中,env->FindClass(class_path)
方法,class_path
一定要和java類的包名和類名對應上