【Android 安装包优化】使用 lib7zr.a 静态库处理压缩文件 ( 交叉编译 lib7zr.a 静态库 | 安卓工程导入静态库 | 配置 CMakeLists.txt 构建脚本 )
文章目录
前置博客 :
- 【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 动态库调用 )
- 【Android 安装包优化】使用 lib7zr.so 动态库处理压缩文件 ( jni 中 main 函数声明 | 命令行处理 | jni 调用 lib7zr.so 函数库处理压缩文件完整代码 )
在之前的一系列博客中使用 lib7zr.so 动态库处理压缩文件 , 本篇博客中使用静态库处理压缩文件 , 仅做参考 ;
一、修改 7zr 交叉编译脚本 Android.mk
之前的博客 【Android 安装包优化】p7zip 源码交叉编译 Android 平台可执行程序 ( 下载 p7zip 源码 | 交叉编译 Android 中使用 7z 可执行程序 ) 中 , 下载并编译了 p7zip 开源项目源码 , 交叉编译出了可以在 Android 平台执行的可执行文件 ;
D:\develop\7zip\p7zip_16.02\CPP\ANDROID\7zr 目录下是 7zr 项目的构建脚本 Android.mk
和 Application.mk
, 主要使用该构建脚本交叉编译出
- 可执行文件 7zr
- 静态库 lib7zr.a ;
进入 7zr 目录下 , 有一个 jni 目录 和 makefile 文件 ,
jni 目录中是 Android.mk 和 Application.mk 两个构建脚本 , 可以使用 ndk-build 进行编译 ;
打开该 makefile 文件 , 该文件最后几行代码给出了相关操作方法 ;
# FIXME
debug:
cd jni ; ndk-build NDK_DEBUG=1
adb push ./libs/armeabi/7zr /data/app/
adb push ./libs/armeabi/gdbserver /data/app/
adb shell chmod 777 /data/app/7zr
adb shell chmod 777 /data/app/gdbserver
adb forward tcp:1234: tcp:1234
adb shell /data/app/gdbserver :1234 /data/app/7zr
进入 D:\develop\7zip\p7zip_16.02\CPP\ANDROID\7zr\jni 目录 , 执行 ndk-build 命令 , 进行交叉编译 ;
修改 Application.mk 构建脚本 :
APP_ABI := armeabi-v7a arm64-v8a x86 x86_64
APP_PLATFORM := android-8
注释可执行文件的编译选项 : -fPIE 指的是生成与地址无关的可执行文件 , 该选项只能应用于可执行文件 , 不能用于静态库编译 ;
# Needed since ANDROID 5, these programs run on android-16 (Android 4.1+)
# -fPIE 指的是生成与地址无关的可执行文件 , 该选项只能应用于可执行文件 ,
# 不能用于动态库编译
# 如果编译动态库 , 需要注释掉下面两个配置
# 如果编译静态库 , 需要注释掉下面两个配置
# 如果编译可执行文件 , 可以保留下面两个配置
#LOCAL_CFLAGS += -fPIE
#LOCAL_LDFLAGS += -fPIE -pie
设置 Android.mk 构建脚本的编译结果 :
include $(BUILD_STATIC_LIBRARY)
-
include $(BUILD_EXECUTABLE)
配置表示生成可执行文件 ; -
include $(BUILD_SHARED_LIBRARY)
配置表示生成 .so 动态库 ; -
include $(BUILD_STATIC_LIBRARY)
配置表示生成 .a 静态库 ;
二、完整的 7zr 交叉编译脚本 Android.mk
修改完成的构建脚本 :
#
# build 7zr for armeabi and armeabi-v7a CPU
#
# WARNING : file generated by generate.py
#
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
# 编译模块
# 如果编译可执行文件, 编译结果是 7zr
# 如果编译动态库, 编译结果是 lib7zr.so
# 如果编译静态库, 编译结果是 lib7zr.a
LOCAL_MODULE := 7zr
# 设置编译器参数
# -I 指定头文件引入目录 , 会引入后面目录中所有的 .h 头文件
LOCAL_CFLAGS := -DANDROID_NDK -fexceptions \
-DNDEBUG -D_REENTRANT -DENV_UNIX \
-DBREAK_HANDLER -D_NO_CRYPTO \
-DUNICODE -D_UNICODE -DUNIX_USE_WIN_FILE \
-I../../../7zip/Archive \
-I../../../7zip/Archive/7z \
-I../../../7zip/Archive/BZip2 \
-I../../../7zip/Archive/Common \
-I../../../7zip/Archive/GZip \
-I../../../7zip/Archive/Cab \
-I../../../7zip/Archive/Lzma \
-I../../../7zip/Archive/Tar \
-I../../../7zip/Archive/Zip \
-I../../../7zip/Archive/Split \
-I../../../7zip/Archive/Z \
-I../../../7zip/Compress \
-I../../../7zip/Crypto \
-I../../../7zip/UI/Console \
-I../../../7zip/UI/Common \
-I../../../Windows \
-I../../../Common \
-I../../../7zip/Common \
-I../../../../C \
-I../../../myWindows \
-I../../../ \
-I../../../include_windows
# 源文件引入
LOCAL_SRC_FILES := \
../../../../CPP/7zip/Archive/7z/7zCompressionMode.cpp \
../../../../CPP/7zip/Archive/7z/7zDecode.cpp \
../../../../CPP/7zip/Archive/7z/7zEncode.cpp \
../../../../CPP/7zip/Archive/7z/7zExtract.cpp \
../../../../CPP/7zip/Archive/7z/7zFolderInStream.cpp \
../../../../CPP/7zip/Archive/7z/7zHandler.cpp \
../../../../CPP/7zip/Archive/7z/7zHandlerOut.cpp \
../../../../CPP/7zip/Archive/7z/7zHeader.cpp \
../../../../CPP/7zip/Archive/7z/7zIn.cpp \
../../../../CPP/7zip/Archive/7z/7zOut.cpp \
../../../../CPP/7zip/Archive/7z/7zProperties.cpp \
../../../../CPP/7zip/Archive/7z/7zRegister.cpp \
../../../../CPP/7zip/Archive/7z/7zSpecStream.cpp \
../../../../CPP/7zip/Archive/7z/7zUpdate.cpp \
../../../../CPP/7zip/Archive/Common/CoderMixer2.cpp \
../../../../CPP/7zip/Archive/Common/DummyOutStream.cpp \
../../../../CPP/7zip/Archive/Common/HandlerOut.cpp \
../../../../CPP/7zip/Archive/Common/InStreamWithCRC.cpp \
../../../../CPP/7zip/Archive/Common/ItemNameUtils.cpp \
../../../../CPP/7zip/Archive/Common/MultiStream.cpp \
../../../../CPP/7zip/Archive/Common/OutStreamWithCRC.cpp \
../../../../CPP/7zip/Archive/Common/ParseProperties.cpp \
../../../../CPP/7zip/Archive/LzmaHandler.cpp \
../../../../CPP/7zip/Archive/SplitHandler.cpp \
../../../../CPP/7zip/Archive/XzHandler.cpp \
../../../../CPP/7zip/Common/CWrappers.cpp \
../../../../CPP/7zip/Common/CreateCoder.cpp \
../../../../CPP/7zip/Common/FilePathAutoRename.cpp \
../../../../CPP/7zip/Common/FileStreams.cpp \
../../../../CPP/7zip/Common/FilterCoder.cpp \
../../../../CPP/7zip/Common/InBuffer.cpp \
../../../../CPP/7zip/Common/InOutTempBuffer.cpp \
../../../../CPP/7zip/Common/LimitedStreams.cpp \
../../../../CPP/7zip/Common/MethodId.cpp \
../../../../CPP/7zip/Common/MethodProps.cpp \
../../../../CPP/7zip/Common/OffsetStream.cpp \
../../../../CPP/7zip/Common/OutBuffer.cpp \
../../../../CPP/7zip/Common/ProgressUtils.cpp \
../../../../CPP/7zip/Common/PropId.cpp \
../../../../CPP/7zip/Common/StreamBinder.cpp \
../../../../CPP/7zip/Common/StreamObjects.cpp \
../../../../CPP/7zip/Common/StreamUtils.cpp \
../../../../CPP/7zip/Common/UniqBlocks.cpp \
../../../../CPP/7zip/Common/VirtThread.cpp \
../../../../CPP/7zip/Compress/Bcj2Coder.cpp \
../../../../CPP/7zip/Compress/Bcj2Register.cpp \
../../../../CPP/7zip/Compress/BcjCoder.cpp \
../../../../CPP/7zip/Compress/BcjRegister.cpp \
../../../../CPP/7zip/Compress/BranchMisc.cpp \
../../../../CPP/7zip/Compress/BranchRegister.cpp \
../../../../CPP/7zip/Compress/ByteSwap.cpp \
../../../../CPP/7zip/Compress/CopyCoder.cpp \
../../../../CPP/7zip/Compress/CopyRegister.cpp \
../../../../CPP/7zip/Compress/DeltaFilter.cpp \
../../../../CPP/7zip/Compress/Lzma2Decoder.cpp \
../../../../CPP/7zip/Compress/Lzma2Encoder.cpp \
../../../../CPP/7zip/Compress/Lzma2Register.cpp \
../../../../CPP/7zip/Compress/LzmaDecoder.cpp \
../../../../CPP/7zip/Compress/LzmaEncoder.cpp \
../../../../CPP/7zip/Compress/LzmaRegister.cpp \
../../../../CPP/7zip/UI/Common/ArchiveCommandLine.cpp \
../../../../CPP/7zip/UI/Common/ArchiveExtractCallback.cpp \
../../../../CPP/7zip/UI/Common/ArchiveOpenCallback.cpp \
../../../../CPP/7zip/UI/Common/Bench.cpp \
../../../../CPP/7zip/UI/Common/DefaultName.cpp \
../../../../CPP/7zip/UI/Common/EnumDirItems.cpp \
../../../../CPP/7zip/UI/Common/Extract.cpp \
../../../../CPP/7zip/UI/Common/ExtractingFilePath.cpp \
../../../../CPP/7zip/UI/Common/HashCalc.cpp \
../../../../CPP/7zip/UI/Common/LoadCodecs.cpp \
../../../../CPP/7zip/UI/Common/OpenArchive.cpp \
../../../../CPP/7zip/UI/Common/PropIDUtils.cpp \
../../../../CPP/7zip/UI/Common/SetProperties.cpp \
../../../../CPP/7zip/UI/Common/SortUtils.cpp \
../../../../CPP/7zip/UI/Common/TempFiles.cpp \
../../../../CPP/7zip/UI/Common/Update.cpp \
../../../../CPP/7zip/UI/Common/UpdateAction.cpp \
../../../../CPP/7zip/UI/Common/UpdateCallback.cpp \
../../../../CPP/7zip/UI/Common/UpdatePair.cpp \
../../../../CPP/7zip/UI/Common/UpdateProduce.cpp \
../../../../CPP/7zip/UI/Console/BenchCon.cpp \
../../../../CPP/7zip/UI/Console/ConsoleClose.cpp \
../../../../CPP/7zip/UI/Console/ExtractCallbackConsole.cpp \
../../../../CPP/7zip/UI/Console/HashCon.cpp \
../../../../CPP/7zip/UI/Console/List.cpp \
../../../../CPP/7zip/UI/Console/Main.cpp \
../../../../CPP/7zip/UI/Console/MainAr.cpp \
../../../../CPP/7zip/UI/Console/OpenCallbackConsole.cpp \
../../../../CPP/7zip/UI/Console/PercentPrinter.cpp \
../../../../CPP/7zip/UI/Console/UpdateCallbackConsole.cpp \
../../../../CPP/7zip/UI/Console/UserInputUtils.cpp \
../../../../CPP/Common/CRC.cpp \
../../../../CPP/Common/CommandLineParser.cpp \
../../../../CPP/Common/CrcReg.cpp \
../../../../CPP/Common/IntToString.cpp \
../../../../CPP/Common/ListFileUtils.cpp \
../../../../CPP/Common/MyString.cpp \
../../../../CPP/Common/MyVector.cpp \
../../../../CPP/Common/MyWindows.cpp \
../../../../CPP/Common/NewHandler.cpp \
../../../../CPP/Common/Sha256Reg.cpp \
../../../../CPP/Common/StdInStream.cpp \
../../../../CPP/Common/StdOutStream.cpp \
../../../../CPP/Common/StringConvert.cpp \
../../../../CPP/Common/StringToInt.cpp \
../../../../CPP/Common/UTFConvert.cpp \
../../../../CPP/Common/Wildcard.cpp \
../../../../CPP/Common/XzCrc64Reg.cpp \
../../../../CPP/Windows/ErrorMsg.cpp \
../../../../CPP/Windows/FileDir.cpp \
../../../../CPP/Windows/FileFind.cpp \
../../../../CPP/Windows/FileIO.cpp \
../../../../CPP/Windows/FileName.cpp \
../../../../CPP/Windows/PropVariant.cpp \
../../../../CPP/Windows/PropVariantConv.cpp \
../../../../CPP/Windows/Synchronization.cpp \
../../../../CPP/Windows/System.cpp \
../../../../CPP/Windows/TimeUtils.cpp \
../../../../CPP/myWindows/myAddExeFlag.cpp \
../../../../CPP/myWindows/mySplitCommandLine.cpp \
../../../../CPP/myWindows/wine_date_and_time.cpp \
../../../../C/7zCrc.c \
../../../../C/7zCrcOpt.c \
../../../../C/7zStream.c \
../../../../C/Alloc.c \
../../../../C/Bcj2.c \
../../../../C/Bcj2Enc.c \
../../../../C/Bra.c \
../../../../C/Bra86.c \
../../../../C/BraIA64.c \
../../../../C/CpuArch.c \
../../../../C/Delta.c \
../../../../C/LzFind.c \
../../../../C/LzFindMt.c \
../../../../C/Lzma2Dec.c \
../../../../C/Lzma2Enc.c \
../../../../C/LzmaDec.c \
../../../../C/LzmaEnc.c \
../../../../C/MtCoder.c \
../../../../C/Sha256.c \
../../../../C/Threads.c \
../../../../C/Xz.c \
../../../../C/XzCrc64.c \
../../../../C/XzCrc64Opt.c \
../../../../C/XzDec.c \
../../../../C/XzEnc.c \
../../../../C/XzIn.c \
# Needed since ANDROID 5, these programs run on android-16 (Android 4.1+)
# -fPIE 指的是生成与地址无关的可执行文件 , 该选项只能应用于可执行文件 ,
# 不能用于动态库编译
# 如果编译动态库 , 需要注释掉下面两个配置
# 如果编译可执行文件 , 可以保留下面两个配置
#LOCAL_CFLAGS += -fPIE
#LOCAL_LDFLAGS += -fPIE -pie
# include $(BUILD_EXECUTABLE) 配置表示生成可执行文件
# include $(BUILD_SHARED_LIBRARY) 配置表示生成 .so 动态库
# include $(BUILD_STATIC_LIBRARY) 配置表示生成 .a 静态库
# 此处生成静态库
include $(BUILD_STATIC_LIBRARY)
三、交叉编译 lib7zr.a 静态库
使用最低版本的 NDK 进行编译 , 使用高版本 NDK 编译各种报错 ;
使用 16.1.4479499 版本的 NDK 进行编译 :
>D:\001_Programs\001_Android\002_Sdk\Sdk\ndk\16.1.4479499\ndk-build.cmd
进入 D:\develop\7zip\p7zip_16.02\CPP\ANDROID\7zr\jni 目录 , 执行如下命令 :
D:\001_Programs\001_Android\002_Sdk\Sdk\ndk\16.1.4479499\ndk-build.cmd
编译要很长时间 , 输出如下结果后 ,
最终在 D:\develop\7zip\p7zip_16.02\CPP\ANDROID\7zr\libs\armeabi-v7a 目录下 , 生成了可执行的 7zr 程序 ;
总共生成了 4 4 4 种 CPU 架构的 静态库 ; 注意静态库的生成位置 D:\develop\7zip\p7zip_16.02\CPP\ANDROID\7zr\obj\local 目录下 ;
静态库编译出来体积比较大 , 此处 lib7zr.a 静态库有 9.15 MB , 静态库编译时将所有的符号都编译在其中 , 因此比动态库大十几倍 ;
动态库编译后体积较小 , 方便分发 , 常用的第三方服务 , 以及开源代码都使用动态库进行分发 ;
编译过程中其它生成文件如下图 :
编译时遇到的错误 :
- 【错误记录】Android Studio 导入外部 so 动态库报错 ( java.lang.UnsatisfiedLinkError | 指定 APK 打包动态库的 CPU 架构 )
- 【错误记录】p7zip 交叉编译 Android 版本 NDK 报错 ( error: case value evaluates to -2 , which cannot be narrowed )
四、Android Studio 导入 lib7zr.a 静态库
主要是修改 CMakeLists.txt 构建脚本 , 其它位置不需要修改 ;
# 指定 CMake 最低版本
cmake_minimum_required(VERSION 3.4.1)
# 设置函数库编译
add_library( # 参数 1 : 设置生成的动态库名称
native-lib
# 参数 2 : 设置生成的函数库类型 : ① 静态库 STATIC ② 动态库 SHARED
SHARED
# 参数 3 : 配置要编译的源文件
../cpp/native-lib.cpp)
# 打印日志信息
# ${ANDROID_ABI} 的作用是获取当前的 CPU 指令集架构
# 当本次编译 armeabi-v7a CPU 架构时 , ${ANDROID_ABI} 值为 armeabi-v7a
# 当本次编译 x86 CPU 架构时 , ${ANDROID_ABI} 值为 x86
message("CMAKE_SOURCE_DIR : ${CMAKE_SOURCE_DIR}, ANDROID_ABI : ${ANDROID_ABI}")
# 到预设的目录查找 log 库 , 将找到的路径赋值给 log-lib
# 这个路径是 NDK 的 ndk-bundle\platforms\android-29\arch-arm\usr\lib\liblog.so
# 不同的 Android 版本号 和 CPU 架构 需要到对应的目录中查找 , 此处是 29 版本 32 位 ARM 架构的日志库
#
# 可以不配置 :
# 可以不进行该配置, 直接在后面的 target_link_libraries 中链接 log 也不会出错
find_library(
log-lib
log)
# 打印日志库位置
message(${log-lib})
# 引入静态库 ( 推荐 ) :
# ① 参数 1 ( add ) : 设置引入的静态库名称
# ② 参数 2 ( SHARED ) : 设置引入的函数库类型 : ① 静态库 STATIC ② 动态库 SHARED
# ③ 参数 3 ( IMPORTED ) : 表示引入第三方静态库 , 导入静态库 , 相当于预编译静态库
# 后续还需要设置导入路径 , 配合该配置使用
add_library(
# 设置引入的静态库名称
7zr
# 设置引入的函数库类型为静态库
STATIC
# 表示引入第三方静态库
IMPORTED)
# 设置上述静态库的导入路径
# 设置目标属性参数 :
# ① 参数 1 ( add ) : 要设置哪个函数库的属性
# ② 参数 2 ( PROPERTIES ) : 设置目标属性
# ③ 参数 3 ( IMPORTED_LOCATION ) : 设置导入路径
# ④ 参数 4 : 配置静态库的文件路径
set_target_properties(
# 设置目标
7zr
# 设置属性
PROPERTIES
# 导入路径
IMPORTED_LOCATION
# ${CMAKE_SOURCE_DIR} 是本 CMakeList.txt 构建脚本的路径 , 是 CMake 工具内置的变量
# Android CMake 也内置了一些变量 , 如 ANDROID_ABI
${CMAKE_SOURCE_DIR}/${ANDROID_ABI}/lib7zr.a)
# 打印静态库位置
message("静态库位置 : ${CMAKE_SOURCE_DIR}/${ANDROID_ABI}/lib7zr.a")
# 引入动态库 (不推荐) : 使用下面的方式引入动态库会出现于 Android.mk 配置一样的问题 , 6.0 以上的 Android 系统在运行时出现找不到路径的问题
#add_library(add SHARED IMPORTED)
# 设置函数库的导入路径
#set_target_properties(add PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/../jniLibs/armeabi-v7a/libadd.so)
# 引入动态库 (推荐) :
# 设置变量
# CMAKE_CXX_FLAGS 表示会将 C++ 的参数传给编译器
# CMAKE_C_FLAGS 表示会将 C 参数传给编译器
# 参数设置 : 传递 CMAKE_CXX_FLAGS C+= 参数给编译器时 , 在 该参数后面指定库的路径
# CMAKE_SOURCE_DIR 指的是当前的文件地址
# -L 参数指定动态库的查找路径
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -L${CMAKE_SOURCE_DIR}/../jniLibs/${ANDROID_ABI}")
# 设置头文件查找路径
include_directories(
../cpp/lib7zr/CPP/7zip/Archive
../cpp/lib7zr/CPP/7zip/Archive/7z
../cpp/lib7zr/CPP/7zip/Archive/BZip2
../cpp/lib7zr/CPP/7zip/Archive/Common
../cpp/lib7zr/CPP/7zip/Archive/GZip
../cpp/lib7zr/CPP/7zip/Archive/Cab
../cpp/lib7zr/CPP/7zip/Archive/Lzma
../cpp/lib7zr/CPP/7zip/Archive/Tar
../cpp/lib7zr/CPP/7zip/Archive/Zip
../cpp/lib7zr/CPP/7zip/Archive/Split
../cpp/lib7zr/CPP/7zip/Archive/Z
../cpp/lib7zr/CPP/7zip/Compress
../cpp/lib7zr/CPP/7zip/Crypto
../cpp/lib7zr/CPP/7zip/UI/Console
../cpp/lib7zr/CPP/7zip/UI/Common
../cpp/lib7zr/CPP/Windows
../cpp/lib7zr/CPP/Common
../cpp/lib7zr/CPP/7zip/Common
../cpp/lib7zr/C
../cpp/lib7zr/CPP/myWindows
../cpp/lib7zr/CPP
../cpp/lib7zr/CPP/include_windows)
# 链接函数库
# 参数 1 : 本构建脚本要生成的动态库目标
# 参数 2 ~ ... : 后面是之前预编译的动态库或静态库 , 或引入的动态库
target_link_libraries(
native-lib
# 表示 编译 native-lib 模块, 要链接 lib7zr.so 模块
7zr
${log-lib})
五、参考资料
参考资料 :
- 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\ 目录下 ;
- 下载地址 :
- GitHub 项目源码 : https://github.com/han1202012/7-Zip
相关文章
- android scaleanimation动画,【Android动画九章】-RotateAnimation(旋转动画)和ScaleAnimation(尺寸动画)…[通俗易懂]
- android开机动画多长时间_Android开机动画原理分析
- Android toArray
- android 浏览器 开发,Android 浏览器的开发实例分享
- 2018年Unity结合Android SDK下载安装及配置教程
- android 定时器重置,Android定时器延迟和重置[通俗易懂]
- android调用相册并显示图片_Android获取相册列表
- Android resource linking failed_android sdk location should not
- eclipse安卓项目_eclipse开发android
- Android Services Library_android freeware
- Android安卓系统使用fastboot无法刷入TWRP Recovery
- Android Intent用法全面详解
- 【Android NDK 开发】Kotlin 语言中使用 NDK ( 创建支持 Kotlin 的 NDK 项目 | Kotlin 语言中使用 NDK 要点 | 代码示例 )
- 【Android 逆向】应用数据目录 ( Android 应用数据目录 /data/data/package.name | 存放 SharedPreference 的 shared_pref 目录 )
- 【Android 逆向】ART 脱壳 ( InMemoryDexClassLoader 脱壳 | dex_file.cc 中创建 DexFile 实例对象的相关函数分析 )
- 【Android UI】贝塞尔曲线 ④ ( 使用 android.graphics.Path 提供的 cubicTo 方法绘制三阶贝塞尔曲线示例 )
- 【错误记录】Android Studio 编译报错 ( Could not resolve com.android.tools.build:gradle:7.4.2. )
- Android 两种方式实现类似水波扩散效果详解手机开发
- Android 写一个属于自己的Rxjava(二)详解手机开发
- 使用UserAgent分辨出Android设备类型的安全做法