概要
作者上一文通过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类的包名和类名对应上