文章目录
一、JNI 中 main 函数声明
二、命令字符串切割并传入 main 函数
三、完整代码示例
1、完整 jni 代码
2、完整 java 代码
3、执行结果
四、参考资料
前置博客 :
【Android 安装包优化】使用 lib7zr.so 动态库处理压缩文件 ( 修改 7zr 交叉编译脚本 Android.mk | 交叉编译 lib7zr.so 动态库 )
【Android 安装包优化】使用 lib7zr.so 动态库处理压缩文件 ( 拷贝 lib7zr.so 动态库到 Android Studio 工程 | 配置 build.gradle 构建脚本 )
【Android 安装包优化】使用 lib7zr.so 动态库处理压缩文件 ( 拷贝 lib7zr.so 动态库头文件到 Android 工程中 | 配置 CMakeLists.txt 构建脚本 )
【Android 安装包优化】使用 lib7zr.so 动态库处理压缩文件 ( 测试 lib7zr.so 动态库调用 )
一、JNI 中 main 函数声明
使用 7zr 可执行程序处理压缩文件时时 , 调用的是其主函数 , CPP\7zip\UI\Console\MainAr.cpp 中的 main 函数 , 传入 7z a outputFile inputFile -mx=compressDegree -tcompressType 压缩命令 , 或 7z x [输入文件] -o[输出目录] 解压命令 , 都是使用该主函数接收相关参数 ;
int MY_CDECL main ( #ifndef _WIN32 int numArgs, char *args[] #endif )
int numArgs 参数表示字符串个数 ;
如 7zr a files.7z files -mx=9 -t7z 命令中 , 有 6 66 个字符串 , 由 5 55 个空格隔开 ;
char *args[] 是 指针数组 , 数组中的元素是 char * 类型的指针 , 就是字符串 , 这是个字符串数组 ;
7zr 程序中的主要的头文件是 7zTypes.h , 该头文件中 声明了主要的 类型 和 函数 ; 引入该头文件 ;
#include <7zTypes.h>
声明外部函数 :
// 表示该函数在其它代码中实现 // 这是 CPP\7zip\UI\Console\MainAr.cpp 中的 main 函数 extern int MY_CDECL main ( #ifndef _WIN32 int numArgs, char *args[] #endif );
点击声明左侧的双向箭头按钮 , 可以跳转到 MainAr.cpp 的 main 函数位置 ;
跳转位置 :
二、命令字符串切割并传入 main 函数
调用 main 函数 , 需要传入对应的参数 , 分别是
int numArgs 字符串个数 ; char *args[] 字符串数组 ; 指针数组 , 每个数组元素中都有一个 char * 指针元素 , 指向字符串 ; int MY_CDECL main ( #ifndef _WIN32 int numArgs, char *args[] #endif )
从 Java 传入 C 的指令如下 :
7zr a files.7z files -mx=9 -t7z
使用空格将上述指令切割成 6 66 个字符串 , 然后传入 main 函数 ;
字符串切割过程 :
// 命令示例 : 7zr a files.7z files -mx=9 -t7z // 参数个数 int argCount = 0; // 存放多个字符串, 最多 20 个字符串 , 每个最多 1024 个字符 char argArray[20][1024] = {0}; //分割字符串 将值填入变量 // 获取 cmd_java 字符串长度 int cmd_size = strlen(cmd_java); // 二维数组 循环控制变量, 第一个是字符串数组 , 第二个是字符串中的字符数组 int str_index = 0, char_index = 0; // 标记字符是否是非空字符, tab, 如果是则设置 1 , 如果不是设置 0 // 开始时默认 0, 不是空格 int isChar = 0; // 逐个字节遍历 字符 for(int i = 0; i < cmd_size; i ++){ // 获取一个字符 char c = cmd_java[i]; //LOGI("遍历 %d . %c , cmd_size = %d", i, c, cmd_size); switch (c) { case ' ': // 判断是否是空格 case '\t': // 判断是否是 TAB 空格 if(isChar){ // 如果上一个字符不是空格 , 则需要结束当前的字符串 argArray[str_index][char_index++] = '\0'; // 字符串索引自增 1 str_index ++; // 字符串内字符索引归零 char_index = 0; // 设置当前的字符为空格标志位 1 isChar = 0; }else{ // 如果之前是空格, 那么现在也是空格 , // 说明命令中有多个空格 , 此处不做任何处理 } break; default: isChar = 1; // 将当前字符放入数组中 argArray[str_index][char_index++] = c; break; } } // 如果最后一位不是空格 , 则需要手动将最后一个字符串写入到数组中 if (cmd_java[cmd_size - 1] != ' ' && cmd_java[cmd_size - 1] != '\t') { // 如果上一个字符不是空格 , 则需要结束当前的字符串 argArray[str_index][char_index++] = '\0'; // 字符串索引自增 1 str_index ++; } // 统计字符串个数 argCount = str_index; // 拼装字符串数组 char *args[] = {0}; for (int i = 0; i < argCount; ++i) { args[i] = argArray[i]; // 打印字符串数组 LOGI("%d . %s", i, args[i]); }
最终的字符串个数是 argCount , 字符串数组 args ;
将这两个参数传入 main 函数即可 ;
三、完整代码示例
1、完整 jni 代码
完整 jni 层 C++ 代码如下 :
#include <jni.h> #include <string> #include <7zTypes.h> #include "logging_macros.h" // 表示该函数在其它代码中实现 // 这是 CPP\7zip\UI\Console\MainAr.cpp 中的 main 函数 extern int MY_CDECL main ( #ifndef _WIN32 int numArgs, char *args[] #endif ); extern "C" JNIEXPORT void JNICALL Java_kim_hsl_a7_1zip_MainActivity_executeCmd(JNIEnv* env, jobject thiz, jstring cmd) { // 将 Java 字符串转为 C 字符串 const char *cmd_java = env->GetStringUTFChars(cmd, 0); LOGI("jni 中处理压缩文件命令 : %s", cmd_java); // 命令示例 : 7zr a files.7z files -mx=9 -t7z // 参数个数 int argCount = 0; // 存放多个字符串, 最多 20 个字符串 , 每个最多 1024 个字符 char argArray[20][1024] = {0}; //分割字符串 将值填入变量 // 获取 cmd_java 字符串长度 int cmd_size = strlen(cmd_java); // 二维数组 循环控制变量, 第一个是字符串数组 , 第二个是字符串中的字符数组 int str_index = 0, char_index = 0; // 标记字符是否是非空字符, tab, 如果是则设置 1 , 如果不是设置 0 // 开始时默认 0, 不是空格 int isChar = 0; // 逐个字节遍历 字符 for(int i = 0; i < cmd_size; i ++){ // 获取一个字符 char c = cmd_java[i]; //LOGI("遍历 %d . %c , cmd_size = %d", i, c, cmd_size); switch (c) { case ' ': // 判断是否是空格 case '\t': // 判断是否是 TAB 空格 if(isChar){ // 如果上一个字符不是空格 , 则需要结束当前的字符串 argArray[str_index][char_index++] = '\0'; // 字符串索引自增 1 str_index ++; // 字符串内字符索引归零 char_index = 0; // 设置当前的字符为空格标志位 1 isChar = 0; }else{ // 如果之前是空格, 那么现在也是空格 , // 说明命令中有多个空格 , 此处不做任何处理 } break; default: isChar = 1; // 将当前字符放入数组中 argArray[str_index][char_index++] = c; break; } } // 如果最后一位不是空格 , 则需要手动将最后一个字符串写入到数组中 if (cmd_java[cmd_size - 1] != ' ' && cmd_java[cmd_size - 1] != '\t') { // 如果上一个字符不是空格 , 则需要结束当前的字符串 argArray[str_index][char_index++] = '\0'; // 字符串索引自增 1 str_index ++; } // 统计字符串个数 argCount = str_index; // 拼装字符串数组 char *args[] = {0}; for (int i = 0; i < argCount; ++i) { args[i] = argArray[i]; // 打印字符串数组 LOGI("%d . %s", i, args[i]); } // 量参数传入 main 函数 main(argCount, args); // 释放 Java 字符串以及 C 字符串 env->ReleaseStringUTFChars(cmd, cmd_java); LOGI("7zr 命令执行完毕 !"); }