学习笔记 初识jni调用流程"/>
[安卓开发基础]NDK学习笔记 初识jni调用流程
- 1. 初识NDK
NDK(Native Develop Kits ),NDK 可以将C/C++ 编译成可执行的文件.so, JNI (java native interface) Java 本地开发接口,c/c++与Java通信的协议。,C/C++ 运行效率高一点(C/C++ -----(.exe)),Java运行效率相对低一点(Java---(*.class)---JVM---机器)。
Java(跨平台)-------jni---------C/C++(硬件操作)
arm 架构---x86/armeabi
x86架构----libs/x86
2.ndk 环境配置:
- Ndk 自带例子:
- 1.创建一个工程JNIDDemo1
声明native 方法,
static 静态块调用so库。
static {
System.loadLibrary("javaCallC");//javaCallC 的名称
}
package com.example.JNIDDemo1;/*** Created by zengjx on 2018/4/11.*/
public class JNI {static {System.loadLibrary("javaCallC");}public void helloFromJava(){System.out.println("helloFromJava");}public int javaadd(int x,int y){System.out.println("javaadd");return x+y;}public void print(String s){System.out.println(s);}//写 native 方法public native int add(int x,int y);public native int del(int a ,int b);public native String getString(String str);public native int[] getIntArray(int[] array);public native int getStringLen(String str);}
-
2.在src目录下 用javah 生成头文件;
- 3.创建 jni目录,将头文件剪切放到 jni目录下;
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_example_JNIDDemo1_JNI */#ifndef _Included_com_example_JNIDDemo1_JNI
#define _Included_com_example_JNIDDemo1_JNI
#ifdef __cplusplus
extern "C" {
#endif
/** Class: com_example_JNIDDemo1_JNI* Method: add* Signature: (II)I*/
JNIEXPORT jint JNICALL Java_com_example_JNIDDemo1_JNI_add(JNIEnv *, jobject, jint, jint);/** Class: com_example_JNIDDemo1_JNI* Method: del* Signature: (II)I*/
JNIEXPORT jint JNICALL Java_com_example_JNIDDemo1_JNI_del(JNIEnv *, jobject, jint, jint);/** Class: com_example_JNIDDemo1_JNI* Method: getString* Signature: (Ljava/lang/String;)Ljava/lang/String;*/
JNIEXPORT jstring JNICALL Java_com_example_JNIDDemo1_JNI_getString(JNIEnv *, jobject, jstring);/** Class: com_example_JNIDDemo1_JNI* Method: getIntArray* Signature: ([I)[I*/
JNIEXPORT jintArray JNICALL Java_com_example_JNIDDemo1_JNI_getIntArray(JNIEnv *, jobject, jintArray);/** Class: com_example_JNIDDemo1_JNI* Method: getStringLen* Signature: (Ljava/lang/String;)I*/
JNIEXPORT jint JNICALL Java_com_example_JNIDDemo1_JNI_getStringLen(JNIEnv *, jobject, jstring);#ifdef __cplusplus
}
#endif
#endif
- 4.根据头文件编写C文件文件名称与JNI 的javaCallC 相同。
static { System.loadLibrary("javaCallC"); }
本地函数命名规则 Java_包名_native所在的类名_native函数名
第二个参数:jobject调用 当前函数的对象
第一个参数 JNIEnv JNINativeInterface (**env)(*env)->
JNINativeInterface : 接口函数指针表
基本数据类型:
引用类型:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include "com_example_JNIDDemo1_JNI.h"
#include <android/log.h>
#define TAG "JNI_TAG"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__)char* _JString2Cstr(JNIEnv* env,jstring jstr);/** Class: com_example_JNITest2_JNI* Method: add* Signature: (II)I*/
JNIEXPORT jint JNICALL JNICALL Java_com_example_JNIDDemo1_JNI_add(JNIEnv * env, jobject jobject, jint x, jint y){int result =0;result=x+y;LOGI("LOGI----result%d,%d,%d",x,y,result);/**************c调用java*****************/jclass cls;jmethodID mid;jmethodID mid_add;jmethodID mid_string;cls=(*env)->FindClass(env,"com/example/JNIDDemo1/JNI");//找到字节码mid= (*env)->GetMethodID(env,cls,"helloFromJava","()V");//找到方法//创建对象(可选 同一个java类中 不要创建对象jobject )//通过对象调用方法(*env)->CallVoidMethod(env,jobject,mid);//第二个 函数//public int javaadd(int, int);// descriptor: (II)Imid_add= (*env)->GetMethodID(env,cls,"javaadd","(II)I");//通过对象调用方法int res =(*env)->CallIntMethod(env,jobject,mid_add,123,456);LOGI("LOGI--c调用 java add--%d",res);//第3个// public void print(java.lang.String);// descriptor: (Ljava/lang/String;)Vmid_string= (*env)->GetMethodID(env,cls,"print","(Ljava/lang/String;)V");//通过对象调用方法jstring jstr =(*env)->NewStringUTF(env,"print from c");(*env)->CallVoidMethod(env,jobject,mid_string,jstr);return result;}/** Class: com_example_JNITest2_JNI* Method: del* Signature: (II)I*/
JNIEXPORT jint JNICALL Java_com_example_JNIDDemo1_JNI_del(JNIEnv *env, jobject jobject, jint a, jint b){int result =0;result=a-b;LOGI("LOGI----result%d",result);return result;}char* _JString2Cstr(JNIEnv* env,jstring jstr){char* cstr=NULL;//获取String.class 字节码LOGI("LOGI----resultcstr%s","_JString2Cstr");jclass classstring=(*env)->FindClass(env,"java/lang/String");//找到String 类型的字节码LOGI("LOGI----resultcstr%s","_JString2Cstr 2");jstring strencode=(*env)->NewStringUTF(env,"GB2312");LOGI("LOGI----resultcstr%s","_JString2Cstr 3");//获取 方法 ID 号//找到 classstring 的 getByte 方法jmethodID mid =(*env)->GetMethodID(env,classstring,"getBytes","Ljava/lang/String;)[B");LOGI("LOGI----resultcstr%s","_JString2Cstr 4");jbyteArray barr=(jbyteArray)(*env)->CallObjectMethod(env,jstr,mid,strencode);LOGI("LOGI----resultcstr%s","_JString2Cstr 5");//获取数组的长度jsize alen =(*env)->GetArrayLength(env,barr);LOGI("LOGI----resultcstr_JString2Cstr 6 %d",alen);//获取数组首地址jbyte* ba=(*env)->GetByteArrayElements(env,barr,JNI_FALSE);if(alen>0){//是否有内容cstr=(char*)malloc(alen+1);memcpy(cstr,ba,alen);cstr[alen]=0;//"结束符"}(*env)->ReleaseByteArrayElements(env,barr,ba,0);LOGI("LOGI---_JString2Cstr end :%s",cstr);return cstr;}JNIEXPORT jstring JNICALL Java_com_example_JNIDDemo1_JNI_getString(JNIEnv *env, jobject jobject, jstring jstr){jsize size;char acbuf[]="wwwwwwwwwwwwwww";int strlen=0;char *cstr;int i=0;cstr = (*env)->GetStringUTFChars(env, jstr, NULL);//获得字符串转为 字符串指针if (cstr == NULL) {//用到分配内存可能会失败return NULL; /* OutOfMemoryError already thrown */}size= (*env)->GetStringUTFLength(env, jstr);LOGI("Get string from java size:%d\n",size);// strlen=strlen(cstr);// LOGI("Get string from java size:%d\n",strlen);LOGI("Get string from java :%s\n", cstr);for(i=0;i<size;i++){LOGI("Get string from java :%c\n", cstr[i]);*(cstr+i)+=1;LOGI("Get string from java :%c\n", cstr[i]);}// (*env)->ReleaseStringUTFChars(env, jstr, cstr);//释放空间// return (*env)->NewStringUTF(env,acbuf);return (*env)->NewStringUTF(env,cstr);}
- 5.编写Android.mk 文件:
LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE :=javaCallCLOCAL_SRC_FILES := javaCallC.cLOCAL_LDLIBS += -lloginclude $(BUILD_SHARED_LIBRARY)#include $(BUILD_STATIC_LIBRARY)
Application.mk 文件代码。(看文件中注释)
APP_ABI := all
#APP_ABI:= armeabi armeabi-v7a x86 mips mips-r2 mips-r2-sf
#如果是普通arm处理器的Android手机,使用APP_ABI := armeabi;
#如果是x86处理器的,使用APP_ABI := x86,等等。
#如果APP_ABI := all,会编译所有指令的so
APP_STL := stlport_static
#NDK中C++标准库、STL的配置
#如未配置可能出现错误: fatal error: iostream: No such file or directory
---------------------
作者:Ruffian-痞子
来源:CSDN
原文:
版权声明:本文为博主原创文章,转载请附上博文链接!
APP_MODULES := javaCallC
APP_ABI := armeabi
---------- cut here ------------------
#当前目录
LOCAL_PATH := $(call my-dir)
#清除上次编译的信息
include $(CLEAR_VARS)
#在这里指定最终生成的文件名字
LOCAL_MODULE := hello-jni
# 要编译的c代码文件名
LOCAL_SRC_FILES := hello-jni.c
#要生成的是一个动态链接库
include $(BUILD_SHARED_LIBRARY)
---------- cut here ------------------
- C代码添加log:
Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE :=Hello
LOCAL_SRC_FILES := Hello.c Hello2.c
LOCAL_LDLIBS += -llog
include $(BUILD_SHARED_LIBRARY)
#include $(BUILD_STATIC_LIBRARY)
加载 liblog.so
liblog.so 在NDK 的路径:
C代码添加:
#include <android/log.h>
#define TAG "JNI_TAG"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__)
Log.h :
Log
优先级
Prio 优先级 tag标记 可以过滤
5.在jni 目录下 执行 ndk-build: 编译生成.so文件。
-
6.调用:
package com.example.JNIDDemo1;import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;public class MyActivity extends Activity {private TextView textView;Button btn;/*** Called when the activity is first created.*/JNI jni =new JNI();//创建类@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.main);inittextView();// add();}public void inittextView(){textView=(TextView)findViewById(R.id.tv_log);btn=(Button)findViewById(R.id.btn);btn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {add();}});}public void add(){int ret=0;ret= jni.add(12,23);//调用native方法。Log.i("MyActivity","计算结果:"+jni.add(12,23));// textView.setText("计算结果:"+jni.add(12,23));textView.setText("计算结果:"+jni.add(12,23)+"字符串:"+jni.getString("abc"));}
}
C 调用 java:
-
- Javap 命令 生成 sigenature 签名
Eclipse:在bin/classes 目录下 :
Class 路径:
F:\ideaCode\JNIDDemo1\out\production\JNIDDemo1\com\example\JNIDDemo1
在JNI.class 路径下输入 javap -p -s JNI 输出如下信息:
Android studio :class 文件位置:
F:\AS\AndNDKDemo\app\build\intermediates\classes\debug\com\foundation\zengjx\andndkdemo
更多推荐
[安卓开发基础]NDK学习笔记 初识jni调用流程
发布评论