文章目录

  • 一、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 _WIN32int numArgs, char *args[]#endif
)

int numArgs 参数表示字符串个数 ;

7zr a files.7z files -mx=9 -t7z 命令中 , 有 666 个字符串 , 由 555 个空格隔开 ;

char *args[] 是 指针数组 , 数组中的元素是 char * 类型的指针 , 就是字符串 , 这是个字符串数组 ;

7zr 程序中的主要的头文件是 7zTypes.h , 该头文件中 声明了主要的 类型 和 函数 ; 引入该头文件 ;

#include <7zTypes.h>

声明外部函数 :

// 表示该函数在其它代码中实现
// 这是 CPP\7zip\UI\Console\MainAr.cpp 中的 main 函数
extern int MY_CDECL main(
#ifndef _WIN32int numArgs, char *args[]
#endif
);

点击声明左侧的双向箭头按钮 , 可以跳转到 MainAr.cpp 的 main 函数位置 ;

跳转位置 :

二、命令字符串切割并传入 main 函数


调用 main 函数 , 需要传入对应的参数 , 分别是

  • int numArgs 字符串个数 ;

  • char *args[] 字符串数组 ; 指针数组 , 每个数组元素中都有一个 char * 指针元素 , 指向字符串 ;

int MY_CDECL main
(#ifndef _WIN32int numArgs, char *args[]#endif
)

从 Java 传入 C 的指令如下 :

7zr a files.7z files -mx=9 -t7z

使用空格将上述指令切割成 666 个字符串 , 然后传入 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';// 字符串索引自增 1str_index ++;// 字符串内字符索引归零char_index = 0;// 设置当前的字符为空格标志位 1isChar = 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';// 字符串索引自增 1str_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 _WIN32int 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';// 字符串索引自增 1str_index ++;// 字符串内字符索引归零char_index = 0;// 设置当前的字符为空格标志位 1isChar = 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';// 字符串索引自增 1str_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 命令执行完毕 !");
}

2、完整 java 代码

