Android Studio下NDK开发流程

以前Android NDK开发需要在Eclipse或源码环境下,简历并配置Android.mk和Application.mk,并且还要通过java命令生产.h头文件才能编译生成so库,相当麻烦。随着AS作为官方Android开发工具,现在准备在AS上开发JNI应用,发现在AS上编译NDK非常方便,本文将介绍如何在Android Studio上实现NDK开发。


1、简介

JNI

JNI 是Java Native Inteface的缩写,是Java中定义的一种用于连接Java和C/C++接口的一种实现方式。

NDK

NDK 是 Native Developmentit的缩写,是Google在Android开发中提供的一套用于快速创建native工程的一个工具。 
使用这个工具可以很方便的编写和调试JNI的代码

Gradle

Gradle 是一个基于Apache Ant和Apache Maven概念的项目自动化建构工具。它使用一种基于Groovy的特定领域语言(DSL)来声明项目设置。
环境要求

  • Android Studio 2.2或更高版本
  • Gradle 2.2或更高版本
  • Android NDK r10e或更高 下载地址
  • Build Tools 19.0.0或更高

2、开始集成

a) 创建一个简单的Android项目

新建一个Android测试项目,命名为:JniDemo。 

b) 配置NDK路径

找到AS的状态栏,打开File->Project Structure,在Android NDK location栏选择离线NDK保存路径. 

c) 配置gradle.properties文件

JNI模块构建方式有3种: 

  • 手动ndk-build构建。该方式需要手动编写Android.mk和Application.mk文件,然后手动调用ndk-build命令生成so文件,属于早期NDK开发方式,过程比较繁琐。 
  • 自动ndk-build构建。使用ndkCompile工具自动构建so文件,需要手动生成头文件。 
  • gradle-experimental方式全自动构建。 

我们使用最简单最方便的构建方式,所以使用第二种。找到工程中的gradle.properties文件,添加以下代码:

android.useDeprecatedNdk=true


d) 配置build.gradle文件

找到主module中的build.gradle文件,添加一下代码:

ndk{ 
    moduleName "JniCore"//编译生成so库的名字,注意不要lib和.so,和loadLibrary里面的参数一致
    ldLibs "log", "z", "m" //添加日志依赖库
    abiFilters "armeabi", "armeabi-v7a", "x86" //指定生成编译支持的平台so
}


e) JNI编码

在java同级创建一个jni目录,相关的C/C++源码放在该目录下。我们这里以实现MD5哈希摘要为例。 


f) JNI注册

目前JNI注册方式有两种:静态注册和动态注册。个人偏向于使用动态注册,一方面可以防止方法名hook,另外一方面省了写.h文件。 

JNI入口文件:main.c

/* DO NOT EDIT THIS FILE - it is machine generated */
        #include <jni.h>
        #include <android/log.h>
        #include <stdlib.h>
        #include <stdio.h>

        #include "md5.h"

        #define LOG_ENABLE
        #define  LOG_TAG "JNI_LOG"
        #define  LOGI(...)  __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
        #define  LOGE(...)  __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)

        //指定注册的类,需要跟Java中native方法所在的包名一致
        #define JNIREG_CLASS "com/luoxudong/jnidemo/natives/JniCore"

        JNIEXPORT jstring JNICALL n_md5(JNIEnv * env, jobject jObj, jstring plaintext)
        {
            if (plaintext == NULL)
           {
                return NULL;
           }
           const char *pPlaintext = (*env)->GetStringUTFChars(env, plaintext, 0);
           char cMD5[32 + 1] = {0};
           MD5(pPlaintext, strlen(pPlaintext), cMD5);
         (*env)->ReleaseStringUTFChars(env, plaintext, pPlaintext);
          jstring ret = (*env)->NewStringUTF(env, (char *)cMD5);
          return ret;
        }

        static JNINativeMethod method_table[] = {
               {"md5", "(Ljava/lang/String;)Ljava/lang/String;", (void *)n_md5}
        };

        static int registerNativeMethods(JNIEnv* env, const char* className, JNINativeMethod* gMethods, int numMethods)
        {
         jclass clazz;
          clazz = (*env)->FindClass(env, className);
           if (clazz == NULL)
          {
              return JNI_FALSE;
          }
          if ((*env)->RegisterNatives(env, clazz, gMethods, numMethods) < 0)
          {
             return JNI_FALSE;
         }
         return JNI_TRUE;
        }

        static int registerNatives(JNIEnv* env)
        {
           if (!registerNativeMethods(env, JNIREG_CLASS, method_table, sizeof(method_table) / sizeof(method_table[0])))
          {
              return JNI_FALSE;
          }
           return JNI_TRUE;
        }

        JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved)
        {
          JNIEnv* env = NULL;
          jint result = -1;
         if ((*vm)->GetEnv(vm, (void **)&env, JNI_VERSION_1_4) != JNI_OK)
          {
              return -1;
          }
         if (!registerNatives(env)) //注册
          {
              return -1;
          }
         result = JNI_VERSION_1_4;

          return result;
        }

MD5头文件:md5.h

省略...

MD5原文件:md5.c

省略...

g) JAVA代码实现

创建类com.luoxudong.jnidemo.natives.JniCore.java文件,需要跟main.c中的”com/luoxudong/jnidemo/natives/JniCore”对应。 

native文件:JniCore.java

package com.luoxudong.jnidemo.natives;

       public class JniCore {
         static {
             System.loadLibrary("JniCore");
          }
          public static native String md5(String text);
       }

h) native方法调用

package com.luoxudong.jnidemo;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

import com.luoxudong.jnidemo.natives.JniCore;

public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);
      TextView msgTxt = (TextView) findViewById(R.id.tv_msg);
      msgTxt.setText(JniCore.md5("test"));
    }
}

i) 生成so文件

编译工程,在app/build/intermediates/ndk/debug/lib下面可以看到生成的各平台so文件。 

j) 其他

源码下载地址:JniDemo
转载请注明出处:http://www.luoxudong.com/?p=139

有4人对 “Android Studio下NDK开发流程”留言了

  1. Thank you for every one of your labor on this web site. My daughter really loves managing investigations and it’s really obvious why. Most people learn all regarding the lively mode you present rewarding techniques through this web site and even inspire participation from some others on the point then our favorite princess is really starting to learn a whole lot. Take advantage of the rest of the year. You are always doing a splendid job.

  2. I simply wanted to thank you so much once more. I am not sure the things that I would’ve sorted out without the type of solutions revealed by you over that situation. It truly was an absolute hard matter in my opinion, however , seeing the very specialised strategy you resolved that made me to leap over gladness. I will be happy for this service and then pray you realize what a great job you happen to be providing teaching people today using your web site. Most likely you have never got to know any of us.

  3. I’m commenting to let you be aware of of the awesome discovery my child developed browsing the blog. She came to find a good number of details, including how it is like to have a great coaching character to get certain people completely comprehend a number of advanced issues. You actually did more than her desires. I appreciate you for coming up with such effective, dependable, edifying and cool guidance on that topic to Emily.

  4. I precisely had to say thanks all over again. I’m not certain the things I could possibly have created in the absence of the actual hints discussed by you concerning such concern. It actually was a real difficult condition for me personally, but discovering a new professional fashion you handled it forced me to cry for delight. I’m grateful for the assistance and as well , have high hopes you comprehend what a powerful job you’re carrying out educating men and women by way of your blog. I am certain you’ve never come across all of us.

发表评论

电子邮件地址不会被公开。