在一个android项目的发布过程中,需要对代码进行混淆,遇到了不少问题,现在对这些问题和解决方法进行一次总结。
首先代码混淆的方式,根据编译sdk版本的不同,分为两种:
1.低版本sdk下,eclipse项目的工作目录中包含proguard.cfg和project.properties文件,则只需在project.properties文件末尾添加proguard.config=proguard.cfg,在将项目打包成apk,此时代码已完成混淆。
2.高版本的sdk下, eclipse项目的工作目录中包含proguard-project.txt和project.properties文件,这时需要在proguard-project.txt文件中进行如下配置,再将项目导出,即可完成混淆。
# This file is automatically generated by Android Tools.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
#
# This file must be checked in Version Control Systems.
#
# To customize properties used by the Ant build system edit
# "ant.properties", and override values to adapt the script to your
# project structure.
#
# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
proguard.config=/Volumes/develop/eclispe/sdk/tools/proguard/proguard-android.txt:proguard-project.txt
# Project target.
target=android-17
其中/Volumes/develop/eclispe/sdk/tools 为我的android sdk所在文件夹的绝对目录。
2.编写proguard-project.txt文件:
在混淆时,需要注意的一点是,native方法和一些public方法因为没有在类内部中调用的方法,在混淆后,并没有被编译到apk文件中。然后apk被安装运行后,会抱方法找不到的异常。所以在proguard-project文件里,需要对这种情况进行声明。
保持native方法不被混淆
-keepclasseswithmembernames class * {
native <methods>;
}
保持view的get ,set方法不被混淆
-keepclassmembers public class * extends android.view.View {
void set*(***);
*** get*();
}
上面的内容可以在 sdk path下的tools/proguard/proguard-android.txt可以找到。
还有就是继承parcelable的类和自定义控件也需要进行声明,保持不被混淆,否则parcelable对象会在传递的过程中出错,自定义控件也会无法编译。
-keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet);
}
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet,int);
}
下面是一个proguard-property.txt文件的事例说明:-optimizationpasses 5 # 指定代码的压缩级别
-dontusemixedcaseclassnames # 是否使用大小写混合
-dontskipnonpubliclibraryclasses # 是否混淆第三方jar
-dontpreverify # 混淆时是否做预校验
-verbose # 混淆时是否记录日志
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/* # 混淆时所采用的算法
-keep public class * extends android.app.Activity # 保持哪些类不被混淆
-keep public class * extends android.app.Application # 保持哪些类不被混淆
-keep public class * extends android.app.Service # 保持哪些类不被混淆
-keep public class * extends android.content.BroadcastReceiver # 保持哪些类不被混淆
-keep public class * extends android.content.ContentProvider # 保持哪些类不被混淆
-keep public class * extends android.app.backup.BackupAgentHelper # 保持哪些类不被混淆
-keep public class * extends android.preference.Preference # 保持哪些类不被混淆
-keep public class com.android.vending.licensing.ILicensingService # 保持哪些类不被混淆
-keepclasseswithmembernames class * { # 保持 native 方法不被混淆
native <methods>;
}
-keepclasseswithmembers class * { # 保持自定义控件类不被混淆
public <init>(android.content.Context, android.util.AttributeSet);
}
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet, int); # 保持自定义控件类不被混淆
}
-keepclassmembers class * extends android.app.Activity { # 保持自定义控件类不被混淆
public void *(android.view.View);
}
-keepclassmembers enum * { # 保持枚举 enum 类不被混淆
public static **[] values();
public static ** valueOf(java.lang.String);
}
-keep class * implements android.os.Parcelable { # 保持 Parcelable 不被混淆
public static final android.os.Parcelable$Creator *;
}
-keep class MyClass; # 保持自己定义的类不被混淆
3.第三方jar包的引入:
由于项目中引用了不少第三方的jar包,混淆时需要将这些jar包也混淆进去。否则在导出apk文件时,会报出 类1 can't find referenced class 类2,You may need to specify addtional library jars(using '-libraryjars') 的异常,导致apk无法导出。此时则需要将所引用的jar包加入: -libraryjarslibs/Android_SDK.jar
在引入第三方jar时,可能会出现找不到某个类的引用而无法导出apk的情况。这时可以使用这种方法来解决: -dontwarn android.net.http.**
4.混淆成功
混淆成功后,在eclipse的proguard文件夹里,会出现这4个文件:
dump.txt – 描述.apk文件中所有类文件间的内部结构
mapping.txt – 列出了原始的类,方法和字段名与混淆后代码间的映射。这个文件很重要,当你从release版本中收到一个bug报告时,可以用它来翻译被混淆的代码。
seeds.txt – 列出了未被混淆的类和成员
usage.txt – 列出了从.apk中删除的代码
应用发布时,记得保存这些文件,因为下一次版本更新,这些文件会被覆盖掉,mappig里面字段的名字也会改变,这样你再进行bug修复时,找不到对应的类,那就悲剧了。
混淆成功,得到apk后,记得将apk安装在真机上跑跑,确保无错误后再进行发布。
引用资料:http://my.eoe.cn/eric_wu/archive/4358.html 点击打开链接
http://proguard.sourceforge.net/index.html#点击打开链接