package zeus.plugin;
import android.text.TextUtils;
import java.io.File;
import java.io.IOException;
import java.util.zip.ZipFile;
import dalvik.system.DexFile;
/***
* 加载任意后缀的zip格式的classLoader,主要用来加载apk文件
* 如果插件是放在SD卡目录下,最好的格式是jar,有些手机的DexFile只能识别apk或者jar后缀的,因为apk格式会被清理软件当作未安装apk文件清理掉
* <p>
* Created by huangjian on 2016/6/21.
*/
class ZeusPluginClassLoader extends ClassLoader {
protected String mRawLibPath;
protected final String mDexOutputPath;
protected File[] mFiles;
protected ZipFile[] mZips;
protected DexFile[] mDexs;
protected String[] mLibPaths;
private boolean mInitialized;
public final String mRawDexPath;
final private String mPluginId;
public ZeusPluginClassLoader(String pluginId, String dexPath, String dexOutputDir, String libPath,
ClassLoader parent) {
super(parent);
if (dexPath == null || dexOutputDir == null)
throw new NullPointerException();
mPluginId = pluginId;
mRawDexPath = dexPath;
mDexOutputPath = dexOutputDir;
mRawLibPath = libPath;
}
public String getPluginId() {
return mPluginId;
}
/***
* 初始化
*/
protected synchronized void ensureInit() {
if (mInitialized) {
return;
}
String[] dexPathList;
mInitialized = true;
dexPathList = mRawDexPath.split(":");
int length = dexPathList.length;
mFiles = new File[length];
mZips = new ZipFile[length];
mDexs = new DexFile[length];
for (int i = 0; i < length; i++) {
File pathFile = new File(dexPathList[i]);
mFiles[i] = pathFile;
if (pathFile.isFile()) {
try {
mZips[i] = new ZipFile(pathFile);
} catch (IOException ioex) {
System.out.println("Failed opening '" + pathFile
+ "': " + ioex);
}
try {
String outputName =
generateOutputName(dexPathList[i], mDexOutputPath);
mDexs[i] = DexFile.loadDex(dexPathList[i], outputName, 0);
} catch (IOException e) {
e.printStackTrace();
}
}
}
generateLibPath();
}
protected void generateLibPath() {
//优先查找本地添加的lib库,然后在去系统级别的去找,防止自己的插件中so跟系统存在的so重名了
String pathList;
String systemPathList = System.getProperty("java.library.path", ".");
String pathSep = System.getProperty("path.separator", ":");
String fileSep = System.getProperty("file.separator", "/");
if (mRawLibPath != null) {
if (systemPathList.length() > 0) {
if (mRawLibPath.endsWith(pathSep)) {
pathList = mRawLibPath + systemPathList;
} else {
pathList = mRawLibPath + pathSep + systemPathList;
}
} else {
pathList = mRawLibPath;
}
} else {
pathList = systemPathList;
}
mLibPaths = pathList.split(pathSep);
int length = mLibPaths.length;
for (int i = 0; i < length; i++) {
if (!mLibPaths[i].endsWith(fileSep))
mLibPaths[i] += fileSep;
}
}
protected static String generateOutputName(String sourcePathName,
String outputDir) {
StringBuilder newStr = new StringBuilder(80);
newStr.append(outputDir);
if (!outputDir.endsWith("/"))
newStr.append("/");
String sourceFileName;
int lastSlash = sourcePathName.lastIndexOf("/");
if (lastSlash < 0)
sourceFileName = sourcePathName;
else
sourceFileName = sourcePathName.substring(lastSlash + 1);
int lastDot = sourceFileName.lastIndexOf(".");
if (lastDot < 0)
newStr.append(sourceFileName);
else
newStr.append(sourceFileName, 0, lastDot);
newStr.append(".dex");
return newStr.toString();
}
protected Class<?> loadClass(String className, boolean resolve) throws ClassNotFoundException {
Class<?> clazz = findLoadedClass(className);
if (clazz == null) {
try {
clazz = getParent().loadClass(className);
} catch (ClassNotFoundException e) {
}
if (clazz == null) {
try {
clazz = findClass(className);
} catch (ClassNotFoundException e) {
throw e;
}
}
}
return clazz;
}
/***
* 每个插件里也可能有多个dex文件,挨个的查找dex文件
*/
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
ensureInit();
Class clazz;
int length = mFiles.length;
for (int i = 0; i < length; i++) {
if (mDexs[i] != null) {
String slashName = name.replace('.', '/');
clazz = mDexs[i].loadClass(slashName, this);
if (clazz != null) {
return clazz;
}
}
}
throw new ClassNotFoundException(name + " in loader " + this);
}
/**
* 只查找插件自己是否存在该class
*
* @param className 类名字
* @return 类对象
* @throws ClassNotFoundException
*/
public Class<?> loadClassByself(String className) throws ClassNotFoundException {
Class<?> clazz = findLoadedClass(className);
if (clazz == null) {
clazz = findClass(className);
}
return clazz;
}
@Override
protected String findLibrary(String libname) {//根据插件的pathInfo查找对应的so
ensureInit();
String fileName = System.mapLibraryName(libname);
for (String libPath : mLibPaths) {
String pathName = libPath + fileName;
File test = new File(pathName);
if (test.exists()) {
return pathName;
}
}
return null;
}
}