文档章节

使用C++ 进行NDK开发,非C!

梁金堂
 梁金堂
发布于 2015/01/17 14:37
字数 906
阅读 62
收藏 1

网上的很多教程讲的NDK开发都是用C语言来做的,但是又有很多代码是用C++写的.虽然说可以使用C调用C++,但是C调用C++的难度比C++调用C的难度大.原因C++容易兼容C,但反之需要复杂的操作,特别是调用成员函数的操作.

我们都知道JNI支持C++开发,java的本地代码调用:

JNIEXPORT 和 JNICALL 这两个宏确保函数在本地库外可见,又根据函数的命名和java 本地方法是一一对应的.

这样就可以根据方法名直接找到该函数.但是据我所知,只适合C语言,或者extern "C",但是一旦使用了这些,又会

增加C调用C++的复杂度.说的有错误请指正.

 

但是在使用jni开发中,JNIEXPORT 和 JNICALL 不是必须.我们可以完全可以手动进行本地方法的注册.

我们会用到jni中的RegisterNatives函数对本地方法进行注册.以下是例子重要代码.

//jni.cpp

#include <jni.h>
#include<Stdio.h>
//如果#include <iostream>
// 需在 在Application.mk 添加 APP_STL := gnustl_static
#include "Math.h"
#include "ALOG.h"

 jint  Java_com_example_ndkwithcpp_Tools_add(JNIEnv *env,
		jobject obj, jint a, jint b);

static JNINativeMethod methods[] = { { "add", "(II)I",
		(void*) Java_com_example_ndkwithcpp_Tools_add } };

static const char *classPathName = "com/example/ndkwithcpp/Tools";

//可以对同一个java class的所有本地方法一次性注册.
static int registerNativeMethods(JNIEnv* env, const char* className,
		JNINativeMethod* gMethods, int numMethods) {

	jclass clazz;
	clazz = env->FindClass(className);
	if (clazz == NULL) {
		return JNI_FALSE;
	}
	if (env->RegisterNatives(clazz, gMethods, numMethods) < 0) {
		return JNI_FALSE;
	}
	return JNI_TRUE;
}

jint JNI_OnLoad(JavaVM* vm, void* reserved) {
	jint result = -1;
	JNIEnv* env = NULL;

	if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
		goto bail;
	}

	if (registerNativeMethods(env, classPathName, methods,
			sizeof(methods) / sizeof(methods[0])) != JNI_TRUE) {
		goto bail;
	}

	result = JNI_VERSION_1_4;
	bail:

	LOGI("JNI_ONload code: '%d' ", result);
	LOGI("版权所有,http://xxx.com/xxx\n");

	return result;
}

jint Java_com_example_ndkwithcpp_Tools_add(JNIEnv *env, jobject obj, jint a,
		jint b) {
	Math math;
	int c = math.add(a,b);
	return c;
} 

需要注意的是,使用C++和C调用jni 函数的方式是不同的.如c这样调用 (*env)->fun(env,参数1,参数2,..)

而C++确是这样调用的,env->fun(参数1,参数2,...);

而对于vm也是一样的.C的是(*vm)->fun(vm,参数1,参数2,...);

//ALOG.h

extern "C" int __android_log_print(int prio, const char *tag, const char *fmt,
		...);
//prio取值如下
typedef enum android_LogPriority {
	ANDROID_LOG_UNKNOWN = 0,
	ANDROID_LOG_DEFAULT, /* only for SetMinPriority() */
	ANDROID_LOG_VERBOSE,
	ANDROID_LOG_DEBUG,
	ANDROID_LOG_INFO,
	ANDROID_LOG_WARN,
	ANDROID_LOG_ERROR,
	ANDROID_LOG_FATAL,
	ANDROID_LOG_SILENT, /* only for SetMinPriority(); must be last */
} android_LogPriority;
//tag为标签。
#ifndef LOG_TAG
#define LOG_TAG "DEBUG"
#endif

