How to enable multidex on Android builds?

I’ve just tried to add another library to my project, and it seems that with all the other libs in there I’ve exceeded the dex method limit. 

I’ve seen that I can use multidex to split the dex file into multiple parts, but I’m not sure how I go about this in an Enterprise build:

http://developer.android.com/tools/building/multidex.html

All the docs I see refer to “gradle”, and I’m not sure if Corona Enterprise uses that.

Has anyone else used multidex, and if so could you please give me a few pointers?

Hi,

 

I just wanted to contribute to the discussion. I would also like to get multi-dex support working with the ant build system and Corona Enterprise. This is a question that is also asked in the forums here

 

There are indeed ways to implement multi-dex support in ant. See the answers shown in the link, particularly #2 of the “checkmarked” answer. They involve updating the build.xml file.

 

But our build.xml file is already set up to build Corona Enterprise properly. So integrating these two things is pretty non-trivial, and we were wondering if anyone has any insight, guidance, or experience into doing so. 

Thanks in advance!

Actually the corona build.xml is non different than regular build.xml with additional things added to it by Corona.

You can modify it to suit your needs, only leave the Corona stuff in -pre-build which basically compiles your lua files and certifyBuild in -post-package if you use it. The rest is up to you.

Hi,

 

I just wanted to contribute to the discussion. I would also like to get multi-dex support working with the ant build system and Corona Enterprise. This is a question that is also asked in the forums here

 

There are indeed ways to implement multi-dex support in ant. See the answers shown in the link, particularly #2 of the “checkmarked” answer. They involve updating the build.xml file.

 

But our build.xml file is already set up to build Corona Enterprise properly. So integrating these two things is pretty non-trivial, and we were wondering if anyone has any insight, guidance, or experience into doing so. 

Thanks in advance!

Actually the corona build.xml is non different than regular build.xml with additional things added to it by Corona.

You can modify it to suit your needs, only leave the Corona stuff in -pre-build which basically compiles your lua files and certifyBuild in -post-package if you use it. The rest is up to you.

It’s been a while since I originally posted this, at the time I ended up removing some libraries that were replaced with others, and that took me back under the method limit. I’m now back at this problem, my issue is that I don’t know enough about the build process to know how to modify that build.xml file to use multi dexing.

I followed the link in @davepayne’s post, which led me here: https://github.com/ruboto/ruboto-irb/blob/master/build.xml

I tried modifying my own build.xml using that which gives me this:

