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

FEAT:支持提前生成配置,避免第一次打开的时候解析类导致黑屏。 #43

Merged
merged 1 commit into from
Jan 2, 2019
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
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,31 @@
import android.annotation.TargetApi;
import android.app.Application;
import android.app.FragmentManager;
import android.app.ProgressDialog;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.preference.Preference;
import android.preference.Preference.OnPreferenceClickListener;
import android.preference.PreferenceFragment;
import android.support.v7.app.AppCompatActivity;
import android.widget.Toast;

import com.google.gson.Gson;

import java.lang.reflect.Method;

import dalvik.system.PathClassLoader;
import me.firesun.wechat.enhancement.util.HookParams;
import me.firesun.wechat.enhancement.util.SearchClasses;


public class SettingsActivity extends AppCompatActivity {
Expand Down Expand Up @@ -93,6 +101,61 @@ public boolean onPreferenceClick(Preference pref) {
return true;
}
});

Preference generate = findPreference("generate");
generate.setOnPreferenceClickListener(new OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference pref) {
final Context context = getApplication();
if (context == null) {
return false;
}
final PackageManager packageManager = context.getPackageManager();
if (packageManager == null) {
return false;
}

final ProgressDialog dialog = new ProgressDialog(getActivity());
dialog.setCancelable(false);
dialog.setMessage(getResources().getString(R.string.generating));
dialog.show();

new Thread(new Runnable() {
@Override
public void run() {
boolean success = false;
try {
PackageInfo packageInfo = packageManager.getPackageInfo(HookParams.WECHAT_PACKAGE_NAME, 0);
String wechatApk = packageInfo.applicationInfo.sourceDir;
PathClassLoader wxClassLoader = new PathClassLoader(wechatApk, ClassLoader.getSystemClassLoader());
SearchClasses.generateConfig(wechatApk, wxClassLoader, packageInfo.versionName);

String config = new Gson().toJson(HookParams.getInstance());
SharedPreferences.Editor editor = context.getSharedPreferences(HookParams.WECHAT_ENHANCEMENT_CONFIG_NAME, Context.MODE_WORLD_READABLE).edit();
editor.clear();
editor.putString("params", config);
editor.commit();

success = true;

} catch (Throwable e) {
e.printStackTrace();
}

final String msg = getResources().getString(success ? R.string.generate_success : R.string.generate_failed);
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
dialog.dismiss();
Toast.makeText(getApplication(), msg, Toast.LENGTH_SHORT).show();
}
});
}
}, "generate-config").start();

return true;
}
});
}

private Application getApplication() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,30 +1,55 @@
package me.firesun.wechat.enhancement.util;


import android.util.Log;

import net.dongliu.apk.parser.bean.DexClass;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import de.robv.android.xposed.XposedHelpers;

import static de.robv.android.xposed.XposedBridge.log;
import de.robv.android.xposed.XposedBridge;

