较新的NDK版本是r10b,Android Studio对NDK开发的支持还处于构思阶段,所以很多工作比如用javah生成头文件等工作还要自己做。今天用一个例子来演示AS中的NDK开发。
新建一个项目SecondNdkTest
在此项目中新建一个Module叫ndklibrary,作为so库单独划出来。在library中新建一个java类SecondLib,内容如下:
package com.linc.ndklibrary;/** * Created by linc on 15-3-29. */public class SecondLib { // Native implementation static { System.loadLibrary("SecondLib"); } //int array public static native int[] intMethod(); //string array public static native String[] stringMethod();}
Build—>Make Module’ndklibrary’,这样SecondLib就编译完成了,通过SecondLib.class,用javah生成C的头文件,如下:
AndroidStudioProjects/SecondNdkTest/ndklibrary/src/main$ javah -d jni -classpath ../../build/intermediates/classes/debug com.linc.ndklibrary.SecondLibAndroidStudioProjects/SecondNdkTest/ndklibrary/src/main$ lsAndroidManifest.xml java jni resAndroidStudioProjects/SecondNdkTest/ndklibrary/src/main$ ls jni/com_linc_ndklibrary_SecondLib.h
头文件内容如下:
/* DO NOT EDIT THIS FILE - it is machine generated */#include <jni.h>/* Header for class com_linc_ndklibrary_SecondLib */#ifndef _Included_com_linc_ndklibrary_SecondLib#define _Included_com_linc_ndklibrary_SecondLib#ifdef __cplusplusextern "C" {#endif/* * Class: com_linc_ndklibrary_SecondLib * Method: intMethod * Signature: ()[I */JNIEXPORT jintArray JNICALL Java_com_linc_ndklibrary_SecondLib_intMethod (JNIEnv *, jclass);/* * Class: com_linc_ndklibrary_SecondLib * Method: stringMethod * Signature: ()[Ljava/lang/String; */JNIEXPORT jobjectArray JNICALL Java_com_linc_ndklibrary_SecondLib_stringMethod (JNIEnv *, jclass);#ifdef __cplusplus}#endif#endif
Native代码实现
在jni目录中新建c文件SecondLib.c与头文件对应,分别实现上述两个方法,内容如下:
#include "com_linc_ndklibrary_SecondLib.h" const static int length=10; //int array JNIEXPORT jintArray JNICALL Java_com_linc_ndklibrary_SecondLib_intMethod (JNIEnv *env, jclass obj) { jintArray array; array=(*env)->NewIntArray(env,10); int i=1; for(;i<=10;++i) { (*env)->SetIntArrayRegion(env,array,i-1,1,&i); } //get array length int len=(*env)->GetArrayLength(env,array); //array content jint* elems=(*env)->GetIntArrayElements(env,array,0); return array; } //string array JNIEXPORT jobjectArray JNICALL Java_com_linc_ndklibrary_SecondLib_stringMethod (JNIEnv *env, jclass obj) { jclass class=(*env)->FindClass(env,"java/lang/String"); jobjectArray string=(*env)->NewObjectArray(env,(jsize)length, class,0); jstring jstr; char* _char[]={"my ","name ","is ", "linc!!","正在","学习", "JNI","和","NDK","技术!" }; int i=0; for(;i<length;++i) { jstr=(*env)->NewStringUTF(env,_char[i]); (*env)->SetObjectArrayElement(env,string,i,jstr); } return string; }
编译
在local.properties中加入ndk路径:
ndk.dir=/opt/ndk/android-ndk-r10b
然后在ndklibrary的build.gradle中defaultConfig中加入ndk定义,如下:
defaultConfig { minSdkVersion 15 targetSdkVersion 22 versionCode 1 versionName "1.0" ndk{ moduleName "SecondLib" } }
这样就可以直接编译了,不用自己编写make文件了。
Build—>Make Module’ndklibrary’,生成的so如下:
AndroidStudioProjects/SecondNdkTest$ find -name *.so./ndklibrary/build/intermediates/ndk/debug/lib/armeabi/libSecondLib.so./ndklibrary/build/intermediates/ndk/debug/lib/armeabi-v7a/libSecondLib.so./ndklibrary/build/intermediates/ndk/debug/lib/mips/libSecondLib.so./ndklibrary/build/intermediates/ndk/debug/lib/x86/libSecondLib.so./ndklibrary/build/intermediates/ndk/debug/obj/local/armeabi/libSecondLib.so./ndklibrary/build/intermediates/ndk/debug/obj/local/armeabi-v7a/libSecondLib.so./ndklibrary/build/intermediates/ndk/debug/obj/local/mips/libSecondLib.so./ndklibrary/build/intermediates/ndk/debug/obj/local/x86/libSecondLib.so
注:
至于直接在Activity中用native的方法请参考下面的前两个链接。我遇到了问题没有得到解决:
$ javah -d jni -classpath /opt/sdk/platforms/android-5.1/android.jar;../../build/intermediates/classes/debug com.linc.secondndktest.MainActivityError: no classes specifiedbash: ../../build/intermediates/classes/debug/: Is a directory
参考:
http://blog.csdn.net/rznice/article/details/42295215
http://blog.csdn.net/sodino/article/details/41946607
http://stackoverflow.com/questions/10483959/javah-error-android-app-activity-not-found
http://blog.csdn.net/lincyang/article/details/6705143