\<?xml version="1.0" encoding="UTF-8"?\> \<project name="MyGame" default="help"\> \<property file="local.properties" /\> \<property file="ant.properties" /\> \<loadproperties srcFile="project.properties" /\> \<!-- quick check on sdk.dir --\> \<fail message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through an env var" unless="sdk.dir" /\> \<import file="custom\_rules.xml" optional="true" /\> \<!-- version-tag: custom --\> \<import file="${sdk.dir}/tools/ant/build.xml" /\> \<!-- allow building with debug cert this is only used if ant debug is used in build.sh instead of ant release --\> \<target name="-set-debug-mode" depends="-setup"\> \<!-- record the current build target --\> \<property name="build.target" value="debug" /\> \<if\> \<condition\> \<and\> \<istrue value="${project.is.testapp}" /\> \<istrue value="${emma.enabled}" /\> \</and\> \</condition\> \<then\> \<property name="build.is.instrumented" value="true" /\> \</then\> \<else\> \<property name="build.is.instrumented" value="false" /\> \</else\> \</if\> \<!-- whether the build is a debug build. always set. --\> \<property name="build.is.packaging.debug" value="true" /\> \<!-- signing mode: debug --\> \<property name="build.is.signing.debug" value="false" /\> \<!-- Renderscript optimization level: none --\> \<property name="renderscript.opt.level" value="${renderscript.debug.opt.level}" /\> \</target\> \<!-- BEGIN added multidex stuff --\> \<property name="second\_dex\_file" value="${out.absolute.dir}/classes2.dex" /\> \<macrodef name="multi-dex-helper"\> \<element name="external-libs" optional="yes" /\> \<sequential\> \<union id="out.dex.jar.input.ref.union"\> \<resources refid="out.dex.jar.input.ref"/\> \</union\> \<if\> \<condition\> \<uptodate targetfile="${out.absolute.dir}/classes.dex" \> \<srcfiles dir="${out.classes.absolute.dir}" includes="\*\*/\*.class"/\> \<srcresources refid="out.dex.jar.input.ref.union"/\> \</uptodate\> \</condition\> \<then\> \<echo\>Java classes and jars are unchanged.\</echo\> \</then\> \<else\> \<echo\>Converting compiled files and external libraries into ${out.absolute.dir} (multi-dex)\</echo\> \<delete file="${out.absolute.dir}/classes2.dex"/\> \<echo\>Dexing ${out.classes.absolute.dir} and ${toString:out.dex.jar.input.ref}\</echo\> \<apply executable="${dx}" failonerror="true" parallel="true"\> \<arg value="--dex" /\> \<arg value="--multi-dex" /\> \<arg value="--output=${out.absolute.dir}" /\> \<arg line="${jumbo.option}" /\> \<arg line="${verbose.option}" /\> \<arg path="${out.classes.absolute.dir}" /\> \<path refid="out.dex.jar.input.ref" /\> \<external-libs /\> \</apply\> \<sleep seconds="1"/\> \</else\> \</if\> \</sequential\> \</macrodef\> \<macrodef name="dex-helper"\> \<element name="external-libs" optional="yes" /\> \<attribute name="nolocals" default="false" /\> \<sequential\> \<!-- sets the primary input for dex. If a pre-dex task sets it to something else this has no effect --\> \<property name="out.dex.input.absolute.dir" value="${out.classes.absolute.dir}" /\> \<!-- set the secondary dx input: the project (and library) jar files If a pre-dex task sets it to something else this has no effect --\> \<if\> \<condition\> \<isreference refid="out.dex.jar.input.ref" /\> \</condition\> \<else\> \<path id="out.dex.jar.input.ref"\> \<path refid="project.all.jars.path" /\> \</path\> \</else\> \</if\> \<condition property="verbose.option" value="--verbose" else=""\> \<istrue value="${verbose}" /\> \</condition\> \<condition property="jumbo.option" value="--force-jumbo" else=""\> \<istrue value="${dex.force.jumbo}" /\> \</condition\> \<if\> \<condition\> \<not\> \<available file="${second\_dex\_file}" /\> \</not\> \</condition\> \<then\> \<!-- Regular DEX process. We would prefer to use the Android SDK ANT target, but we need to detect the "use multidex" error. https://android.googlesource.com/platform/sdk/+/tools\_r21.1/anttasks/src/com/android/ant/DexExecTask.java --\> \<mapper id="pre-dex-mapper" type="glob" from="libs/\*.jar" to="bin/dexedLibs/\*-dexed.jar"/\> \<!-- FIXME(uwe): Output something about what we are doing --\> \<apply executable="${dx}" failonerror="true" parallel="false" dest="${out.dexed.absolute.dir}" relative="true"\> \<arg value="--dex" /\> \<arg value="--output" /\> \<targetfile/\> \<arg line="${jumbo.option}" /\> \<arg line="${verbose.option}" /\> \<fileset dir="." includes="libs/\*" /\> \<external-libs /\> \<mapper refid="pre-dex-mapper"/\> \</apply\> \<apply executable="${dx}" resultproperty="dex.merge.result" outputproperty="dex.merge.output" parallel="true"\> \<arg value="--dex" /\> \<arg value="--output=${intermediate.dex.file}" /\> \<arg line="${jumbo.option}" /\> \<arg line="${verbose.option}" /\> \<arg path="${out.classes.absolute.dir}" /\> \<fileset dir="${out.dexed.absolute.dir}" includes="\*-dexed.jar" /\> \<external-libs /\> \</apply\> \<if\> \<condition\> \<contains string="${dex.merge.output}" substring="method ID not in [0, 0xffff]: 65536"/\> \</condition\> \<then\> \<echo message="The package contains too many methods. Switching to multi-dex build." /\> \<multi-dex-helper\> \<external-libs\> \<external-libs/\> \</external-libs\> \</multi-dex-helper\> \</then\> \<else\> \<echo message="${dex.merge.output}"/\> \<fail status="${dex.merge.result}"\> \<condition\> \<not\> \<equals arg1="${dex.merge.result}" arg2="0"/\> \</not\> \</condition\> \</fail\> \</else\> \</if\> \</then\> \<else\> \<multi-dex-helper\> \<external-libs\> \<external-libs/\> \</external-libs\> \</multi-dex-helper\> \</else\> \</if\> \</sequential\> \</macrodef\> \<target name="-package" depends="-dex, -package-resources, -post-package-resources"\> \<!-- only package apk if \*not\* a library project --\> \<do-only-if-not-library elseText="Library project: do not package apk..." \> \<if condition="${build.is.instrumented}"\> \<then\> \<package-helper\> \<extra-jars\> \<!-- Injected from external file --\> \<jarfile path="${emma.dir}/emma\_device.jar" /\> \</extra-jars\> \</package-helper\> \</then\> \<else\> \<package-helper /\> \</else\> \</if\> \</do-only-if-not-library\> \</target\> \<target name="-post-package-resources"\> \<!-- FIXME(uwe): This is hardcoded for one extra dex file. It should iterate over all classes?.dex files --\> \<property name="second\_dex\_path" value="assets/classes2.jar" /\> \<property name="second\_dex\_jar" value="${out.dexed.absolute.dir}/${second\_dex\_path}" /\> \<property name="second\_dex\_copy" value="${out.dexed.absolute.dir}/classes.dex" /\> \<if\> \<condition\> \<and\> \<available file="${second\_dex\_file}" /\> \<or\> \<not\> \<uptodate srcfile="${second\_dex\_file}" targetfile="${out.absolute.dir}/${resource.package.file.name}" /\> \</not\> \<uptodate srcfile="${out.absolute.dir}/${resource.package.file.name}" targetfile="${out.absolute.dir}/${resource.package.file.name}.d" /\> \</or\> \</and\> \</condition\> \<then\> \<echo\>Adding ${second\_dex\_path} to ${resource.package.file.name}\</echo\> \<exec executable="aapt" dir="${out.dexed.absolute.dir}"\> \<arg line='remove -v "${out.absolute.dir}/${resource.package.file.name}" ${second\_dex\_path}'/\> \</exec\> \<copy file="${second\_dex\_file}" tofile="${second\_dex\_copy}"/\> \<mkdir dir="${out.dexed.absolute.dir}/assets"/\> \<zip destfile="${second\_dex\_jar}" basedir="${out.dexed.absolute.dir}" includes="classes.dex" /\> \<delete file="${second\_dex\_copy}"/\> \<!-- FIXME(uwe): Use zip instead of aapt? --\> \<exec executable="aapt" dir="${out.dexed.absolute.dir}" failonerror="true"\> \<arg line='add -v "${out.absolute.dir}/${resource.package.file.name}" ${second\_dex\_path}'/\> \</exec\> \<!-- EMXIF --\> \</then\> \</if\> \</target\> \<!-- END multidex stuff --\> \<!-- Run the "Corona Builder" in the pre-build step. --\> \<target name="-pre-build"\> \<mkdir dir="${basedir}/assets" /\> \<exec executable="${CoronaEnterpriseDir}/Corona/mac/bin/lua" failonerror="true"\> \<arg value="-e" /\> \<arg value="package.path='${CoronaEnterpriseDir}/Corona/shared/bin/?.lua;${CoronaEnterpriseDir}/Corona/shared/bin/?/init.lua;'..package.path" /\> \<arg value="${CoronaEnterpriseDir}/Corona/shared/bin/Compile.lua" /\> \<arg value="mac" /\> \<arg value="${CoronaEnterpriseDir}" /\> \<env key="LUA\_CPATH" value="${CoronaEnterpriseDir}/Corona/mac/bin/?.so"/\> \<env key="TARGET\_PLATFORM" value="android"/\> \<env key="PROJECT\_DIR" value="${basedir}"/\> \<env key="CORONA\_COPY\_PNG\_PRESERVE" value="--preserve"/\> \<env key="CONFIGURATION" value="${ant.project.invoked-targets}"/\> \<env key="CORONA\_ASSETS\_DIR" value="${basedir}/../Corona"/\> \<env key="CORONA\_TARGET\_RESOURCES\_DIR" value="${basedir}/assets"/\> \<env key="CORONA\_TARGET\_EXECUTABLE\_DIR" value="${basedir}/assets"/\> \<env key="BUNDLE\_ID" value="com.mycompany.templateapp"/\> \</exec\> \</target\> \<!-- This certifies the built APK before digitally signing it. --\> \<target name="-post-package"\> \<exec executable="${CoronaEnterpriseDir}/Corona/mac/bin/CertifyBuild.sh" failonerror="true"\> \<env key="CORONA\_APK\_PATH" value="${out.packaged.file}"/\> \<env key="CORONA\_RESOURCE\_CAR\_PATH" value="${basedir}/assets"/\> \</exec\> \</target\> \</project\>

