天天看点

Android Studio 使用JNI入门

本文适合于在Android Studio使用JNI的新手,也适合于从Eclipse中转移到Android Studio过来的开发者。
           
本人见识有限,若有纰漏,欢迎批评指正。极客精神,人人共享~
           
1. 开发平台:
Operating System:Mac OS X 10.11.3
Software: Android Studio 1.5.1
           
2. 开始搭建JNI平台:
1)确保本地上已经有NDK:

        
Android Studio 使用JNI入门
2)新建一个新的Module。
           
3)修改配置,打开如下图所示的三个文件:
           
Android Studio 使用JNI入门
在build.gradle(Android Studio Tab上显示为Module的名字)文件中添加ndk的说明:
Android Studio 使用JNI入门
moduleName是JNI库的名字,在此处JNI库的名字是“libmyjnitest.so”。 在gradle.properties文件的末尾添加“android.useDeprecatedNdk=true”。 在local.properties文件中注明路径:
Android Studio 使用JNI入门
4)添加jni目录:
右击module,可以直接添加jni,如下图:
           
平台基本搭建完成,以下可以开始写代码了。      
3. 新建一个Java文件作为具有native方法的测试类。
           
/**
	 * Created by zhuozengsi on 3/6/16.
	 */
	public final class MyJNITest {
	
	    public static native String printSomething(String str);
	    public static native long calFromJNI(int n);
	
	    static {
	        System.loadLibrary("myjnitest");
	    }
	
	    public static long calFromJava(int n){
	        long sum = 0;
	        for (int i = 1; i <= n; i++){
	            sum += i;
	        }
	        return sum;
	    }
	
	}
           
我新建了一个MyJNITest 类,并在类中声明了两个native方法,并在static块中加载JNI库,注意:
该处的JNI库要和第2步中配置的ndk的moduleName相同。
4. Build -> Make Project 或者Build -> Make Module,目的是编译一下Java文件,生成class文件。
           
此时应该能在build/intermediates/classes/bebug 中看到编译成功的class文件,如下图所示:

        
Android Studio 使用JNI入门
5. 在terminal中将用cd命令将目录切换到build/intermediates/classes/bebug,然后执行以下命令:
javah -jni packageName.classFile
           
packageName是包名称,classFile是具有native方法的Class文件,如此处的 MyJNITest应该为:
           
javah -jni com.sige.test1.MyJNITest
           
执行成功的话,会在debug目录下生成一个头文件,此处是:com_sige_test1_MyJNITest.h,一般命名都是按照包名加类名来的,如下图。
Android Studio 使用JNI入门
将头文件剪切到创建的jni目录中。头文件的内容为:
           
/* DO NOT EDIT THIS FILE - it is machine generated */
	#include <jni.h>
	/* Header for class com_sige_test1_MyJNITest */
	
	#ifndef _Included_com_sige_test1_MyJNITest
	#define _Included_com_sige_test1_MyJNITest
	#ifdef __cplusplus
	extern "C" {
	#endif
	/*
	 * Class:     com_sige_test1_MyJNITest
	 * Method:    printSomething
	 * Signature: (Ljava/lang/String;)Ljava/lang/String;
	 */
	JNIEXPORT jstring JNICALL Java_com_sige_test1_MyJNITest_printSomething
	  (JNIEnv *, jclass, jstring);
	
	/*
	 * Class:     com_sige_test1_MyJNITest
	 * Method:    calFromJNI
	 * Signature: (I)J
	 */
	JNIEXPORT jlong JNICALL Java_com_sige_test1_MyJNITest_calFromJNI
	  (JNIEnv *, jclass, jint);
	
	#ifdef __cplusplus
	}
	#endif
	#endif
           
6. 在jni目录中创建C文件或者创建C++文件,名字自定,我这里是:myjnitest.cpp。
将头文件中定义的方法复制到C/C++文件中,实现那些方法:
           
//
	// Created by Zhuozengsi on 3/6/16.
	//
	#include "com_sige_test1_MyJNITest.h"
	#include <stdio.h>
	#include "test_cpp.h"
	JNIEXPORT jstring JNICALL Java_com_sige_test1_MyJNITest_printSomething
	        (JNIEnv * env, jclass clazz, jstring str){
	
	    printf("Hello, JNI");
	
	    //return env->NewString((const jchar *) str, sizeof(str));
	    return get_string(env);
	
	
	}
	
	JNIEXPORT jlong JNICALL Java_com_sige_test1_MyJNITest_calFromJNI
	        (JNIEnv *env, jclass, jint n){
	
	    jlong sum = 0;
	    for (int i = 1; i <= n; ++i) {
	        sum += n;
	    }
	    return sum;
	}
           
可以在该文件调用其他C/C++代码,如get_string(env)就是调用自己定义的函数。
           
7. 可以在其他地方调用native方法了。如在MainActivity中调用:
            
String strFromJNI = MyJNITest.printSomething("hello");
Log.i("TAG", "message from jni: " + strFromJNI);
           
输出结果为:
Android Studio 使用JNI入门