天天看點

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入門