It seemed to build ok, but when I installed and tried to open on my device I get this error:

06-12 14:23:47.166: E/AndroidRuntime(9662): FATAL EXCEPTION: main 06-12 14:23:47.166: E/AndroidRuntime(9662): Process: com.quiztix.mygame, PID: 9662 06-12 14:23:47.166: E/AndroidRuntime(9662): java.lang.RuntimeException: Unable to get provider com.ansca.corona.storage.FileContentProvider: java.lang.ClassNotFoundException: Didn't find class "com.ansca.corona.storage.FileContentProvider" on path: DexPathList[[zip file "/data/app/com.quiztix.mygame-1.apk"],nativeLibraryDirectories=[/data/app-lib/com.quiztix.mygame-1, /vendor/lib, /system/lib]] 06-12 14:23:47.166: E/AndroidRuntime(9662): at android.app.ActivityThread.installProvider(ActivityThread.java:5056) 06-12 14:23:47.166: E/AndroidRuntime(9662): at android.app.ActivityThread.installContentProviders(ActivityThread.java:4648) 06-12 14:23:47.166: E/AndroidRuntime(9662): at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4562) 06-12 14:23:47.166: E/AndroidRuntime(9662): at android.app.ActivityThread.access$1600(ActivityThread.java:161) 06-12 14:23:47.166: E/AndroidRuntime(9662): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1325) 06-12 14:23:47.166: E/AndroidRuntime(9662): at android.os.Handler.dispatchMessage(Handler.java:102) 06-12 14:23:47.166: E/AndroidRuntime(9662): at android.os.Looper.loop(Looper.java:157) 06-12 14:23:47.166: E/AndroidRuntime(9662): at android.app.ActivityThread.main(ActivityThread.java:5356) 06-12 14:23:47.166: E/AndroidRuntime(9662): at java.lang.reflect.Method.invokeNative(Native Method) 06-12 14:23:47.166: E/AndroidRuntime(9662): at java.lang.reflect.Method.invoke(Method.java:515) 06-12 14:23:47.166: E/AndroidRuntime(9662): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1265) 06-12 14:23:47.166: E/AndroidRuntime(9662): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1081) 06-12 14:23:47.166: E/AndroidRuntime(9662): at dalvik.system.NativeStart.main(Native Method) 06-12 14:23:47.166: E/AndroidRuntime(9662): Caused by: java.lang.ClassNotFoundException: Didn't find class "com.ansca.corona.storage.FileContentProvider" on path: DexPathList[[zip file "/data/app/com.quiztix.mygame-1.apk"],nativeLibraryDirectories=[/data/app-lib/com.quiztix.mygame-1, /vendor/lib, /system/lib]] 06-12 14:23:47.166: E/AndroidRuntime(9662): at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:67) 06-12 14:23:47.166: E/AndroidRuntime(9662): at java.lang.ClassLoader.loadClass(ClassLoader.java:497) 06-12 14:23:47.166: E/AndroidRuntime(9662): at java.lang.ClassLoader.loadClass(ClassLoader.java:457) 06-12 14:23:47.166: E/AndroidRuntime(9662): at android.app.ActivityThread.installProvider(ActivityThread.java:5041) 06-12 14:23:47.166: E/AndroidRuntime(9662): ... 12 more 06-12 14:23:47.186: W/ActivityManager(821): Force finishing activity com.quiztix.mygame/com.ansca.corona.CoronaActivity

