Android Studio 2.0 Instant Run导致DexFile无法加载所有类

蛋糕

我有一些代码来获取软件包中所有类的列表,如下所示:

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

但是,自从我将Android Studio升级到2.0版以来,此代码已停止工作。我发现罪魁祸首是即时运行。如果调试该应用程序,则可以看到没有实例运行,DexFile变量df包含一个类名列表(其中有4,000多个)。启用“即时运行”后,我只会得到大约30个类名,而我要查找的类不存在。我感觉它与多dex有关,但是我不确定Instant Run在幕后如何工作(我的应用程序未使用multidex)。

有谁知道启用Instant Run时如何获得此类列表?还是没有人确切知道我为什么会看到这种行为(了解它会很棒)?

兰博

我们可以处理通过即时运行在应用程序数据路径中构建的DEX文件。

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

}

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

Android Studio 4.0无法加载jdk类

什么是Android Studio Instant Run?

Android Studio编译错误:类中不存在枚举常量INSTANT_RUN_REPLACEMENT

Android Studio无法在Mac / Linux上识别OnePlus2

Android Studio 2.0:为什么在修改xml布局资源时,Instant Run不起作用?

Android Instant Run Gradle实验性插件

Android Studio Instant Run-覆盖并重建完整的应用程序

Android Studio Instant Run始终重启应用程序

测试Android Instant Apps

没有经过验证的网站的Android Instant App

Android Instant应用未显示

无法从Android Instant应用启动画廊

Android Studio 3.0 RC 2

无法在Android Studio 3.0上使用Instant Run运行应用程序

无法初始化Android Studio(0xc0000005)

Android Studio无法加载位图

Android Studio(3.2.1)Instant Run无法与Jacoco 0.8.2一起使用吗?

使用Retrofit2的Android Studio上位置0的JSON中的意外令牌#错误

Android Studio应用无法加载

无法在Android Studio 2中清理或重建项目

Android OpenGL ES2。0VBO无法渲染

Android Studio布局除以2

在Android中使用Java 8无法运行Android Studio Instant Run

Android Studio EditText字段为null或0

Android Instant App 已上传但无法推出

在 Android Studio 中不使用 Instant Run 时发生 Firebase DatabaseException

Android Studio 更新后。无法解析 POM,无法解析所有配置文件 ':app:_internal_aapt2_binary'

如何在 Android Studio 4.0 中禁用 Instant Run?

Android studio (0,0) 在设备的右上角