2014-10-29 5 views
2

я хотел бы использовать подход ApplicationWrapepr использовать multidex в моем приложении, как описано здесь https://plus.google.com/104023661970539138053/posts/YTMf8ADTcFgсписок Android Multidex всех классов

Я использовал опцию --minimal магистрального-DEX вместе с удерживающую файлом, как это:

android/support/multidex/ZipUtil.class 
android/support/multidex/ZipUtil$CentralDirectory.class 
android/support/multidex/MultiDex$V14.class 
android/support/multidex/MultiDexExtractor$1.class 
android/support/multidex/MultiDexExtractor.class 
com/<mypackage>/common/MyApplication.class 
com/<mypackage>/common/MyApplicationWrapper.class 
com/<mypackage>/common/ui/DashboardActivity.class 
android/support/multidex/MultiDexApplication.class 
android/support/multidex/MultiDex.class 
android/support/multidex/MultiDex$V19.class 
android/support/multidex/MultiDex$V4.class 

Это приводит к перечисленным классам в моем основном файле dex, который в порядке. Я, чем использовать библиотеку, которая использует следующий код для перечисления всех классов в файле dexfile, но просто получает записи основного «clesses.dex», а не все другие загруженные файлы dex, потому что новый DexFile проверяет только «classes.dex», :

приватный статический список getPaths (final String [] sourcePaths) { Результат списка = новый ArrayList();

for (String s : sourcePaths) { 
    try { 
    DexFile dexfile = new DexFile(s); 
    Enumeration<String> entries = dexfile.entries(); 

    while (entries.hasMoreElements()) { 
     result.add(entries.nextElement()); 
    } 
    } catch (IOException ioe) { 
    Log.w(TAG, "cannot open file=" + s + ";Exception=" + ioe.getMessage()); 
    } 
} 

return result; 
} 

сейчас единственный путь получает определяется с:

application.getApplicationContext().getApplicationInfo().sourceDir; 

что приводит к Somthing как /data/../myapplicationname.apk

Есть еще одна возможность получить все классы файлы dex перечислены? Или все классы в настоящее время в ClassLoaders? Библиотека имеет важное значение для проекта и использует этот подход для поиска компонентных реализаций через отражение позже.

EDIT1: , если обнаружено, что файл classes2.dex помещается под: /data/data/com./code_cache/secondary-dexes/com.-1.apk.classes2.dex

однако при использовании нового DexFile() с этим путем IOEsxception генерируется с сообщением «невозможно открыть файл dexfile».

ответ

5

DexFile принимает путь к файлу zip/apk и извлекает его, чтобы найти файл .dex. Итак, если вы используете .dex в качестве пути, он выдает ошибку.

Также компания Google опубликовала статью Building Apps with Over 65K Methods для решения проблемы --multi-dex.

Я пишу класс для загрузки всех классов. Вы можете прочитать по адресу: http://xudshen.info/2014/11/12/list-all-classes-after-multidex/

import android.content.Context; 
import android.content.SharedPreferences; 
import android.content.pm.ApplicationInfo; 
import android.content.pm.PackageManager; 
import android.os.Build; 

import java.io.File; 
import java.io.IOException; 
import java.util.ArrayList; 
import java.util.Enumeration; 
import java.util.List; 

import dalvik.system.DexFile; 

/** 
* Created by [email protected] on 14/11/13. 
*/ 
public class MultiDexHelper { 
    private static final String EXTRACTED_NAME_EXT = ".classes"; 
    private static final String EXTRACTED_SUFFIX = ".zip"; 

    private static final String SECONDARY_FOLDER_NAME = "code_cache" + File.separator + 
      "secondary-dexes"; 

    private static final String PREFS_FILE = "multidex.version"; 
    private static final String KEY_DEX_NUMBER = "dex.number"; 

    private static SharedPreferences getMultiDexPreferences(Context context) { 
     return context.getSharedPreferences(PREFS_FILE, 
       Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB 
         ? Context.MODE_PRIVATE 
         : Context.MODE_PRIVATE | Context.MODE_MULTI_PROCESS); 
    } 

