Sponsored By

Troubleshooting Unity build for Android platform

Listing out the common problems faced when building for Android from Unity with the solutions that worked for me. This should be a handy troubleshooting guide when doing the build.

Shobhit Samaria, Blogger

July 10, 2017

26 Min Read
Game Developer logo in a gray background | Game Developer

So after releasing my games Mr. Mustachio and Mr. Mustachio 2 on iOS, it was time to focus on android build as well. Since I was using Unity, it allows for cross platform development and the same project can be build for Android as well. All that you have to do is switch the build platform, set the appropriate keys and passwords, set the android sdk paths and hit the build button. Unity will build the apk for you to distribute! If you have a small project, this should work beautifully. However, chances are that it won’t be as simple as that. A bit complex project is likely to run into a few issues before you get the final build. I ran into a quite a few and spent a few days fixing all the stuff before managing to get the build up and running. It was apparent that quite a few people were facing the same issues on the internet. In order to help out people who could possibly run into the same issues, I am going to list them out with the solutions.

 

The setup:

Unity 5.6.0f3,  Android Studio 2.3, MacOS Sierra

 

1.   Unable to list target platforms.

So to build for Android, you need to install the Android SDK. The usual way to do it is to install the Android Studio which does all the work for you by installing the latest SDK usually on the default path of <user>/Library/Android. Then you correctly setup the path to the android SDK in the Unity preferences and eagerly hit the build button! And you hit the first roadblock :(

The build does not take off and you see this error message :

Unable to list target platforms. Please make sure the android sdk path is correct.

Solution : No need to double check the sdk path as it would be correct (actually it wouldn’t hurt to make sure!). The problem sems to be that unity is compatible with a certain version of Android SDK Tools (<user>/Library/Android/sdk/tools). Now Android Studio would have installed the latest version which doesn’t work with Unity. So you have to downgrade the SDK Tools. First download the compatible SDK Tools version. I found that 25.2.5 worked for me. But I doesn’t seem to be available for download now. Hopefully 25.0.1 should work.

https://dl.google.com/android/repository/build-tools_r25.0.1-macosx.zip

(google for links to download windows or linux versions)

Unzip the file and replace the ‘tools’ folder in your Android SDK location (<user>/Library/Android/sdk/tools). Rerun the build and this time it should not give this error.

Of course, now the Android SDK Manager will complain that the latest build tools are not installed. For this, I keep two Android SDK folders in my Library, one for the Android Studio with the latest build tools and one for Unity with downgraded tools folder. Hopefully this should not be an issue in the newer versions of Unity.

Helpful Link : https://forum.unity3d.com/threads/android-deployment-error.444133/#post-2876464

 

2. Merging the different AndroidManifest.xml of the various plugins

This is not a problem but just a caution. It is very likely that multiple plugins are being used in your project. Some plugins would need to make some changes or additions to the main AndroidManifest.xml. Some plugins like Facebook, Google Play Games, Fabric etc provide a button in their settings to update the xml file. Some plugins (like Heyzap etc.) might provide you a copy of AndroidManifest.xml and ask you to put it in your Assets/Plugins/Android/ folder. You need to be careful in this regard to ensure that all the changes required by all the plugins are in the final main AndroidManifest.xml. There is no easy way to do it. You just have to be careful and observe what changes each plugin makes to the xml and ensure that those changes do not get overwritten or changed or removed.

 

3a. Unable to merge android manifests. See the Console for more details.

So the build is commencing peacefully and all looks good and suddenly you get this dreaded message. Arghh…

This means that in your project under Assets/Plugins/Android there are multiple AndroidManifest.xml files, probably from the different plugins that you use.

Solution : This is a nasty one as there is no quick fix for this. Unfortunately this means you have to go through them all and sort out the conflicts so that only one xml file has the correct attributes. Going through the console log gives you the idea what exactly is the conflict so that part becomes easy.

For instance I had a plugin that had “android:icon=”@drawable/app_icon” android:label=”@string/app_name”” in its android manifest while I also had them in my main AndroidManifest.xml with the values changed. So I had to remove the attributes from the plugin xml and kept them only in my main xml.

 

3b. Unable to merge android manifests. See the Console for more details.

Again? Yes you might have resolved all conflicts in the visible android manifest xml or you may not have been able to find the conflicts and you run the build again and you receive this message again! Well there are some ‘hidden’ xmls as well. There are several ways a plugin can be provided in Unity. The plugin can be a Android Library project which is a folder with a special structure and an AndroidManifest.xml in its base and a project.properties file which contains the string android.library=true. This xml is visible and can be easily changed by us. However the plugin can also be an Android Archive (aar) which is a zip file with all the resources. There is a manifest xml within this aar as well and that gets merged as well and if there is a conflict in there, then it needs to resolved as well.

Solution : If the conflict can be resolved by changing the main AndroidManifest.xml then good enough. But if that does not help, then you have to change the xml within the jar as well. Copy the aar file somewhere. Change its extension to zip file. Unzip it and make the necessary changes to the AndroidManifest.xml inside it. Now we have to recreate the aar file. We should just zip the folder and change the extension to jar, right? Well no. That doesn’t work. You have to recreate the jar by using the java ‘jar’ command.

jar cvf plugin.aar -C PluginFolder/ .

Once done, make sure that the jar opens correctly and there is an AndroidManifest.xml in the root. Ensure that there are no extra files such as hidden .meta files.

Replace the plugin’s aar file in your project with the new aar file just created. This should resolve the conflicts.

Helpful Link : http://stackoverflow.com/questions/38860912/modifying-contents-of-android-aar-file-converting-to-and-from-zip-format

 

4. Error building Player: IOException: android-support-v4.jar already exists

The jar name might change but the error would remain the same. All the plugins would require some jars especially the ones from the android sdk. It is very likely that the same jar would be provided by multiple plugins resulting in a build error pointing out the duplicate jar.

Solution : The solution is pretty straightforward. The duplicate jar name is present in the build error. Using that you need to search the Assets/Plugins/Android folder for the similarly named jars. Keep only one copy and remove the unnecessary ones. If you are using Google Play Games plugin which uses the PlayServicesResolver (or any other plugin that uses it), then you will find that there is an AssetPostProcessor which automatically adds android sdk jars which are required. They are added back even if you delete them. So it is better to delete the jars in the other locations such as the Facebook plugin folder etc. These jars are usually versioned so make sure to keep the correct or the higher version of the jar.

 

5. Multiple PlayServicesResolver provided by various plugins

PlayServicesResolver is a google provided solution for play services jar management to ensure correct jars of the correct version are present in your project. However this can cause a problem if several plugins provide it PlayServicesResolver in the unity package leading to an import at the same location and resulting in compile errors.

Solution : I solved this problem by importing the plugins separately in different projects and then merging the DependencyResolver manually. There is usually a file in the package which defines which which jars are needed to maintained and resolved. I usually keep the Google Play plugin’s resolver and there is a file called GPGSDependencies.cs which defines the jars needed for Google Play Games plugin. I just append the jars needed by other plugins in this file itself. I do have to careful when updating the plugins so that the changes are not lost on an update. But this works for now. I only faced this issue once and should be a rare occurrence for many.

 

6. Dex limit error : Too many field references: 131000; max is 65536.

If you are using several plugins, Google Play Game Services, have some ad sdks added (which is very likely these days), then you are very likely to run into this error. This error basically means that your app uses more than 64K java methods which is an upper limit and the build fails. There is a whole lot of stuff on the internet explaining what the dex limit is and why it happens, so I won’t be going into any of that stuff. The problem is that you have too many methods and the build is complaining about that.

Solution :

a) First check if you can reduce the method count by removing any unused plugins which you don’t need. This is unlikely to happen or even solve the issue but is worth a try.

