Android平台NDK编程

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

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

1.创建Android项目

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

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文件夹下面来。如下:

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

a.配置Android.mk文件

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

#返回当前文件在系统中的路径,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包等。

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平台。

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函数命名等,这些都是有规则的。

Android平台NDK编程

时间: 2024-08-27 02:08:41

Android平台NDK编程的相关文章

两分钟学会Android平台NDK编程(无须Eclipse和cygwin,可使用命令行打包多个so)

之前在进行cocos2dx开发时,已经详细介绍了如何将win32的c++代码移植到Android平台,当再次回顾时,发现一些基础的东西理解并不是很彻底,今天使用Android NDK提供的一个例子做一个简单的移植.在进行该demo前,请确认你已经配置了Android开发环境和安装了最新的Android NDK. 1.创建Android项目 创建一个Android项目 , 包名是com.example.hellojni,创建一个Activity作为程序进入的Acitivity,命名为HelloJn

超全Android JNI&NDK编程总结

由于网上关于JNI/NDK相关的知识点介绍的比较零散而且不具备参照性,所以写了这篇JNI/NDK学习笔记,便于作为随时查阅的工具类型的文章,本文主要的介绍了在平时项目中常用的命令.JNI数据类型.签名等,便于查阅相关资料.文末相关参考资料比较适合刚接触或者不熟悉Android NDK开发的朋友参阅. 常用命令 javac 编译java源文件生成.class文件 由于JNI对应的头文件由javah工具根据对应的.class文件生成,所以在进行JNI编程之前,写好Java代码后需要先编译,在使用ja

Android Studio Ndk 编程

现在开发Android程序基本都已经从Eclipse转到了Android Studio了, 最近项目需求, 需要用到ndk编程, 于是就折腾了一下. 开发环境 Android Studio 1.5.1 android-ndk-r10e gradle 2.8 首先我们新建一个工程叫做NdkDemo, 创建后的工程目录结构如下 然后我们打开gradle.properties文件, 在文件的尾端写一句, 如果没有写这一句会编译不通过 android.useDeprecatedNdk=true 接着配置

android平台蓝牙编程

Android平台支持蓝牙网络协议栈,实现蓝牙设备之间数据的无线传输. 本文档描述了怎样利用android平台提供的蓝牙API去实现蓝牙设备之间的通信,蓝牙设备之间的通信主要包括了四个步骤:设置蓝牙设备.寻找局域网内可能或者匹配的设备.连接设备和设备之间的数据传输.以下是建立蓝牙连接的所需要的一些基本类: BluetoothAdapter类:代表了一个本地的蓝牙适配器.他是所有蓝牙交互的的入口点.利用它你可以发现其他蓝牙设备,查询绑定了的设备,使用已知的MAC地址实例化一个蓝牙设备和建立一个Bl

Android?Studio?NDK编程-环境搭建及Hello!

一,下载 安装android-ndk开发包 NDK各个版本链接二,新建项目NDKDemo,选择空Activity就可以:(注:Android studio 2.2,可通过SDK Tools 添加LLDB,CMake,更方便的开发jni程序了) 三,按F12,配置项目NDK路径: 四,在MainActivity中添加如下代码: static {    System.loadLibrary("MyJni");//导入生成的链接库文件}public native String getStri

Android jni/ndk编程二:jni数据类型转换(primitive,String,array)

一.数据类型映射概述 从我们开始jni编程起,就不可能避开函数的参数与返回值的问题.java语言的数据类型和c/c++有很多不同的地方,所以我们必须考虑当在java层调用c/c++函数时,怎么正确的把java的参数传给c/c++函数,怎么正确的从c/c++函数获取正确的函数返回值:反之,当我们在c/c++中使用java的方法或属性时,如何确保数据类型能正确的在java和c/c++之间转换. 回顾我们上一篇文章中的那个c函数: #include <stdio.h> #include <jn

Android jni/ndk编程五:jni异常处理

在Java的编程中,我们经常会遇到各种的异常,也会处理各种的异常.处理异常在java中非常简单,我们通常会使用try-catch-finally来处理,也可以使用throw简单抛出一个异常.那么在jni编程的时候我们又是如何处理异常的呢? 异常处理流程 jni规范已经给我们做好了所有需要做的事情.回想一下处理异常的过程: 我们首先要在有可能产生异常的地方检测异常 处理异常 是的,我觉得异常的处理就是可以简单的总结为两步,在异常处理中我们通常会打印栈信息等.在jni编程中,异常处理的思路应该也与之

Android jni/ndk编程三:native访问java

一.访问静态字段 Java层的field和method,不管它是public,还是package.private和protected,从 JNI都可以访问到,Java面向语言的封装性不见了. 静态字段和非静态的字段访问方式不同,jni规范提供了一系列带static标示的访问静态字段的函数: jobject (*GetStaticObjectField)(JNIEnv*, jclass, jfieldID); jboolean (*GetStaticBooleanField)(JNIEnv*, j

Android jni/ndk编程四:jni引用类型

一.JNI引用类型 JNI支持三种类型的 opaque reference:local references, global references,和weak global references,下面我们将逐一探讨. local references 大部分JNI 函数都会创建LocalRef,如NewObject创建一个实例,并返回一个指向该实例的LocalRef.LocalRef只在本线程的 native method中有效. 一但native method返回,LocalRef 将被释放.