Is anyone able to give a foolproof guide on how to get it up and running?

I’m unfamiliar with multidex, however I got this error when I didn’t include the Corona.jar in my build [I copy the jar files manually].

Maybe since you have modified the build.xml you will have to copy it over on your own as well?

That seems to have done the trick for me.  

Although it wasn’t just the Corona.jar file I had to copy, I also had to copy:

All contents of armeabi-v7a

JNLua.jar

network.jar

res>raw folder

and also comment out this line in project.properties file:

android.library.reference.1=${CoronaEnterpriseDir}/Corona/android/lib/Corona

It seems to have built and ran correctly, but I’ve only tested it a little bit since I got it working so can’t say for sure.

Can someone from Corona comment on whether making these changes is likely to break anything that I may have overlooked?

Sorry, I thought the only jar needed to resolve your issue the Corona.jar, I too, indeed, had to go through the steps you described.

We have been releasing games this way for almost a year and everything is fine.

What you have to remember is to update the Corona libraries every time you update Corona Enterprise.

Ok that’s great, thanks for letting me know.  

@krystian6  

Have you integrated Facebook login into your app? As soon as I tested FB my app crashed, this was to be expected as my project.properties still had this in it:

android.library.reference.1=../../../../mainrepo/enterprise/Plugins/sdk-facebook/android

which is where I had the facebook project stored.  

I’ve tried taking the libs + res files from the facebook proj and moving them into my project as I did with the Corona files but I then had this error:

06-18 12:03:34.847: I/dalvikvm(24494): Could not find method com.facebook.Session.getActiveSession, referenced from method facebook.FacebookController.facebookLogin 06-18 12:03:34.847: W/dalvikvm(24494): VFY: unable to resolve static method 17239: Lcom/facebook/Session;.getActiveSession ()Lcom/facebook/Session; 06-18 12:03:34.847: D/dalvikvm(24494): VFY: replacing opcode 0x71 at 0x0015 06-18 12:03:34.847: I/dalvikvm(24494): Could not find method com.facebook.Session.getActiveSession, referenced from method facebook.FacebookController.facebookLogout 06-18 12:03:34.847: W/dalvikvm(24494): VFY: unable to resolve static method 17239: Lcom/facebook/Session;.getActiveSession ()Lcom/facebook/Session; 06-18 12:03:34.847: D/dalvikvm(24494): VFY: replacing opcode 0x71 at 0x0000 06-18 12:03:34.847: I/dalvikvm(24494): Could not find method com.facebook.Session.getActiveSession, referenced from method facebook.FacebookController.facebookRequest 06-18 12:03:34.847: W/dalvikvm(24494): VFY: unable to resolve static method 17239: Lcom/facebook/Session;.getActiveSession ()Lcom/facebook/Session; 06-18 12:03:34.847: D/dalvikvm(24494): VFY: replacing opcode 0x71 at 0x0007 06-18 12:03:34.847: I/dalvikvm(24494): Could not find method com.facebook.AppEventsLogger.activateApp, referenced from method facebook.FacebookController.publishInstall 06-18 12:03:34.847: W/dalvikvm(24494): VFY: unable to resolve static method 17217: Lcom/facebook/AppEventsLogger;.activateApp (Landroid/content/Context;Ljava/lang/String;)V 06-18 12:03:34.847: D/dalvikvm(24494): VFY: replacing opcode 0x71 at 0x0004 06-18 12:03:34.847: D/dalvikvm(24494): DexOpt: unable to opt direct call 0x434a at 0x27 in Lfacebook/FacebookController;.facebookLogin 06-18 12:03:34.847: D/dalvikvm(24494): DexOpt: unable to opt direct call 0x4351 at 0x37 in Lfacebook/FacebookController;.facebookLogin 06-18 12:03:34.857: I/dalvikvm(24494): DexOpt: unable to optimize static field ref 0x1857 at 0x3a in Lfacebook/FacebookController;.facebookLogin 06-18 12:03:34.857: I/dalvikvm(24494): Failed resolving Lfacebook/FacebookController$FacebookEventHandler; interface 2555 'Lcom/facebook/Session$StatusCallback;' 06-18 12:03:34.857: W/dalvikvm(24494): Link of class 'Lfacebook/FacebookController$FacebookEventHandler;' failed 06-18 12:03:34.857: D/dalvikvm(24494): DexOpt: unable to opt direct call 0xdfa5 at 0x4d in Lfacebook/FacebookController;.facebookLogin 06-18 12:03:34.857: I/dalvikvm(24494): Failed resolving Lfacebook/FacebookController$FacebookEventHandler; interface 2555 'Lcom/facebook/Session$StatusCallback;' 06-18 12:03:34.857: W/dalvikvm(24494): Link of class 'Lfacebook/FacebookController$FacebookEventHandler;' failed 06-18 12:03:34.857: D/dalvikvm(24494): DexOpt: unable to opt direct call 0xdfa5 at 0x72 in Lfacebook/FacebookController;.facebookLogin 06-18 12:03:34.857: D/dalvikvm(24494): DexOpt: unable to opt direct call 0x4345 at 0x15 in Lfacebook/FacebookController;.facebookRequest 06-18 12:03:34.857: I/dalvikvm(24494): Failed resolving Lfacebook/FacebookController$FacebookRequestCallbackListener; interface 2548 'Lcom/facebook/Request$Callback;' 06-18 12:03:34.857: W/dalvikvm(24494): Link of class 'Lfacebook/FacebookController$FacebookRequestCallbackListener;' failed 06-18 12:03:34.857: D/dalvikvm(24494): DexOpt: unable to opt direct call 0xdfaa at 0x1a in Lfacebook/FacebookController;.facebookRequest 06-18 12:03:34.867: I/Corona(24494): Runtime error 06-18 12:03:34.867: I/Corona(24494): java.lang.NoClassDefFoundError: com.facebook.Session 06-18 12:03:34.867: I/Corona(24494): Java Stack Trace: 06-18 12:03:34.867: I/Corona(24494): facebook.FacebookController.facebookLogin(FacebookController.java:143) 06-18 12:03:34.867: I/Corona(24494): facebook.LuaLoader$LoginWrapper.invoke(LuaLoader.java:98) 06-18 12:03:34.867: I/Corona(24494): com.ansca.corona.JavaToNativeShim.nativeTapEvent(Native Method) 06-18 12:03:34.867: I/Corona(24494): com.ansca.corona.JavaToNativeShim.tapEvent(JavaToNativeShim.java:387) 06-18 12:03:34.867: I/Corona(24494): com.ansca.corona.input.RaiseTapEventTask.executeUsing(RaiseTapEventTask.java:43) 06-18 12:03:34.867: I/Corona(24494): com.ansca.corona.CoronaRuntimeTaskDispatcher$TaskEvent.Send(CoronaRuntimeTaskDispatcher.java:148) 06-18 12:03:34.867: I/Corona(24494): com.ansca.corona.events.EventManager.sendEvents(EventManager.java:91) 06-18 12:03:34.867: I/Corona(24494): com.ansca.corona.Controller.updateRuntimeState(Controller.java:285) 06-18 12:03:34.867: I/Corona(24494): com.ansca.corona.graphics.opengl.CoronaGLSurfaceView$CoronaRenderer.onDrawFrame(CoronaGLSurfaceView.java:417) 06-18 12:03:34.867: I/Corona(24494): com.ansca.corona.graphics.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1622) 06-18 12:03:34.867: I/Corona(24494): com.ansca.corona.graphics.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1377) 06-18 12:03:34.867: I/Corona(24494): stack traceback: 06-18 12:03:34.867: I/Corona(24494): [C]: in function 'newLogin' 06-18 12:03:34.867: I/Corona(24494): ?: in functio

