- android studio搭建JNI开发环境
- 下载NDK并配置到工程中
https://developer.android.google.cn/ndk/downloads/index.html
File->Project Structure
②创建JNI目录:New->Folder->JNI Folder
③编写java native函数,并在jni目录下完成c侧实现
④配置编译:
Makefile,创建Android.mk 如下:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := my_service_jni
LOCAL_SRC_FILES := my_service_jni.c
LOCAL_LDLIBS := -llog //注意此处不加该编译lib导致无法使用android封装的日志模块
include $(BUILD_SHARED_LIBRARY)
配置build.gradle
defaultConfig {
applicationId "com.example.myservice"
minSdkVersion 15
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
ndk {
moduleName "my_service_jni" //待编译生成的目标.so文件名称
abiFilters "arm64-v8a"
}
}
externalNativeBuild{
ndkBuild{
path "src/main/jni/Android.mk" // 指定makefile,或者使用cmake
}
}
- java调用c,c调用java返回string类型demo
C调用java:套路:jclass->jmethodID->call
JAVA调用C:套路:实现JNI_OnLoad函数并注册方法
static const char *className = "com/example/myservice/MyServiceJni";
void GetProjVersion(void);
static void JNICALL HelloService(JNIEnv *env, jobject obj)
{
LOGE("HELLO SERVICE JNI");
GetProjVersion();
}
static jstring JNICALL HandlerClientMsg(JNIEnv *env, jobject obj, jstring s)
{
// c接收java的 string类型
const char *s1;
s1 = (*env)->GetStringUTFChars(env, s, NULL);
LOGE("%s-%d: %s", __func__, __LINE__, s1); //需要将jtring s转换成c侧的char *,使用完成后需要释放
(*env)->ReleaseStringUTFChars(env, s, s1);
// c返回java string类型
char *retStr = "hello java i am c";
return (*env)->NewStringUTF(env, retStr);
}
static const JNINativeMethod g_method[] = {
{ "HelloService",
"()V",
(void *)HelloService,
},
{
"HandlerClientMsg",
"(Ljava/lang/String;)Ljava/lang/String;", // 不要漏掉 ‘;’,漏掉会导致加载so失败
(jstring *)HandlerClientMsg,
}
};
JNIEnv *env = NULL;
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm,void* reserved)
{
LOGE("in JNI_Onload");
if((*vm)->GetEnv(vm,(void**)&env,JNI_VERSION_1_6)!=JNI_OK){
return -1;
}
jclass cls = (*env)->FindClass(env, className);
if (cls == NULL) {
LOGE("Can not find %s", className);
return -1;
}
if ((*env)->RegisterNatives(env, cls, g_method, sizeof(g_method) / sizeof(g_method[0])) != JNI_OK) {
LOGE("Register native method fail");
return -1;
}
return JNI_VERSION_1_6;
}
void GetProjVersion(void)
{
jclass regionClass = (*env)->FindClass(env, className);
if (regionClass != NULL) {
jmethodID methodId = (*env)->GetStaticMethodID(env, regionClass, "getProjVersion", "()Ljava/lang/String;");
jstring jVersion = (jstring) (*env)->CallStaticObjectMethod(env, regionClass, methodId);
char *version = (char *) (*env)->GetStringUTFChars(env, jVersion, NULL);
LOGE("GetVersionFromJava = %s", version);
}
}
java侧代码:
package com.example.myservice;
public class MyServiceJni {
private static final String LIB_NAME = "hello";
private static final String VERSION = "11.0";
public MyServiceJni() {
}
public void myServiceJniInit() {
System.loadLibrary(LIB_NAME);
}
public static String getProjVersion() {
return VERSION;
}
public native void HelloService();
public native String HandlerClientMsg(String msg);
}
问题:
- javah 找不到类文件的解决办法?对于动态注册JNI native接口时需要编辑签名字符串,比较简单的方式就是用javah根据java定义的native函数生成对应的头文件后拷贝。
set classpath=E:\..\app\src\main\java (com.xxx.xxx.test.java在E:\..\app\src\main\java\xxx\目录下)
javah –jni com.xxx.test 这样就可以在xxx目录下生成对应的头文件了。