这篇已经是"一步一步学习androidNDK编程"的第四篇了,在这篇中,我们将会在java中传递代码给c代码。

首先,我们新建一个android工程"ndkdata",

第一步:

同样的首先声明native方法,如下:

public native int add(int a,int b);public native String helloSir(String name);public native int[] intMethod(int[] intArray);
可以看到我这里声明了三个方法,用来传递不同的数据类型给c代码

第二步:

由于我们的这些方法都是声明在MainActivity.java中的,所以我们需要首先将该MainActivity.java用javac编译为.class文件,然后运用javah,生成对应的.h头文件。

将该MainActivity.java用javac编译为.class文件:这个就是运行该android工程即可在bin/classes目录下生成对应的.class文件。

命令行下进入bin/classes所在的目录:执行javah com.example.ndkdata.MainActivity即可在该目录下生成对应的com_example_ndkdata_MainActivity.h头文件了,内容如下:

/* DO NOT EDIT THIS FILE - it is machine generated */#include <jni.h>/* Header for class com_example_ndkdata_MainActivity */#ifndef _Included_com_example_ndkdata_MainActivity#define _Included_com_example_ndkdata_MainActivity#ifdef __cplusplusextern "C" {#endif/* * Class:     com_example_ndkdata_MainActivity * Method:    add * Signature: (II)I */JNIEXPORT jint JNICALL Java_com_example_ndkdata_MainActivity_add  (JNIEnv *, jobject, jint, jint);/* * Class:     com_example_ndkdata_MainActivity * Method:    helloSir * Signature: (Ljava/lang/String;)Ljava/lang/String; */JNIEXPORT jstring JNICALL Java_com_example_ndkdata_MainActivity_helloSir  (JNIEnv *, jobject, jstring);/* * Class:     com_example_ndkdata_MainActivity * Method:    intMethod * Signature: ([I)[I */JNIEXPORT jintArray JNICALL Java_com_example_ndkdata_MainActivity_intMethod  (JNIEnv *, jobject, jintArray);#ifdef __cplusplus}#endif#endif
接下来我们在ndkdata工程中,创建jni目录,然后再将刚才生成的 com_example_ndkdata_MainActivity.h文件拷贝到该目录下,然后创建我们的c代码:hello.c

com_example_ndkdata_MainActivity.h中生成的方法添加到hello.c文件中这里需要添加参数,因为默认生成的只有方法的参数类型,没有参数对象,并且引入对应的头文件,如下:

#include<stdio.h>#include<jni.h>#include "com_example_ndkdata_MainActivity.h"JNIEXPORT jint JNICALL Java_com_example_ndkdata_MainActivity_add  (JNIEnv * env, jobject obj, jint x, jint y) {      }JNIEXPORT jstring JNICALL Java_com_example_ndkdata_MainActivity_helloSir  (JNIEnv * env, jobject obj, jstring jstr) {      }JNIEXPORT jintArray JNICALL Java_com_example_ndkdata_MainActivity_intMethod  (JNIEnv * env, jobject obj, jintArray arr) {        }
接下来就是实现我们的c代码了,如下:

#include<stdio.h>#include<jni.h>#include "com_example_ndkdata_MainActivity.h"JNIEXPORT jint JNICALL Java_com_example_ndkdata_MainActivity_add (JNIEnv * env, jobject obj, jint x, jint y) { return x+y;}/*** 返回值 char* 这个代表char数组的首地址* Jstring2CStr 把java中的jstring的类型转化成一个c语言中的char 字符串*/char*  Jstring2CStr(JNIEnv*  env,  jstring  jstr){<span style="white-space:pre"></span> char*  rtn  =  NULL;<span style="white-space:pre"></span> jclass  clsstring  =  (*env)->FindClass(env,"java/lang/String"); //String<span style="white-space:pre"></span> jstring  strencode  =  (*env)->NewStringUTF(env,"GB2312"); // 得到一个java字符串 "GB2312"<span style="white-space:pre"></span> jmethodID  mid  =  (*env)->GetMethodID(env,clsstring,  "getBytes",  "(Ljava/lang/String;)[B"); //[ String.getBytes("gb2312");<span style="white-space:pre"></span> jbyteArray  barr=  (jbyteArray)(*env)->CallObjectMethod(env,jstr,mid,strencode); // String .getByte("GB2312");<span style="white-space:pre"></span> jsize  alen  =  (*env)->GetArrayLength(env,barr); // byte数组的长度<span style="white-space:pre"></span> jbyte*  ba  =  (*env)->GetByteArrayElements(env,barr,JNI_FALSE);<span style="white-space:pre"></span> if(alen  >  0)<span style="white-space:pre"></span> {<span style="white-space:pre"></span> rtn  =  (char*)malloc(alen+1);     //"\0"<span style="white-space:pre"></span> memcpy(rtn,ba,alen);<span style="white-space:pre"></span> rtn[alen]=0;<span style="white-space:pre"></span> }<span style="white-space:pre"></span> (*env)->ReleaseByteArrayElements(env,barr,ba,0); //<span style="white-space:pre"></span> return rtn;}JNIEXPORT jstring JNICALL Java_com_example_ndkdata_MainActivity_helloSir (JNIEnv * env, jobject obj, jstring jstr) { //在c语言中 是没有java的String<span style="white-space:pre"></span>char* cstr = Jstring2CStr(env, jstr);<span style="white-space:pre"></span>// c语言中的字符串 都是以'\0' 作为结尾<span style="white-space:pre"></span>char arr[7]= {' ','h','e','l','l','o','\0'};<span style="white-space:pre"></span>strcat(cstr,arr);<span style="white-space:pre"></span>return (*env)->NewStringUTF(env,cstr);}JNIEXPORT jintArray JNICALL Java_com_example_ndkdata_MainActivity_intMethod (JNIEnv * env, jobject obj, jintArray arr) {}

编写完了hello.c之后,需要编写Android.mk,内容如下:

#交叉编译编译c/c++代码所依赖的配置文件#获取当前Android.mk的路径  LOCAL_PATH := $(call my-dir)#变量初始化操作include $(CLEAR_VARS)#libhello.so 其实生成的libhello.so就是在我们这个模块的名称前面加上lib后边加上.soLOCAL_MODULE    := helloLOCAL_SRC_FILES := hello.cinclude $(BUILD_SHARED_LIBRARY)
现在就需要在cygwine的命令行下进入该工程ndkdata的根目录下,执行"ndk-build"命令生成对应的可直接运行的二进制文件,注意每次在执行"ndk-build"之后最好将android工程clean一下。

在“ndk-build”成功之后,需要在java代码中引入这些库文件:

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

注意这里的"hello",就是我们在Android.mk文件中写的模块名,即LOCAL_MODULE的值。

现在,就可以执行声明的native方法了,在java代码中直接调用即可,是不是很简单呢。

源码下载








更多相关文章

  1. android 透明显示
  2. android背景选择器selector用法
  3. Android(安卓)Studio 之 AndroidManifest.xml文件中的android:la
  4. 安装android sdk 遇到几个问题
  5. android:sharedUserId="android.uid.system" 系统级权限并重新系
  6. android studio打包apk时遇见的一些问题
  7. android国际化
  8. 最简单的android底部导航栏 + Fragment的实现方式
  9. Android命令行获取WiFi列表以及参数

随机推荐

  1. Android O/P/Q 版本如何预装 APK
  2. CMake学习
  3. Android 电子书应用完全开源代码
  4. MTP in Android
  5. Android 抢购功能(时间戳之间的倒计时)
  6. Android 获取网络视频某一帧图片
  7. Android(安卓)Lottie动画初探
  8. Unity3D和Android之间的方法交互(jar模式
  9. Android 渗透测试学习手册(一)Android 安全
  10. Android使用AOP