b) If that doesn’t work, then the next recommended option is to use Progaurd. Proguard is a tool used to obfuscate and trim unused classes and methods. It is not enabled by default in Unity. So you have to make certain changes to make it happen. It can not be enabled using the ‘Internal (default)’ build option provided by Unity. You will have to use the new ‘Gradle Build’ option. This build works using gradle build file which Unity provides by default. We will have to override this build file and add some options to it to enable Progaurd. This can be done easily. There is a template file in the following location : <Unity Location>/PlaybackEngines/AndroidPlayer/Tools/GradleTemplates/mainTemplate.gradle. Copy this template file and paste it in your project Assets/Plugins/Android folder. This step overrides the default gradle template (see https://docs.unity3d.com/Manual/android-gradle-overview.html). In the new template file, just change the minifyEnabled option to true.

 

buildTypes {

debug {

jniDebuggable true

}

release {

// Set minifyEnabled to true if you want to run ProGuard on your project

minifyEnabled true

proguardFiles getDefaultProguardFile(‘proguard-android.txt’), ‘proguard-unity.txt’

**SIGNCONFIG**

}

}

 

Now Progaurd may strip out the code which you actually need leading to ClassDefinitionNotFound errors or random crashes or just that functionality doesn’t work as intended. This is solved by providing progaurdFiles (see above in the build file just below the minifyEnabled option). These files provide configuration regarding the class files we need to keep. See https://www.guardsquare.com/en/proguard/manual/usage for more information on how to provide this information in the config file. The android sdk and unity classes already have predefined config files which are automatically added in the build file as seen above. But the additional plugins that you add need to be protected by you. You can start by checking the documentation of the plugins you use to check if they provide any progaurd files. If they do, then copy them over to you project and add it to the list of progaurdFiles in the build file (comma seperated list).

So how do we ensure that everything works correctly and nothing important has been stripped off? Well, the honest answer is I don’t know. I tried really hard but failed to get Progaurd working on my project. Progaurd not only strips but also obfuscates the code i.e. it changes the names of methods and classes for protection. However this leads to some problems in native calls to methods in some plugins. I tried many options in the config files, went through the Progaurd documentation, quite a bit of stuff on the stack-overflow but I couldn’t figure out a definitive way of solving my problem. It also generates some logs showing which files have been stripped and which have been included etc. but the sheer size of the logs is overwhelming. My app kept crashing and I never could figure out why. After several tries, I gave up. especially since the other method (multidex option) looked much simpler and much more robust.

c) Use the Multidex option — https://developer.android.com/studio/build/multidex.html . If you are targeting Android 4.0 and above, then this option can be used.

