How to avoid 65k method limit while using Google Play Services - android

If you find yourself writing a big Android application that depends on many different libraries (which I would recommend instead of reinventing the wheel) it is very likely that you have already come across the 65k method limit of the Dalvik executable file classes.dex. Furthermore, if you depend on large libraries like the Google Play Services SDK which itself in already contained more than 20k methods in version 5.0 you are forced to use tricks like stripping packages or multidex support to avoid errors while packaging. With Android's new runtime ART which is publicly available since Android Lollipop multiple dex files are easier to handle, but currently developers are still forced to do method counting.
What is the simplest way to reduce your application`s method count while using Google Play Services?

The biggest change for developers that came with the 6.5 release of the Google Play Services was probably the Granular Dependency Management. Google managed to split up it's library to allow developers to depend only on certain components which they really need for their apps.
Since version 6.5 developers are no longer forced to implement the complete Google Play Services library in their app, but can selectively depend on components like this:
compile 'com.google.android.gms:play-services-fitness:6.5.+'
compile 'com.google.android.gms:play-services-wearable:6.5.+'
compile 'com.gogole.android.gms:play-services-maps:6.5.+'
...
If you want to compile the complete library into your app, you can still do so:
compile 'com.google.android.gms:play-services:6.5.+'
A complete list of available packages can be found on the Android Developers site.

For someone who do not use Android Studio w/gradle or don't want to implement ProGuard to you project.
It's possible to avoid 65k while using google-play-services
by keeping some packages that you really want to use by using jarjar. For example, in my project I want to implement only google map and google location I lean my google-play-services.jar like this.
Download jarjar HERE
Create new file call 'services.rules'
edit it as follow
keep com.google.android.gms.maps.*
keep com.google.android.gms.location.*
Copy your original google-play-services.jar / jarjar-1.4.jar / services.rules into the same folder
start command prompt and type..
java -jar jarjar-1.4.jar process services.rules google-play-services.jar google-lean.jar
That's it you will get a new .jar that size was reduce a lot (method also)
use it instaed of google-play-services.jar and dex over 56k will gone.
Here is .jar that was lean already as mention above.

I know this question is old but for those of you who face this issue while working on eclipse and cannot use the above answer
please follow the steps
if you don't want to download android studio to get the lib projects
you can download lib files from here
https://www.dropbox.com/s/1pf73czcn7pyqgi/com.google.android.gms.rar?dl=0
and skip to step 4
1 - first of all you still need android studio to download your dependencies
you can download it from here
https://developer.android.com/sdk/index.html
2 - then in your build.gradle inside your app add the below lines
dependencies {
compile 'com.google.android.gms:play-services-maps:7.5.0'
//map , gcm or any specific api for a hole list visit the below link
//https://developers.google.com/android/guides/setup
}
and then hit sync project with gradle file
after that you will get to lib projects
play-services-base
play-services-maps
right click on them to get their path
4 - create project inside eclipse delete the generate files inside src folder
, res folder and manifest
5- copy res and manifest from play-services-base to your project
6 - copy file inside play-services-base/jars to the libs folder of your project
normally named classes.jar (please rename it to any other name so it won't conflict with other project)
7- add this jar to build paths then right click on project / properties / java build path / order and export tab check the added jar
8- right click on project / properties / android / check is lib
9- make the same steps for play-services-maps
10 - now you got to lib projects one is called googleBase and the other is called googleMaps (or any other name)
11 - add them to your project as libraries
now add the following lines to your manifest
<!-- Include required permissions for Google Maps API to run-->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-feature
android:glEsVersion="0x00020000"
android:required="true"/>
<meta-data
android:name="com.google.android.gms.version"
android:value="#integer/google_play_services_version" />
<meta-data
android:name="com.google.android.maps.v2.API_KEY"
android:value="" />
for a complete tutorial with images please refer to below link
http://androidninja.quora.com/Prevent-65-K-Methods-Count-When-Using-Google-Lib-on-Android-with-eclipse-adt

Related

Extra activity entries in manifest due to third party library

I'm using google-play-services library in my app which is a eclipse project.
When final apk creating, it's containing some extra entries in manifest.xml file which is showing as containing ads alert when publishing app.
Extra entries showing like -
<activity android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode"
android:name="com.google.android.gms.ads.AdActivity"
android:theme="#android:style/Theme.Translucent" />
How could we ignore/remove these entries from final apk?
<activity android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode"
android:name="com.google.android.gms.ads.AdActivity"
android:theme="#android:style/Theme.Translucent"
tools:node="remove" />
I think tools:node="remove"can be used for gradle build or will work for eclipse build as well?
It is added by admob library. So if you don't want it and you don't want your app to contain ads, you should exclude admob from your project.
tools:node="remove" is for removing unwanted permission from other libraries that is used in your project and yes, it won't work in eclipse.
UPDATE:
Seems that you are using an old version of google-play-services which contains all modules as a single .jar file. I suggest that you find out which module of google-play-service you need for this project and only add that one with it's dependencies instead of adding all modules of google-play-services as a single jar. And this version you are using possibly is version 8.4.0 of google-play-service (or even older than it) so it is much better to use one of the newer versions.
For using only the module that your project needs and using a latest version of it, you should do as follows. Let's assume that you just need 'play-services-maps`. So you go to
<android-sdk-folder>/extras/google/m2repository/com/google/android/gms/play-services-maps
and open one of the recent versions like 11.0.4 (or less but I suggest to choose one of 10+ versions) and get the .aar file and add it to your eclipse project (if you don't know how to use .aar file in eclipse read this). Also open the play-services-maps-x.x.x.pom file to see what is the other library that maps needs (which are play-services-base and play-services-basement in this example) and go to their folder and add their .aar files to your project too and check their .pom files as well to include tehir dependencies.
Yes, it is kind of tedious job, but it is the way to add this gradle-based-distributed libraries to eclipse.

Correct way to use <uses- library> to create module that depend on an external JAR library

In this page: https://developer.android.com/studio/projects/android-library.html#Considerations
It states that:
You can develop a library module that depends on an external library. (for example, the Maps external library). In this case, the dependent app must build against a target that includes the external library (for example, the Google APIs Add-On). Note also that both the library module and the dependent app must declare the external library in their manifest files, in a element.
So I tried to do what the paragraph says above.
1- I created a module that has this in its gradle:
compile 'com.twitter.sdk.android:twitter-core:3.0.0'
compile 'com.twitter.sdk.android:tweet-ui:3.0.0'
2- and I added this in my manifest.xml
<uses-library
android:name="com.twitter.sdk"
android:required="true"/>
3- I imported my .aar file to my main app.
4- I added the same code into my main app manifest.xml
<uses-library
android:name="com.twitter.sdk"
android:required="true"/>
But of-course it shows an error:
Delete <uses-library> from your manifest. It it only for cases where you are trying to use a "library" that is part of a device's firmware. The "Maps" example that they cite is from the long-obsolete Google Maps V1 for Android implementation.
I am not aware of any device manufacturer that has advised its developers to add <uses-library> elements to their manifest for com.twitter.sdk.

Extract play-services-ads jar from google-play-services 6.5+

Question:
How to extract play-services-ads.jar from google-play-services.jar ?
Background:
Since last update of google play services we may not include whole lib in our project when we need only one part of it source. The problem is that i cant add google-play-services.jar as library dependency in my project, it can be done only as file dependency. So i need somehow add only play-services-ads.jar, not the whole google-play-services.jar to avoid library method limit 65,536.
Using Android Studio, you can take advantage of the split Google Play Services libraries, ensuring you only include the part of Google Play Services necessary for what you need.
In your case, you will need to include the following AARs from AndroidSDK\extras\google\m2repository:
* com.google.android.gms:play-services-ads:6.5.87
* com.google.android.gms:play-services-base:6.5.87
And the following AARs from AndroidSDK\extras\android\m2repository:
* com.android.support:support-v4:21.0.3
Note that these are AARs and not JARs.

Safe way to resolve dependency conflict for Drive and Dropbox?

I would like to integrate my app with a variety of file storage services. I followed the quickstart instructions for the Drive sdk, which adds a bunch of jars to my projects libs directory. Additionally, the Dropbox sdk requires the following list of jars:
commons-logging-1.1.1.jar
dropbox-android-sdk-1.5.3.jar
httpclient-4.0.3.jar
httpcore-4.0.1.jar
httpmime-4.0.3.jar
json-simple-1.1.jar
Once all of these are added to my project, I get the following error when I try to run:
Dex Loader] Unable to execute dex: Multiple dex files define
Lorg/apache/http/entity/mime/FormBodyPart;
If I remove the httpmime jar added for Dropbox, my project runs fine. But is this a safe way to resolve the conflict? Is there an alternative method with which I can build my project and include all the required jars?
Assuming no version conflicts this would work fine. Compare the httpmime-4.0.3.jar to the httpmime jar that Drive added to your libs directory. If they're the same, then it's fine. If they're different, then you'll have to find out the differences between the two and insure that they're not breaking changes. As a last resort you could also repackage one of the SDKs with its required version of httpmime in a jar selectively obfuscated with ProGuard, though that's a hassle.
If you are developing with Eclipse, consider using Google Plugin for Eclipse. It provides a way to add any of the Google's SDK to your app. All the jars are added automatically.

