首页 > 其他分享 >JNI开发

JNI开发

时间:2023-10-01 23:57:08浏览次数:33  
标签:jstring return String 开发 static env JNI public

JNI(java native interface),Java本地开发接口,实现JAVA和C语言之间的相互调用。

一、NDK

  • NDK,Native Develop Kits,是JNI开发的工具包(在Android Studio中下载即可)

二、项目创建

  • 普通项目:模板Empty Activity(Java)
  • JNI项目:模板Native C++(Java + C)
    • 会多一些默认配置

三、快速实现

  • 1、新建java类 + native方法

    package com.example.jni;
    
    public class Utils {
        // 加载c文件
        static {
            System.loadLibrary("encrypt");
        }
    
        // 1、java实现
        public static String v0(String data) {
            return data + "hello world";
        }
    
        // 2、native方法(声明即可,具体在c语言中实现)
        public static native int v1(int data1, int data2);
    }
  • 2、创建c文件 + 创建函数【Java_包名_类名_方法名】

    • 在【cpp】目录下,右键【new】选择【C/C++ Source File】,记得文件后缀改成【.c】
    • 快捷键:直接输入java类中定义的native方法名【v1】,根据提示选择后回车
      #include <jni.h>
      
      JNIEXPORT jint JNICALL
      Java_com_example_jni_Utils_v1(JNIEnv *env, jclass clazz, jint data1, jint data2) {
          return data1 + data2 + 100;
      }
  • 3、c编译配置

  • 4、java类中加载c文件

    package com.example.jni;
    
    public class Utils {
        static {
            System.loadLibrary("encrypt");
        }
    
        // 1、java实现
        public static String v0(String data) {
            return data + "hello world";
        }
    
        // 2、c实现
        public static native int v1(int data1, int data2);
    }
  • 5、逆向和反编译

    • jadx反编译并定位到了native方法
    • 将apk包中的so文件导出到ida中进一步分析

      点击进入后,按F5,并可以导入jni.h头文件等操作

四、类型对照

  • JNIEXPORT jstring JNICALL
    Java_com_example_jni_Utils_v2(JNIEnv *env, jclass clazz, jstring data) {
        // jstring转c语言中的字符串
        char *newData = (*env)->GetStringUTFChars(env, data, 0);
    
        newData[0] = 'a';
        newData[3] = 'x';
    
        // c语言中的字符串转jstring
        return (*env)->NewStringUTF(env, newData);
    }

