Android平台NDK编程

转自:http://blog.csdn.net/wangbin_jxust/article/details/37389383html

以前在进行cocos2dx开发时,已经详细介绍了如何将win32的c++代码移植到Android平台,当再次回顾时,发现一些基础的东西理解并非很完全,今天使用Android NDK提供的一个例子作一个简单的移植。在进行该demo前,请确认你已经配置了Android开发环境和安装了最新的Android NDK。java

1.建立Android项目

建立一个Android项目 , 包名是com.example.hellojni,建立一个Activity做为程序进入的Acitivity,命名为HelloJni。c++

2.建立 C 文件

建立一个C文件,放一个函数,该函数的做用是获取当前cpu架构并以字符串的形式返回。请注意该函数的格式: Java_包名的下划线链接_Java文件名_java函数名。架构

#include <string.h>
#include <jni.h>

jstring
Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env,
                                                  jobject thiz )
{
#if defined(__arm__)
  #if defined(__ARM_ARCH_7A__)
    #if defined(__ARM_NEON__)
      #define ABI "armeabi-v7a/NEON"
    #else
      #define ABI "armeabi-v7a"
    #endif
  #else
   #define ABI "armeabi"
  #endif
#elif defined(__i386__)
   #define ABI "x86"
#elif defined(__mips__)
   #define ABI "mips"
#else
   #define ABI "unknown"
#endif

    return (*env)->NewStringUTF(env, "Hello from JNI !  Compiled with ABI " ABI ".");
}

 

3.配置JNI

在该Android项目的根目录(即AndroidManifest.xml文件所在目录)下建立一个文件夹,命名为jni(注意,文件名不能写错哦)函数

在jni目录下,建立Android.mk和Application.mk两个文件,同时将C文件也放进jni文件夹下面来。以下:ui

这里的nick文件夹,能够先忽略不看,这是为后面的打包多个so准备的。spa

a.配置Android.mk文件

Android.mk文件实际上一个很小的NDK构建脚本,它的语法在: NDK安装目录/docs/ANDROID-MK.html,下文代码也对一些基本属性添加了注释。.net

#返回当前文件在系统中的路径,mk文件开始时必须定义该变量
LOCAL_PATH := $(call my-dir)

#CLEAR_VARS 变量由构建系统提供,由于有大量的全局变量,在本次构建前,清除上一次的
include $(CLEAR_VARS)
#LOCAL_MODULE 实际是项目名,用于区分各个项目,名字必须是惟一的并且不包含空格,最终的so库,命名也会是   lib项目名.so
LOCAL_MODULE    := hello-jni
#要编译的c or cpp文件,注意不须要在这里列举头文件或者include的文件,构建系统会自动帮你依赖这些文件
LOCAL_SRC_FILES := hello-jni.c
#构建系统提供的变量
include $(BUILD_SHARED_LIBRARY)

 

b.配置Application.mk文件

Application.mk文件其实是对应用程序自己描述的文件,它定义了应用程序须要的功能模块的列表、针对不一样cpu架构打包不一样的so]、要构建release或者debug包等。debug

APP_ABI := XXX,这里的XXX就是指不一样的平台,能够选填的有x86,armeabi,armeabi-v7a,mips,all,值得一提的是,选择all,则会构建出全部平台的so,若是不填该项,默认构建为armeabi的。同时,做者也作过一个实验,构建armeabi平台的so是能够运行在intel x86架构cpu平台的,可是构建x86平台的so则不能在armeabi平台上运行的,这样看来,应该是intel针对armeabi作了兼容,可是若是想要so  以最小的能耗运行在intel x86平台,仍是要指定构建的so为x86平台。code

4.打包so以及如何打包多个so

在当前Android项目的根目录下,运行 NDK安装路径/ndk-build,则开始打包so。

另外,若是运行    NDK安装路径/ndk-build clean,会clean当前全部的so;

运行 NDK安装路径/ndk-build -B V=1,则强制从新打包,

若是想要打包多个so,则能够在Android.mk定义多个modules,或者写多个Android.mk,每一个Android.mk定义一个modules,我这里在jni目录下又建立了一个nick文件夹,用于放置新的C文件。

此时,只须要改动jni目录下的Android.mk,再次对nick文件夹的C代码打包便可。jni下的Android.mk文件:

#返回当前文件在系统中的路径,mk文件开始时必须定义该变量
LOCAL_PATH := $(call my-dir)

#CLEAR_VARS 变量由构建系统提供,由于有大量的全局变量,在本次构建前,清除上一次的
include $(CLEAR_VARS)
#LOCAL_MODULE 实际是项目名,用于区分各个项目,名字必须是惟一的并且不包含空格,最终的so库,命名也会是   lib项目名.so
LOCAL_MODULE    := hello-jni
#要编译的c or cpp文件,注意不须要在这里列举头文件或者include的文件,构建系统会自动帮你依赖这些文件
LOCAL_SRC_FILES := hello-jni.c
#构建系统提供的变量
include $(BUILD_SHARED_LIBRARY)

#对nick文件夹下的代码打包so
include $(CLEAR_VARS)
LOCAL_MODULE    := hello-jni-mine
LOCAL_SRC_FILES := nick/hello-jni.c
include $(BUILD_SHARED_LIBRARY)

 

是的,你没看错,从新加上LOCAL_MODULE和LOCAL_SRC_FILES变量从新配置一下便可。

5.jni调用

在Activity中,咱们使用static 关键词将加载so放在函数体中,以保证直接先加载so.

static {
        System.loadLibrary("hello-jni");
    }

要注意的是,System.loadLibrary()中填写的并非完整的so名,而是去掉前缀lib和后缀.so的,也就是Android.mk中的LOCAL_MODULE变量。

 

java层的函数要用native关键词声明此次调用native层的函数,若是该java函数是public native String  XXXX(),那么在这里就是调用C代码中的Java_com_example_hellojni_HelloJni_stringFromJNI()函数。

以上就是Android平台打包so和调用的一个最基本的demo,其实整个流程仍是比较简单的,有一些规定的命名是不能随便修改的,若是jni文件夹名,Android.mk,Application.mk文件名,被java层调用的C函数命名等,这些都是有规则的。

相关文章
相关标签/搜索