How to get version of referenced internal library from apk

I've created apk by maven + eclipse.
It is a single file and has internal references to libraries given by mvn dependencies. On my android everything works great, but I need to display in runtime version of referenced libs. I know how to display version of my application (from androidManifest.xml), but the problem is to get version of other used library, which in some way is included to my apk.
Inside apk I don't see my referenced jars, I suppose it is made by class.dex.
I found the way to get version from jar lib, but it doesn't work for apk.
Can we found version of internal reference library at run-time?
Let me rephrase your question.
You have developed a mobile app which uses third party library and your goal is to find the version of that third party library from APK.
If i have understood it correctly,
then i faced a similar requirement recently.
Firstly the third party jar's manifest will have version information.
When you built APK this manifest info that contains the version info wont be merged with APK's AndroidManifest file.
AndroidManifest schema does not seem to provide this facility.
In our case we ship the library ,so one probable solution is that we can probably add the version info into metadata element inside activity element in Android Manifest file of the library so that apk when it is built it will copy the activity element from the library's android manifest to the app's android manifest.This way we can pass that version info of a library to main APK's Android Manifest.
May be we can make a request to modify the schema of Android manifest to give provision to include version info of internal library.
Please check the following link.
https://developer.android.com/guide/topics/manifest/manifest-element.html
The other solution could be one can possibly use jarsigner to insert custom entry (that contains info on version of third party library into APK's manifest file after building APK.
Thats again not a standard solution.

Categories

Resources