六、示例

  • 1、Java调用C示例

    • 字符串拼接
      • java中的方法声明
        // 字符串拼接
        public static native String v3(String data1, String data2);    
      • encrypt.c
        #include <jni.h>
        #include <string.h>
        #include <malloc.h>
        
        JNIEXPORT jstring JNICALL
        Java_com_example_jni_Utils_v3(JNIEnv *env, jclass clazz, jstring data1, jstring data2) {
            char *res1 = (*env)->GetStringUTFChars(env, data1, 0);
            char *res2 = (*env)->GetStringUTFChars(env, data2, 0);
            char *result = malloc(strlen(res1) + strlen(res2) + 1);
            strcpy(result, res1);
            strcat(result, res2);
            return (*env)->NewStringUTF(env, result);
        }
  • 2、C调用Java示例

    • 静态方法
      • java中的方法声明
        package com.example.jni;
        
        public class Utils {
            static {
                System.loadLibrary("encrypt");
            }
        
            // c调用java静态方法
            public static native String v4();
        }
      • C语言中需要调用的java方法声明
        package com.example.jni;
        
        public class SignQuery {
            public static String getPart1() {
                return "hello";
            }
        
            public static String getPart2(int len) {
                return "world".substring(2);
            }
        
            public static String getPart3(String prev) {
                return "NB";
            }
        
            public static int getPart4(String prev, int v1) {
                return 100;
            }
        }
      • encrypt.c
        #include <jni.h>
        #include <string.h>
        #include <malloc.h>
        
        JNIEXPORT jstring JNICALL
        Java_com_example_jni_Utils_v4(JNIEnv *env, jclass clazz) {
            // 1、找类 (类名路径分隔符"/")
            jclass cls = (*env)->FindClass(env, "com/example/jni/SignQuery");
        
            // 2、找静态方法 (参数3:方法名, 参数4:JNI签名)
            jmethodID methodId1 = (*env)->GetStaticMethodID(env, cls, "getPart1", "()Ljava/lang/String;");
            jmethodID methodId2 = (*env)->GetStaticMethodID(env, cls, "getPart2", "(I)Ljava/lang/String;");
            jmethodID methodId3 = (*env)->GetStaticMethodID(env, cls, "getPart3", "(Ljava/lang/String;)Ljava/lang/String;");
            jmethodID methodId4 = (*env)->GetStaticMethodID(env, cls, "getPart4", "(Ljava/lang/String;I)I");
        
            // 3、调用静态方法 (参数3:jmethodID,如果方法有参数,则以位置参数的形式依次写上)
            // 调用方法时,需要根据返回值类型来进行选择
            jstring res1 = (*env)->CallStaticObjectMethod(env, cls, methodId1);
            jstring res2 = (*env)->CallStaticObjectMethod(env, cls, methodId2, 100);
            jstring res3 = (*env)->CallStaticObjectMethod(env, cls, methodId3, (*env)->NewStringUTF(env, "come on!"));
            jint res4 = (*env)->CallStaticIntMethod(env, cls, methodId4, (*env)->NewStringUTF(env, "my god!"), 28);
        
            // 4、jstring => c语言字符串
            char *result1 = (*env)->GetStringUTFChars(env, res1, 0);
            char *result2 = (*env)->GetStringUTFChars(env, res2, 0);
            char *result3 = (*env)->GetStringUTFChars(env, res3, 0);
        
            // 5、c语言中字符串相关操作
            char *result = malloc(strlen(result1) + strlen(result2) + strlen(result3) + 1);
            strcpy(result, result1);
            strcat(result, result2);
            strcat(result, result3);
        
            // 6、C语言字符串 => jstring
            return (*env)->NewStringUTF(env, result);
        }
    • 实例方法
      • java中的方法声明
        package com.example.jni;
        
        public class Utils {
            static {
                System.loadLibrary("encrypt");
            }
        
            // c调用java实例方法
            public static native String v5();
        }
      • C语言中需要调用的java方法声明
        package com.example.jni;
        
        public class GetSign {
            String name;
            int age;
        
            public GetSign(String name, int age){
                this.name = name;
                this.age = age;
            }
        
            public String getPart1() {
                return this.name;
            }
        
            public String getPart2(int len) {
                return "world".substring(2);
            }
        
            public String getPart3(String prev) {
                return "NB";
            }
        
            public int getPart4(String prev, int v1) {
                return 100;
            }
        }
      • encrypt.c
        #include <jni.h>
        #include <string.h>
        #include <malloc.h>
        
        JNIEXPORT jstring JNICALL
        Java_com_example_jni_Utils_v5(JNIEnv *env, jclass clazz) {
            // 1、找类 (类名路径分隔符"/")
            jclass cls = (*env)->FindClass(env, "com/example/jni/GetSign");
        
            // 2、找构造方法
            jmethodID init = (*env)->GetMethodID(env, cls, "<init>", "(Ljava/lang/String;I)V");
        
            // 3、实例化对象
            jobject obj = (*env)->NewObject(env, cls, init, (*env)->NewStringUTF(env, "eliwang"), 28);
        
            // 4、找实例方法
            jmethodID methodId1 = (*env)->GetMethodID(env, cls, "getPart1", "()Ljava/lang/String;");
            jmethodID methodId2 = (*env)->GetMethodID(env, cls, "getPart2", "(I)Ljava/lang/String;");
            jmethodID methodId3 = (*env)->GetMethodID(env, cls, "getPart3", "(Ljava/lang/String;)Ljava/lang/String;");
            jmethodID methodId4 = (*env)->GetMethodID(env, cls, "getPart4", "(Ljava/lang/String;I)I");
        
            // 5、执行实例方法
            jstring res1 = (*env)->CallObjectMethod(env, obj, methodId1);
            jstring res2 = (*env)->CallObjectMethod(env, obj, methodId2, 100);
            jstring res3 = (*env)->CallObjectMethod(env, obj, methodId3, (*env)->NewStringUTF(env, "come on!"));
            jint res4 = (*env)->CallIntMethod(env, obj, methodId4, (*env)->NewStringUTF(env, "my god!"), 28);
        
            // 6、jstring => c语言字符串
            char *result1 = (*env)->GetStringUTFChars(env, res1, 0);
            char *result2 = (*env)->GetStringUTFChars(env, res2, 0);
            char *result3 = (*env)->GetStringUTFChars(env, res3, 0);
        
            // 7、c语言中字符串相关操作
            char *result = malloc(strlen(result1) + strlen(result2) + strlen(result3) + 1);
            strcpy(result, result1);
            strcat(result, result2);
            strcat(result, result3);
        
            // 8、C语言字符串 => jstring
            return (*env)->NewStringUTF(env, result);
        }