I figured that maybe I needed to copy the src/com/facebook folder into my project but that hasn’t worked either.

The only other thing I can think is to copy those files into src/com/myproj and rename package com.facebook; to package com.quiztix.myapp;  

Thought I’d ask first, in case you have any advice on this.  

Thanks,

Alan

Yeah, I do.

I have facebook sdk copied to a enterprise/plugins/sdk-facebook directory

Then I reference this directory in my project properties:

android.library.reference.1=${CoronaEnterpriseDir}/Plugins/<path to sdk>

and it seems to be working ok.

Please remember to add in the facebook sdk’s project.properties

android.library=true

Also you have to have in your project’s libs directory:

facebook.jar

from Corona’s plugins.

Hmmm. That’s exactly how I had it all setup before implementing multidex. 

I’ve just undone all of today’s changes so that my project matches your description, but I still get the errors posted above. It’s as if it hasn’t linked that facebook project correctly to my own project.

Before implementing multidexing my project.properties contained this:

android.library.reference.1=${CoronaEnterpriseDir}/Corona/android/lib/Corona android.library.reference.2=../../../../mainrepo/enterprise/Plugins/sdk-facebook/android

When I copied across the Corona files as you first suggested, I had to comment out the Corona line above (leaving just the facebook line) otherwise it wouldn’t work. I’m a bit confused why the Facebook line still works for you if you had to manually copy across the Corona files, and why it doesn’t work for me. 

Is there perhaps another setting in your build.xml file or elsewhere that I may have missed out?

Did you have to add the multidex stuff to your facebook sdk’s build.xml file as well?   

I’m running out of ideas about how to get this to work  :frowning:

Sorry Alan,

please bring it to private if you still have issues.

Uhmm… have you actually got the facebook sdk there?

I had to download it manually I think, or get it from some old corona enterprise plugins, now whenever I update corona I have to copy it manually.

PM me and we can take it to skype if you have more issues.

Krystian was kind enough to take a look at this for me, but we’ve had no joy yet.  

Can someone from Corona maybe comment on anything that could be causing this problem?  

There’s more detail in the earlier posts, but to sum it up:

  1. Needed to use multidexing due to dalvik 65536 method limit.

  2. Added multidexing, the apk built successfully but on running it said that some Corona files were missing.  

  3. @krystian6 suggested copying the Corona files from the Enterprise folder into the project, instead of referencing them in project.properties - this worked and the app would run. 

  4. Facebook login now fails - it seems for the same reason that the Corona files did. However I do not seem to be able to just copy the Facebook SDK files into my project, because there are some src/com/facebook files which require the AndroidManifest that is in the Facebook SDK project and I cannot have 2 in my project (unless I’m missing something).

  5. Now stuck as I cannot work out how to include the referenced project in my multidex build.

My CoronaApplication.java contains this:

