我正在开发一个刚刚变大的应用程序(每个dex达到65535方法计数)。它集成了三星Spen SDK时达到了极限。
我决定使用proguard,并且编译成功。但是,当我打开spen draw活动时,它崩溃了以下日志:
E/AndroidRuntime( 7144): java.lang.UnsatisfiedLinkError: Native method not found: com.bst.HwBeautify.BeautifyNative.nativeCBInitEngine:()I
E/AndroidRuntime( 7144): at com.bst.HwBeautify.BeautifyNative.nativeCBInitEngine(Native Method)
E/AndroidRuntime( 7144): at com.bst.HwBeautify.BeautifyNative.cbInitEngine(SourceFile:107)
E/AndroidRuntime( 7144): at com.bst.HwBeautify.BeautifyManager.b(SourceFile:87)
E/AndroidRuntime( 7144): at com.bst.HwBeautify.BeautifyManager.a(SourceFile:85)
E/AndroidRuntime( 7144): at com.bst.HwBeautify.BeautifyManager$1.run(SourceFile:64)
E/AndroidRuntime( 7144): at java.lang.Thread.run(Thread.java:856)
这个缺失的方法可以在proguard / seeds.txt
中找到...
com.bst.HwBeautify.BeautifyNative
com.bst.HwBeautify.BeautifyNative: int nativeCBInitEngine()
com.bst.HwBeautify.BeautifyNative: void nativeCBCloseEngine()
...
和proguard / dumps.txt
+ Method: nativeCBInitEngine()I
Access flags: 0x108
= static native int nativeCBInitEngine()
和BeautifyNative.class也在obfuscated.jar中(obfuscated / com / bst / HwBeautify /),所以我不知道为什么它说UnsatisfiedLinkError。
然后我决定尝试custom class loading。这也行不通,但这是一个不同的故事。此外,我将重新编码许多部分,以使我的应用程序兼容辅助罐。
调查问题,我尝试创建一个适用于Spen SDK的最小应用程序。慢慢地,我将我的大型应用程序的一部分放到了小型但工作的应用程序中。
通过添加更多图像无意中复制了该错误。更清楚的是,当我只有res / drawable-hdpi上的图像时,应用程序不会崩溃(此处崩溃属于与上面相同的日志)。但是当我添加res / drawable-xhdpi时,它会崩溃。与res / drawable-ldpi和res / drawable-mdpi相同的故事。
还有一件事:如果我使用adb install -r appname.apk
安装大应用程序,而小应用程序(相同的软件包名称,相同的应用程序名称)仍然安装,那么大应用程序工作正常。但如果我在安装大应用程序之前卸载小应用程序,后者就会崩溃。
我的问题:
这是我的proguard.cfg
#################################################################################################
# Standard Configuration for Android App
# See http://proguard.sourceforge.net/index.html#manual/examples.html
# -optimizationpasses 2
-dontoptimize
-dontobfuscate
-dontpreverify
-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-verbose
# -allowaccessmodification
# -optimizations !code/simplification/arithmetic,!field/*,!class/merging/*,!code/allocation/variable
-keepattributes *Annotation*
-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.view.View {
public <init>(android.content.Context);
public <init>(android.content.Context, android.util.AttributeSet);
public <init>(android.content.Context, android.util.AttributeSet, int);
public void set*(...);
}
-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.content.Context {
public void *(android.view.View);
public void *(android.view.MenuItem);
}
-keepclassmembers class * implements android.os.Parcelable {
static android.os.Parcelable$Creator CREATOR;
}
-keepclassmembers class * implements java.io.Serializable
{
private static final java.io.ObjectStreamField[] serialPersistentFields;
private void writeObject(java.io.ObjectOutputStream);
private void readObject(java.io.ObjectInputStream);
java.lang.Object writeReplace();
java.lang.Object readResolve();
}
-keepclassmembers class **.R$* {
public static <fields>;
}
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
# adding this in to preserve line numbers so that the stack traces
# can be remapped
-renamesourcefileattribute SourceFile
-keepattributes SourceFile,LineNumberTable
#################################################################################################
# For RoboSpice
# See https://groups.google.com/forum/?fromgroups=#!topic/robospice/xGLRbGkLwQU
#Request classes purged by Proguard as they are "empty", others are kept
-keep class com.limbocitizen.android.playground.model.**
#RoboSpice requests and Results must be kept as they are used by reflection via Jackson
-keepclassmembers class com.limbocitizen.android.playground.request.** {
public void set*(***);
public *** get*();
public *** is*();
}
### XML SERIALIZER SETTINGS
-keepclassmembers,allowobfuscation class * {
@org.simpleframework.xml.* <fields>;
@org.simpleframework.xml.* <init>(...);
}
### Json SERIALIZER SETTINGS
-keepclassmembers,allowobfuscation class * {
@org.codehaus.jackson.annotate.* <fields>;
@org.codehaus.jackson.annotate.* <init>(...);
}
-keepclasseswithmembers class * {
native <methods>;
}
#Warnings to be removed. Otherwise maven plugin stops, but not dangerous
-dontwarn android.support.**
-dontwarn com.sun.xml.internal.**
-dontwarn com.sun.istack.internal.**
-dontwarn org.codehaus.jackson.**
-dontwarn org.springframework.**
-dontwarn java.awt.**
-dontwarn javax.security.**
-dontwarn java.beans.**
-dontwarn javax.xml.**
-dontwarn java.util.**
-dontwarn org.w3c.dom.**
-dontwarn com.octo.android.robospice.persistence.**
-dontwarn org.bouncycastle.**
-dontwarn com.nostra13.**
-dontwarn com.opentok.**
-dontwarn com.pubnub.api.**
-dontwarn com.google.gson.**
-dontwarn com.google.android.**
-dontwarn chesspresso.**
-dontwarn com.parse.**
-dontwarn com.testflightapp.**
-dontwarn org.msgpack.**
-dontwarn com.bugsense.**
-dontwarn biz.source_code.base64Coder.**
-dontwarn org.codehaus.jackson.**
-dontwarn com.bst.**
-dontwarn com.google.common.**
-dontwarn com.samsung.**
-dontwarn org.apache.commons.pool.**
-dontwarn org.ccil.cowan.tagsoup.**
-dontwarn com.opentok.**
-dontwarn com.tokbox.**
-dontwarn main.java.tokbox.org.**
-dontwarn tokbox.org.**
-dontwarn com.google.android.youtube.player.**
-dontwarn org.slf4j.**
-dontwarn org.codehaus.jackson.**
-dontwarn com.facebook.**
-keep class android.support.v4.content.Loader
-keep class com.google.android.gms.maps.GoogleMapOptions
-keep class android.support.v4.content.Loader$OnLoadCompleteListener
-keep class com.icannhas.qualitytime.utils.parse.objects.ParseChatMessage
-keep class com.tokbox.rumor.client.message.Message
-keep class org.codehaus.jackson.node.ObjectNode
#################################################################################################
# For Actionbarsherlock
# See http://actionbarsherlock.com/faq.html
-keep class android.support.v4.app.** { *; }
-keep interface android.support.v4.app.** { *; }
-keep class com.actionbarsherlock.** { *; }
-keep interface com.actionbarsherlock.** { *; }
-keepattributes *Annotation*
#################################################################################################
我的build.xml
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright 2011 Google Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<project name="appname" default="help">
<!-- The local.properties file is created and updated by the 'android' tool.
It contains the path to the SDK. It should *NOT* be checked into
Version Control Systems. -->
<property file="local.properties" />
<!-- The ant.properties file can be created by you. It is only edited by the
'android' tool to add properties to it.
This is the place to change some Ant specific build properties.
Here are some properties you may want to change/update:
source.dir
The name of the source directory. Default is 'src'.
out.dir
The name of the output directory. Default is 'bin'.
For other overridable properties, look at the beginning of the rules
files in the SDK, at tools/ant/build.xml
Properties related to the SDK location or the project target should
be updated using the 'android' tool with the 'update' action.
This file is an integral part of the build system for your
application and should be checked into Version Control Systems.
-->
<property file="ant.properties" />
<!-- The project.properties file is created and updated by the 'android'
tool, as well as ADT.
This contains project specific properties such as project target, and library
dependencies. Lower level build properties are stored in ant.properties
(or in .classpath for Eclipse projects).
This file is an integral part of the build system for your
application and should be checked into Version Control Systems. -->
<loadproperties srcFile="project.properties" />
<!-- quick check on sdk.dir -->
<fail
message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through an env var"
unless="sdk.dir"
/>
<!--
Import per project custom build rules if present at the root of the project.
This is the place to put custom intermediary targets such as:
-pre-build
-pre-compile
-post-compile (This is typically used for code obfuscation.
Compiled code location: ${out.classes.absolute.dir}
If this is not done in place, override ${out.dex.input.absolute.dir})
-post-package
-post-build
-pre-clean
-->
<import file="custom_rules.xml" optional="true" />
<!-- Import the actual build file.
To customize existing targets, there are two options:
- Customize only one target:
- copy/paste the target into this file, *before* the
<import> task.
- customize it to your needs.
- Customize the whole content of build.xml
- copy/paste the content of the rules files (minus the top node)
into this file, replacing the <import> task.
- customize to your needs.
***********************
****** IMPORTANT ******
***********************
In all cases you must update the value of version-tag below to read 'custom' instead of an integer,
in order to avoid having your file be overridden by tools such as "android update project"
-->
<!-- version-tag: 1 -->
<import file="${sdk.dir}/tools/ant/build.xml" />
</project>
和custom_rules.xml
<?xml version="1.0" encoding="UTF-8"?>
<project name="custom_rules">
<!--
Suppress "Warning: can't write resource [META-INF/MANIFEST.MF] (Duplicate zip entry [classes.jar:META-INF/MANIFEST.MF])".
Per http://www.dancartoon.com/2012/01/14/fixing-proguard-warning-cant-write-resource-meta-infmanifest-mf/
Target "-obfuscate" copied from ${sdk.dir}/tools/ant/build.xml v21.
-->
<target name="-obfuscate">
<if condition="${proguard.enabled}">
<then>
<property name="obfuscate.absolute.dir" location="${out.absolute.dir}/proguard" />
<property name="preobfuscate.jar.file" value="${obfuscate.absolute.dir}/original.jar" />
<property name="obfuscated.jar.file" value="${obfuscate.absolute.dir}/obfuscated.jar" />
<!-- input for dex will be proguard's output -->
<property name="out.dex.input.absolute.dir" value="${obfuscated.jar.file}" />
<!-- Add Proguard Tasks -->
<property name="proguard.jar" location="${android.tools.dir}/proguard/lib/proguard.jar" />
<taskdef name="proguard" classname="proguard.ant.ProGuardTask" classpath="${proguard.jar}" />
<!-- Set the android classpath Path object into a single property. It'll be
all the jar files separated by a platform path-separator.
Each path must be quoted if it contains spaces.
-->
<pathconvert property="project.target.classpath.value" refid="project.target.class.path">
<firstmatchmapper>
<regexpmapper from='^([^ ]*)( .*)$$' to='"\1\2"'/>
<identitymapper/>
</firstmatchmapper>
</pathconvert>
<!-- Build a path object with all the jar files that must be obfuscated.
This include the project compiled source code and any 3rd party jar
files. -->
<path id="project.all.classes.path">
<pathelement location="${preobfuscate.jar.file}" />
<path refid="project.all.jars.path" />
</path>
<!-- Set the project jar files Path object into a single property. It'll be
all the jar files separated by a platform path-separator.
Each path must be quoted if it contains spaces.
-->
<!--
Old:
<pathconvert property="project.all.classes.value" refid="project.all.classes.path">
New:
-->
<pathconvert property="project.all.classes.value" refid="project.all.jars.path" pathsep=" ">
<firstmatchmapper>
<!--
Old:
<regexpmapper from='^([^ ]*)( .*)$$' to='"\1\2"'/>
<identitymapper/>
New:
-->
<regexpmapper from='^([^ ]*)( .*)$$' to='-injars "\1\2"(!META-INF/MANIFEST.MF)'/>
<regexpmapper from='(.*)' to='-injars \1(!META-INF/MANIFEST.MF)'/>
</firstmatchmapper>
</pathconvert>
<!-- Turn the path property ${proguard.config} from an A:B:C property
into a series of includes: -include A -include B -include C
suitable for processing by the ProGuard task. Note - this does
not include the leading '-include "' or the closing '"'; those
are added under the <proguard> call below.
-->
<path id="proguard.configpath">
<pathelement path="${proguard.config}"/>
</path>
<pathconvert pathsep='" -include "' property="proguard.configcmd" refid="proguard.configpath"/>
<echo>proguard: $${project.all.classes.value}=${project.all.classes.value}</echo>
<mkdir dir="${obfuscate.absolute.dir}" />
<delete file="${preobfuscate.jar.file}"/>
<delete file="${obfuscated.jar.file}"/>
<jar basedir="${out.classes.absolute.dir}"
destfile="${preobfuscate.jar.file}" />
<proguard>
-include "${proguard.configcmd}"
-include "${out.absolute.dir}/proguard.txt"
-injars ${preobfuscate.jar.file}
${project.all.classes.value}
-outjars "${obfuscated.jar.file}"
-libraryjars ${project.target.classpath.value}
-dump "${obfuscate.absolute.dir}/dump.txt"
-printseeds "${obfuscate.absolute.dir}/seeds.txt"
-printusage "${obfuscate.absolute.dir}/usage.txt"
-printmapping "${obfuscate.absolute.dir}/mapping.txt"
</proguard>
</then>
</if>
</target>
</project>