|
|
|
|
@ -25,6 +25,7 @@ import java.lang.reflect.Method; |
|
|
|
|
import java.util.HashMap; |
|
|
|
|
import java.util.LinkedHashMap; |
|
|
|
|
import java.util.Map; |
|
|
|
|
import java.util.Objects; |
|
|
|
|
import java.util.concurrent.ConcurrentHashMap; |
|
|
|
|
import java.util.concurrent.CountDownLatch; |
|
|
|
|
import java.util.concurrent.Executors; |
|
|
|
|
@ -36,9 +37,9 @@ import dalvik.system.DexClassLoader; |
|
|
|
|
import okhttp3.Response; |
|
|
|
|
|
|
|
|
|
public class JarLoader { |
|
|
|
|
private ConcurrentHashMap<String, DexClassLoader> classLoaders = new ConcurrentHashMap<>(); |
|
|
|
|
private ConcurrentHashMap<String, Method> proxyMethods = new ConcurrentHashMap<>(); |
|
|
|
|
private ConcurrentHashMap<String, Spider> spiders = new ConcurrentHashMap<>(); |
|
|
|
|
private final ConcurrentHashMap<String, DexClassLoader> classLoaders = new ConcurrentHashMap<>(); |
|
|
|
|
private final ConcurrentHashMap<String, Method> proxyMethods = new ConcurrentHashMap<>(); |
|
|
|
|
private final ConcurrentHashMap<String, Spider> spiders = new ConcurrentHashMap<>(); |
|
|
|
|
private volatile String recentJarKey = ""; |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
@ -54,53 +55,12 @@ public class JarLoader { |
|
|
|
|
return loadClassLoader(cache, "main"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// private boolean loadClassLoader1(String jar, String key) {
|
|
|
|
|
// boolean success = false;
|
|
|
|
|
// try {
|
|
|
|
|
// File cacheDir = new File(App.getInstance().getCacheDir().getAbsolutePath() + "/catvod_csp");
|
|
|
|
|
// if (!cacheDir.exists())
|
|
|
|
|
// cacheDir.mkdirs();
|
|
|
|
|
// DexClassLoader classLoader = new DexClassLoader(jar, cacheDir.getAbsolutePath(), null, App.getInstance().getClassLoader());
|
|
|
|
|
// // make force wait here, some device async dex load
|
|
|
|
|
// int count = 0;
|
|
|
|
|
// do {
|
|
|
|
|
// try {
|
|
|
|
|
// Class classInit = classLoader.loadClass("com.github.catvod.spider.Init");
|
|
|
|
|
// if (classInit != null) {
|
|
|
|
|
// Method method = classInit.getMethod("init", Context.class);
|
|
|
|
|
// method.invoke(null, App.getInstance());
|
|
|
|
|
// System.out.println("自定义爬虫代码加载成功!");
|
|
|
|
|
// success = true;
|
|
|
|
|
// try {
|
|
|
|
|
// Class proxy = classLoader.loadClass("com.github.catvod.spider.Proxy");
|
|
|
|
|
// Method mth = proxy.getMethod("proxy", Map.class);
|
|
|
|
|
// proxyMethods.put(key, mth);
|
|
|
|
|
// } catch (Throwable th) {
|
|
|
|
|
//
|
|
|
|
|
// }
|
|
|
|
|
// break;
|
|
|
|
|
// }
|
|
|
|
|
// Thread.sleep(200);
|
|
|
|
|
// } catch (Throwable th) {
|
|
|
|
|
// th.printStackTrace();
|
|
|
|
|
// }
|
|
|
|
|
// count++;
|
|
|
|
|
// } while (count < 5);
|
|
|
|
|
//
|
|
|
|
|
// if (success) {
|
|
|
|
|
// classLoaders.put(key, classLoader);
|
|
|
|
|
// }
|
|
|
|
|
// } catch (Throwable th) {
|
|
|
|
|
// th.printStackTrace();
|
|
|
|
|
// }
|
|
|
|
|
// return success;
|
|
|
|
|
// }
|
|
|
|
|
private boolean loadClassLoader(String jar, String key) { |
|
|
|
|
if (classLoaders.contains(key)) return true; |
|
|
|
|
if (classLoaders.containsKey(key)) return true; |
|
|
|
|
final String TAG = "JarLoader"; |
|
|
|
|
final File jarFile = new File(jar); |
|
|
|
|
final AtomicBoolean success = new AtomicBoolean(false); |
|
|
|
|
DexClassLoader classLoader = null; |
|
|
|
|
DexClassLoader classLoader; |
|
|
|
|
// 1. 前置校验
|
|
|
|
|
if (!validateJarFile(jarFile, TAG)) return false; |
|
|
|
|
// 2. 准备缓存目录
|
|
|
|
|
@ -241,9 +201,10 @@ public class JarLoader { |
|
|
|
|
private void cleanupResources(DexClassLoader loader, String tag) { |
|
|
|
|
if (loader != null) { |
|
|
|
|
try { |
|
|
|
|
Field pathList = loader.getClass().getSuperclass().getDeclaredField("pathList"); |
|
|
|
|
Field pathList = Objects.requireNonNull(loader.getClass().getSuperclass()).getDeclaredField("pathList"); |
|
|
|
|
pathList.setAccessible(true); |
|
|
|
|
Object dexPathList = pathList.get(loader); |
|
|
|
|
assert dexPathList != null; |
|
|
|
|
Field dexElements = dexPathList.getClass().getDeclaredField("dexElements"); |
|
|
|
|
dexElements.setAccessible(true); |
|
|
|
|
dexElements.set(dexPathList, new Object[0]); |
|
|
|
|
@ -261,8 +222,9 @@ public class JarLoader { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private DexClassLoader loadJarInternal(String jar, String md5, String key) { |
|
|
|
|
if (classLoaders.contains(key)) |
|
|
|
|
if (classLoaders.containsKey(key)){ |
|
|
|
|
return classLoaders.get(key); |
|
|
|
|
} |
|
|
|
|
File cache = new File(App.getInstance().getFilesDir().getAbsolutePath() + "/" + key + ".jar"); |
|
|
|
|
if (!md5.isEmpty()) { |
|
|
|
|
if (cache.exists() && MD5.getFileMd5(cache).equalsIgnoreCase(md5)) { |
|
|
|
|
@ -272,6 +234,7 @@ public class JarLoader { |
|
|
|
|
} |
|
|
|
|
try { |
|
|
|
|
Response response = OkGo.<File>get(jar).execute(); |
|
|
|
|
assert response.body() != null; |
|
|
|
|
InputStream is = response.body().byteStream(); |
|
|
|
|
OutputStream os = new FileOutputStream(cache); |
|
|
|
|
try { |
|
|
|
|
@ -313,6 +276,7 @@ public class JarLoader { |
|
|
|
|
if (spiders.containsKey(key)) |
|
|
|
|
return spiders.get(key); |
|
|
|
|
DexClassLoader classLoader = null; |
|
|
|
|
assert jarKey != null; |
|
|
|
|
if (jarKey.equals("main")) |
|
|
|
|
classLoader = classLoaders.get("main"); |
|
|
|
|
else { |
|
|
|
|
@ -339,7 +303,8 @@ public class JarLoader { |
|
|
|
|
DexClassLoader classLoader = classLoaders.get("main"); |
|
|
|
|
String clsKey = "Json" + key; |
|
|
|
|
String hotClass = "com.github.catvod.parser." + clsKey; |
|
|
|
|
Class jsonParserCls = classLoader.loadClass(hotClass); |
|
|
|
|
assert classLoader != null; |
|
|
|
|
Class<?> jsonParserCls = classLoader.loadClass(hotClass); |
|
|
|
|
Method mth = jsonParserCls.getMethod("parse", LinkedHashMap.class, String.class); |
|
|
|
|
return (JSONObject) mth.invoke(null, jxs, url); |
|
|
|
|
} catch (Throwable th) { |
|
|
|
|
@ -353,7 +318,8 @@ public class JarLoader { |
|
|
|
|
DexClassLoader classLoader = classLoaders.get("main"); |
|
|
|
|
String clsKey = "Mix" + key; |
|
|
|
|
String hotClass = "com.github.catvod.parser." + clsKey; |
|
|
|
|
Class jsonParserCls = classLoader.loadClass(hotClass); |
|
|
|
|
assert classLoader != null; |
|
|
|
|
Class<?> jsonParserCls = classLoader.loadClass(hotClass); |
|
|
|
|
Method mth = jsonParserCls.getMethod("parse", LinkedHashMap.class, String.class, String.class, String.class); |
|
|
|
|
return (JSONObject) mth.invoke(null, jxs, name, flag, url); |
|
|
|
|
} catch (Throwable th) { |
|
|
|
|
@ -362,14 +328,14 @@ public class JarLoader { |
|
|
|
|
return null; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public Object[] proxyInvoke(Map params) { |
|
|
|
|
public Object[] proxyInvoke(Map<String,String> params) { |
|
|
|
|
try { |
|
|
|
|
Method proxyFun = proxyMethods.get(recentJarKey); |
|
|
|
|
if (proxyFun != null) { |
|
|
|
|
return (Object[]) proxyFun.invoke(null, params); |
|
|
|
|
} |
|
|
|
|
} catch (Throwable th) { |
|
|
|
|
|
|
|
|
|
th.printStackTrace(); |
|
|
|
|
} |
|
|
|
|
return null; |
|
|
|
|
} |
|
|
|
|
|