package com.quiztix.mygame; import android.util.Log; import com.naef.jnlua.LuaState; import android.os.\*; import android.content.Context; import android.support.multidex.\*; public class CoronaApplication extends MultiDexApplication { /\*\* Called when your application has started. \*/ @Override public void onCreate() { // Set up a Corona runtime listener used to add custom APIs to Lua. com.ansca.corona.CoronaEnvironment.addRuntimeListener(new CoronaApplication.CoronaRuntimeEventHandler()); } @Override protected void attachBaseContext(Context base) { super.attachBaseContext(base); MultiDex.install(base); }

I’ve added the android-support-multidex.jar library to my project, and my build.xml is unchanged from my earlier post, and I’ve tried with and without having 

android.library.reference.1=../../../../quiztixmain/enterprise/Plugins/sdk-facebook/android

in my project.properties file (the location of the SDK is valid btw, it’s worked in my project for over a year when not using multidexing).

After trying lots of different things I still can’t get it to detect the FB-sdk project files (for all I know it’s not actually building them in as it would when not using multi-dexing).

If a Corona engineer could give some advice that would be a huge help.

Is anyone from Corona please able to offer some advice on how to get multidex working with Corona+ant?

Again I ended up having to circumvent the problem by removing some lesser used libs, but now I’m at the point where I’m trying to add some more libs but that is causing me to go over the 65536 limit.  

I’m sure one of Corona’s Android engineers will have experience in this, and will know how to get multi-dex working in a project which also has references in it’s project.properties file…but no one from Corona has replied at all to this topic since it was first posted back in January.

It’s been a while since I originally posted this, at the time I ended up removing some libraries that were replaced with others, and that took me back under the method limit. I’m now back at this problem, my issue is that I don’t know enough about the build process to know how to modify that build.xml file to use multi dexing.

I followed the link in @davepayne’s post, which led me here: https://github.com/ruboto/ruboto-irb/blob/master/build.xml

I tried modifying my own build.xml using that which gives me this:

\<?xml version="1.0" encoding="UTF-8"?\> \<project name="MyGame" default="help"\> \<property file="local.properties" /\> \<property file="ant.properties" /\> \<loadproperties srcFile="project.properties" /\> \<!-- quick check on sdk.dir --\> \<fail message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through an env var" unless="sdk.dir" /\> \<import file="custom\_rules.xml" optional="true" /\> \<!-- version-tag: custom --\> \<import file="${sdk.dir}/tools/ant/build.xml" /\> \<!-- allow building with debug cert this is only used if ant debug is used in build.sh instead of ant release --\> \<target name="-set-debug-mode" depends="-setup"\> \<!-- record the current build target --\> \<property name="build.target" value="debug" /\> \<if\> \<condition\> \<and\> \<istrue value="${project.is.testapp}" /\> \<istrue value="${emma.enabled}" /\> \</and\> \</condition\> \<then\> \<property name="build.is.instrumented" value="true" /\> \</then\> \<else\> \<property name="build.is.instrumented" value="false" /\> \</else\> \</if\> \<!-- whether the build is a debug build. always set. --\> \<property name="build.is.packaging.debug" value="true" /\> \<!-- signing mode: debug --\> \<property name="build.is.signing.debug" value="false" /\> \<!-- Renderscript optimization level: none --\> \<property name="renderscript.opt.level" value="${renderscript.debug.opt.level}" /\> \</target\> \<!-- BEGIN added multidex stuff --\> \<property name="second\_dex\_file" value="${out.absolute.dir}/classes2.dex" /\> \<macrodef name="multi-dex-helper"\> \<element name="external-libs" optional="yes" /\> \<sequential\> \<union id="out.dex.jar.input.ref.union"\> \<resources refid="out.dex.jar.input.ref"/\> \</union\> \<if\> \<condition\> \<uptodate targetfile="${out.absolute.dir}/classes.dex" \> \<srcfiles dir="${out.classes.absolute.dir}" includes="\*\*/\*.class"/\> \<srcresources refid="out.dex.jar.input.ref.union"/\> \</uptodate\> \</condition\> \<then\> \<echo\>Java classes and jars are unchanged.\</echo\> \</then\> \<else\> \<echo\>Converting compiled files and external libraries into ${out.absolute.dir} (multi-dex)\</echo\> \<delete file="${out.absolute.dir}/classes2.dex"/\> \<echo\>Dexing ${out.classes.absolute.dir} and ${toString:out.dex.jar.input.ref}\</echo\> \<apply executable="${dx}" failonerror="true" parallel="true"\> \<arg value="--dex" /\> \<arg value="--multi-dex" /\> \<arg value="--output=${out.absolute.dir}" /\> \<arg line="${jumbo.option}" /\> \<arg line="${verbose.option}" /\> \<arg path="${out.classes.absolute.dir}" /\> \<path refid="out.dex.jar.input.ref" /\> \<external-libs /\> \</apply\> \<sleep seconds="1"/\> \</else\> \</if\> \</sequential\> \</macrodef\> \<macrodef name="dex-helper"\> \<element name="external-libs" optional="yes" /\> \<attribute name="nolocals" default="false" /\> \<sequential\> \<!-- sets the primary input for dex. If a pre-dex task sets it to something else this has no effect --\> \<property name="out.dex.input.absolute.dir" value="${out.classes.absolute.dir}" /\> \<!-- set the secondary dx input: the project (and library) jar files If a pre-dex task sets it to something else this has no effect --\> \<if\> \<condition\> \<isreference refid="out.dex.jar.input.ref" /\> \</condition\> \<else\> \<path id="out.dex.jar.input.ref"\> \<path refid="project.all.jars.path" /\> \</path\> \</else\> \</if\> \<condition property="verbose.option" value="--verbose" else=""\> \<istrue value="${verbose}" /\> \</condition\> \<condition property="jumbo.option" value="--force-jumbo" else=""\> \<istrue value="${dex.force.jumbo}" /\> \</condition\> \<if\> \<condition\> \<not\> \<available file="${second\_dex\_file}" /\> \</not\> \</condition\> \<then\> \<!-- Regular DEX process. We would prefer to use the Android SDK ANT target, but we need to detect the "use multidex" error. https://android.googlesource.com/platform/sdk/+/tools\_r21.1/anttasks/src/com/android/ant/DexExecTask.java --\> \<mapper id="pre-dex-mapper" type="glob" from="libs/\*.jar" to="bin/dexedLibs/\*-dexed.jar"/\> \<!-- FIXME(uwe): Output something about what we are doing --\> \<apply executable="${dx}" failonerror="true" parallel="false" dest="${out.dexed.absolute.dir}" relative="true"\> \<arg value="--dex" /\> \<arg value="--output" /\> \<targetfile/\> \<arg line="${jumbo.option}" /\> \<arg line="${verbose.option}" /\> \<fileset dir="." includes="libs/\*" /\> \<external-libs /\> \<mapper refid="pre-dex-mapper"/\> \</apply\> \<apply executable="${dx}" resultproperty="dex.merge.result" outputproperty="dex.merge.output" parallel="true"\> \<arg value="--dex" /\> \<arg value="--output=${intermediate.dex.file}" /\> \<arg line="${jumbo.option}" /\> \<arg line="${verbose.option}" /\> \<arg path="${out.classes.absolute.dir}" /\> \<fileset dir="${out.dexed.absolute.dir}" includes="\*-dexed.jar" /\> \<external-libs /\> \</apply\> \<if\> \<condition\> \<contains string="${dex.merge.output}" substring="method ID not in [0, 0xffff]: 65536"/\> \</condition\> \<then\> \<echo message="The package contains too many methods. Switching to multi-dex build." /\> \<multi-dex-helper\> \<external-libs\> \<external-libs/\> \</external-libs\> \</multi-dex-helper\> \</then\> \<else\> \<echo message="${dex.merge.output}"/\> \<fail status="${dex.merge.result}"\> \<condition\> \<not\> \<equals arg1="${dex.merge.result}" arg2="0"/\> \</not\> \</condition\> \</fail\> \</else\> \</if\> \</then\> \<else\> \<multi-dex-helper\> \<external-libs\> \<external-libs/\> \</external-libs\> \</multi-dex-helper\> \</else\> \</if\> \</sequential\> \</macrodef\> \<target name="-package" depends="-dex, -package-resources, -post-package-resources"\> \<!-- only package apk if \*not\* a library project --\> \<do-only-if-not-library elseText="Library project: do not package apk..." \> \<if condition="${build.is.instrumented}"\> \<then\> \<package-helper\> \<extra-jars\> \<!-- Injected from external file --\> \<jarfile path="${emma.dir}/emma\_device.jar" /\> \</extra-jars\> \</package-helper\> \</then\> \<else\> \<package-helper /\> \</else\> \</if\> \</do-only-if-not-library\> \</target\> \<target name="-post-package-resources"\> \<!-- FIXME(uwe): This is hardcoded for one extra dex file. It should iterate over all classes?.dex files --\> \<property name="second\_dex\_path" value="assets/classes2.jar" /\> \<property name="second\_dex\_jar" value="${out.dexed.absolute.dir}/${second\_dex\_path}" /\> \<property name="second\_dex\_copy" value="${out.dexed.absolute.dir}/classes.dex" /\> \<if\> \<condition\> \<and\> \<available file="${second\_dex\_file}" /\> \<or\> \<not\> \<uptodate srcfile="${second\_dex\_file}" targetfile="${out.absolute.dir}/${resource.package.file.name}" /\> \</not\> \<uptodate srcfile="${out.absolute.dir}/${resource.package.file.name}" targetfile="${out.absolute.dir}/${resource.package.file.name}.d" /\> \</or\> \</and\> \</condition\> \<then\> \<echo\>Adding ${second\_dex\_path} to ${resource.package.file.name}\</echo\> \<exec executable="aapt" dir="${out.dexed.absolute.dir}"\> \<arg line='remove -v "${out.absolute.dir}/${resource.package.file.name}" ${second\_dex\_path}'/\> \</exec\> \<copy file="${second\_dex\_file}" tofile="${second\_dex\_copy}"/\> \<mkdir dir="${out.dexed.absolute.dir}/assets"/\> \<zip destfile="${second\_dex\_jar}" basedir="${out.dexed.absolute.dir}" includes="classes.dex" /\> \<delete file="${second\_dex\_copy}"/\> \<!-- FIXME(uwe): Use zip instead of aapt? --\> \<exec executable="aapt" dir="${out.dexed.absolute.dir}" failonerror="true"\> \<arg line='add -v "${out.absolute.dir}/${resource.package.file.name}" ${second\_dex\_path}'/\> \</exec\> \<!-- EMXIF --\> \</then\> \</if\> \</target\> \<!-- END multidex stuff --\> \<!-- Run the "Corona Builder" in the pre-build step. --\> \<target name="-pre-build"\> \<mkdir dir="${basedir}/assets" /\> \<exec executable="${CoronaEnterpriseDir}/Corona/mac/bin/lua" failonerror="true"\> \<arg value="-e" /\> \<arg value="package.path='${CoronaEnterpriseDir}/Corona/shared/bin/?.lua;${CoronaEnterpriseDir}/Corona/shared/bin/?/init.lua;'..package.path" /\> \<arg value="${CoronaEnterpriseDir}/Corona/shared/bin/Compile.lua" /\> \<arg value="mac" /\> \<arg value="${CoronaEnterpriseDir}" /\> \<env key="LUA\_CPATH" value="${CoronaEnterpriseDir}/Corona/mac/bin/?.so"/\> \<env key="TARGET\_PLATFORM" value="android"/\> \<env key="PROJECT\_DIR" value="${basedir}"/\> \<env key="CORONA\_COPY\_PNG\_PRESERVE" value="--preserve"/\> \<env key="CONFIGURATION" value="${ant.project.invoked-targets}"/\> \<env key="CORONA\_ASSETS\_DIR" value="${basedir}/../Corona"/\> \<env key="CORONA\_TARGET\_RESOURCES\_DIR" value="${basedir}/assets"/\> \<env key="CORONA\_TARGET\_EXECUTABLE\_DIR" value="${basedir}/assets"/\> \<env key="BUNDLE\_ID" value="com.mycompany.templateapp"/\> \</exec\> \</target\> \<!-- This certifies the built APK before digitally signing it. --\> \<target name="-post-package"\> \<exec executable="${CoronaEnterpriseDir}/Corona/mac/bin/CertifyBuild.sh" failonerror="true"\> \<env key="CORONA\_APK\_PATH" value="${out.packaged.file}"/\> \<env key="CORONA\_RESOURCE\_CAR\_PATH" value="${basedir}/assets"/\> \</exec\> \</target\> \</project\>

It seemed to build ok, but when I installed and tried to open on my device I get this error:

06-12 14:23:47.166: E/AndroidRuntime(9662): FATAL EXCEPTION: main 06-12 14:23:47.166: E/AndroidRuntime(9662): Process: com.quiztix.mygame, PID: 9662 06-12 14:23:47.166: E/AndroidRuntime(9662): java.lang.RuntimeException: Unable to get provider com.ansca.corona.storage.FileContentProvider: java.lang.ClassNotFoundException: Didn't find class "com.ansca.corona.storage.FileContentProvider" on path: DexPathList[[zip file "/data/app/com.quiztix.mygame-1.apk"],nativeLibraryDirectories=[/data/app-lib/com.quiztix.mygame-1, /vendor/lib, /system/lib]] 06-12 14:23:47.166: E/AndroidRuntime(9662): at android.app.ActivityThread.installProvider(ActivityThread.java:5056) 06-12 14:23:47.166: E/AndroidRuntime(9662): at android.app.ActivityThread.installContentProviders(ActivityThread.java:4648) 06-12 14:23:47.166: E/AndroidRuntime(9662): at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4562) 06-12 14:23:47.166: E/AndroidRuntime(9662): at android.app.ActivityThread.access$1600(ActivityThread.java:161) 06-12 14:23:47.166: E/AndroidRuntime(9662): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1325) 06-12 14:23:47.166: E/AndroidRuntime(9662): at android.os.Handler.dispatchMessage(Handler.java:102) 06-12 14:23:47.166: E/AndroidRuntime(9662): at android.os.Looper.loop(Looper.java:157) 06-12 14:23:47.166: E/AndroidRuntime(9662): at android.app.ActivityThread.main(ActivityThread.java:5356) 06-12 14:23:47.166: E/AndroidRuntime(9662): at java.lang.reflect.Method.invokeNative(Native Method) 06-12 14:23:47.166: E/AndroidRuntime(9662): at java.lang.reflect.Method.invoke(Method.java:515) 06-12 14:23:47.166: E/AndroidRuntime(9662): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1265) 06-12 14:23:47.166: E/AndroidRuntime(9662): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1081) 06-12 14:23:47.166: E/AndroidRuntime(9662): at dalvik.system.NativeStart.main(Native Method) 06-12 14:23:47.166: E/AndroidRuntime(9662): Caused by: java.lang.ClassNotFoundException: Didn't find class "com.ansca.corona.storage.FileContentProvider" on path: DexPathList[[zip file "/data/app/com.quiztix.mygame-1.apk"],nativeLibraryDirectories=[/data/app-lib/com.quiztix.mygame-1, /vendor/lib, /system/lib]] 06-12 14:23:47.166: E/AndroidRuntime(9662): at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:67) 06-12 14:23:47.166: E/AndroidRuntime(9662): at java.lang.ClassLoader.loadClass(ClassLoader.java:497) 06-12 14:23:47.166: E/AndroidRuntime(9662): at java.lang.ClassLoader.loadClass(ClassLoader.java:457) 06-12 14:23:47.166: E/AndroidRuntime(9662): at android.app.ActivityThread.installProvider(ActivityThread.java:5041) 06-12 14:23:47.166: E/AndroidRuntime(9662): ... 12 more 06-12 14:23:47.186: W/ActivityManager(821): Force finishing activity com.quiztix.mygame/com.ansca.corona.CoronaActivity

Is anyone able to give a foolproof guide on how to get it up and running?

I’m unfamiliar with multidex, however I got this error when I didn’t include the Corona.jar in my build [I copy the jar files manually].

Maybe since you have modified the build.xml you will have to copy it over on your own as well?