android Studio jni 编程

1.

创建一个Empty Activity的工程,命名为jniTest1,如果没有下载过ndk,那就那就去下载,选择菜单栏的 SDK Manager

勾选上 Android SDK -> SDK Tools-> NDK ,然后点击Apply。



也可以自己下载到任意目录,然后修改local.properties(SDK Location) 文件,ndk.dir=你下载ndk的目录

# Location of the SDK. This is only used by Gradle.
# For customization when using a Version Control System, please read the
# header note.
sdk.dir=/Users/zhaoyan/Development/sdk
ndk.dir=/Users/zhaoyan/Development/android-ndk-r10b


在gradle.properties(Project Properties)中添加下面一句
android.useDeprecatedNdk=true


在build.gradle(Module:app)文件的defaultConfig节点里添加以下代码

ndk {
            moduleName "JniTest"
            ldLibs "log", "z", "m"
            abiFilters "armeabi", "armeabi-v7a", "x86"
        }
moduleName "JniTest"这是生成so的名字

ldLibs 是需要包含的本地库

abiFilters 显示指定支持的ABIs


然后在jni目录下创建一个c++文件 jniTest.cpp



然后bulid工程,就会工程目录下的jniTest1/app/build/intermediates/ndk/debug目录生成Android.mk文件以及so文件

Android.mk

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)

LOCAL_MODULE := JniTest
LOCAL_LDFLAGS := -Wl,--build-id
LOCAL_LDLIBS := \
	-llog \
	-lz \
	-lm \

LOCAL_SRC_FILES := \
	/Users/zhaoyan/code/test/jniTest1/app/src/main/jni/jnitest.cpp \

LOCAL_C_INCLUDES += /Users/zhaoyan/code/test/jniTest1/app/src/main/jni
LOCAL_C_INCLUDES += /Users/zhaoyan/code/test/jniTest1/app/src/debug/jni

include $(BUILD_SHARED_LIBRARY)



2.
创建一个java类myJNI

public class myJNI {
    //加载so库
    static {
        System.loadLibrary("JniTest");
    }

    //native方法
    public static native String sayHello();
}

加载的库名和配置build.gradle文件中写的moduleName名要相同

然后调出Terminal,位置在菜单的View->Tool Windows->Terminal,执行命令

 cd /<工程目录>/app/build/intermediates/classes/debug/<包路径>
然后执行 ls命令,你会看到 myJNI.class 文件,然后执行命令

 javap -s myJNI

pzhaoyandeMacBook-Pro:jnitest1 zhaoyan$ javap -s myJNI
Compiled from "myJNI.java"
public class com.wolf.jnitest1.myJNI extends java.lang.Object{
public com.wolf.jnitest1.myJNI();
  Signature: ()V
public static native java.lang.String sayHello(); 
  Signature: ()Ljava/lang/String;
static {};
  Signature: ()V
}


()Ljava/lang/String; 一会儿动态注册函数的时候会用。


修改jnitest.cpp文件,添加如下代码

//
// Created by zhaoyan on 2016/11/27.
//
#include <jni.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
#include <android/log.h>
#define  LOG_TAG    "jnitest"
#define  LOGD(...)  __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__)

static jstring jni_sayHello(JNIEnv *env, jobject obj)
{
    return env->NewStringUTF("JNI sayHello");
}

/**
 * JNINativeMethod由三部分组成:(1)Java中的函数名;
						  (2)函数签名,格式为(输入参数类型)返回值类型;
						  (3)native函数名
 */
static JNINativeMethod gMethods[] = {
    {"sayHello", "()Ljava/lang/String;", (void *)jni_sayHello},
};


jint JNI_OnLoad(JavaVM *vm, void *reserved)
{
    JNIEnv *env = NULL;
    jint result = JNI_FALSE;

    if (vm->GetEnv((void **)&env, JNI_VERSION_1_4) != JNI_OK) { ////从JavaVM获取JNIEnv
        LOGD("Error GetEnv\n");
        return result;
    }
    assert(env != NULL);
    //获取类引用,这里可以找到要注册的类,前提是这个类已经加载到java虚拟机中
    jclass clazz = env->FindClass("com/wolf/jnitest1/myJNI");
    if (clazz == NULL) {
    	return result;
    }
    //注册方法,把本地函数和一个java类方法关联起来
    if (env->RegisterNatives(clazz, gMethods, sizeof(gMethods) / sizeof(gMethods[0])) < 0) {
		return result;
	}

    return JNI_VERSION_1_4;
}

JNI_OnLoad()函数。该函数在Java程序调用System.loadLibrary()时,被调用执行,所以会在这个函数里做一些初始化工作,与之相对应的是
 JNI_OnUnload()函数,该函数会在so释放是调用,做一些清除工作,实际测试的时候app退出也没调用。

在java代码里调用

String str = myJNI.sayHello();
返回的字符串就是 JNI sayHello

这里有个需要注意的地方,那就是c 和 c++ 的对JNIEnv的定义不同

    jclass clazz = env->FindClass("com/wolf/jnitest1/myJNI");       //c++
    jclass cla = (*env)->FindClass(env, "com/wolf/jnitest1/myJNI"); // c
下面的错误就是我在cpp文件里写了c的代码。

Error:(51, 24) error: base operand of '->' has non-pointer type 'JNIEnv {aka _JNIEnv}'





猜你喜欢

转载自blog.csdn.net/langzxz/article/details/53366594