package kim.hsl.a7_zipimport android.os.Build
import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import java.io.*class MainActivity : AppCompatActivity() {companion object {val TAG = "MainActivity"init {System.loadLibrary("native-lib")}}override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)copy7zr()compress7z()uncompress7z()compress7zJni()}/*** 将 7zr 文件拷贝到应用私有目录*/fun copy7zr() {Log.i(TAG, "开始拷贝 7zr 文件")// /data/user/0/kim.hsl.a7_zip/files/7zrvar exeFile = File(filesDir, "7zr")Log.i(TAG, "filesDir = ${filesDir.absolutePath} , exeFile = ${exeFile.absolutePath}")// 查看该文件是否存在, 如果存在设置该文件可执行// 如果不存在 , 拷贝文件if (exeFile.exists()) {exeFile.setExecutable(true)Log.i(TAG, "内置存储空间存在该 /data/user/0/kim.hsl.a7_zip/files/7zr 文件")return} else {Log.i(TAG, "内置存储空间不存在 7zr 可执行文件 , 开始拷贝文件")}// 如果不存在 , 拷贝文件var inputStream: InputStream = assets.open("libs/arm64-v8a/7zr")// /data/user/0/kim.hsl.a7_zip/files/7zrvar fileOutputStream: FileOutputStream = FileOutputStream(exeFile)Log.i(TAG, "Build.CPU_ABI = ${Build.CPU_ABI}")// 不同 CPU 架构拷贝不同的可执行程序if (Build.CPU_ABI.startsWith("armeabi-v7a")) {inputStream = assets.open("libs/armeabi-v7a/7zr")} else if (Build.CPU_ABI.startsWith("arm64-v8a")) {inputStream = assets.open("libs/arm64-v8a/7zr")} else if (Build.CPU_ABI.startsWith("x86")) {inputStream = assets.open("libs/x86/7zr")} else if (Build.CPU_ABI.startsWith("x86_64")) {inputStream = assets.open("libs/x86_64/7zr")}// 拷贝文件var buffer: ByteArray = ByteArray(1024)var readCount = inputStream.read(buffer);while (readCount != -1) {fileOutputStream.write(buffer)readCount = inputStream.read(buffer);}fileOutputStream.flush()fileOutputStream.close()Log.i(TAG, "拷贝 7zr 文件结束")}/*** 使用 7zr 进行压缩*/fun compress7z() {// /data/user/0/kim.hsl.a7_zip/files/7zrvar exeFile = File(filesDir, "7zr")// 执行前赋予可执行权限exeFile.setExecutable(true)var file_7z = File("${filesDir.absolutePath}/files.7z")if(file_7z.exists()){file_7z.delete()}var cmd = "${exeFile.absolutePath} a ${filesDir.absolutePath}/files.7z ${filesDir.absolutePath} -mx=9 -t7z"Log.i(TAG, "压缩命令 : $cmd")var process: Process = Runtime.getRuntime().exec(cmd)// 读取命令执行过程数据var reader = BufferedReader(InputStreamReader(process.inputStream))while (true) {val line = reader.readLine()if (line != null) {Log.i(TAG, "$line")}else{break}}reader.close()val exitValue = process.exitValue()Log.i(TAG, "压缩文件 , 执行完毕 , exitValue = $exitValue")}/*** 判定命令是否执行完毕* 调用 process.exitValue 方法 , 如果没有执行完毕 , 会抛异常,* 如果执行完毕会返回一个确定的值*/fun isComplete(process: Process): Boolean {try {// 已经执行完毕process.exitValue()return true} catch (e: IllegalThreadStateException) {// 未执行完毕return false}}/*** 使用 7zr 进行解压缩*/fun uncompress7z() {// /data/user/0/kim.hsl.a7_zip/files/7zrvar exeFile = File(filesDir, "7zr")// 执行前赋予可执行权限exeFile.setExecutable(true)// 删除解压目录var unzip_file = File("${filesDir.absolutePath}/unzip_file")if(unzip_file.exists()){recursionDeleteFile(unzip_file)}var cmd = "${exeFile.absolutePath} x ${filesDir.absolutePath}/files.7z -o${filesDir.absolutePath}/unzip_file"Log.i(TAG, "解压缩命令 : $cmd")var process: Process = Runtime.getRuntime().exec(cmd)// 读取命令执行过程数据var reader = BufferedReader(InputStreamReader(process.inputStream))while (true) {val line = reader.readLine()if (line != null) {Log.i(TAG, "$line")}else{break}}reader.close()val exitValue = process.exitValue()Log.i(TAG, "解压缩文件 , 执行完毕 , exitValue = $exitValue")}/*** 递归删除文件*/fun recursionDeleteFile(file: File) {if (file.isDirectory) {// 如果是目录 , 则递归删除file.listFiles().forEach {// ForEach 循环删除目录recursionDeleteFile(it)}} else {// 如果是文件直接删除file.delete()}}/*** 使用 7zr 进行压缩*/fun compress7zJni() {// /data/user/0/kim.hsl.a7_zip/files/7zrvar exeFile = File(filesDir, "7zr")// 执行前赋予可执行权限exeFile.setExecutable(true)// 删除原有的压缩文件, 如果存在var file_7z = File("${filesDir.absolutePath}/files_jni.7z")if(file_7z.exists()){file_7z.delete()}var cmd = "${exeFile.absolutePath} a ${filesDir.absolutePath}/files_jni.7z ${filesDir.absolutePath} -mx=9 -t7z"Log.i(TAG, "Jni 压缩命令 : $cmd")// 调用 jni 方法处理压缩文件executeCmd(cmd)}external fun executeCmd(cmd: String): Unit
}

3、执行结果

