文章的目的为了记录使用java 进行android app 开发学习的经历。本职为嵌入式软件开发,公司安排开发app,临时学习,完成app的开发。开发流程和要点有些记忆模糊,赶紧记录,防止忘记。
相关链接:
开源 java android app 开发(一)开发环境的搭建-CSDN博客
开源 java android app 开发(二)工程文件结构-CSDN博客
开源 java android app 开发(三)GUI界面布局和常用组件-CSDN博客
开源 java android app 开发(四)GUI界面重要组件-CSDN博客
开源 java android app 开发(五)文件和数据库存储-CSDN博客
开源 java android app 开发(六)多媒体使用-CSDN博客
开源 java android app 开发(七)通讯之Tcp和Http-CSDN博客
开源 java android app 开发(八)通讯之Mqtt和Ble-CSDN博客
开源 java android app 开发(九)后台之线程和服务-CSDN博客
开源 java android app 开发(十)广播机制-CSDN博客
开源 java android app 开发(十一)调试、发布-CSDN博客
开源 java android app 开发(十二)封库.aar-CSDN博客
开源 java android app 开发(十三)自定义绘图控件--游戏摇杆
开源 java android app 开发(十四)自定义绘图控件--波形图
开源 java android app 开发(十五)自定义绘图控件--仪表盘
开源 java android app 开发(十六)自定义绘图控件--圆环
推荐链接:
开源C# .net mvc 开发(一)WEB搭建_c#部署web程序-CSDN博客
开源 C# .net mvc 开发(二)网站快速搭建_c#网站开发-CSDN博客
开源 C# .net mvc 开发(三)WEB内外网访问(VS发布、IIS配置网站、花生壳外网穿刺访问)_c# mvc 域名下不可訪問內網,內網下可以訪問域名-CSDN博客
开源 C# .net mvc 开发(四)工程结构、页面提交以及显示_c#工程结构-CSDN博客
开源 C# .net mvc 开发(五)常用代码快速开发_c# mvc开发-CSDN博客
本章节主要内容是:前面有讲过怎么封库为aar,但是在应用中发现,aar封装以后在点击调用的函数定义,实际可以看到封库的源码,对于代码的保护太不友好。这里主要介绍,如何讲代码封为aar以后,怎么进行混淆,防止代码被反向破解。
1.aar封装库的解析效果
2.aar封装库混淆的办法
3.aar混淆的效果演示
一、aar封装库的解析效果
如果参照十二章封库很容易得到以下的效果,在Mainactiviy.java可以使用mylib-debug.aar这个库的
DataProcessor类。

但是当使用鼠标点击类以后,android studio 会将整个类显示出来,想要的类加密混淆的效果并没有出现

二、aar封装库混淆的办法
造成封装库mylib-debug.aar没有混淆成功的原因是,在应用项目中引用的不是Release AAR。
要生成Release AAR需要有几个地方的修改。
1.检查 Library 模块的 build.gradle
确认您的 mylibrary/build.gradle 文件配置:
检查 Library 模块的 build.gradle
确认您的 mylibrary/build.gradle 文件配置:
apply plugin: 'com.android.library'
android {
compileSdkVersion 28 // 或者 29,确保与您的环境匹配
defaultConfig {
minSdkVersion 16
targetSdkVersion 28
}
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
// 添加这些配置
crunchPngs false
shrinkResources false
}
}
// 添加编译选项
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}

2.简化混淆规则
暂时使用一个非常简单的 proguard-rules.pro 来测试:
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
# 基本保留规则
-keepattributes Exceptions, InnerClasses, Signature, Deprecated, SourceFile, LineNumberTable
# 保留所有公共类和方法(测试阶段)
-keep public class * {
public protected *;
}
# 忽略所有警告
-ignorewarnings
-dontwarn **

3.点击右边栏上的Gradle->mylib->other->assembleRelease,assembleRelease需要双击或右键执行

最后生成mylib-release.aar,将生成的mylib-release.aar替换mylib-debug.aar

三、aar混淆的效果演示
再次使用鼠标点击DataProcessor类以后,DataProcessor中除了public函数,其余的private都进行了处理,混淆了源码,实现了加密的目的

