Android Studio 之ndk

前言

本文只涉及在Android Studio(以下简称as)中ndk的使用,基本不涉及原理性讲解。

ndk&cmake

在最新的as中 使用ndk,都是通过配置cmake脚本实现的。

CMake是个开源的跨平台自动化建构系统,它用配置文件控制建构过程(build process)的方式和Unix的Make相似,只是CMake的配置文件取名为CmakeLists.txt——[bing网典]

cmake最大的特点就是跨平台,可以根据不同平台生成相应的脚本,在linux下生成 .sh文件,windows下就就可以生成.bat文件,当然 我们编译so库也可以生成makefile文件,但是cmake直接使用的脚本文件是需要自己编写的。就生成as中生成so来说,大致流程就是cmake通过cmakelist脚本生成makefile脚本,ndk使用make工具执行.mk脚本,即使用相应的编译或其他工具执行真正的操作。
对于较小型 且无跨平台需求的项目 ,直接通过.mk文件编译就可以了。

准备

在使用ndk开发前,需要做些前期准备
ndk配置
在project structure中
这里写图片描述
若尚未下载,点击Download下载即可.
javah命令配置
javah就是将使用native方法的类生成c或c++的头文件,
当然,如果对jni的语法已经非常熟悉可以忽略此操作.
在as的setting中 进入External Tools:
这里写图片描述
可以直接复制

JDKPath/bin/javah
-classpath . -jni -o ModuleFileDir\src\main\jni$PromptFileClassModuleFileDir$\src\main\java
配置完以后 就可以看到

创建工程

正常方式创建一个android 工程。创建完成后在在main下新建一个jni文件夹。
创建jni文件夹

创建我们的加载动态库的类,并添加调用本地方法的api。

public class NativeTest {

    public native String getNativeText(String name);
    public native int getNativeNum(int num1,int num2);
    static {
        System.loadLibrary("ndk_test");
    }

}

通过javah动态生成.h文件,执行javah命令后,会在在jni文件夹里创建一个.h文件,文件名 可以自定义.
这里写图片描述
编写.c或 .cpp文件,导入.h文件,并实现头文件中声明的方法.

编写makefile文件
这里写图片描述

下面就是配置gradle文件了,直接贴gradle文件

//
// Created by gqs on 2016/10/26.
//
#include <jni.h>
#include <string.h>
#include "jni_test.h"


/**

* 工具方法

* 作用: 把java中的string 转化成一个c语言中的char数组

* 接受的参数 envjni环境的指针

* jstr 代表的是要被转化的java的string 字符串

* 返回值 : 一个c语言中的char数组的首地址 (char 字符串)

*/

char* jstring2CStr(JNIEnv* env, jstring jstr)

{
    char* rtn = NULL;
    jclass clsstring = (*env)->FindClass(env,"java/lang/String");

    jstring strencode = (*env)->NewStringUTF(env,"GB2312");

    jmethodID mid =

            (*env)->GetMethodID(env,clsstring,"getBytes","(Ljava/lang/String;)[B");

// String.getByte("GB2312");

    jbyteArray barr=

            (jbyteArray)(*env)->CallObjectMethod(env,jstr,mid,strencode);

    jsize alen = (*env)->GetArrayLength(env,barr);

    jbyte* ba = (*env)->GetByteArrayElements(env,barr,JNI_FALSE);

    if(alen > 0)

    {

        rtn = (char*)malloc(alen+1); //"\0"

        memcpy(rtn,ba,alen);

        rtn[alen]=0;

    }

    (*env)->ReleaseByteArrayElements(env,barr,ba,0); //

    return rtn;

}

JNIEXPORT jstring JNICALL Java_com_gqs_ndkdemo_NativeTest_getNativeText
  (JNIEnv *env, jobject obj, jstring name)
  {
      char  str[50];
      char *hello = "Hello ";
      strcpy (str,hello);
      char* cstr = jstring2CStr(env,name);
      strcat(str,cstr);//拼接两个字符串  
      return (*env)->NewStringUTF(env,str);
  }

/*
 * Class:     com_gqs_ndkdemo_NativeTest
 * Method:    getNativeNum
 * Signature: ()I
 */
JNIEXPORT jint JNICALL Java_com_gqs_ndkdemo_NativeTest_getNativeNum
  (JNIEnv *env, jobject obj, jint num1, jint num2)
  {

return num1+ num2;
  }
apply plugin: 'com.android.application'

android {
    compileSdkVersion 24
    buildToolsVersion "24.0.1"
    defaultConfig {
        applicationId "com.gqs.ndkdemo"
        minSdkVersion 14
        targetSdkVersion 24
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        ndk{
        //生成so库的名称 要和Android.mk文件指定的一直
            moduleName "jni_test"
            //生成支持不同cpu类型的动态库
            abiFilters "armeabi","armeabi-v7a","x86"
        }
    }
    externalNativeBuild {
        ndkBuild {
        //配置makefile文件路径
            path 'src/main/jni/Android.mk'
        }
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    testCompile 'junit:junit:4.12'
}

OK ,下面就可以直接运行了,good luck!
代码下载:http://download.csdn.net/detail/gqs519/9672544

发表评论