2021-05-07 13:32:12.520 31022-31022/kim.hsl.a7_zip I/MainActivity: 开始拷贝 7zr 文件
2021-05-07 13:32:12.524 31022-31022/kim.hsl.a7_zip I/MainActivity: filesDir = /data/user/0/kim.hsl.a7_zip/files , exeFile = /data/user/0/kim.hsl.a7_zip/files/7zr
2021-05-07 13:32:12.525 31022-31022/kim.hsl.a7_zip I/MainActivity: 内置存储空间存在该 /data/user/0/kim.hsl.a7_zip/files/7zr 文件
2021-05-07 13:32:12.527 31022-31022/kim.hsl.a7_zip I/MainActivity: 压缩命令 : /data/user/0/kim.hsl.a7_zip/files/7zr a /data/user/0/kim.hsl.a7_zip/files/files.7z /data/user/0/kim.hsl.a7_zip/files -mx=9 -t7z
2021-05-07 13:32:19.027 31022-31022/kim.hsl.a7_zip I/MainActivity: 7-Zip (a) [64] 16.02 : Copyright (c) 1999-2016 Igor Pavlov : 2016-05-21
2021-05-07 13:32:19.027 31022-31022/kim.hsl.a7_zip I/MainActivity: p7zip Version 16.02 (locale=utf8,Utf16=on,HugeFiles=on,64 bits,8 CPUs LE)
2021-05-07 13:32:19.027 31022-31022/kim.hsl.a7_zip I/MainActivity: Scanning the drive:
2021-05-07 13:32:19.027 31022-31022/kim.hsl.a7_zip I/MainActivity: 11 folders, 8 files, 7403414 bytes (7230 KiB)
2021-05-07 13:32:19.027 31022-31022/kim.hsl.a7_zip I/MainActivity: Creating archive: /data/user/0/kim.hsl.a7_zip/files/files.7z
2021-05-07 13:32:19.027 31022-31022/kim.hsl.a7_zip I/MainActivity: Items to compress: 19
2021-05-07 13:32:19.027 31022-31022/kim.hsl.a7_zip I/MainActivity: Files read from disk: 8
2021-05-07 13:32:19.027 31022-31022/kim.hsl.a7_zip I/MainActivity: Archive size: 941905 bytes (920 KiB)
2021-05-07 13:32:19.027 31022-31022/kim.hsl.a7_zip I/MainActivity: Everything is Ok
2021-05-07 13:32:19.028 31022-31022/kim.hsl.a7_zip I/MainActivity: 压缩文件 , 执行完毕 , exitValue = 0
2021-05-07 13:32:19.036 31022-31022/kim.hsl.a7_zip I/MainActivity: 解压缩命令 : /data/user/0/kim.hsl.a7_zip/files/7zr x /data/user/0/kim.hsl.a7_zip/files/files.7z -o/data/user/0/kim.hsl.a7_zip/files/unzip_file
2021-05-07 13:32:19.059 31022-31022/kim.hsl.a7_zip I/MainActivity: 7-Zip (a) [64] 16.02 : Copyright (c) 1999-2016 Igor Pavlov : 2016-05-21
2021-05-07 13:32:19.059 31022-31022/kim.hsl.a7_zip I/MainActivity: p7zip Version 16.02 (locale=utf8,Utf16=on,HugeFiles=on,64 bits,8 CPUs LE)
2021-05-07 13:32:19.059 31022-31022/kim.hsl.a7_zip I/MainActivity: Scanning the drive for archives:
2021-05-07 13:32:19.059 31022-31022/kim.hsl.a7_zip I/MainActivity: 1 file, 941905 bytes (920 KiB)
2021-05-07 13:32:19.059 31022-31022/kim.hsl.a7_zip I/MainActivity: Extracting archive: /data/user/0/kim.hsl.a7_zip/files/files.7z
2021-05-07 13:32:19.185 31022-31022/kim.hsl.a7_zip I/MainActivity: --
2021-05-07 13:32:19.185 31022-31022/kim.hsl.a7_zip I/MainActivity: Path = /data/user/0/kim.hsl.a7_zip/files/files.7z
2021-05-07 13:32:19.185 31022-31022/kim.hsl.a7_zip I/MainActivity: Type = 7z
2021-05-07 13:32:19.185 31022-31022/kim.hsl.a7_zip I/MainActivity: Physical Size = 941905
2021-05-07 13:32:19.185 31022-31022/kim.hsl.a7_zip I/MainActivity: Headers Size = 333
2021-05-07 13:32:19.185 31022-31022/kim.hsl.a7_zip I/MainActivity: Method = LZMA2:23
2021-05-07 13:32:19.186 31022-31022/kim.hsl.a7_zip I/MainActivity: Solid = +
2021-05-07 13:32:19.186 31022-31022/kim.hsl.a7_zip I/MainActivity: Blocks = 1
2021-05-07 13:32:19.186 31022-31022/kim.hsl.a7_zip I/MainActivity: Everything is Ok
2021-05-07 13:32:19.186 31022-31022/kim.hsl.a7_zip I/MainActivity: Folders: 11
2021-05-07 13:32:19.186 31022-31022/kim.hsl.a7_zip I/MainActivity: Files: 8
2021-05-07 13:32:19.186 31022-31022/kim.hsl.a7_zip I/MainActivity: Size:       7403414
2021-05-07 13:32:19.186 31022-31022/kim.hsl.a7_zip I/MainActivity: Compressed: 941905
2021-05-07 13:32:19.186 31022-31022/kim.hsl.a7_zip I/MainActivity: 解压缩文件 , 执行完毕 , exitValue = 0
2021-05-07 13:32:19.187 31022-31022/kim.hsl.a7_zip I/MainActivity: Jni 压缩命令 : /data/user/0/kim.hsl.a7_zip/files/7zr a /data/user/0/kim.hsl.a7_zip/files/files_jni.7z /data/user/0/kim.hsl.a7_zip/files -mx=9 -t7z
2021-05-07 13:32:19.188 31022-31022/kim.hsl.a7_zip I/octopus: jni 中处理压缩文件命令 : /data/user/0/kim.hsl.a7_zip/files/7zr a /data/user/0/kim.hsl.a7_zip/files/files_jni.7z /data/user/0/kim.hsl.a7_zip/files -mx=9 -t7z
2021-05-07 13:32:19.188 31022-31022/kim.hsl.a7_zip I/octopus: 0 . /data/user/0/kim.hsl.a7_zip/files/7zr
2021-05-07 13:32:19.188 31022-31022/kim.hsl.a7_zip I/octopus: 1 . a
2021-05-07 13:32:19.188 31022-31022/kim.hsl.a7_zip I/octopus: 2 . /data/user/0/kim.hsl.a7_zip/files/files_jni.7z
2021-05-07 13:32:19.188 31022-31022/kim.hsl.a7_zip I/octopus: 3 . /data/user/0/kim.hsl.a7_zip/files
2021-05-07 13:32:19.188 31022-31022/kim.hsl.a7_zip I/octopus: 4 . -mx=9
2021-05-07 13:32:19.188 31022-31022/kim.hsl.a7_zip I/octopus: 5 . -t7z
2021-05-07 13:32:26.301 31022-31022/kim.hsl.a7_zip I/octopus: 7zr 命令执行完毕 !