DataProcessor中所有的私有变量和函数已经被替换掉
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.example.mylib;
public class DataProcessor {
public static final byte[] a = new byte[]{1, 22, 116, 37, 54, -107, 51, -95, 119, -126, 34, 51, 68, 85, 0, 0, 0, 7, 0, -97, 0, 0};
public static final byte[] b = new byte[22];
public static final byte[] c = new byte[]{-112, -27, 75, 29, 125, 58, -23, -52, 97, -98, 92, -19};
public static final byte[] d = new byte[]{120, -7, -28, 71, -22, -84, -47, -97, 84, 52, -39, -69, -103, 9, 37, -52, 60, -3, 114, -92, -11, 86};
public static final byte[] e = new byte[]{79, -50, 97, -20, 99, 35, -111, 45, -16, -15, -56, -114, -45, 88, -94, 62, -88, 103, -79, 118, 50, 18};
public static final byte[] f = new byte[]{90, -33, -30, -112, 28, -90, -80, 67, 124, 79, -50, 97, -20, 99, 35, -111, 45, -16, -15, -56, -114, -45};
public DataProcessor() {
}
public byte[] generateProcessedData(byte[] var1, byte var2, byte[] var3) {
if (var1 != null && var1.length == 4) {
if (var3 != null && var3.length == 5) {
byte[] var10000 = a;
byte[] var6 = b;
int var4 = var10000.length;
System.arraycopy(var10000, 0, var6, 0, var4);
int var7;
for(var7 = 0; var7 < 4; ++var7) {
b[var7 + 2] = var1[var7];
}
var10000 = b;
var10000[8] = var2;
var10000[9] = 35;
var10000 = var6 = new byte[4];
var10000[0] = 18;
var10000[1] = 52;
var10000[2] = 86;
var10000[3] = 120;
int var8;
for(var8 = 0; var8 < 4; ++var8) {
b[var8 + 10] = var6[var8];
}
for(var7 = 0; var7 < 5; ++var7) {
byte var9 = var3[var7];
if (var7 >= 0 && var7 <= 4) {
b[var7 + 14] = var9;
}
}
b[19] = 0;
for(var7 = 0; var7 < 11; ++var7) {
var10000 = var1 = b;
var10000[19] += var1[var7 + 8];
}
byte[] var10;
for(var7 = 0; var7 < (var1 = c).length; ++var7) {
(var10 = b)[var7 + 8] = (byte)(var10[var7 + 8] ^ var1[var7]);
}
var10000 = var6 = new byte[17];
System.arraycopy(b, 1, var6, 0, 5);
System.arraycopy(b, 8, var6, 5, 12);
var8 = 0;
int var11 = var10000.length;
int var12;
for(var12 = 65535; var8 < var11; ++var8) {
var12 ^= var6[var8] & 255;
for(var4 = 0; var4 < 8; ++var4) {
if ((var12 & 1) != 0) {
var12 = var12 >> 1 ^ 'ꀁ';
} else {
var12 >>= 1;
}
}
}
var7 = var12 & '\uffff';
var10000 = var1 = b;
var1[20] = (byte)(var7 >> 8);
var10000[21] = (byte)(var7 & 255);
for(var7 = 0; var7 < var1.length; ++var7) {
var10 = b;
byte var13 = var1[var7];
byte var14 = 0;
for(int var5 = 0; var5 < 8; ++var5) {
var14 = (byte)(var14 << 1 | var13 & 1);
var13 = (byte)(var13 >> 1);
}
var10[var7] = var14;
}
switch(37) {
case 37:
var6 = d;
break;
case 38:
var6 = e;
break;
case 39:
var6 = f;
break;
default:
return (byte[])b.clone();
}
for(var8 = 0; var8 < var6.length; ++var8) {
var10000 = b;
var10000[var8] ^= var6[var8];
}
return (byte[])b.clone();
} else {
throw new IllegalArgumentException("数据字段必须为5字节");
}
} else {
throw new IllegalArgumentException("地址数据必须为4字节");
}
}
public boolean validateReceivedData(byte[] var1) {
if (var1 != null && var1.length == 14) {
if (var1[2] == -96 && var1[3] == 35) {
byte var3 = 0;
for(int var2 = 2; var2 < 13; ++var2) {
var3 += var1[var2];
}
return var3 == var1[13];
} else {
return false;
}
} else {
return false;
}
}
}