I have an issue which I'm pretty sure is related to multidex. Basically one of the libraries I use has a .properties resource bundle in a jar. As my application started growing I started having issues with it. I've made a couple of posts about it in the past but never had any solutions (post 1, post 2). Post 2 actually has a lot more details about the issue.
Basically this resource is missing unless I force some of the code on that Jar to run on the Application onCreate method. At least that was the issue until yesterday.
Yesterday I update a jar that has nothing to do with this but is now larger than it used to be (which I'm assuming means it has more methods), and now the code fails again on this same issue java.util.MissingResourceException: Can't find bundle for base name javax.servlet.LocalStrings, locale en_US but now it fails for everyone, not just some users.
I took apart the apks using apktool for one that works and one that doesn't (basically downgrading those unrelated jars) and there is an unknown folder in both apks but the one that works has those LocalStrings.properties in that folder and the one that doesn't work doesn't have them in that folder. I have unzipped those unrelated jars just to make sure and they don't have that javax.servlet package in there and they are jars so they don't have anything else that might affect the gradle build.
Basically my theory right now is that those jars are just large enough to push the javax.servlet stuff out of the first dex file, but that isn't entirely right because the properties files don't even go in the dex file. If I just unzip the apk, I can see the javax package on the root folder and the resource files inside the right place but not LocalStrings.properties whereas if I do that for an apk that works, I can see LocalStrings.properties in there.
Right now I've been testing multiDexKeepProguard and I got all javax.servlet to go in the main dex file but I still can't get LocalStrings.properties to show up in the apk, even with:
-keepclassmembers class **$Properties
I've also tried a few other crazy things like putting the LocalStrings.properties files inside my main app package using the javax.servlet package and it didn't help either.
So what else can I try? Is this a bug or am I doing something wrong?
Thanks.
Edit: I would like to report that I've once again gotten past this issue by removing a dependency (an ad network) that I'm no longer using. I realized I still had that dependency when I used dex2smali to look at the first dex file and saw it was there. So it definitely appears to be an issue with the size of the jars it puts on the first dex file.
Edit: I have this on my proguard settings:
-keep class javax.** {*;}
-keep interface javax.** {*;}
-keepclassmembers class javax.** {*;}
-keepclassmembers class **$Properties
Not sure if this was the right way to do it, but apparently proguard was mistakenly deleting the *.properties files for me.
What fixed it was doing a build with
minifyEnabled false
and then going back to
minifyEnabled true
After that, the *.properties files were all available in the final build again.
It looks like your package property file is stripped by ProGuard. I am not sure whether you have tried below configurations
-keep class javax.servlet.**
or
-keep class javax.servlet.** { *; }
or
-optimizations !javax.servlet
-dontoptimize
Also, more additional references:
shrink-code: https://developer.android.com/studio/build/shrink-code
Processing resource files: https://docs.huihoo.com/proguard/manual/examples.html
-keeppackagenames https://stackoverflow.com/a/5866755/8034839
How to tell ProGuard to keep everything in a particular package?
I have Android library project. There are some .aj files (aspectJ) with pointcuts.
I need to obfuscate compiled artifact (jar). When i obfuscate it and add as library to another project, aspects stops working.
Can anyone help with obfuscation using ProGuard? Some configuration examples or any useful information.
May be it is not possible at all? Are there some alternatives?
Thanks.
I also have an android library with aspects. My pointcuts are not for my library code, but for the app's code (pointcuts on Activity.onCreate, for example), so people who use my library are already expected to set up their android projects as AspectJ projects.
Everything works perfectly without Proguard, but despite making every exception I can think of I couldn't get the advice to apply if my library jar was obfuscated. I verified that the aspect class and all methods and fields were kept in the mapping.
Here's the final version of my proguard config that didn't get the aspects working, although everything compiles fine and there are no errors:
...some config, the injar included my iajc compiled library project with aspects
-optimizations !code/allocation/variable,!code/simplification/arithmetic,!field/*,!class/merging/*
-optimizationpasses 3
-dontpreverify
-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-dontskipnonpubliclibraryclassmembers
-verbose
-keepattributes Exceptions,InnerClasses,Signature,Deprecated,
SourceFile,LineNumberTable,*Annotation*,EnclosingMethod
# This is the package of my aspects
-keep class my.package.aspectj.** { *; }
# This is all the public methods that my aspect code calls in to
-keep class my.package.allthethingsmyaspectscall.** { *; }
...keep some other classes not related to this
With all this my aspects still didn't apply.
My solution was to copy my aspect files into the client app's project at install time so that it is in their app classpath and gets woven when their app gets built.
I'm using a jar of which I don't have the source code. I started using the proguard tool and some of the functionality of the implementation of this jar stop working, so I tried changing the proguard configuration by adding (As seen in another question):
-keep class com.myexternaljar.** { public protected *; }
But it still doesn't behave as it should. So I'm guessing that this jar uses some other external classes that are being modified by the proguard tool.
Is there any configuration that can keep all the classes in a certain jar and all the classes that aren't in the jar itself but that are used by it?
I have an Android App which consists on different modules. The Main module is using some libs like Google's GSON or the v4.support.package. A custom build script with the right proguard.cfg will build it, too.
Now I must integrate another "Android-Library" which uses partly the same libs (GSON support.v4). Beside from getting a lot of Notes like
Note: duplicate definition of program class [com.google.gson.Gson]
I get also some Notes like
[proguard] Note: com.google.gson.UnsafeAllocator: can't find dynamically referenced class sun.misc.Unsafe
[proguard] Note: the configuration refers to the unknown class 'sun.misc.Unsafe'
that I find strange cause i have some 'keeps' in my Proguard.cfg especially for that:
-keepattributes Signature, Annotation
-keep class com.google.gson.** {*;}
-keep class sun.misc.Unsafe { *; }
which works well on my project without referencing the module-library inside it.
I'm on the Latest SDK and Tools, and added a custom proguard.cfg to the module-library, which works well on the module-lib itself (if build in standalone-mode).
It seems to me, that the build is not depending on custom proguard.cfg inside library-projects. Any idea on what to try highly appreciated
I finally found a solution for it myself:
with the last Android Tools (16), every Android-Library gets compiled on its own first.
So when the lib has not a "standart" build and defines some custom build script including proguard --keeps, and this --keeps are defined on the same Project (excluding Android SDK classes, as thei're not compiled) it leads to an proguard error.
The Solution was do remove proguard out of the lib and copy the --keeps inside the main App
The definitive reference for using Scala on android seems to be here: http://www.scala-lang.org/node/160
Unfortunately, all the references on using scala with android are based around Scala 2.7 and refer to a custom build android-library.jar, with a couple of cryptic references suggesting that this custom build isn't needed for later versions of android (I'm using 2.1 / API v7)
So... What are the steps needed to use Scala 2.8 in an android project? Preferably using eclipse and the Android tools that Google supplies for that IDE.
Edit:
My new way of doing this is to use my Eclipse plugin: https://github.com/banshee/AndroidProguardScala (the readme has instructions for installing and a pointer to a normal Eclipse update site).
The old answer still works, but the new way is just better.
[The old way]
My approach:
Use the normal Android/eclipse tools for creating a Java project.
Add a second project containing the Scala code. That way I get to keep the generated code for future reference (I'm new at both Android and Scala). This project can reference android.jar.
The scala project produces a jar file that's used in the java project
Use proguard to strip the library. I believe this avoids the need for the scala-android.jar that was used in 2.7
I haven't used this for anything more ambitious than hello, world though, so take it as more of a set of hints.
In the scala project, I add a builder (Builder > New) that's just a shell script called pguard in the root directory of the project containing:
#!/bin/sh
cd $1
PROGUARD=$HOME/dev/proguard/lib/proguard.jar
LIBS=
OUTPUT=lib/proguard.jar
rm -f $OUTPUT
AJAR=/Users/jamesmoore/dev/android-sdk-mac_86/platforms/android-7/android.jar
# java -jar $PROGUARD -injars 'bin:lib/scala-library.jar(!META-INF/MANIFEST.MF,!library.properties)' -outjar $OUTPUT -libraryjars #proguard.txt
java -Xmx1g -jar $PROGUARD -injars 'bin:lib/scala-library.jar(!META-INF/MANIFEST.MF,!library.properties)' -outjar $OUTPUT -libraryjars $AJAR #proguard.txt
The builder has Location set to:
${build_project}/pguard
And both working directory and arguments set to
${build_project}
Also in the root of the scala project, there's a proguard arguments file #proguard.txt:
-dontwarn
-dontoptimize
-dontobfuscate
-dontskipnonpubliclibraryclasses
-dontskipnonpubliclibraryclassmembers
-keepattributes Exceptions,InnerClasses,Signature,Deprecated,
SourceFile,LineNumberTable,*Annotation*,EnclosingMethod
-keep public class com.banshee.** {
public protected *;
}
You'll want to change the -keep arguments to keep your own code, of course.
In the java project, I add the jar file that's produced by the scala project (I use lib/proguard.jar in the script above).
Don't add the scala project as a required project in the java project's build path, though. That will add the scala class files in addition to the jar file and confuse dex (since it'll get both the .class files and the same things in the jar). As far as I can tell, Eclipse will build everything in the workspace, so when you hit the go button, both projects get built.
After much investigation, it really does look like Proguard is essential to keep the size and speed of deploying the application to reasonable levels.
Sadly, there is no suitable way to embed proguard as a build step. Using scripts might be a possibility, but I also need to support Windows, Linux and OSX environments.
I was also unsure about the twin-project solution, as it prevented Scala code from using the generated resources file R.java, which I wanted to be able to do.
In the end, I was able to make both SBT and Ant build an android 2.1 application using Scala 2.8. Ant was the favourite final solution as it works with the same file organisation as Android's eclipse plugin. I've written up the solution here: http://scala-ide.assembla.com/wiki/show/ae55a-oWSr36hpeJe5avMc/Developing_for_Android
Eclipse then launches Ant as an external tool to package and install the application.
I'm now using a modification of my previous answer to run on Windows: just move everything into #proguard_windows.txt so you don't have to worry about running as a script.
My new #proguard_windows.txt looks like:
-injars bin;lib/scala-library.jar(!META-INF/MANIFEST.MF,!library.properties)
-outjar gen/scandroid.jar
-libraryjars lib/android.jar
-dontwarn
-dontoptimize
-dontobfuscate
-dontskipnonpubliclibraryclasses
-dontskipnonpubliclibraryclassmembers
-keepattributes Exceptions,InnerClasses,Signature,Deprecated,
SourceFile,LineNumberTable,*Annotation*,EnclosingMethod
-keep public class com.banshee.** { public protected *; }
-keep public class org.xml.sax.EntityResolver { public protected *; }
And note that in windows, you need to use a semicolon for -injars. Nasty.
The builder looks like this:
(running cygwin here, so the cat option path takes a slash)
James#Greine:/cygdrive/c/Users/james/workspace/Scala2$ cat .externalToolBuilders/proguard.launch
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="org.eclipse.ui.externaltools.ProgramBuilderLaunchConfigurationType">
<booleanAttribute key="org.eclipse.debug.ui.ATTR_LAUNCH_IN_BACKGROUND" value="false"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="C:\Windows\System32\java.exe"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_RUN_BUILD_KINDS" value="full,incremental,auto,"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_TOOL_ARGUMENTS" value="-Xmx1g -jar lib/proguard.jar #proguard_windows.txt"/>
<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_TRIGGERS_CONFIGURED" value="true"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${build_project}"/>
</launchConfiguration>
You'll want to put this in .externalToolBuilders/proguard.launch.
The interesting thing here is that it's just a java command, not any kind of shell script, so it's fairly easy to port between Windows/Mac (and I'm assuming Linux, but haven't done that yet), since you're just changing the location of the actual java binary.
(Submitting this as a new answer because it's a bit different than the one that got marked as the correct(ish) answer)
I have been using Proguard to treeshake the Scala library in Eclipse/ADT builds, but it leaves a lot to be desired. It's slow and it messes up the other .class files, so you have to rebuild the project more often than not.
Inspired by these questions and some of the issues in the Android issue tracker, I have made another tool (based on Jar Jar Links) which I now use to treeshake the scala library. With this build step I'm actually fairly happy with the whole Eclipse+ADT Scala on Android situation. Maybe it'll work for you too, give it a spin, it's available from http://code.google.com/p/treeshaker/
If you are comfortable using the Gradle build tool, then the Android plugin for Gradle makes this whole process extremely simple. See: https://github.com/jvoegele/gradle-android-plugin/wiki