Android 混淆出错各种解决办法

版权声明:此文章转载自极客头条

如需转载请联系听云College团队成员小尹 邮箱:yinhy#tingyun.com


Android 混淆出错各种解决办法

android使用打包过程中proguard混淆后, 会导致一些错误

1. 写在视图xml中的onClick响应出错. 因为写在xml中的onClick是通过反射调用的, proguard认为它们没有在代码中被调用过, 所以将它们从代码中除掉或改名了. 解决方法:

在proguard.cfg中添加以下代码, 就可以防止被配在视图xml中的onClick方法被proguard优化掉

-keepclassmembers class * extends android.app.Activity {

public void *(android.view.View);

}

2. jni反调java方法

这些类或方法同样可能会被proguard认为没有调用过而被除掉, 或都被改名. 这些方法最好统一写在一个类中, 然后这个类不作优化, 或是找出所有jni调用过的类与方法, 在proguard.cfg中配置, 不对它们作优化

3. 其它反射调用的java类与方法

使用反射时一定要注意proguard可能会认为那些方法未被调用过, 会在代码优化过程中将它们改名或除去. 在使用反射的地方一定要在proguard.cfg中配置, 不优化反射调用过的类和方法

最后在proguard优化过后会产生一些文件

dump.txt – 描述.apk文件中所有类文件间的内部结构

mapping.txt – 列出了原始的类,方法和字段名与混淆后代码间的映射。这个文件很重要,当你从release版本中收到一个bug报告时,可以用它来翻译被混淆的代码。

seeds.txt – 列出了未被混淆的类和成员

usage.txt – 列出了从.apk中删除的代码

要注意分析mapping.txt与usage.txt看xml视图中写的onClick响应函数, jni调用到的java类与方法, 反射调用过的类与方法是否被混淆或重命名

-keep class com.badlogic.gdx.backends.android.**{ *;}

像这样的只是不混淆:这个包下的类(不包括子包里的东西),用到一个第三文的类就要把这个类所在的包,像上面加上

还要注意的是android-support-v4.jar这个包问题,这里加上了对这个jar包的处理

第三方jar的混淆,

