首页 > 代码库 > android proguard使用心得和遇到的若干问题以及解决思路。
android proguard使用心得和遇到的若干问题以及解决思路。
今天决定对项目使用混淆工具proguard。于是便开始找proguard究竟放在sdk的什么地方,果不其然,我在sdk目录的tools文件夹中找到了proguard的文件夹。
配置方法这里简单的说明一下。
打开要混淆的android项目,找到project.properties文件。
后面添加上proguard.config=android.pro
现在我来解释说明一下这句话,后面的android.pro是proguard的配置文件,主要是告诉proguard应该怎么混淆文件。那么这个配置文件在哪里呢?
网上都是直接复制的,没有追其根源。我们可以在前面提到的proguard的文件夹里面,找到proguard-android.txt。这个是默认的混淆配置,已经针对android的代码做了优化了,但是并没有添加我们自己的混淆逻辑。
这个文件就是我后面的android.pro。我是这么做的,把该文件复制到项目中,然后修改名字为android.pro。
因此也就是告诉各位这个文件的名字没有硬性要求的,只要是正确的配置文件就可以了。
之后就开始立马签名文件了,然后自己反编译文件,发现里面都是abcd的类名,不由得很开心。
之后立马开始安装,果然就开始报错了。这里我们要分析错误的来源,才能正确开始添加我们自己编写的的配置代码到配置文件中。有些机子是直接就死机的,那么我们无法看到错误报告,有些是有系统自带report的报告,我们可以看到相关的堆栈错误。那么怎么解决直接死机崩溃,没有堆栈日志的情况呢?我们可以连接机子到电脑,在eclipse中看到设备,然后让它死机,那么我们同样可以再logcat中看到死机的原因。
这里要搞清楚,我们不是debug模式,因此报出的错误都是这样的
后面是unkonw source。因为我们没有关联相关的代码,因此是和开发模式是不同的,是看不到具体在第几行的。不过好在我们可以知道是什么方法的名字出现了异常。因此我们可以反编译混淆过的代码,查看和对比没有混淆的代码。发现问题所在,接下来我们才可以添加我们自己的混淆配置。接下来,我要举例说明遇到的问题,和解决的思路,供大家参考。
1.解决案例一:下面看一下部分的代码。
public abstract class Model { @Column(name = "Id") private Long mId = null; //下面这个函数是另一个类里面的 private Field getIdField(Class<?> type) { if (type.equals(Model.class)) { try { return type.getDeclaredField("mId"); } catch (NoSuchFieldException e) { Log.e("Impossible!", e); } } else if (type.getSuperclass() != null) { return getIdField(type.getSuperclass()); } return null; }
如果我们直接的混淆的话,那么mId肯定会变成了abcd之类的词汇。
而在下面的方法中出现了反射方法。
type.getDeclaredField("mId");
那么我们在混淆之后肯定会报错的。并且返回一个null,笔者当时就是报了个空指针异常,程序的主要作用是查找指定类,发现它的id,并把具有该性质的类放入集合中。
很好,我们发现了这个错误。下面我们就开始添加如下的配置:
-keepclassmembernames class *******************.Model{
java.lang.Long mId;
}
上面的一连串*号是我的包名。
笔者一开始是这么写的。
-keepclassmembernames class *******************.Model{
Long mId;
}
后来查看了proguard文件夹下面examples文件夹下面的许多pro文件,发现了他们的共性,发现不是基本类型是不能这么写的。
后来在混淆之后,在项目中发现了这么个文件夹proguard。这个文件夹是混淆过程中产生的相关的日志文件。
大家可以再mapping.txt文件中找到proguard究竟给你混淆了什么,同时保留了什么。我对上面的Model类尝试了搜索,看看mId是不是混淆了,还是说保留了。
***********.Model -> com.a.d:
java.lang.Long mId -> mId
结果搜索到这些语句
可以看到Model类已经被混淆成com.a.d了。而我们希望保留的mId,也确实没有混淆了。
2.解决案例二:
由于笔者的项目使用了fastjson框架,发现在解析从服务器下来的数据的时候发生了异常。
大家都知道json数据里面的成员变量是有具体的含义的,比如{username:‘xiaoming‘,password:‘dddddddd‘};
而我自己写的model,里面对应的username肯定是混淆的。因此我们要解析json数据,肯定是不希望它被混淆的。
因此我们可以在配置文件中添加如下:
-keep class com.xxxx.json.model.**{
*;
}
把json包下的实体类全部保留。
上面描述了两个解决案例:更多的配置例子可以查看sdk的proguard文件夹下面的examples目录。
接下来解释几个配置参数加深大家对proguard的配置的理解:
保留所有的本地native方法不被混淆。这点在我们做ndk开发的时候很重要。
-keepclasseswithmembernames class * {
native <methods>;
}
保留所有的set和get开头的方法。
-keepclassmembers public class * extends android.view.View {
void set*(***);
*** get*();
}
# We want to keep methods in Activity that could be used in the XML attribute onClick
我们保留在activity中的方法参数是view的方法,这样的话,我们在xml里面编写onClick就不会被影响了。
-keepclassmembers class * extends android.app.Activity {
public void *(android.view.View);
}
接下来附上相关的proguard的配置解释,是笔者从网上搜罗的。
-keepclasseswithmembers 指定的类和类成员被保留,假如指定的类成员存在的话
最后谢谢各位的阅读。
android proguard使用心得和遇到的若干问题以及解决思路。