您的位置:首页 > 编程语言 > C语言/C++

java中通过ndk调用c/c++ 例子,详细解释

2014-12-25 12:54 531 查看
        上篇文章中已经介绍了,关于NDK开发环境的搭建,这里不做赘述。这篇文章主要是通过一个例子来说明如何通过eclispe自动生成.h头文件,适合初学者。本篇文章主要是参考:http://blog.csdn.net/super_level/article/details/21243533。

1 创建含有本地代码的Android Project

该过程分为以下两步:

创建普通的Android Application工程(注意最小支持的API版本要不小于14)
加入本地代码支持  目的是可以自动生成.so文件,以便在MainActivitiy中能够加载库文件从而调用c/c++
创建工程:



加入本地代码支持:



名字选择默认的TestNDK就可以了。

完成结果:

2 编写java端代码和c++端代码

2.1 java端代码

Java端,注意不要继承自Android中的类,否则javah编译头文件时要指定android类路径。

在NativeClass.java文件中:

package com.example.testndk;

import android.util.Log;

public class NativeClass {
//数组a中的每个元素都加上b,返回值为在C++中数据是否为a中数据拷贝得到的(按值拷贝还是传递指针)
public static native boolean jniArrayAdd(int[] a, int b);  //加
// 在C++中创建Java中的int数组,其中元素为 数组a中的对应元素乘以b
public static native int[] jnitArrayMul(int[] a,int b);  //乘以
static {
Log.i("NativeClass","before load library");
System.loadLibrary("TestNDK");//注意这里为自己指定的.so文件,无lib前缀,亦无后缀
Log.i("NativeClass","after load library");
}
}

Java端调用JNI方法的代码:

将MainActivity改为:

package com.example.testndk;

import java.util.Arrays;

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

public class MainActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView tv = new TextView(this);
int[] array = new int[]{1,2,3};
String str = "数组,调用C++前" + Arrays.toString(array);//将数组转成字符串
boolean isCopyOfArrayInCpp = NativeClass.jniArrayAdd(array, 1);
System.out.println(isCopyOfArrayInCpp);//然后java在print的时候都是调用对象的toString方法就会把o改成false输出
str += "\n 在c++中为副本?  " + isCopyOfArrayInCpp;
str += "\n数组,调用C++后:" + Arrays.toString(array);
tv.setText(str);
setContentView(tv);
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}

}


2.2 编写c++代码,实现java中native函数

#include <jni.h>
#include "com_example_testndk_NativeClass.h"
#include <android/log.h>
#ifdef __cplusplus
extern "C"{
#endif
JNIEXPORT jboolean JNICALL Java_com_example_testndk_NativeClass_jniArrayAdd
(JNIEnv * env, jclass, jintArray array, jint b){
jsize size = env ->GetArrayLength(array);

jboolean isCopy = false;
jint *pArray = (jint*) env ->GetPrimitiveArrayCritical(array,&isCopy);
for(int i = 0; i < size ; i++){
pArray[i] += b;
}
env->ReleasePrimitiveArrayCritical(array,pArray,JNI_COMMIT);//JNI_COMMIT 对java数组进行更行,但是不释放java数组
__android_log_print(ANDROID_LOG_DEBUG, "frank", "isCopy= %d",isCopy);//输出的的isCopy= 0;说明是false,0是false也是Null(string 输出的时候)
return isCopy;
}
#ifdef __cplusplus
}
#endif
如果要log输出的话,android.mk里面需要配置:



添加:LOCAL_LDLIBS := -landroid -llog {这个库文件}

3 配置自动生成头文件:

3.1 对每一个程序配置javah命令



配置如下:



里面需要写的分别是:

C:\Program Files\Java\jdk1.7.0_51\bin\javah.exe 

${workspace_loc:/WifiIp}

-classpath src -d jni com.example.wifiip.MainActivity(注意这种写法是在MainAvitvity里面去声明native方法的时候写的一种格式)

然后再run里面执行 wifiip_javah 就可以了(这里并不是TestNDK这个工程,换了另外一个工程)

3.2 通用的头文件生成配置如下

如果每一个程序都像上面一样去配置是不是会很麻烦,所以就有一种通用的配置:



需要填的分别是:

Generate C and C++ Header

C:\Program Files\Java\jdk1.7.0_51\bin\javah.exe

${project_loc}/jni

-classpath "${project_classpath};${env_var:ANDROID_SDK_HOME}/platforms/android-14/android.jar"${java_type_name}

注意这个ANDROID_SDK_HOME,需要在path环境变量里面去配置:



在尾部加上D:\program\studyprogram\adt-bundle-windows-x86-20130219\sdk;(你的SDK的路径)

然后配置好之后。就可以用这个命令去生成.h头文件了,注意生成的时候一定要:



4 配置生成的.so文件的目标平台

ava是跨平台的可是C++生成动态链接文件不是!!!同是Android,底层的CPU架构不同,动态链接文件也不同。。。好吧,这个我不知道原因。。。

于是乎,还得为不同的CPU创建不同的动态链接库文件,好在一行命令搞定~所有的动态链接一起打包,管他是哪个CPU,统统适用,Happy啊。



再编译时在libs下面就会生成三种平台下的.so文件。

5 结果



后续:要进行对jni层进行调试。比较麻烦。等用到的时候再去学习吧。

这样就把整个java层调用c/c++层说明了。

工程下载链接地址http://download.csdn.net/detail/u011563903/8301923
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  JNI eclipse android NDK