前言
汇总了一下众多大佬的性能优化文章,知识点,主要包含:
UI优化/启动优化/崩溃优化/卡顿优化/安全性优化/弱网优化/APP深度优化等等等~
本篇是第四篇:安全性优化 [非商业用途,如有侵权,请告知我,我会删除]
强调一下: 性能优化的开发文档跟之前的面试文档一样,需要的跟作者直接要。
安全性优化
1、Android应用加固实现方案
Android应用加固的诸多方案中,其中一种就是基于dex的加固,本文介绍基于dex的加固方案。
原理:在AndroidManifest中指定启动Application为壳Module的Application,生成APK后,将壳Module的AAR文件和加密后的APK中的dex文件合并,然后重新打包签名。安装应用运行后,通过壳Module的Application来解密dex文件,然后再加载dex。
存在的问题:解密过程,会还原出来未加密的原dex文件,通过一些手段,还是可以获得未加密的dex。
1.1 实现
APK和壳AAR的生成
新建工程,然后新建一个Module,作为壳Module,名字随意,这里命名为shell。
在壳Module中新建继承自Application的ShellApplication,重写attachBaseContext方法,在这个方法加载原来的dex
public class ShellApplication extends Application {
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
try {
//获取应用APK
File apkFile = new File(getApplicationInfo().sourceDir);
//解压目录
File apkUnzipDir = getDir("apk", Context.MODE_PRIVATE);
apkUnzipDir = new File(apkUnzipDir, "unzip");
//如果不存在,则解压
if (!apkUnzipDir.exists()) {
apkUnzipDir.mkdirs();
//解压
ZipUtils.unzipFile(apkFile, apkUnzipDir);
//过滤所有.dex文件
File[] files = apkUnzipDir.listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return name.endsWith(".dex");
}
});
//解密
File decryptDir = new File(apkUnzipDir, "decrypt");
decryptDir.mkdirs();
ArrayList<File> list = new ArrayList<>();
for (File file : files) {
if (file.getName().endsWith("classes.dex")) {
list.add(file);
} else {
File decryptFile = new File(decryptDir, file.getName());
EncryptUtils.decrypt(file.getAbsolutePath(), decryptFile.getAbsolutePath());
//添加到list中
list.add(decryptFile);
//删除加密的dex文件
file.delete();
}
}
//加载.dex文件
ClassLoaderUtil.loadDex(this, list);
} else {
ArrayList<File> list = new ArrayList<>();
list.add(new File(apkUnzipDir, "classes.dex"));
File decryptDir = new File(apkUnzipDir, "decrypt");
File[] files = decryptDir.listFiles();
for (File file : files) {
list.add(file);
}
//加载.dex文件
ClassLoaderUtil.loadDex(this, list);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
修改app的AndroidManifest中application节点的name为壳Module的Application
<application
android:name="com.wangyz.shell.ShellApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
在Gradle面板,双击app/Tasks/build/目录下的assembleRelease,生成未签名的APK
在app/build/outputs/apk/release/目录下,可以找到生成的apk:app-release-unsigned.apk
在Android Studio中,点击Build-Make Module ‘shell’,生成AAR。
在shell/build/outputs/aar/目录下,可以找到生成的aar:shell-debug.aar
加壳的过程
加壳的实现流程如下:
这里选择Eclipse新建Java工程来操作。
项目结构说明:
- input:存放需要加壳的apk和aar
- keystore:存放签名用到的keystore文件
- output:打包后输出目录,signed为签名后的apk
需要配置的环境变量:
- 由于要用到dx来将jar转换成dex,因此需要配置dx的路径。在SDK/build-tools/下,有对应不同版本的build工具,这里选择28.0.0,进入28.0.0文件夹,可以看到dx.bat文件。在电脑的环境变量中,修改path,增加dx.bat路径:
- 由于要用到jarsigner来签名apk,因此需要配置jarsigner的环境变量。一般Java开发的话,JDK配置好了后,这个就不需要再配置了。
配置好上面的环境变量后,关掉eclipse,然后重新启动eclipse
Main类中的代码逻辑:
try {
// APK
File apkFile = new File("input/app-debug.apk");
// 壳AAR
File shellFile = new File("input/shell-debug.aar");