-optimizationpasses 5
-dontusemixedcaseclassnames 
-dontskipnonpubliclibraryclasses 
-dontpreverify 
-verbose 
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/* 
-keep public class * extends android.app.Activity                          // 继承activity,application,service,broadcastReceiver,contentprovider....不进行混淆
-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
                                                                                                                      // 这里处理第三方的jar包,第三方JAR包处理开始
-libraryjars /libs/android-support-v4.jar
-libraryjars /libs/gdx-backend-android.jar
-libraryjars /libs/gdx.jar
                                                                                                                        // 这里不对第三方的jar包的提出WARN    
-dontwarn com.badlogic.**
-dontwarn android.support.v4.**
-dontwarn android.support.v4.view.**
                                                                                                                        // 这里对第三方jar包的类不进行混淆
-keep class com.badlogic.gdx.backends.android.**{ *;}
-keep class com.badlogic.gdx.**{ *;}
-keep class com.badlogic.gdx.graphics.g2d.**{ *;}
-keep class com.badlogic.gdx.graphics.**{ *;}
-keep class android.support.v4.view.**{ *;}
                                                                                                                            // 这里第三方JAR包处理结束
-keepclasseswithmembernames class * {                                                           // natvie 方法不混淆
    native ; 
} 
-keepclasseswithmembers class * {                                                                    // 对于所有类,有这个构造函数不进行混淆,主要是为了在layout中的,自定义的view
    public (android.content.Context, android.util.AttributeSet); 
} 
-keepclasseswithmembers class * { 
    public (android.content.Context, android.util.AttributeSet, int); 
} 
-keepclassmembers class * extends android.app.Activity {                                   // 这个主要是在layout 中写的onclick方法android:onclick="onClick",不进行混淆
   public void *(android.view.View); 
} 
-keepclassmembers enum * { 
    public static **[] values(); 
    public static ** valueOf(java.lang.String); 
} 
-keep class * implements android.os.Parcelable { 
  public static final android.os.Parcelable$Creator *; 
}

1-----------------------------------------------引用--------------------------------------------------------

如果工程引入了Android-support-v4的jar类库,那么在工程打包混淆时,就会出现报错提示。例如提示你:You may need to specify additional library jars (using '-libraryjars')。 

这里先给出解决方案,稍后我们再来解释如何处理类似情况: 

在proguard.cfg里的后面,添加如下内容:

 1.-libraryjars /android-support-v4.jar 
 2.-dontwarn android.support.v4.** 
 3.-keep class android.support.v4.** { *; } 
 4.-keep public class * extends android.support.v4.** 
 5.-keep public class * extends android.app.Fragment

然后你再打包看看,应该可以正常生成apk安装包了。

打包出错:

情况一:

 "类1 can't find referenced class 类2" 字面上的意思就是类1找不到类2的引用;它会建议你:"You may need to specify additional library jars (using '-libraryjars').";

需要使用-libraryjars加上项目中使用到的第三方库就OK了。

例如:-libraryjars /android-support-v4.jar

注意:这里引用方式是当前工程的根目录(也可以配置其他目录),也就是说,你要把第三方jar放到当前目录下,否则就会警告说找不到jar文件!

情况二:

例如: can't find superclass or interface android.os.Parcelable$ClassLoaderCreator,碰到这样的情况,可以使用-dontwarn com.xx.yy.**,不对错误提出警告。

注意:使用这个方式的话,要确保自己没有用到这个库里面的类!否则就会抛ClassNotFoundException!

情况三:

在工程中确实用到了该类,采用上面方式还是不行。这个时候就要再增加一项:-keep class com.xx.yy.** { *;},让当前类不混淆。

小结:

对于引用第三方包的情况,可以采用下面方式避免打包出错:

-libraryjars /aaa.jar

-dontwarn com.xx.yy.**

-keep class com.xx.yy.** { *;} 

最后打包成功,还要在机子上跑跑,看看有没有问题。本篇文章来源于 Linux公社网站(www.linuxidc.com)  原文链接:http://www.linuxidc.com/Linux/2012-07/66798.htm

-----------------------------------------------------------------------------------2--------------------------------------------------------------------

proguard.cfg配置

稍微深入想一下混淆后的结果,你就会发现,如果一些提供给外部的类、方法、变量等名字被改变了,那么程序本身的功能就无法正常实现。那么Proguard如何知道哪些东西是可以改名,而哪些是不能改变的呢?

这个是靠proguard.cfg文件来进行配置的。Android工程中默认自动生成的proguard.cfg已经针对Android的一般情况进行了配置,我们打开这个配置文件。内容大概如下:

 1.-optimizationpasses 5 
2.-dontusemixedcaseclassnames 
3.-dontskipnonpubliclibraryclasses 
4.-dontpreverify 
5.-verbose 
6.-optimizations !code/simplification/arithmetic,!field/*,!class/merging/* 
7. 
8.-keep public class * extends android.app.Activity 
9.-keep public class * extends android.app.Application 
10.-keep public class * extends android.app.Service 
11.-keep public class * extends android.content.BroadcastReceiver 
12.-keep public class * extends android.content.ContentProvider 
13.-keep public class * extends android.app.backup.BackupAgentHelper 
14.-keep public class * extends android.preference.Preference 
15.-keep public class com.android.vending.licensing.ILicensingService 
16. 
17.-keepclasseswithmembernames class * { 
18.    native ; 
19.} 
20. 
21.-keepclasseswithmembers class * { 
22.    public (android.content.Context, android.util.AttributeSet); 
23.} 
24. 
25.-keepclasseswithmembers class * { 
26.    public (android.content.Context, android.util.AttributeSet, int); 
27.} 
28. 
29.-keepclassmembers class * extends android.app.Activity { 
30.   public void *(android.view.View); 
31.} 
32. 
33.-keepclassmembers enum * { 
34.    public static **[] values(); 
35.    public static ** valueOf(java.lang.String); 
36.} 
37. 
38.-keep class * implements android.os.Parcelable { 
39.  public static final android.os.Parcelable$Creator *; 
40.}

它主要保留了继承自Activity、Application、Service、BroadcastReceiver、ContentProvider、 BackupAgentHelper、Preference和ILicensingService的子类。因为这些子类,都是可能被外部调用的。

另外,它还保留了含有native方法的类、构造函数从xml构造的类(一般为View的子类)、枚举类型中的values和valueOf静态方法、继承Parcelable的跨进程数据类。 

在实际的一个工程项目中,可能Google自动生成的配置不能胜任我们的混淆工作。所以,我们往往需要自己编写一些ProGuard配置。这方面的资料在官网的Manual -> Usage里有详细说明,大家可以研究一下。

想阅读更多技术文章,请访问听云技术博客,访问听云官方网站感受更多应用性能优化魔力。

关于作者

郝淼emily

重新开始,从心开始

我要评论

评论请先登录,或注册