查询在 jni 层压缩的文件 :

C:\Users\octop>adb shell
walleye:/ $ su
walleye:/ # cd /data/user/0/kim.hsl.a7_zip/files/
walleye:/data/user/0/kim.hsl.a7_zip/files # ls -la
total 3028
drwxrwx--x 3 u0_a455 u0_a455    4096 2021-05-07 13:32 .
drwx------ 5 u0_a455 u0_a455    4096 2021-05-07 13:19 ..
-rwx------ 1 u0_a455 u0_a455  994304 2021-05-07 13:19 7zr
-rw------- 1 u0_a455 u0_a455  941905 2021-05-07 13:32 files.7z
-rw------- 1 u0_a455 u0_a455 1124135 2021-05-07 13:32 files_jni.7z
drwx------ 3 u0_a455 u0_a455    4096 2021-05-07 13:19 unzip_file
walleye:/data/user/0/kim.hsl.a7_zip/files #

四、参考资料


参考资料 :

  • 7-Zip 官网 : https://www.7-zip.org/

Android NDK 编译构建脚本参考文档 :

  • ndk-build 脚本 : https://developer.android.google.cn/ndk/guides/ndk-build
  • Android.mk 构建脚本 : https://developer.android.google.cn/ndk/guides/android_mk
  • Application.mk 构建脚本 : https://developer.android.google.cn/ndk/guides/application_mk

博客资源 : 源码 , 编译后的可执行文件, 在 7zip\p7zip_16.02\CPP\ANDROID\7zr\libs\ 目录下 ;

  • 下载地址 : https://download.csdn.net/download/han1202012/18215890
  • GitHub 项目源码 : https://github.com/han1202012/7-Zip

