2016-04-08 3 views
9

ich einige Code hatte eine Liste aller Klassen in einem Paket zu erhalten, die in etwa so aussah:Android Studio 2.0 Instant-Run führt DexFile nicht alle Klassen laden

try { 
    DexFile df = new DexFile(context.getPackageCodePath()); 
    for (Enumeration<String> iter = df.entries(); iter.hasMoreElements();) { 
     String s = iter.nextElement(); 
    } 
} catch (IOException e) { 
    e.printStackTrace(); 
} 

jedoch dieser Code funktioniert nicht mehr da Ich habe mein Android Studio auf Version 2.0 aktualisiert. Ich habe festgestellt, dass der Übeltäter Instant Run ist. Wenn ich die App debuggen kann, sehe ich, dass die DexFile-Variable, df, ohne Instanzlauf eine Liste von Klassennamen (über 4.000 davon) enthält. Wenn Instant Run aktiviert ist, erhalte ich nur ungefähr 30 Klassennamen, und die Klassen, nach denen ich suche, sind nicht vorhanden. Ich habe das Gefühl, dass es etwas mit Multidex zu tun hat, aber ich bin mir nicht sicher, wie Instant Run unter der Decke funktioniert (meine App benutzt kein Multidex).

Weiß jemand, wie ich mit Instant Run eine Liste von Klassen wie diesem bekommen kann? Oder weiß jemand genau, warum ich dieses Verhalten sehe (wäre es toll, es zu verstehen)?

+0

Bitte nehmen Sie sich einen Blick auf diese [Antwort] (http://stackoverflow.com/questions/36572515/dexfile-in-2-0-versions-of-android-studio-and -Grabbel). InstantRun hat die DexFile-Logik zerstört. – Sol

Antwort

4

Wir können die DEX-Dateien verarbeiten, die von Instant-Run in Anwendungsdatenpfad erstellt werden.

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); 

    if (LogUtil.isDebugModeEnable()) { 
     LogUtil.d("MultiDexHelper", 
        "getSourcePaths sourceDir=" + applicationInfo.sourceDir + ", dataDir=" + applicationInfo.dataDir); 
    } 

    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); 

    if (LogUtil.isDebugModeEnable()) { 
     LogUtil.d("MultiDexHelper", "getSourcePaths totalDexNumber=" + totalDexNumber); 
    } 

    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() + "'"); 
     } 
    } 
    try { 
     // handle dex files built by instant run 
     File instantRunFilePath = new File(applicationInfo.dataDir, 
              "files" + File.separator + "instant-run" + File.separator + "dex"); 
     if (LogUtil.isDebugModeEnable()) { 
      LogUtil.d("MultiDexHelper", "getSourcePaths instantRunFile exists=" + instantRunFilePath.exists() + ", isDirectory=" 
        + instantRunFilePath.isDirectory() + ", getAbsolutePath=" + instantRunFilePath.getAbsolutePath()); 
     } 
     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()); 
       } 
      } 
     } 
    } catch (Throwable e) { 
     LogUtil.e("MultiDexHelper", "getSourcePaths parse instantRunFilePath exception", e); 
    } 

    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; 
// } 

/** 
* scan parent class's sub classes 
* 
* @param context 
* @param packageName 
* @param parentClass 
* @param <T> 
* @return 
*/ 
public static <T> Set<Class<? extends T>> scanClasses(Context context, String packageName, Class<T> parentClass) { 
    Set<Class<? extends T>> classes = new HashSet<Class<? extends T>>(); 
    try { 
     ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); 
     for (String path : getSourcePaths(context)) { 
      if (LogUtil.isDebugModeEnable()) { 
       LogUtil.d("MultiDexHelper", "scanClasses path=" + path); 
      } 
      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()) { 
        String className = dexEntries.nextElement(); 
        if (LogUtil.isDebugModeEnable()) { 
         LogUtil.d("MultiDexHelper", "scanClasses className=" + className); 
        } 
        if (className.toLowerCase().startsWith(packageName.toLowerCase())) { 
         Class clazz = classLoader.loadClass(className); 
         if (LogUtil.isDebugModeEnable()) { 
          LogUtil.d("MultiDexHelper", 
             "scanClasses clazz=" + clazz + ", parentClass=" + parentClass + ", equals=" + clazz 
               .getSuperclass().equals(parentClass)); 
         } 
         if (clazz.getSuperclass().equals(parentClass)) { 
          classes.add(clazz); 
         } 
        } 
       } 
      } catch (Throwable e) { 
       LogUtil.e("MultiDexHelper", "scanClasses Error at loading dex file '" + 
         path + "'", e); 
      } 
     } 
    } catch (Throwable e) { 
     LogUtil.e("MultiDexHelper", "scanClasses exception", e); 
    } 
    return classes; 
} 

}

Verwandte Themen