七、静态和动态注册

  • 静态注册

    • C语言中函数名和Java中函数名之间的对应关系
      Java_包名_类名_函数名

      c文件中的函数名

  • 动态注册

    • DynamicUtils.java
      package com.example.jni;
      
      public class DynamicUtils {
          static {
              System.loadLibrary("dynamic");
          }
      
          // JNI动态注册
          public static native int add(int v1, int v2);
      }
    • dynamic.c
      #include <jni.h>
      
      jint plus(JNIEnv *env, jobject obj, jint v1, jint v2){
          return v1 + v2;
      }
      
      static JNINativeMethod gMethods[] = {
              {"add", "(II)I", (void *) plus},
      };
      
      JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
      
          JNIEnv *env = NULL;
      
          // 在java虚拟机中获取env
          if ((*vm)->GetEnv(vm, (void **) &env, JNI_VERSION_1_6) != JNI_OK) {
              return JNI_ERR;
          }
      
          // 找到Java中的类
          jclass clazz = (*env)->FindClass(env, "com/example/jni/DynamicUtils");
      
          // 将类中的方法注册到JNI中 (RegisterNatives)
          int res = (*env)->RegisterNatives(env, clazz, gMethods, 1);
          if (res < 0) {
              return JNI_ERR;
          }
      
          return JNI_VERSION_1_6;
      }

      dynamic.c需要添加编译配置

标签:jstring,return,String,开发,static,env,JNI,public
From: https://www.cnblogs.com/eliwang/p/17731690.html

相关文章

  • Symchk.exe是微软提供的一个命令行工具,用于下载符号文件以帮助调试问题。符号文件包含
    Symchk.exe是微软提供的一个命令行工具,用于下载符号文件以帮助调试问题。符号文件包含用于将二进制文件映射回源代码的关键信息,可帮助开发人员在调试期间确定问题的根本原因。使用Symchk.exe,您可以指定要下载符号文件的二进制文件,该工具会查找相关的PDB文件并将其下载到本地计算......
  • 开发者必看!苹果App Store重大调整:App上架必须有ICP备案号
    日前,苹果AppStore迎来重大调整,即日起中国大陆上架的App必须具备有效的互联网信息服务提供者(ICP)备案号。简单说,新App现在需要填写备案号才能提审,这就要求开发者应用需有备案号,另外,如果海外App不申请备案号,则无法在中国大陆上架。苹果AppStore部分App上架要求还包括:游戏App必须......
  • Mac安装Java开发工具包
    1.检查你是否安装了Java软件首先,检查你是否已安装Java开发工具包版本8或更高版本。要检查是否已安装JDK(以及安装的是哪个版本),打开终端窗口并输入:java-version,然后按Enter键。下面的示例显示了Java版本1.8.0_91--“1”后面就是版本号:如果已安装Java8或更高版......
  • Windows:安装 Java 开发工具包
    1.检查你是否已安装Java软件首先,检查你是否已安装Java开发工具包版本8或更高版本。要检查是否已安装JDK(以及安装的是哪个版本),打开命令提示符窗口并输入:java-version,然后按Enter键。下面的示例显示了Java版本1.8.0_92--“1”后面就是版本号。如果已安装Java8......
  • 开发人员常用命令
    添加指定需要开放的端口:firewall-cmd--add-port=123/tcp--permanent重载入添加的端口:firewall-cmd--reload查询指定端口是否开启成功:firewall-cmd--query-port=123/tcp远程拉取所有分支gitremoteupdateorigin......
  • springboot web开发静态资源的映射规则
    前言我们之间介绍过SpringBoot自动配置的原理,基本上是如下:xxxxAutoConfiguration:帮我们给容器中自动配置组件;xxxxProperties:配置类来封装配置文件的内容;web开发中都在org.springframework.boot.autoconfigure.web包下今天看的静态资源映射规则都在org.springframework.boot.aut......
  • springboot web开发整合Freemarker 模板引擎
    目录Freemarker添加依赖配置文件ymlcontrollerhtmlFreemarker简介:FreeMarker是一款模板引擎:即一种基于模板和要改变的数据,并用来生成输出文本(HTML网页,电子邮件,配置文件,源代码等)的通用工具。它不是面向最终用户的,而是一个Java类库,是一款程序员可以嵌入他们所开发产品的组......
  • 02_nodejs开发环境安装
    02【nodejs开发环境安装】1.版本介绍在命令窗口中输入node-v可以查看版本0.x完全不技术ES64.x部分支持ES6特性5.x部分支持ES6特性(比4.x多些),属于过渡产品,现在来说应该没有什么理由去用这个了6.x支持98%的ES6特性8.x支持ES6特性2.Node.js运行环境配置:通过Node.js......
  • springboot web开发springmvc自动配置原理
    前言我们也知道springboot启用springmvc基本不用做什么配置可以很方便就使用了但是不了解原理,开发过程中遇到点问题估计就比较头疼,不管了解的深不深入,先巴拉一番再说…下面我们先看看官网…我的版本是2.3.2版本,发现官网改动也比较大…不同版本自己巴拉下吧,结构虽然变化了,但......
  • springboot web开发登录拦截器
    在SpringBoot中我们可以使用HandlerInterceptorAdapter这个适配器来实现自己的拦截器。这样就可以拦截所有的请求并做相应的处理。应用场景日志记录,可以记录请求信息的日志,以便进行信息监控、信息统计等。权限检查:如登陆检测,进入处理器检测是否登陆,如果没有直接返回到登陆页面。性......