【Android 安装包优化】使用 lib7zr.so 动态库处理压缩文件 ( jni 中 main 函数声明 | 命令行处理 | jni 调用 lib7zr.so 函数库处理压缩文件完整代码 )相关推荐

  1. 【Android 安装包优化】使用 lib7zr.a 静态库处理压缩文件 ( 交叉编译 lib7zr.a 静态库 | 安卓工程导入静态库 | 配置 CMakeLists.txt 构建脚本 )

    文章目录 一.修改 7zr 交叉编译脚本 Android.mk 二.完整的 7zr 交叉编译脚本 Android.mk 三.交叉编译 lib7zr.a 静态库 四.Android Studio 导入 ...

  2. 【Android 安装包优化】使用 lib7zr.so 动态库处理压缩文件 ( 测试 lib7zr.so 动态库调用 )

    文章目录 一.拷贝 p7zip 源码中的头文件到 Android Studio 项目中 二.完整代码示例 1.Java 层代码 2.JNI 层代码 3.日志头文件 4.执行结果 四.参考资料 前置博客 ...

  3. 【Android 安装包优化】使用 lib7zr.so 动态库处理压缩文件 ( 拷贝 lib7zr.so 动态库头文件到 Android 工程中 | 配置 CMakeLists.txt 构建脚本 )

    文章目录 一.拷贝 p7zip 源码中的头文件到 Android Studio 项目中 二.配置 CMakeLists.txt 构建脚本 1.导入动态库 2.导入头文件 三.完整 CMakeLists ...

  4. 【Android 安装包优化】使用 lib7zr.so 动态库处理压缩文件 ( 拷贝 lib7zr.so 动态库到 Android Studio 工程 | 配置 build.gradle 构建脚本 )

    文章目录 一.拷贝 lib7zr.so 动态库到 Android Studio 工程 二.配置 Module 下的 build.gradle 构建脚本 三.参考资料 一.拷贝 lib7zr.so 动态 ...

  5. 【Android 安装包优化】使用 lib7zr.so 动态库处理压缩文件 ( 修改 7zr 交叉编译脚本 Android.mk | 交叉编译 lib7zr.so 动态库 )

    文章目录 一.修改 7zr 交叉编译脚本 Android.mk 二.完整的 7zr 交叉编译脚本 Android.mk 三.交叉编译 lib7zr.so 动态库 四.参考资料 一.修改 7zr 交叉编 ...

  6. 【Android 安装包优化】开启资源压缩 ( 资源压缩配置 | 启用严格模式的资源引用检查 | 自定义保留/移除资源配置 | 资源压缩效果 )

    文章目录 一.开启资源压缩 二.启用严格模式的资源引用检查 三.自定义保留/移除资源配置 四.资源压缩效果 五.完整配置 1.keep.xml 配置 2.build.gradle 构建脚本 六.参考资 ...

  7. 【Android 安装包优化】WebP 应用 ( 4.0 以下兼容 WebP | Android Studio 中使用 libwebp.so 库向下兼容版本 | libwebp 库测试可用性 )

    文章目录 一. Android Studio 中导入 libwebp.so 库 二. Android Studio 中测试 libwebp.so 库 三.参考资料 一. Android Studio ...

  8. 【Android 安装包优化】资源混淆 ( resources.arsc 资源映射表文件格式 | 头文件 数据格式 | 全局字符串池 数据格式 | 包数据 数据格式 | 包头 数据格式 )

    文章目录 一.resources.arsc 资源映射表文件格式 二.头文件 数据格式 三.全局字符串池 数据格式 四.包数据 数据格式 1.包头 数据格式 2.资源类型字符串池 数据格式 3.资源名称 ...

  9. 【Android 安装包优化】资源混淆 ( resources.arsc 资源映射表混淆 | resources.arsc 资源映射表二进制格式分析 | 混淆全局字符串池和资源名称字符串池 )

    文章目录 一.resources.arsc 资源映射表 混淆 二.resources.arsc 资源映射表二进制格式分析 三.参考资料 资源混淆时 , 需要修改混淆 resources.arsc 资源 ...

最新文章

  1. python-Django-01基础配置
  2. ERPLAB中文教程:ERPLAB安装与添加通道
  3. Docker中运行EOS FOR MAC
  4. python默认参数只被解释一次_深入讲解Python函数中参数的使用及默认参数的陷阱...
  5. java自定义标签简单_JSP 自定义标签之一 简单实例
  6. java分隔符算法_《Java数据结构和算法》栈 分隔符分配
  7. bzoj1596[Usaco2008 Jan]电话网络*
  8. list lt map gt java_利用Set 对Listlt;Maplt;String,Objectgt;gt; 中的map对象中某一个属性去重...
  9. python时间序列预测不连续怎么办_手把手教你用Python处理非平稳时间序列(附代码)...
  10. 翻译: 全球导航卫星系统 (GNSS) 的演进
  11. IPV4地址详细解释
  12. 云计算认证系列:CKA认证
  13. 优衣库真的是一家技术驱动型公司?
  14. 枯燥的寒假生活(二) 武汉大学老教务系统提交表单时的密码加密方式
  15. html鼠标经过图片有浮起效果,CSS实现鼠标滑过卡片上浮效果的示例
  16. Python基础学习的一些记录
  17. Ubuntu18及22安装NVIDIA驱动、CUDA、CUDNN、Pytorch
  18. 我的世界服务器无限装备指令2020,我的世界手机版指令表
  19. Windows环境下编译pjsip
  20. 计算机组成原理题库(唐朔飞)

热门文章

  1. WinForm 里面ListBox的问题
  2. 导航狗IT周报-2018年05月18日
  3. as用百度地图不联网就gg
  4. 自动生成Hibernate框架结构
  5. Android 开发笔记 ListView异步加载图片
  6. 【转】奴性哲学十句话,洗脑常用词!!!
  7. Hessian(C#)介绍及使用说明
  8. 脚本调用后台代码 asp.net ajax
  9. GARFIELD@05-04-2005
  10. day26-3 模拟ssh远程执行命令