#define LOGI(fmt,...)\
	__android_log_print(ANDROID_LOG_INFO,LOG_TAG, \
			"at %s(%d)-%s:\n" fmt "\n", __FILE__, __LINE__, __FUNCTION__,##__VA_ARGS__)


而对于LOG,注意要先声明 extern "C" int __android_log_print(int prio, const char *tag, const char *fmt,...); 再定义宏.这里的LOGI函数加入了__FILE__, __LINE__, __FUNCTION__宏,可以在log中快速找到LOGI的位置.如 at jni/jni.cpp(48)-JNI_OnLoad:

宏定义的\表示将一行分成多行,但是\后面不许接任何字符,包括空格,如果代码预览不正常,自己改正.

//Math.h

class Math {
public:
	int add(int a, int b);
};

//Math.cpp

#include"Math.h"

int Math::add(int a, int b) {
	return a + b;
}

//Android.mk

LOCAL_PATH := $(call my-dir)
 LOCAL_CPP_EXTENSION := .cpp
 
include $(CLEAR_VARS)
LOCAL_LDLIBS += -L$(SYSROOT)/usr/lib -llog
LOCAL_MODULE    := jni
LOCAL_SRC_FILES := LOCAL_SRC_FILES := Math.cpp jni.cpp

include $(BUILD_SHARED_LIBRARY)

第二句LOCAL_CPP_EXTENSION,扩展名为cpp

LOCAL_LDLIBS += -L$(SYSROOT)/usr/lib -llog
使用了这句,就不用再使用#include <utils/Log.h>了.

LOCAL_SRC_FILES:=为要编译的源文件,包括include进去的头文件的函数实现.如Math.cpp

 

//Application.mk

APP_ABI := all

//Tools.java

package com.example.ndkwithcpp;

public class Tools {
	public native int add(int a, int b);

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


至于如何使用NDK工具编译代码,自己找教程吧.

 

© 著作权归作者所有

梁金堂
粉丝 9
博文 15
码字总数 17275
作品 0
玉林
私信 提问
Android NDK开发简介

最近由于项目的需要,使用到了Android的NDK技术,对项目核心算法跨平台的移植。简答而言,就是使用C对原来的算法进行了改进,并集成到原来的app项目里。 从前的项目一直没有使用NDK进行开发的...

zhiweiofli
2013/03/07
0
0
JNI和NDK的区别

NDK(Native Development Kit)“原生”也就是二进制 android常用的开发方式是java封装的库,而这些库的底层实现是由C/C++实现,如媒体,图形库等 java调用这样实现就需要用JNI(Java Native...

长平狐
2013/01/06
62
0
JNI和NDK的区别

NDK(Native Development Kit)“原生”也就是二进制 android常用的开发方式是java封装的库,而这些库的底层实现是由C/C++实现,如媒体,图形库等 java调用这样实现就需要用JNI(Java Native...

鉴客
2012/03/09
181
0
JNI和NDK的区别

NDK(Native Development Kit)“原生”也就是二进制 android常用的开发方式是java封装的库,而这些库的底层实现是由C/C++实现,如媒体,图形库等 java调用这样实现就需要用JNI(Java Native...

晨曦之光
2012/03/01
1K
0
android studio 使用CMAKE

原文地址 前言 之前,每次需要边写C++代码的时候,我的内心都是拒绝的。 1. 它没有代码提示!!!这意味着我们必须自己手动敲出所有的代码,对于一个新手来说,要一个字母都不错且大小写也要...

shzwork
05/20
0
0

没有更多内容

加载失败,请刷新页面

加载更多

数组算法

/*数组的相关的算法操作:1、在数组中找最大值/最小值*/class Test11_FindMax{public static void main(String[] args){int[] array = {4,2,6,8,1};//在数组中找最大...

architect刘源源
29分钟前
1
0
okhttp3 以上版本在安卓9.0无法请求数据的解决方案

应用官方的说明:在 Android 6.0 中,我们取消了对 Apache HTTP 客户端的支持。 从 Android 9 开始,默认情况下该内容库已从 bootclasspath 中移除且不可用于应用。且Android P 限制了明文流量...

chenhongjiang
今天
11
0
简单示例:NodeJs连接mysql数据库

开篇引用网上的说法: 简单的说 Node.js 就是运行在服务端的 JavaScript。Node.js 是一个基于Chrome JavaScript 运行时建立的一个平台。Node.js是一个事件驱动I/O服务端JavaScript环境,基于...

李朝强
今天
8
0
大数据学习路线

年薪30W大数据学习路线图: 一、Hadoop入门,了解什么是Hadoop 1、Hadoop产生背景 2、Hadoop在大数据、云计算中的位置和关系 3、国内外Hadoop应用案例介绍 4、国内Hadoop的就业情况分析及课程...

陈小君
今天
3
0
解读 Kylin 3.0.0 | 更敏捷、更高效的 OLAP 引擎

在近期的 Apache Kylin Meetup 成都站上,我们邀请到 Kyligence 架构师 & Apache Kylin Committer 倪春恩对 Kylin 3.0.0 版本的一些重要功能及改进从使用到原理进行了介绍: Apache Kylin 在...

ApacheKylin
今天
6
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部