public final class ReflectionUtil {

private static final Map classesCache = new HashMap();

private static boolean xposedExist;

static {
try {
Class.forName("de.robv.android.xposed.XposedBridge");
xposedExist = true;
} catch (ClassNotFoundException e) {
xposedExist = false;
}
}

public static void log(String msg) {
if (msg == null) {
return;
}

if (xposedExist) {
XposedBridge.log(msg);
} else {
Log.i("Xposed", "[WechatEnhancement] " + msg);
}
}

public static Method findMethodsByExactParameters(Class clazz, Class returnType, Class... parameterTypes) {
if (clazz == null) {
return null;
}

List<Method> list = Arrays.asList(XposedHelpers.findMethodsByExactParameters(clazz, returnType, (Class[]) Arrays.copyOf(parameterTypes, parameterTypes.length)));
// List<Method> list = Arrays.asList(XposedHelpers.findMethodsByExactParameters(clazz, returnType, (Class[]) Arrays.copyOf(parameterTypes, parameterTypes.length)));
List<Method> list = Arrays.asList(findMethodsByExactParametersInner(clazz, returnType, (Class[]) Arrays.copyOf(parameterTypes, parameterTypes.length)));
if (list.isEmpty())
return null;
else if (list.size() > 1) {
Expand Down Expand Up @@ -74,10 +99,79 @@ public static Classes findClassesFromPackage(ClassLoader loader, List<String> cl
return cs;
}

private static Map<String, Method> methodCache = new HashMap<>();

private static String getParametersString(Class<?>... clazzes) {
StringBuilder sb = new StringBuilder("(");
boolean first = true;
for (Class<?> clazz : clazzes) {
if (first)
first = false;
else
sb.append(",");

if (clazz != null)
sb.append(clazz.getCanonicalName());
else
sb.append("null");
}
sb.append(")");
return sb.toString();
}

public static Method findMethodExact(Class<?> clazz, String methodName, Class<?>... parameterTypes) {
String fullMethodName = clazz.getName() + '#' + methodName + getParametersString(parameterTypes) + "#exact";

if (methodCache.containsKey(fullMethodName)) {
Method method = methodCache.get(fullMethodName);
if (method == null)
throw new NoSuchMethodError(fullMethodName);
return method;
}

try {
Method method = clazz.getDeclaredMethod(methodName, parameterTypes);
method.setAccessible(true);
methodCache.put(fullMethodName, method);
return method;
} catch (NoSuchMethodException e) {
methodCache.put(fullMethodName, null);
throw new NoSuchMethodError(fullMethodName);
}
}

public static Method[] findMethodsByExactParametersInner(Class<?> clazz, Class<?> returnType, Class<?>... parameterTypes) {
List<Method> result = new LinkedList<>();
for (Method method : clazz.getDeclaredMethods()) {
if (returnType != null && returnType != method.getReturnType())
continue;

Class<?>[] methodParameterTypes = method.getParameterTypes();
if (parameterTypes.length != methodParameterTypes.length)
continue;

boolean match = true;
for (int i = 0; i < parameterTypes.length; i++) {
if (parameterTypes[i] != methodParameterTypes[i]) {
match = false;
break;
}
}

if (!match)
continue;

method.setAccessible(true);
result.add(method);
}
return result.toArray(new Method[result.size()]);
}

public static final Method findMethodExactIfExists(Class clazz, String methodName, Class... parameterTypes) {
Method method = null;
try {
method = XposedHelpers.findMethodExact(clazz, methodName, (Class[]) Arrays.copyOf(parameterTypes, parameterTypes.length));
// method = XposedHelpers.findMethodExact(clazz, methodName, (Class[]) Arrays.copyOf(parameterTypes, parameterTypes.length));
method = findMethodExact(clazz, methodName, (Class[]) Arrays.copyOf(parameterTypes, parameterTypes.length));
} catch (Error | Exception e) {
}
return method;
Expand All @@ -86,7 +180,7 @@ public static final Method findMethodExactIfExists(Class clazz, String methodNam
public static final Class findClassIfExists(String className, ClassLoader classLoader) {
Class c = null;
try {
c = XposedHelpers.findClass(className, classLoader);
c = Class.forName(className, false, classLoader);
} catch (Error | Exception e) {
}
return c;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,26 @@
import de.robv.android.xposed.callbacks.XC_LoadPackage;
import me.firesun.wechat.enhancement.Main;

import static de.robv.android.xposed.XposedBridge.log;
import static me.firesun.wechat.enhancement.util.ReflectionUtil.log;

public class SearchClasses {
private static List<String> wxClasses = new ArrayList<>();
private static XSharedPreferences preferencesInstance = null;

public static void init(Context context, XC_LoadPackage.LoadPackageParam lpparam, String versionName) {
public static void init(Context context, XC_LoadPackage.LoadPackageParam lparam, String versionName) {

if (loadConfig(lpparam, versionName))
if (loadConfig(lparam, versionName))
return;

log("failed to load config, start finding...");

generateConfig(lparam.appInfo.sourceDir, lparam.classLoader, versionName);

saveConfig(context);
}

public static void generateConfig(String wechatApk, ClassLoader classLoader, String versionName) {

HookParams hp = HookParams.getInstance();
hp.versionName = versionName;
hp.versionCode = HookParams.VERSION_CODE;
Expand All @@ -49,8 +57,11 @@ public static void init(Context context, XC_LoadPackage.LoadPackageParam lpparam

ApkFile apkFile = null;
try {
apkFile = new ApkFile(lpparam.appInfo.sourceDir);
apkFile = new ApkFile(wechatApk);
DexClass[] dexClasses = apkFile.getDexClasses();

wxClasses.clear();

for (int i = 0; i < dexClasses.length; i++) {
wxClasses.add(ReflectionUtil.getClassName(dexClasses[i]));
}
Expand All @@ -66,14 +77,14 @@ public static void init(Context context, XC_LoadPackage.LoadPackageParam lpparam

//LuckMoney
try {
Class ReceiveUIParamNameClass = ReflectionUtil.findClassesFromPackage(lpparam.classLoader, wxClasses, "com.tencent.mm", 1)
Class ReceiveUIParamNameClass = ReflectionUtil.findClassesFromPackage(classLoader, wxClasses, "com.tencent.mm", 1)
.filterByMethod(String.class, "getInfo")
.filterByMethod(int.class, "getType")
.filterByMethod(void.class, "reset")
.firstOrNull();
hp.ReceiveUIParamNameClassName = ReceiveUIParamNameClass.getName();

Class RequestCallerClass = ReflectionUtil.findClassesFromPackage(lpparam.classLoader, wxClasses, "com.tencent.mm", 1)
Class RequestCallerClass = ReflectionUtil.findClassesFromPackage(classLoader, wxClasses, "com.tencent.mm", 1)
.filterByField("foreground", "boolean")
.filterByMethod(void.class, int.class, String.class, int.class, boolean.class)
.filterByMethod(void.class, "cancel", int.class)
Expand All @@ -85,7 +96,7 @@ public static void init(Context context, XC_LoadPackage.LoadPackageParam lpparam
void.class, RequestCallerClass, int.class)
.getName();

Class NetworkRequestClass = ReflectionUtil.findClassesFromPackage(lpparam.classLoader, wxClasses, "com.tencent.mm", 1)
Class NetworkRequestClass = ReflectionUtil.findClassesFromPackage(classLoader, wxClasses, "com.tencent.mm", 1)
.filterByMethod(void.class, "unhold")
.filterByMethod(RequestCallerClass)
.firstOrNull();
Expand All @@ -95,7 +106,7 @@ public static void init(Context context, XC_LoadPackage.LoadPackageParam lpparam
RequestCallerClass)
.getName();

Class ReceiveLuckyMoneyRequestClass = ReflectionUtil.findClassesFromPackage(lpparam.classLoader, wxClasses, "com.tencent.mm.plugin.luckymoney", 1)
Class ReceiveLuckyMoneyRequestClass = ReflectionUtil.findClassesFromPackage(classLoader, wxClasses, "com.tencent.mm.plugin.luckymoney", 1)
.filterByField("msgType", "int")
.filterByMethod(void.class, int.class, String.class, JSONObject.class)
.firstOrNull();
Expand All @@ -105,15 +116,15 @@ public static void init(Context context, XC_LoadPackage.LoadPackageParam lpparam
void.class, int.class, String.class, JSONObject.class)
.getName();

hp.LuckyMoneyRequestClassName = ReflectionUtil.findClassesFromPackage(lpparam.classLoader, wxClasses, "com.tencent.mm.plugin.luckymoney", 1)
hp.LuckyMoneyRequestClassName = ReflectionUtil.findClassesFromPackage(classLoader, wxClasses, "com.tencent.mm.plugin.luckymoney", 1)
.filterByField("talker", "java.lang.String")
.filterByMethod(void.class, int.class, String.class, JSONObject.class)
.filterByMethod(int.class, "getType")
.filterByNoMethod(boolean.class)
.firstOrNull()
.getName();

hp.GetTransferRequestClassName = ReflectionUtil.findClassesFromPackage(lpparam.classLoader, wxClasses, "com.tencent.mm.plugin.remittance", 1)
hp.GetTransferRequestClassName = ReflectionUtil.findClassesFromPackage(classLoader, wxClasses, "com.tencent.mm.plugin.remittance", 1)
.filterByField("java.lang.String")
.filterByNoField("int")

Expand All @@ -122,7 +133,7 @@ public static void init(Context context, XC_LoadPackage.LoadPackageParam lpparam
.firstOrNull()
.getName();

Class LuckyMoneyReceiveUIClass = XposedHelpers.findClass(hp.LuckyMoneyReceiveUIClassName, lpparam.classLoader);
Class LuckyMoneyReceiveUIClass = ReflectionUtil.findClassIfExists(hp.LuckyMoneyReceiveUIClassName, classLoader);
hp.ReceiveUIMethod = ReflectionUtil.findMethodsByExactParameters(LuckyMoneyReceiveUIClass,
boolean.class, int.class, int.class, String.class, ReceiveUIParamNameClass)
.getName();
Expand All @@ -134,7 +145,7 @@ public static void init(Context context, XC_LoadPackage.LoadPackageParam lpparam

//ADBlock
try {
Class XMLParserClass = ReflectionUtil.findClassesFromPackage(lpparam.classLoader, wxClasses, "com.tencent.mm.sdk.platformtools", 0)
Class XMLParserClass = ReflectionUtil.findClassesFromPackage(classLoader, wxClasses, "com.tencent.mm.sdk.platformtools", 0)
.filterByMethod(Map.class, String.class, String.class)
.firstOrNull();
hp.XMLParserClassName = XMLParserClass.getName();
Expand All @@ -148,7 +159,7 @@ public static void init(Context context, XC_LoadPackage.LoadPackageParam lpparam

//AntiRevoke
try {
ReflectionUtil.Classes storageClasses = ReflectionUtil.findClassesFromPackage(lpparam.classLoader, wxClasses, "com.tencent.mm.storage", 0);
ReflectionUtil.Classes storageClasses = ReflectionUtil.findClassesFromPackage(classLoader, wxClasses, "com.tencent.mm.storage", 0);
Class MsgInfoClass = storageClasses
.filterByMethod(boolean.class, "isSystem")
.firstOrNull();
Expand All @@ -175,12 +186,12 @@ public static void init(Context context, XC_LoadPackage.LoadPackageParam lpparam

//Photo Limits
try {
Class SelectConversationUIClass = XposedHelpers.findClass(hp.SelectConversationUIClassName, lpparam.classLoader);
Class SelectConversationUIClass = XposedHelpers.findClass(hp.SelectConversationUIClassName, classLoader);
hp.SelectConversationUICheckLimitMethod = ReflectionUtil.findMethodsByExactParameters(SelectConversationUIClass,
boolean.class, boolean.class)
.getName();

hp.ContactInfoClassName = ReflectionUtil.findClassesFromPackage(lpparam.classLoader, wxClasses, "com.tencent.mm.storage", 0)
hp.ContactInfoClassName = ReflectionUtil.findClassesFromPackage(classLoader, wxClasses, "com.tencent.mm.storage", 0)
.filterByMethod(String.class, "getCityCode")
.filterByMethod(String.class, "getCountryCode")
.firstOrNull()
Expand All @@ -189,8 +200,6 @@ public static void init(Context context, XC_LoadPackage.LoadPackageParam lpparam
} catch (Error | Exception e) {
log("Search Photo Limits Classes Failed!");
}

saveConfig(context);
}

private static int getVersionNum(String version) {
Expand Down
Loading