IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    [原]Android实战技巧之二十三:Android Studio的NDK开发

    lincyang发表于 2015-03-29 12:04:54
    love 0

    较新的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.SecondLib
    AndroidStudioProjects/SecondNdkTest/ndklibrary/src/main$ ls
    AndroidManifest.xml  java  jni  res
    AndroidStudioProjects/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 __cplusplus
    extern "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.MainActivity
    Error: no classes specified
    bash: ../../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



沪ICP备19023445号-2号
友情链接