Android提供NDK开发包来提供Android平台的C++开发,用来扩展Android SDK的功能。主要包括Android NDK构建系统和JNI实现与原生代码通信两部分。

一、Android NDK构建系统

1.1 构建库

  Android NDK的构建系统是基于GNU Make的。Android GNU Make系统除了需要一些内部的GNU片段外,还需要两个文件:Android.mk和Application.mk。Android NDK源码给了很多的例子,以HelloJni为例,Android.mk源码:

#Android.mk必须以LOCAL_PATH变量开头
LOCAL_PATH := $(call my-dir)
#清除除了LOCAL_PATH以外的LOCAL_<name>变量,例如LOCAL_MODULE与LOCAL_SRC_FILES等
include $(CLEAR_VARS)
#每一个原生组件被称为一个模块
LOCAL_MODULE := hello-jni
#源文件
LOCAL_SRC_FILES := hello-jni.c
#编译为共享库,即后缀名为.so
include $(BUILD_SHARED_LIBRARY)

  Application.mk源码: 

 #一般选择APP_ABI := armeabi-v7a就够了
 APP_ABI := all

  为了建立可供主应用程序使用的模块,必须将该模块变成共享库。按照上述必不可少的步骤,可以继续编译多个共享库。

  Android也可以编译静态库(后缀名为.a),但是实际的Android应用程序并不直接使用静态库,并且应用程序包中也不包含静态库。静态库可以用来构建共享库。但是,当静态库与多个共享库相连时,应用程序包中会包含静态库的多个副本,徒增应用程序包的大小。这种情况下,可以不构建静态库,而是将通用模块作为共享库建立起来,动态连接依赖模块以消除重复的副本。如下Android.mk实现的是共享库之间的代码共享。

LOCAL_PATH := $(call my-dir)

#第三方AVI库
include $(CLEAR_VARS)
LOCAL_MODULE := avilib
LOCAL_SRC_FILES := avilib.c
include $(BUILD_SHARED_LIBRARY) #原生模块1
include $(CLEAR_VARS)
LOCAL_MODULE := module1
LOCAL_SRC_FILES := module1.c LOCAL_SHARED_LIBRARIES := avilib
include $(BUILD_SHARED_LIBRARY) #原生模块2
include $(CLEAR_VARS)
LOCAL_MODULE := module2
LOCAL_SRC_FILES := module2.c LOCAL_SHARED_LIBRARIES := avilib
include $(BUILD_SHARED_LIBRARY) 

1.2 Prebuilt库

  共享模块编译时要求有源代码,为此Android提供了Prebuilt库,以下场合,Prebuilt库是非常有用的:

  1. 想在不发布源代码的情况下将你的模块发布给他人;
  2. 想使用共享模块的预建版来加速构建过程。

  其他构建系统变量:

  LOCAL_CFLAGS:一组可选的编译器标志,在编译C和C++源文件的时候会被传送给编译器;

  LOCAL_CPP_FLAGS:一组可选的编译器标志,在只编译C++源文件时被传送给编译器;

  LOCAL_LDLIBS:链接标志的可选列表,它主要用于传送要进行动态链接的系统库列表。如链接日志库:

  LOCAL_LDFLAGS += -llog

  APP_CPPFLAGS:编译器标志,在编译任何模块的C++源文件时这些标志都会被传送给编译器。

  nkd-build脚本命令:

ndk-build –C /project path
ndk-build –B
ndk-build clean

二、JNI实现与原生代码通信

  Java层代码如下:

public class HelloJni extends Activity
{
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState); TextView tv = new TextView(this);
tv.setText( stringFromJNI() );
setContentView(tv);
} /* A native method that is implemented by the
* 'hello-jni' native library, which is packaged
* with this application.
*/
public native String stringFromJNI(); /* This is another native method declaration that is *not*
* implemented by 'hello-jni'. This is simply to show that
* you can declare as many native methods in your Java code
* as you want, their implementation is searched in the
* currently loaded native libraries only the first time
* you call them.
*
* Trying to call this function will result in a
* java.lang.UnsatisfiedLinkError exception !
*/
public native String unimplementedStringFromJNI(); /* this is used to load the 'hello-jni' library on application
* startup. The library has already been unpacked into
* /data/data/com.example.hellojni/lib/libhello-jni.so at
* installation time by the package manager.
*/
static {
System.loadLibrary("hello-jni");
}
}  

  JNI代码如下,其中Java方法stringFromJNI不带任何参数,但是原生方法带两个参数:

jstring
Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env,
jobject thiz )
{
return (*env)->NewStringUTF(env, "Hello from JNI !");
}

  第一个参数JNIEnv是指向可用JNI函数表的借口指针;第二个参数jobjects是HelloJni类实例的Java对象引用。

  这里注意C与C++代码稍有不同,C代码如下:

  return (*env)->NewStringUTF(env, "Hello from JNI ! ");

  C++代码如下:

  return env->NewStringUTF("Hello from JNI ! ");

  这是因为C++代码中,JNIEnv实际上是一个C++类实例,JNI函数以成员函数的形式存在,因此JNI方法调用不要求JNIEnv实例作参数。

2.1 C/C++ 头文件生成器:javah

  JDK自带一个名为javah的命令行工具,该工具由Java类文件的原始定义生成原生函数名及其参数列表,这样程序员避免编写繁杂多余的定义。C/C++源文件只需要包含这个头文件并提供原生方法实现。

  javah的参数列表如下:

C:\Users\jiayayao>javah
用法:
javah [options] <classes>
其中, [options] 包括:
-o <file> 输出文件 (只能使用 -d 或 -o 之一)
-d <dir> 输出目录
-v -verbose 启用详细输出
-h --help -? 输出此消息
-version 输出版本信息
-jni 生成 JNI 样式的标头文件 (默认值)
-force 始终写入输出文件
-classpath <path> 从中加载类的路径
-cp <path> 从中加载类的路径
-bootclasspath <path> 从中加载引导类的路径
<classes> 是使用其全限定名称指定的
(例如, java.lang.Object)。

  生成头文件的命令行参数如下:

 javah -classpath bin/classes com.example.hellojni.Hellojni  

2.2 数据类型

Java有两种数据类型:基本数据类型和引用数据类型:基本数据类型中Java/JNI/C++的映射关系如下:

  引用类型的类型映射关系如下:

  引用类型以不透明的引用方式传递给原生代码,而不是以原生数据类型的的形式呈现,因此引用类型不能直接使用和修改。JNI提供了与这些引用类型密切相关的一组API。

  字符串操作:

// 创建字符串
jstring javaString;
javaString = (*env)->NewStringUTF(env, "hello world!");
// 内存溢出时,会返回NULL,注意判空 // 将Java字符串转换成C字符串
const jbyte* str;
jboolean isCopy;
str = (*env)->GetStringUTFChars(env, javaString, &isCopy);
if ( != str) { } // 释放字符串
(*env)->ReleaseStringUTFChars(env, javaString, str);

  数组操作:

// 创建数组
jintArray javaArray;
javaArray = (*env)->NewIntArray(env, );
if(!=javaArray) { }

// Get<Type>ArrayRegion函数将给定的基本Java数组复制到给定的C数组中
// 将Java数组区复制到C数组中
jint nativeArray[];
(*env)->GetIntArrayRegion(env, javaArray, , , nativeArray); // 从C数组向Java数组提交所做的修改
(*env)->SetIntArrayRegion(env, javaArray, , , nativeArray);

  原生方法的内存分配超出了虚拟机的管理范围,且不能用虚拟机的垃圾回收器回收原生方法中的内存。

  原生代码回到Java损耗性能,建议将所有需要的参数传递给原生代码调用,而不是让原生代码回到Java中。

  先记录这么多,以后接着补充。

