2

I'm working on an Android game, built with Unity (5.4.3), which uses many plugins. As a result of this, we are now hitting the DEX limit which limits the number of method calls to less than 65536 (see How to shrink code - 65k method limit in dex). We're over the limit resulting in build errors. ("trouble writing output: Too many field references: 68467; max is 65536.").

I am trying to see if any plugins are not used, but at the moment I am just randomly removing .jar and .aar files and then hitting 'build' again. I am having difficulty in finding a scientific way to figure out which plugins may not be used.

I know I can use multidex, but such approaches involve getting our project building with Android Studio, which seems like a big task. In order to try and get the game building again asap, I'd like to try and remove any unused/unreferenced plugins.

Thanks.

Community
  • 1
  • 1
  • Don't know why you got the down vote, it's a perfectly valid question – jmcorallo May 15 '17 at 11:42
  • Thanks @jmcorallo. I'm reasonably new to Android development, so I'm having to learn about the idiosyncrasies of Android! Hopefully the question is legitimate, but I'm hoping to improve my Android knowledge. – FinbarSaunders May 15 '17 at 13:02

2 Answers2

1

A better way than randomly removing files would be the following. To use a plugin from C# you need to write:

[DllImport ("PluginName")]
private static extern float FooPluginFunction ();

So you can search all your code for DllImport, and there you can find which ones are used.

It's not a perfect method, but it seems better than just taking things randomly ;)

Update:

Also look for AndroidJavaObject

jmcorallo
  • 334
  • 4
  • 12
  • Please explain how what you have in your answer can be used to find if plugins are being used or not. Remember that plugins could be a third party code written in C++, Java, or Objective-C. – Programmer May 15 '17 at 11:53
  • @Programmer you check which plugins are being referenced by your scripts (optionally you could also check if you script is actually being used). He was *"just randomly removing .jar and .aar files and then hitting 'build' again"*. Like I said, it's not a perfect method, but you can make a list of plugins that you do know for certain that they are being used, and then try deleting the others – jmcorallo May 15 '17 at 12:09
  • The .jar and .aar plugins don't use DllImport so this shouldn't even be an answer – Programmer May 15 '17 at 12:14
  • Thanks you're right, DllImport is for NDK. I updated the answer – jmcorallo May 15 '17 at 12:26
1

The problem with your question is it's really hard to define "which plugins may not be used"...

Simply because a plugin may be referenced in a script means the plugin may be used? Or does the script need to be referenced as well somewhere else?

I mean: let's take the example of a plugin being referenced in a non-MonoBehaviour class that is itself referenced in another MonoBehaviour class. You may not be using the MonoBehaviour class nor the non-MonoBehaviour one: but if you delete the plugin, you will have to either delete the two classes or adapt them (using scripting define symbols maybe).

A quick example of something that could be used would be this:

    List<string> pluginsNotUsed = new List<string>();
    UnityEditor.PluginImporter[] importers = UnityEditor.PluginImporter.GetAllImporters();
    for(int i = 0; i < importers.Length; i++)
    {
        if(!pluginsNotUsed.Contains(importers[i].assetPath))
        {
            pluginsNotUsed.Add(importers[i].assetPath);
        }
    }

    // ---- This part removes the plugins that match the current targeted build platform
    importers = UnityEditor.PluginImporter.GetImporters(UnityEditor.EditorUserBuildSettings.activeBuildTarget);
    for(int i = 0; i < importers.Length; i++)
    {
        if(pluginsNotUsed.Contains(importers[i].assetPath))
        {
            pluginsNotUsed.Remove(importers[i].assetPath);
        }
    }
    // ----

    Object obj = null;
    for(int i = 0; i < pluginsNotUsed.Count; i++)
    {
        // Remove this condition if you want to display all the loaded plugins
        // (including the ones installed withy Unity: C:/Program Files/Unity/Editor/Data/UnityExtensions/Unity/...)
        if(pluginsNotUsed[i].StartsWith("Assets/"))
        {
            obj = UnityEditor.AssetDatabase.LoadAssetAtPath(pluginsNotUsed[i], UnityEditor.AssetDatabase.GetMainAssetTypeAtPath(pluginsNotUsed[i]));
            Debug.Log(pluginsNotUsed[i], obj);
        }
    }

This piece of script will list you all the loaded plugins that are not set to support your current targeted build platform (and that therefore should not be used).
In addition to that you could go further and check for all the loaded plugins that match your current targeted build platform (remove the middle part and use GetImporters(UnityEditor.EditorUserBuildSettings.activeBuildTarget);) and then use some kind of parsing to check in your current solution for references to the found plugins.

Keep in mind what I suggested last will be hard to automate: not even sure there is a way to retrieve all the methods exposed in a plugin in order to check for them in your files. Furthermore you will have to check if the class in which you found such references are used in one of your project scenes or prefabs if you want to be sure you can delete it safely.

Well sorry for the wall of text, also I know I didn't really answered your question but I hope I gave you the right direction :)

Hope this helps,

Kardux
  • 2,117
  • 1
  • 18
  • 20