How to add multidex support to appinventor

Hello community, these days I have been developing an extension for appinventor to support the new API DialogFlow v2 for Java. To make use of DialogFlow v2 is necessary to use 52 libraries, so I had to change the logic of Compiler.java and instead of basing the number of libraries in each file.dex, use an estimated weight of 2MB for each .dex file solving the problem.

I enclose the first version of my Compiler.java for the one that needs to make use of a great number of libraries in its extensions or components.

Greetings!

        private boolean runDx(File classesDir, String dexedClassesDir, boolean secondTry) {

Map<Integer,List<File>> classesList= new TreeMap<>();
  List<File> libList = new ArrayList<File>();
  List<File> inputList = new ArrayList<File>();
  inputList.add(classesDir); //this is a directory, and won't be cached into the dex cache
  inputList.add(new File(getResource(SIMPLE_ANDROID_RUNTIME_JAR)));
  inputList.add(new File(getResource(KAWA_RUNTIME)));
  inputList.add(new File(getResource(ACRA_RUNTIME)));

  for (String jar : SUPPORT_JARS) {
      inputList.add(new File(getResource(jar)));
  }

  for (String lib : uniqueLibsNeeded) {
      libList.add(new File(lib));
  }

  Set<String> addedExtJars = new HashSet<String>();
  for (String type : extCompTypes) {
      String sourcePath = getExtCompDirPath(type) + SIMPLE_ANDROID_RUNTIME_JAR;
      if (!addedExtJars.contains(sourcePath)) {
          libList.add(new File(sourcePath));
          addedExtJars.add(sourcePath);
      }
  }

  int offset = libList.size();
  // Note: The choice of 12 libraries is arbitrary. We note that things
  // worked to put all libraries into the first classes.dex file when we
  // had 16 libraries and broke at 17. So this is a conservative number
  // to try.
  if (!secondTry) {           // First time through, try base + 12 libraries
      if (offset > 12)
          offset = 12;
  } else {
      offset = 0;               // Add NO libraries the second time through!
  }
 
  for (int i = 0; i < offset; i++) {
      inputList.add(libList.get(i));
  }
   System.err.println("runDx -- libraries");
   for (File aFile : inputList) {
     System.err.println(" inputList => " + aFile.getAbsolutePath());
   }
   for (File aFile : libList) {
     System.err.println(" libList => " + aFile.getAbsolutePath());
   }

/**
 * Clasifica las librerias en  listas que tiene cada una un maximo de 2MB.
 * La indexacion falla cuando se superan las 65k lineas de codigo, por eso
 * se ha hecho una relacion de a mayor tamaño de archivo, mas lineas de codigo
 */
  int bytesMega=2000000;
  int classesListNumber=2;
  
  classesList.put(classesListNumber,new ArrayList<File>());
  
  int vueltas=0;
  if (libList.size() - offset > 0) {
      for (int i = offset; i < libList.size(); i++) {
    	  vueltas=vueltas+1;		
    	  
       // LOG.info("NUMERO: "+classesListNumber+" SIZE: "+classSize(getClassList(classesListNumber,classesList)));
          if(classSize(classesList.get(classesListNumber))>bytesMega)
          {
            
              classesListNumber++;
              classesList.put(classesListNumber,new ArrayList<File>());
              classesList.get(classesListNumber).add(libList.get(i));
           
          }else {
            
              //classesList.put(classesListNumber, libList.get(i));
              classesList.get(classesListNumber).add(libList.get(i));
              
          }


      }
  }

  LOG.info("inputList: "+inputList.size());
  LOG.info("VUELTAS: "+vueltas);
  printClassesList(classesList);
  
  DexExecTask dexTask = new DexExecTask();
  dexTask.setExecutable(getResource(DX_JAR));
  dexTask.setOutput(dexedClassesDir + File.separator + "classes.dex");
  dexTask.setChildProcessRamMb(childProcessRamMb);
  if (dexCacheDir == null) {
      dexTask.setDisableDexMerger(true);
  } else {
      createDir(new File(dexCacheDir));
      dexTask.setDexedLibs(dexCacheDir);
  }

  long startDx = System.currentTimeMillis();
  // Using System.err and System.out on purpose. Don't want to pollute build messages with
  // tools output
  boolean dxSuccess;
  synchronized (SYNC_KAWA_OR_DX) {
      setProgress(50);
      dxSuccess = dexTask.execute(inputList);
      LOG.info("DXSUCCESS: "+dxSuccess);
      if (dxSuccess && (classesList.size()>0)){
          LOG.info("INFO: entrado");
          setProgress(60);

        /**
         * Recorre el Map donde estan todas las colecciones de librerias y las va indexando
         */
          for (int i = 2; i <classesList.size()+2 ; i++) {
            
            dexTask.setOutput(dexedClassesDir + File.separator + "classes" + i + ".dex");
            dxSuccess = dexTask.execute(classesList.get(i));
            inputList = new ArrayList<File>();
            hasNumber=i;
          }
          setProgress(75);

      } else if (!dxSuccess) {  // The initial dx blew out, try more conservative
          LOG.info("DX execution failed, trying with fewer libraries.");
          if (secondTry) {        // Already tried the more conservative approach!
              LOG.warning("YAIL compiler - DX execution failed (secondTry!).");
              err.println("YAIL compiler - DX execution failed.");
              userErrors.print(String.format(ERROR_IN_STAGE, "DX"));
              return false;
          } else {
              LOG.info("INFO: relanzando");
              return runDx(classesDir, dexedClassesDir, true);
          }
      }
  }
  if (!dxSuccess) {
      LOG.warning("YAIL compiler - DX execution failed.");
      err.println("YAIL compiler - DX execution failed.");
      userErrors.print(String.format(ERROR_IN_STAGE, "DX"));
      return false;
  }
  String dxTimeMessage = "DX time: " +
          ((System.currentTimeMillis() - startDx) / 1000.0) + " seconds";
  out.println(dxTimeMessage);
  LOG.info(dxTimeMessage);

  return true;

}

4 Likes

Is it working ??