Android的JNI调用(一)的更多相关文章

  1. [置顶] android利用jni调用第三方库——第三篇——编写库android程序整合第三方库libhello.so到自己的库libhelloword.so

    0:前言: 在第二篇中,我们主要介绍了丙方android公司利用乙方C++公司给的动态库,直接调用库中的方法,但是这样方式受限于: 乙方C++公司开发的动态库是否符合jni的规范,如果不规范,则不能直 ...

  2. [置顶] android利用jni调用第三方库——第二篇——编写库android程序直接调用第三方库libhello.so

    0:前言 1:本文主要作为丙方android公司的身份来写 2:作者有不对的地方,请指出,谢谢 [第一篇:android利用jni调用第三方库——编写库libhello.so] [第二篇:androi ...

  3. Android的JNI调用(二)

    Android Studio 2.3在native下已经有了代码提示功能,按照提示下载相应组件就可以debug native代码. 一.Java调用JNI与JNI调用Java 1.1 C调用Java ...

  4. (AIDE)Android Eclipse JNI 调用 .so文件加载问题

    背景:对于Android工程 Eclipse里编译好的.so文件放到 libs\armeabi下以后, 这样.so文件就可以打包到apk文件里,在apk装到手机上以后 在libs\armeabi下的. ...

  5. Android通过JNI调用驱动程序(完全解析实例)

    要达到的目的:android系统中,用JAVA写界面程序,调用jni中间库提供的接口,去操作某个驱动节点,实现read,writer ioctl等操作!这对底层驱动开发人员是很重要的一个调试通道,也是 ...

  6. 【转】Android通过JNI调用驱动程序(完全解析实例)

    原文网址:http://blog.csdn.net/ok138ok/article/details/6560875 要达到的目的:android系统中,用JAVA写界面程序,调用jni中间库提供的接口 ...

  7. Android于JNI调用列出的程序

    1.安装和下载cygwin,下载Android NDK: 2.于ndk工程JNI接口设计: 3.采用C/C++实现本地方法. 4.JNI生成动态链接库.so档: 5.动态链接库副本javaprojec ...

  8. android camera jni调用

    http://www.mamicode.com/info-detail-1002139.html how to compile  library of native camera for androi ...

  9. android studio jni调用入门

    一.开发环境配置: 1.Android Studio 2.3.3 2.android-ndk-r14b-windows-x86_64 二.创建项目 1.新建android项目 2.新建文件 3.编译生 ...

随机推荐

  1. 使用fastjson 获取json字符串中的数组,再转化为java集合对象

    最近,使用layui做一个导出功能,尽管有插件提供导出,但是呢,由于数据中有状态是数字,例如1显示是已支付,但是导出时也希望这样显示,但是导出的还是1: lz没有找到改下这个插件的办法,只能利用服务端 ...

  2. Thymeleaf学习记录(3)--语法

    语法: 标准表达式语法 简单表达: 变量表达式: ${...} 选择变量表达式: *{...} 消息表达式: #{...} 链接网址表达式: @{...} 字面 文本文字:'one text','An ...

  3. nodejs报错 XMLHttpRequest cannot load localhost:3000/test_date/. Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, https.

    z在请求本地的时候  如果ajax的URL 前面没有http的话 就会报错 jq.js:2 XMLHttpRequest cannot load localhost:3000/test_date/. ...

  4. Runtime 打开记事本

    package com.direct.str; import java.io.IOException; public class RunTimeDemo { /** * @param args */ ...

  5. bootstrap 中的 iCheck 全选反选功能的实现

    喜欢bootstrap 风格的同学应该知道,iCheck的样式还是很好看的. 官网: http://www.bootcss.com/p/icheck/ 进入正题,iCheck提供了一些方法,可以进行全 ...

  6. log4net.dll添加报错

    描述: 新建项目Log4Net类库项目,添加log4net.dll,封装Log类对日志进行操作 新建webForm项目添加Log4Net类库生成的dll生成日志,页面报错,未能加载文件或程序集log4 ...

  7. 008Spring & JPA & Hibernate & MySQL

    01下载免安装版MySQL 02安装MySQL a)将MySQL压缩包解压到合适的位置,以C:\programmer\Tools\mysql-5.7.20-winx64路径为例: b)新建系统变量,变 ...

  8. 如何验证一份HTML文档的格式是否正确

    在浏览器中打开 Markup Validation Service . 点击或者激活 Validate by Direct Input 栏. 将整个示范文档的代码(不仅仅是body部分)复制粘贴到在M ...

  9. 软工读书笔记 week 5 ——《构建之法》

    本周主要对<构建之法>中的一部分进行阅读. 一.软件与软件工程究竟是什么? 本书的概论部分就指出“软件 = 程序 + 软件工程”.而我们这门课的名字就叫“现代软件工程”.其实在上课之前,我 ...

  10. c# 设计模式 之:工厂模式之---简单工厂

    1.uml类图如下: 具体实现和依赖关系: 实现:SportCar.JeepCar.HatchbackCar 实现 Icar接口 依赖: Factory依赖 SportCar.JeepCar.Hatc ...