Proguard setting in eclipse - android

Whats the difference between
proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt
and
proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
when I'm using 1st one its crashing with facebook login, but not when i use second, it'll not crash (in release build).
but size get increase from 4 to 5 MB in second.
I'm using API 21.
Facebook sdk 3.0

Without seeing the contents of the proguard files, I can only guess, but I think it's fair to assume that proguard-project.txt contains definitions to keep class names / methods / members / etc relating to the Facebook SDK.
The reason it's crashing in the 1st setting is because it doesn't include your project's proguard settings, meaning it minifies more than the 2nd setting (including the Facebook SDK). Then, in release, the Facebook SDK is possibly loading a class / invoking a method via reflection or something similar, and crashing because it can't find a method / class name which has been minified.
This is also why the 2nd setting results in a larger binary - minifcation means smaller binary, since every class is being reduced from "SomeLongClassName" to "a". The more you minify, the smaller (and more efficient) the resulting binary is.
Minification is an optimization, and shouldnt (IMO) have a higher priority than code coherence and architecture. If you need to exclude several items from minification (which your ProGuard probably does with the Facebook SDK), then you should, and you shouldn't worry about the resulting APK size.

Related

What makes the minified Hello World Android APK so large - 800KB?

This isn't a general gripe about the bloat of Android apps nowadays*, but a very specific question:
If you install Android Studio 2.3.3 and create the "Hello world" sample app (as described in the Building your first app official tutorial), then build a release APK, the resulting file is 825KB (I tested this on Linux, but I suspect the output is the same on other OSes).
I've already enabled ProGuard and there are no images or other resources.
What goes in that APK by default?
Why?
How can that bloat be taken out?
By comparison, in 2013 a Hello World app was under 10Kb.
* I remember when decent fully-functional apps were a few hundred KBs, and by comparison a PWA like Uber is 1% the size of the corresponding Android app
Exclude all AppCompat libraries and you will see size decrease to about 100kb.
appcompat v7 is automatically attached even if you do not use it at all
In your build.gradle, exclude from "dependencies": compile 'com.android.support:appcompat-v7:26.+
You'll also have to edit res\values\styles.xml to become only this:
<resources><style name="AppTheme" parent="android:Theme.Light"></style></resources>
(make sure to remove the <!-- Customize your theme here. --> lines). Also, in MainActivity.java, change the extends AppCompatActivity part to
public class MainActivity extends Activity
Turns out that by removing all sorts of resources and using insane compression, an empty APK can be brought down to 678 bytes (!).
Thanks to Udayraj Deshmukh for pointing out a blog post detailing how to reduce an Android APK's size by 99.99%.

What's the possible reason of non-custom signed APK (generated via debugging) running fine but the custom signed APK (release) not working?

