Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed issue with database upgrade when MultiDex support is enabled. #434

Merged
merged 1 commit into from
Nov 23, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
106 changes: 106 additions & 0 deletions library/src/main/java/com/orm/util/MultiDexHelper.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package com.orm.util;

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.
*/

//http://stackoverflow.com/a/26892658
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;
}
}
12 changes: 4 additions & 8 deletions library/src/main/java/com/orm/util/ReflectionUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -289,15 +289,11 @@ private static Class getDomainClass(String className, Context context) {

private static List<String> getAllClasses(Context context) throws PackageManager.NameNotFoundException, IOException {
String packageName = ManifestHelper.getDomainPackageName(context);
String path = getSourcePath(context);
List<String> classNames = new ArrayList<String>();
DexFile dexfile = null;
try {
dexfile = new DexFile(path);
Enumeration<String> dexEntries = dexfile.entries();
while (dexEntries.hasMoreElements()) {
String className = dexEntries.nextElement();
if (className.startsWith(packageName)) classNames.add(className);
List<String> allClasses = MultiDexHelper.getAllClasses(context);
for (String classString : allClasses) {
if (classString.startsWith(packageName)) classNames.add(classString);
}
} catch (NullPointerException e) {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
Expand All @@ -316,7 +312,7 @@ private static List<String> getAllClasses(Context context) throws PackageManager
}
}
} finally {
if (null != dexfile) dexfile.close();
// if (null != dexfile) dexfile.close();
}
return classNames;
}
Expand Down