    /** 
    * get all the dex path 
    * 
    * @param context the application context 
    * @return all the dex path 
    * @throws PackageManager.NameNotFoundException 
    * @throws IOException 
    */ 
    public static List<String> getSourcePaths(Context context) throws PackageManager.NameNotFoundException, IOException { 
     ApplicationInfo applicationInfo = context.getPackageManager().getApplicationInfo(context.getPackageName(), 0); 
     File sourceApk = new File(applicationInfo.sourceDir); 
     File dexDir = new File(applicationInfo.dataDir, SECONDARY_FOLDER_NAME); 

     List<String> sourcePaths = new ArrayList<String>(); 
     sourcePaths.add(applicationInfo.sourceDir); //add the default apk path 

     //the prefix of extracted file, ie: test.classes 
     String extractedFilePrefix = sourceApk.getName() + EXTRACTED_NAME_EXT; 
     //the total dex numbers 
     int totalDexNumber = getMultiDexPreferences(context).getInt(KEY_DEX_NUMBER, 1); 

     for (int secondaryNumber = 2; secondaryNumber <= totalDexNumber; secondaryNumber++) { 
      //for each dex file, ie: test.classes2.zip, test.classes3.zip... 
      String fileName = extractedFilePrefix + secondaryNumber + EXTRACTED_SUFFIX; 
      File extractedFile = new File(dexDir, fileName); 
      if (extractedFile.isFile()) { 
       sourcePaths.add(extractedFile.getAbsolutePath()); 
       //we ignore the verify zip part 
      } else { 
       throw new IOException("Missing extracted secondary dex file '" + 
         extractedFile.getPath() + "'"); 
      } 
     } 

     return sourcePaths; 
    } 

    /** 
    * get all the classes name in "classes.dex", "classes2.dex", .... 
    * 
    * @param context the application context 
    * @return all the classes name 
    * @throws PackageManager.NameNotFoundException 
    * @throws IOException 
    */ 
    public static List<String> getAllClasses(Context context) throws PackageManager.NameNotFoundException, IOException { 
     List<String> classNames = new ArrayList<String>(); 
     for (String path : getSourcePaths(context)) { 
      try { 
       DexFile dexfile = null; 
       if (path.endsWith(EXTRACTED_SUFFIX)) { 
        //NOT use new DexFile(path), because it will throw "permission error in /data/dalvik-cache" 
        dexfile = DexFile.loadDex(path, path + ".tmp", 0); 
       } else { 
        dexfile = new DexFile(path); 
       } 
       Enumeration<String> dexEntries = dexfile.entries(); 
       while (dexEntries.hasMoreElements()) { 
        classNames.add(dexEntries.nextElement()); 
       } 
      } catch (IOException e) { 
       throw new IOException("Error at loading dex file '" + 
         path + "'"); 
      } 
     } 
     return classNames; 
    } 
} 
+0

привета. Я думаю, это сработает. из-за соображений производительности мы решили использовать явную конфигурацию зависимостей. – Denny1989

+0

работает, где вы потеряете производительность в этом решении? –

1

Если запустить приложение с мгновенным запуском, путь DEX файла необходимо добавить следующее:

// handle dex files built by instant run 
     File instantRunFilePath = new File(applicationInfo.dataDir, 
              "files" + File.separator + "instant-run" + File.separator + "dex"); 

     if (instantRunFilePath.exists() && instantRunFilePath.isDirectory()) { 
      File[] sliceFiles = instantRunFilePath.listFiles(); 
      for (File sliceFile : sliceFiles) { 
       if (null != sliceFile && sliceFile.exists() && sliceFile.isFile() && sliceFile.getName().endsWith(".dex")) { 
        sourcePaths.add(sliceFile.getAbsolutePath()); 
       } 
      } 
     } 
Смежные вопросы