My Android app is coming to the end. Debugging runs OK for many many times without any error. It runs just fine. It's the time for me to build a release and publish the app. I follow all the steps which can be found via Google easily. In fact the signed APK is installed OK and the app starts OK but if user interacts to navigate between screens of the app, it is crashed for no reason. Not all screen switching causes app crash, just some of them and I can notice that maybe it involves Reflection here. I design my own binding system to bind ViewModel behind with the Fragment and using Reflection is a must, no other way.
I totally believe that it is not any fault in my code because the app runs just fine in debug mode. And at the time of nearly completely losing all hope to publish the app, I found a signed version of the APK file in the debug folder (that signed version is generated only if you start debugging the app to run in some targeted device - even some emulator, building in Debug mode won't generate that file). It's very lucky for me that that signed apk works perfectly. I can deploy that APK to a new device and install normally, the app runs expectedly.
So it must be something wrong with the releasing process. Here is some info about configuration for Release mode (mainly in Android Options tab):
Packaging (Packaging properties): Nothing is checked in here.
Linker: I tried both Sdk assemblies only and Sdk and user assemblies but nothing works.
Advanced properties: I checked all options to support all possible CPU architectures (this should not be a problem because in debug mode, all these options are also checked).
At the beginning of learning Xamarin Android, I tried finding information about publishing Android app and did complete a simple test (to deploy a simple app). It worked OK at that time (maybe because it's too simple), but now when it comes to a complex one (mainly involving my binding system which uses reflection heavily) it can be crashed at some user interactions. I also have a separate library project (containing some custom Views) referenced OK in my main project (not sure if that could be a break, however one custom view is used OK while some others may cause crashing). Because all the crashes happen in a compiled build, I cannot debug anything to see what could be wrong.
No code is provided here because there is too much code, it seems to be crashed at many places and one more important reason is the code should not be the problem (for one reason I explained above - it just runs smoothly in debug mode, I even found a signed APK file in debug folder which can be installed OK and the app then runs just OK like in debug mode).
Since you stated you are using a lot of reflection, the first thing to do is:
In the Android Build Settings:
Disable Proguard if it selected
Change the Linker Options to Don't Link
Rebuild a release build
Update: Since this worked and the app no longer crashes.
The linker will sometimes remove code that you want to preserve.
For example:
You will need to determine what classes and/or method are being remove because that have no direct references and are only called via reflection and preserve those to prevent the linker from removing them.
If they are in your code, you can use the [Preserve] attribute.
If they are 3rd party libs or the Xamarin.Android framework, you can create a "hardcoded" fake reference to those classes/members so the linker sees that you need them.
You might have code that you call dynamically via System.Reflection.MemberInfo.Invoke.
If you instantiate types dynamically, you may want to preserve the default constructor of your types.
If you use XML serialization, you may want to preserve the properties of your types.
Ref: https://developer.xamarin.com/guides/android/advanced_topics/linking/

Proguard Optimization Settings: Enabling class merging, casts and field/* in modern API and Proguard versions

I've been obfuscating my apps for a long while, with the following settings I took like mantras, because they were Google's recommendations
-optimizations !code/simplification/arithmetic,!code/simplification/cast,!field/*,!class/merging/*
However, the other day I commented this line by mistake, the app got built correctly, and "apparently" works. I've made a lot of tests and couldn't made it crash.
So I wonder if those disabled optimization settings are needed ...
as of today's Android SDK and latest Proguard versions, I only target devices from Android 4.0.3 onwards (15), and use Proguard 5.1.
and for applications that don't do exotic stuff and have a properly written proguard.cfg instructing to keep the relevant problematic classes, etc.
Most answers here releated to this very issue have conflicting information, and are related to pretty old API versions.
One by one:
!code/simplification/arithmetic
I found a discussion on Google Groups where they say that simplification/arithmethic is not needed for SDK's after Android Donut. I assume then, I can safely enable this optimization.
!class/merging/*
It looks like proguard makes a good job in my projects with this optimization turned on:
[proguard] Number of vertically merged classes: 296
[proguard] Number of horizontally merged classes: 445
Are there other side effects besides the stack traces being incorrect? I mean, side effects related to the application crashing rather than to debug issues. I found this related question but it doesn't conclude wether it is safe or not.
!field/* and !code/simplification/cast
I read in this question answered by ProGuard's author that those were included to avoid bugs with older Proguard versions. So is it safe to activate them on Proguard 5.1?
General advice: there's no guarantee that optimizations won't work, but there's always a risk. What the default Android proguard settings are attempting to do is provide a configuration that minimizes that risk, hence why they appear so conservative for your specific situation.
Enabling those optimizations just means that if something crashes, you can't be as certain as to the root cause. In general, the proguard step has less strong guarantees about what the outputs should be relative to the inputs, which is a source of non-determinism in your program. Small changes in code can result in significantly different changes in runtime behaviour, and it's not possible to know until you actually run the program, depending on your config.
In summary, if you can run your APK, and it all works - then great, the optimizations work for you. But, they're not guaranteed to.
So is it safe to activate them on Proguard [5.1]?
It's a high risk move and I can give you an example where it causes a problem.
We're using ProGuard 5.2.1 and we're hitting a bug when reenabling the field/* optimization (more specifically, field/removal/writeonly seems to be causing the problem). Our code uses protobuf and enabling that optimization causes ProGuard to fail with this message on the third pass of optimizations:
Optimizing...
Unexpected error while evaluating instruction:
Class = [com/google/protobuf/FieldSet$1]
Method = [()V]
Instruction = [308] isub
Exception = [java.lang.IllegalArgumentException] (Value "com/google/protobuf/WireFormat$JavaType!" is not an integer value [proguard.evaluation.value.TypedReferenceValue])
Unexpected error while performing partial evaluation:
Class = [com/google/protobuf/FieldSet$1]
Method = [()V]
Exception = [java.lang.IllegalArgumentException] (Value "com/google/protobuf/WireFormat$JavaType!" is not an integer value [proguard.evaluation.value.TypedReferenceValue])
Warning: Exception while processing task java.io.IOException: java.lang.IllegalArgumentException: Value "com/google/protobuf/WireFormat$JavaType!" is not an integer value [proguard.evaluation.value.TypedReferenceValue]
This is to say that the fact that these optimizations have been disabled for so many years means that they probably haven't been as well maintained as others. Luckily this was caught at compile time but re-enabling some of these optimizations (e.g. horizontally merging classes via class/merging/*) might easily break your app in certain versions/builds of Android without being properly reported back to you "the developer" (e.g. it might crash dexopts or fail to install altogether with VerifyError).

Running apps containing large amount of code

Background
It seems some old Android OSs (and maybe even the newest ones) have a limitation on the amount of code each app can hold.
As I've found, the limitation is on a buffer called "LinearAlloc" .
On 2.2 or 2.3 it's about 5-8 MB , and I think it's 16 or more on others.
The problem
If you have a too large code (and apps can reach this state), you won't be able to install the app at all on older devices, getting the next error (also reported here) :
Installation error: INSTALL_FAILED_DEXOPT
Please check logcat output for more details.
Launch canceled!
What I've found
One solution is to just remove as much code and libraries as possible, but on some huge projects such a thing is very hard to do.
I've found the next links talking about how Facebook solved this, by somehow increasing the limit:
http://www.slashgear.com/how-facebook-fixed-its-gingerbread-dalvik-problem-04272478/
http://arstechnica.com/business/2013/03/how-facebook-dug-deep-within-android-to-fix-its-mobile-app/
https://www.facebook.com/notes/facebook-engineering/under-the-hood-dalvik-patch-for-facebook-for-android/10151345597798920
Also, Google has posted how to solve it by loading code dynamically :
http://android-developers.blogspot.co.il/2011/07/custom-class-loading-in-dalvik.html
The question
How did Facebook do it?
Is it possible to overcome this in other ways too?
Is there any free library that increases/removes the limitation of this buffer?
What is the limitation on newer Android versions, if there is any?
How do other huge apps (and games) handle this issue? Do they put their code into C/C++?
Would loading the dex files dynamically solve this?
The limit is the total number of method references:
https://code.google.com/p/android/issues/detail?id=7147#c6
https://code.google.com/p/android/issues/detail?id=20814#c6
A middle ground between doing nothing and the multi-dex approach described in the FB/Google articles is to use a tool like ProGuard to remove references to unused code at the Java level. See:
http://proguard.sourceforge.net/
http://developer.android.com/tools/help/proguard.html
There is a new solution, made by Google:
https://plus.google.com/+IanLake/posts/JW9x4pcB1rj?utm_source=Android%20Weekly&utm_campaign=59f1f4bf4d-Android_Weekly_125&utm_medium=email&utm_term=0_4eb677ad19-59f1f4bf4d-337848877
http://developer.android.com/reference/android/support/multidex/MultiDexApplication.html
It seems all you have to do is any of the next things:
- extend from "MultiDexApplication" instead of from "Application"
- call MultiDex.install(context) in your application's attachBaseContext
But now I wonder:
Is that really it?
Does it have any issues ? Does it affect performance?
How does it work?
What should be done with ContentProvider, as it's getting called before Application gets initialized?
The post says "gives you MultiDex support on all API 4+ devices (well, until v21, where you get this natively)" . Does it mean that from v21 it will be the default behavior, or just that the class will be built in and you won't need to use the support library's class ?
Will this solution work on Eclipse too?

Testing the "proguarded" application

First - I am not trying to actually obfuscate my code, only optimize and shrink.
I have checked android developers site, I have looked through proguard documentation and I've googled for a few hours. But I still can't find a definitive answer - how do I actually test that my application keeps working after being "proguarded"?
There is a way to export it, install manually onto emulator, then run, see if it works, fix something (sometimes in proguard configurations, sometimes in code), re-export, re-install. That's a bit tedious.
Shrinked and optimized application is a totally different thing from the application I've tested. I can't be sure it will work properly with such changes until I actually test it. Not being able to actually test the application I'm going to publish means I'm publishing untested application. Which isn't something I'd want to.
And while I can stay away from the proguard, it does reduce my application's size significantly which isn't something I can ignore.
Edit: I understand now that to test application I just have to run acceptance tests on exported package. But there is still the question - how do I test my proguard configuration?
The same way you tested it before you processed it with ProGuard. You'll find that once you get your configuration right the end result will just need one final test to confirm things before deployment.
But I would obfuscate, which reduces size quite a bit and avoid optimizing which I have had introduce bugs a number of times over the years.

Categories

Resources