Again it is not enabled by default in Unity. So you have to make certain changes to make it happen. It can not be enabled using the ‘Internal (default)’ build option provided by Unity. You will have to use the new ‘Gradle Build’ option. This build works using gradle build file which Unity provides by default. We will have to override this build file and add some options to it to enable multidex. This can be done easily. There is a template file in the following location : <Unity Location>/PlaybackEngines/AndroidPlayer/Tools/GradleTemplates/mainTemplate.gradle. Copy this template file and paste it in your project Assets/Plugins/Android folder. This step overrides the default gradle template (see https://docs.unity3d.com/Manual/android-gradle-overview.html). In the new build file just add the multiDexEnabled true in the defaultConfig section:

 

defaultConfig {

minSdkVersion 15

targetSdkVersion **TARGETSDKVERSION**

multiDexEnabled true

}

 

If the minimum SDK version that you are targeting is 21 or higher, then this is all that you have to do!

If your target SDK version is lower, then a couple of extra steps needed to be done. Add compile ‘com.android.support:multidex:1.0.1’ to the dependencies section like shown below.

 

dependencies {

compile fileTree(dir: ‘libs’, include: [‘*.jar’])

compile ‘com.android.support:multidex:1.0.1’

**DEPS**}

 

Then in the main AndroidManifest.xml in Assets/Plugins/Android location, make the following change

 

<?xml version=”1.0" encoding=”utf-8"?>

<manifest xmlns:android=”http://schemas.android.com/apk/res/android";

package=”com.example.myapp”>

<application

android:name=”android.support.multidex.MultiDexApplication” >

</application>

</manifest>

 

This step can be a bit of a problem if you are using a custom Android Application class already or some plugin that you use, uses a custom Application class. If the class is a custom class which you have created, then a simple solution is to extend it from MultiDexApplication instead of just Application.

 

public class MyApplication extends MultiDexApplication { … }

 

and use it in manifest android:name=“com.samaria.multidex.MyApplication” >

If the class is a third party plugin class then you cannot extend it directly. So you have to take a longer route.

* Open a new project in Android Studio.

* Add a new Android Archive Module.

* The plugin which has the application class would have provided a jar which contains the .class file either as a jar itself or within an jar. Find which jar it is.

* Create a folder ‘Libraries’ in your android project. Paste the jar in that folder (or copy all of them if you can’t pinpoint the correct one).

* Right click on the jar(s) and select the option ‘Add as Library’ and select the module in the next dropdown. (https://stackoverflow.com/questions/25610727/adding-external-library-in-android-studio)

* Right click on the module and select ‘Open Module Settings’. In the dialog box that appears, select the dependencies tab. Locate all the jars that you have added and change their scope to ‘Provided’. This is important as you don’t want to have multiple copies of these jars included in your final build.

* In dependencies tab, click on the ‘+” sign at the bottom and select ‘Library Dependency’. In the next popup, add the com.android.support:multidex:1.0.1 dependency. Click OK and close the module settings.

* Create a new java class inside the module — MyApplication

* Extend this class from the plugin’s Application class and add the following piece of code to the class

 

public class MyApplication extends SomeOtherApplication {

@Override

protected void attachBaseContext(Context base) {

super.attachBaseContext(base);

MultiDex.install(this);

}

}

 

* Save the class and build the module. You will find the built aar file in the build/output folder.

* Copy the jar file into your unity projects Assets/Plugins/Android folder.

* Change your manifest xml and add android:name=“com.samaria.multidex.MyApplication” >

* This enables multidex on your android build!

Go ahead and build the project and run it on a device. Chances are that your troubles aren’t over as yet! The game would probably crash before starting. The problem here is that in an multidex environment, there are multiple dex files but the primary dex file should contain the classes that are needed at the startup.

So how do we define which classes to keep in the primary dex file? There are two options — add multiDexKeepFile or the multiDexKeepProguard property in your build file. multiDexKeepFile option lets you define a config file in which you can list out individual files that need to be put in the primary dex file. On the other hand multiDexKeepProguard lets you define a config file in which you can define which classes to keep using the Progaurd keep rules (https://www.guardsquare.com/en/proguard/manual/usage#keepoptions) which are far more powerful than defining all the individual classes. So create a new text file multidexKeepConfig.txt and add the following lines to the new cradle build template file:

 

buildTypes {

debug {

jniDebuggable true

}

release {

// Set minifyEnabled to true if you want to run ProGuard on your project

minifyEnabled false

multiDexKeepProguard file(‘multidexKeepConfig.txt’)

**SIGNCONFIG**

}

}

 

In the multidexKeepConfig.txt, you will have to define which files to keep. I assumed all the unity classes should be needed upfront. I have used Fabric and it uses a custom Android Application class which I have extended to add multidex support as shown above. Also just going through my manifest.xml, I found a few classes being used in it and based on all this information I added the following lines to my config file:

 

-keep public class com.crashlytics.** {

public *;

}

-keep public class io.fabric.** {

public *;

}

-keep class com.unity3d.* { *; }

-keep class com.shobhitsamaria.** {*;}

 

Remember that Gradle reads paths relative to the build.gradle file, so the above example works if multidexKeepConfig.txt is in the same directory as the build.gradle file. Now when I build and run the game on android device, it works perfectly! There are some limitations to multidex — read more about it at — https://developer.android.com/studio/build/multidex.html and then decide whether this option is suitable for you.

Also when using the progaurd or the multidex option, you are very likely to run into gradle and android gradle plugin versioning. See the problem number 9 below for an explanation and the solution. Basically you won’t be able to export an app directly but will have to export the build as an Android Project and then use Android Studio to generate an apk.

 

7. Error converting bytecode to dex: Cause: com.android.dex.DexException: Multiple dex files define Lcom/android/vending/billing/BuildConfig

The path to the BuildConfig file may change in the exception but the error remains the same. The problem is that if a plugin is provided as an Android Library Project i.e it has an AndroidManifest.xml, jars and project.properties with android.library=true, then it is compiled into a aar file during the build process. The build process creates a BuildConfig.class file in the location specified by the manifest xml’s ‘package’ property. Sometimes the jar files themselves contain a BuildConfig.class file at the same location which results in multiple files at the same location leading to a build error.

Solution : There is one easy solution and one that requires a bit more hard work. The easy solution is to change the package name in the AndroidManifest.xml of the plugin! That should fix it but I have no idea what other problems this could bring. The second solution is to remove the BuildConfig files from the jar itself. Removing these files causes no problems as they are just build related and stripping them off is not an issue. The java jar files are actually just zip files, therefore the powerful ‘zip’ console command can be used to remove the BuildConfig files easily. See the link below.

Helpful Link : https://stackoverflow.com/questions/4520822/is-there-a-quick-way-to-delete-a-file-from-a-jar-war-without-having-to-extract

https://forum.unity3d.com/threads/android-project-multiple-dex-files-define-lcom-android-vending-billing-buildconfig.408823/

 

8. No resource found that matches the given name (at ‘value’ with value ‘@integer/google_play_services_version’)

If you are developing a game for Android, you very likely would be using Google Play Services for leaderboards, achievements etc. And for that you might be using Google’s Play Services plugin for Unity (https://github.com/playgameservices/play-games-plugin-for-unity) which uses Unity’s Social API for easier cross platform development. This plugin puts in Android Library Project named MainLibProject which has an AndroidManifest.xml which has the following line:

<meta-data android:name=”com.google.android.gms.version” android:value=”@integer/google_play_services_version” />

The google_play_services_version is a placeholder which expects a value to be put in during the build process. You don’t have to explicitly supply the value but it needs to be available in some other xml. So where can this value be found? This value is found in the play-services-basement aar which include a values.xml which defines the value.

<integer name=”google_play_services_version”>10298000</integer>

This basement aar gets included as part of Google Play Services Plugin but when we build we get the above mentioned error.

Solution : The easiest solution is to comment out or delete the <meta-data android:name=”com.google.android.gms.version” android:value=”@integer/google_play_services_version” /> line from the mainLibProject’s xml. I tried that. The project worked just fine. No issues at all! Going through the documentation : https://developers.google.com/android/guides/setup— it says that this line needs to be included when we are using the play services lib located at <android-sdk>/extras/google/google_play_services/libproject/google-play-services_lib/. Now this lib is no longer available and we have to use the split up library components and the docs do not mention that we need to add the version number in the manifest xml.

But it is always better to be safe than sorry. So the second method which solves the problem and also keeps the version value is : Remove or comment out the version value line from the MainLibProject’s AndroidManifest.xml and move it one level above into your project’s main AndroidManifest.xml (Assets/Plugins/Android/AndroidManifest.xml). Here’s what I think happens. The MainLibProject during the build process is converted into an aar. During the compilation, it fails to find the google_play_services_version value as the play-services-basement aar is outside of this library project! The build process fails with the above given error. So moving the line out of this xml into the main project’s xml works just fine as the main project build has the access to the basement bar and is able to correctly populate the value in the manifest xml.

This solution worked for me but if there is any fault in this, then I would gladly like to be corrected.

 

9. Gradle Build error : could not find method multiDexKeepProguard() with argument [file]

I am just writing this error out of memory but it would be somewhat similar. If you see something like this, the issue is likely to be a versioning issue with the Android Gradle Build plugin (https://developer.android.com/studio/releases/gradle-plugin.html) and Gradle version being used. The unity installation package comes with Gradle installation and a gradle build file template which has a specific android gradle plugin version defined. The versions are 2.10 for the android gradle plugin and 2.14 for Gradle itself.

If you are using multidex option with multiDexKeepProguard file, then it won’t work with these versions and throw up the above kind of error.

Solution : You can not and should not change anything that comes with the Unity installation. So the only thing you can do is to change stuff manually by exporting the build as a project and not exporting directly as an apk. On the build settings popup, chose the new ‘Gradle build’ option with the ‘Export as Project’ checkbox checked. The Unity gradle build file defines the version of Android Gradle plugin to use. Something like:

 

dependencies {

classpath ‘com.android.tools.build:gradle:2.1.0’

}

 

To use a different version of the plugin, we need to create a new gradle build file and override the existing one. This can be done easily. There is a template file in the following location : <Unity Location>/PlaybackEngines/AndroidPlayer/Tools/GradleTemplates/mainTemplate.gradle. Copy this template file and paste it in your project Assets/Plugins/Android folder. This step overrides the default gradle template. More about it — https://docs.unity3d.com/Manual/android-gradle-overview.html. Change the dependency version in the newly created file:

 

dependencies {

classpath ‘com.android.tools.build:gradle:2.3.2’

}

 

The build process downloads the dependencies if it does not exist. Also the Android Gradle plugin works with specific Gradle versions only. So you might have to install a different gradle version as well. You can check which version is needed by going through the change log — https://developer.android.com/studio/releases/gradle-plugin.html

The steps to install cradle can be found at : https://gradle.org/install/ and setup the gradle path in the Android Studio. When you open a project in Android Studio, it itself tells you to use latest Cradle and offers to change the required stuff for you.

 

10. Gradle Build failed : java.lang.OutOfMemoryError: Java heap space

So near! and you get this awful error. Everything is setup perfectly, all above build errors have been resolved. In the Android Studio, you hit the ‘Generate Signed APK’ button and everything is building and suddenly you get this Out of Memory error. Well, it turns out you have to define how much memory the gradle build process can use up and sometimes it is not enough. The build process just breaks down when memory is exhausted.

Solution : You have to explicitly increase the amount of memory Gradle build can use. For this you have to create a gradle.properties file in the same folder where your build.gradle file lies. Add the following line to the properties file.

org.gradle.jvmargs=-Xmx1536M

That’s it! Now try to generate the app again and this time everything should build perfectly! Congratulations! You have successfully generated the apk for the Android Platform.

 

11. Google App Signing Issue with Play Game Services

Now a typical workflow for configuring and testing the Google Play Services leaderboards, achievements etc would be to first setup the plugin and make the code related changes. Next up you would create the local keystore and keys to sign the apk. Using the SHA1 fingerprint from the keystone, you will create a linked Android App in the Game Services console. The linked app id would be put in the android manifest. Generate the signed app and deploy it onto a test device and it would work perfectly.

Now you would want to alpha/beta test your app or deploy to production. For that, you need to upload the app to Google Play Console. During this process you agree for Google App Signing, whereby Google keeps track of your upload keys and strips them out of the app and then signs the apk with another key. Now you open up the deployed app for alpha/beta testing. You download the app from the play store and you find that the app either hangs or crashes or works but the Google Play Services are not working. The problem is that the SHA1 fingerprint used to create the linked Android app should be from the keystore used to sign the Unity application. Unfortunately when using the Google App Signing, the uploaded key is removed and Google uses another key to sign the application. This leads to a mismatch which results in this error.

Solution : The problem lies in the created Linked App which uses the wrong SHA1 fingerprint. I solved the problem by taking a longer route. Go to the Google developer console. Under Credentials, you will find the OAuth client id for your Linked App. (https://console.developers.google.com/apis/credentials) Delete it. Go to the Game Services console and delete the linked app. (https://play.google.com/apps/publish/) Recreate the linked app and this time give the SHA1 fingerprint of the Google signing key which is available on the release dashboard of the play console. Google generates the same app id as before so no changes have to be made code wise. (atlas that’s what happened in my case).

However, a simpler solution would be to just edit the OAuth client id and provide the new SHA1 there. So go to the Google developer console and under Credentials, find the OAuth Client Id for the linked app and instead of deleting it, edit it. Change the SHA1 to that of the new signing key and save. This should work the same way as above although I haven’t tested it out.

 

That’s it! Thats all the issues I remember which I came across while trying to build for Android. I hope I have been able to create a handy little troubleshooting guide for building for Android platform on Unity.

 

If you liked this article and found it useful, then do take some time out and try out my games Mr. Mustachio (iOS) and Mr. Mustachio 2 (iOS, Android) and don’t forget to provide your honest rating and review! Thanks for reading!

Read more about:

Blogs
Daily news, dev blogs, and stories from Game Developer straight to your inbox

You May Also Like