[安卓开发基础]NDK学习笔记 初识jni调用流程

编程入门 行业动态 更新时间:2024-10-25 06:30:46

[安卓开发基础]NDK<a href=https://www.elefans.com/category/jswz/34/1770117.html style=学习笔记 初识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 环境配置:

  1. 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:

 

    1. 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调用流程

本文发布于:2024-03-04 16:14:09,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1709761.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:学习笔记   流程   基础   卓开发   jni

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!