diff --git a/app/src/main/java/me/firesun/wechat/enhancement/Main.java b/app/src/main/java/me/firesun/wechat/enhancement/Main.java
index fa94970..fb4a976 100644
--- a/app/src/main/java/me/firesun/wechat/enhancement/Main.java
+++ b/app/src/main/java/me/firesun/wechat/enhancement/Main.java
@@ -17,6 +17,7 @@
import me.firesun.wechat.enhancement.plugin.IPlugin;
import me.firesun.wechat.enhancement.plugin.Limits;
import me.firesun.wechat.enhancement.plugin.LuckMoney;
+import me.firesun.wechat.enhancement.plugin.SecretFriend;
import me.firesun.wechat.enhancement.util.HookParams;
import me.firesun.wechat.enhancement.util.SearchClasses;
@@ -33,6 +34,7 @@ public class Main implements IXposedHookLoadPackage {
new HideModule(),
new LuckMoney(),
new Limits(),
+ new SecretFriend()
};
@Override
diff --git a/app/src/main/java/me/firesun/wechat/enhancement/PreferencesUtils.java b/app/src/main/java/me/firesun/wechat/enhancement/PreferencesUtils.java
index 5b16c00..6818c05 100644
--- a/app/src/main/java/me/firesun/wechat/enhancement/PreferencesUtils.java
+++ b/app/src/main/java/me/firesun/wechat/enhancement/PreferencesUtils.java
@@ -81,6 +81,13 @@ public static boolean isBreakLimit() {
return getInstance().getBoolean("is_break_limit", false);
}
+ public static boolean isEnableSecretFriend() {
+ return getInstance().getBoolean("is_secret_friend", false);
+ }
+
+ public static String secretFriendIds() {
+ return getInstance().getString("secret_friend_ids", "").replace(",", ",");
+ }
}
diff --git a/app/src/main/java/me/firesun/wechat/enhancement/plugin/SecretFriend.java b/app/src/main/java/me/firesun/wechat/enhancement/plugin/SecretFriend.java
new file mode 100644
index 0000000..92e9417
--- /dev/null
+++ b/app/src/main/java/me/firesun/wechat/enhancement/plugin/SecretFriend.java
@@ -0,0 +1,114 @@
+package me.firesun.wechat.enhancement.plugin;
+
+import android.app.Activity;
+import android.content.ClipboardManager;
+import android.content.Context;
+import android.os.Bundle;
+import android.widget.BaseAdapter;
+import android.widget.Toast;
+
+import de.robv.android.xposed.XC_MethodHook;
+import de.robv.android.xposed.XposedHelpers;
+import de.robv.android.xposed.callbacks.XC_LoadPackage;
+import me.firesun.wechat.enhancement.PreferencesUtils;
+import me.firesun.wechat.enhancement.util.HookParams;
+
+import static android.widget.Toast.LENGTH_LONG;
+import static me.firesun.wechat.enhancement.util.ReflectionUtil.log;
+
+public class SecretFriend implements IPlugin {
+
+ //暂时只支持隐藏单个id,多id需要建立对照表
+ private int secretItemIndex = -1;
+ private Class conversationWithCacheAdapterClass;
+
+ @Override
+ public void hook(XC_LoadPackage.LoadPackageParam lpparam) {
+ try {
+ log("SecretFriend hook " + HookParams.getInstance().ConversationWithCacheAdapterClassName);
+ conversationWithCacheAdapterClass = XposedHelpers.findClass(HookParams.getInstance().ConversationWithCacheAdapterClassName, lpparam.classLoader);
+ } catch (Error | Exception e) {
+ }
+
+ XposedHelpers.findAndHookMethod(HookParams.getInstance().ChattingUIClassName, lpparam.classLoader, "onCreate", Bundle.class, new XC_MethodHook() {
+ @Override
+ protected void afterHookedMethod(MethodHookParam param) {
+ try {
+ if (PreferencesUtils.isEnableSecretFriend()) {
+ Activity activity = (Activity) param.thisObject;
+ ClipboardManager cmb = (ClipboardManager) activity.getSystemService(Context.CLIPBOARD_SERVICE);
+ String wechatId = activity.getIntent().getStringExtra("Chat_User");
+ log(wechatId);
+ cmb.setText(wechatId);
+ Toast.makeText(activity, "微信ID:" + wechatId + "已复制到剪切板", LENGTH_LONG).show();
+ }
+ } catch (Error | Exception e) {
+ }
+ }
+ });
+
+// XposedBridge.hookAllConstructors(HookParams.getInstance().ConversationWithCacheAdapterClass, new XC_MethodHook() {
+// @Override
+// protected void afterHookedMethod(MethodHookParam param) throws Throwable {
+// if (PreferencesUtils.isEnableSecretFriend()) {
+// //BaseAdapter adapter = (BaseAdapter) param.thisObject;
+// secretItemIndex = -1;
+// }
+// }
+// });
+
+ XposedHelpers.findAndHookMethod(conversationWithCacheAdapterClass.getSuperclass(),
+ HookParams.getInstance().MMBaseAdapter_getItemInternal, int.class, new XC_MethodHook() {
+ @Override
+ protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
+ if (PreferencesUtils.isEnableSecretFriend() && secretItemIndex > -1) {
+ BaseAdapter adapter = (BaseAdapter) param.thisObject;
+ if (adapter.getClass().equals(conversationWithCacheAdapterClass)) {
+ int index = (int) param.args[0];
+ if (index >= secretItemIndex) {
+ param.args[0] = index + 1;
+ }
+ }
+ }
+ }
+ });
+
+ XposedHelpers.findAndHookMethod(conversationWithCacheAdapterClass.getSuperclass(),"getCount", new XC_MethodHook() {
+ @Override
+ protected void afterHookedMethod(MethodHookParam param) throws Throwable {
+ if (PreferencesUtils.isEnableSecretFriend()) {
+ log("getCount: " + param.thisObject.getClass().getName());
+ if (param.thisObject.getClass().equals(conversationWithCacheAdapterClass)) {
+ if (secretItemIndex > -1) {
+ int size = (int) param.getResult();
+ log("count: " + size);
+ if (size > 0) {
+ param.setResult(size - 1);
+ }
+ }
+ }
+ }
+ }
+ });
+
+ // Hook notifyDataSetChanged() of base adapters
+ XposedHelpers.findAndHookMethod(BaseAdapter.class, "notifyDataSetChanged", new XC_MethodHook() {
+ @Override
+ protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
+ if (PreferencesUtils.isEnableSecretFriend()) {
+ BaseAdapter adapter = (BaseAdapter) param.thisObject;
+ if (adapter.getClass().equals(conversationWithCacheAdapterClass)) {
+ secretItemIndex = -1;
+ for (int i = 0; i < adapter.getCount(); i++) {
+ String username = (String) XposedHelpers.getObjectField(adapter.getItem(i), "field_username");
+ if (username.equals(PreferencesUtils.secretFriendIds())) {
+ secretItemIndex = i;
+ break;
+ }
+ }
+ }
+ }
+ }
+ });
+ }
+}
diff --git a/app/src/main/java/me/firesun/wechat/enhancement/util/HookParams.java b/app/src/main/java/me/firesun/wechat/enhancement/util/HookParams.java
index 0a065be..1fad12d 100644
--- a/app/src/main/java/me/firesun/wechat/enhancement/util/HookParams.java
+++ b/app/src/main/java/me/firesun/wechat/enhancement/util/HookParams.java
@@ -4,7 +4,7 @@ public class HookParams {
public static final String SAVE_WECHAT_ENHANCEMENT_CONFIG = "wechat.intent.action.SAVE_WECHAT_ENHANCEMENT_CONFIG";
public static final String WECHAT_ENHANCEMENT_CONFIG_NAME = "wechat_enhancement_config";
public static final String WECHAT_PACKAGE_NAME = "com.tencent.mm";
- public static final int VERSION_CODE = 46; //大版本变动时候才需要修改
+ public static final int VERSION_CODE = 47; //大版本变动时候才需要修改
public String SQLiteDatabaseClassName = "com.tencent.wcdb.database.SQLiteDatabase";
public String SQLiteDatabaseUpdateMethod = "updateWithOnConflict";
@@ -40,6 +40,13 @@ public class HookParams {
public String versionName;
public int versionCode;
+ public String ChattingUIClassName = "com.tencent.mm.ui.chatting.ChattingUI";
+// public Class ConversationWithCacheAdapterClass;
+ public String ConversationWithCacheAdapterClassName;
+// public Class MMBaseAdapterClass;
+ public String MMBaseAdapterClassName;
+ public String MMBaseAdapter_getItemInternal;
+
private static HookParams instance = null;
private HookParams() {
diff --git a/app/src/main/java/me/firesun/wechat/enhancement/util/ReflectionUtil.java b/app/src/main/java/me/firesun/wechat/enhancement/util/ReflectionUtil.java
index 22eafd2..836b4c3 100644
--- a/app/src/main/java/me/firesun/wechat/enhancement/util/ReflectionUtil.java
+++ b/app/src/main/java/me/firesun/wechat/enhancement/util/ReflectionUtil.java
@@ -292,6 +292,28 @@ public final Classes filterByMethod(Class returnType, String methodName, Class..
return new Classes(arrayList);
}
+ public final Classes filterByMethod(String methodName, Class... parameterTypes) {
+ List arrayList = new ArrayList();
+ for (Object next : this.classes) {
+ Method method = ReflectionUtil.findMethodExactIfExists((Class) next, methodName, (Class[]) Arrays.copyOf(parameterTypes, parameterTypes.length));
+ if (method != null) {
+ arrayList.add(next);
+ }
+ }
+
+ return new Classes(arrayList);
+ }
+
+ public final Classes filterBySuper(Class superClass) {
+ List arrayList = new ArrayList();
+ for (Class next : this.classes) {
+ if (next.getSuperclass() == superClass) {
+ arrayList.add(next);
+ }
+ }
+ return new Classes(arrayList);
+ }
+
public final Class> firstOrNull() {
if (this.classes.isEmpty())
return null;
@@ -303,5 +325,6 @@ else if (this.classes.size() > 1) {
}
return this.classes.get(0);
}
+
}
}
diff --git a/app/src/main/java/me/firesun/wechat/enhancement/util/SearchClasses.java b/app/src/main/java/me/firesun/wechat/enhancement/util/SearchClasses.java
index 9d18d58..c2e20a0 100644
--- a/app/src/main/java/me/firesun/wechat/enhancement/util/SearchClasses.java
+++ b/app/src/main/java/me/firesun/wechat/enhancement/util/SearchClasses.java
@@ -11,6 +11,7 @@
import org.json.JSONObject;
+import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -200,6 +201,35 @@ public static void generateConfig(String wechatApk, ClassLoader classLoader, Str
} catch (Error | Exception e) {
log("Search Photo Limits Classes Failed!");
}
+
+ //SecretFriend
+ try {
+ Class conversationWithCacheAdapterClass = ReflectionUtil.findClassesFromPackage(classLoader, wxClasses, "com.tencent.mm.ui.conversation", 0)
+ .filterByMethod("clearCache")
+ .firstOrNull();
+ hp.ConversationWithCacheAdapterClassName = conversationWithCacheAdapterClass.getName();
+ log("ConversationWithCacheAdapterClassName: " + hp.ConversationWithCacheAdapterClassName);
+ log(conversationWithCacheAdapterClass.getSuperclass().getName());
+
+// Class MMBaseAdapterClass = ReflectionUtil.findClassesFromPackage(classLoader, wxClasses, "com.tencent.mm.ui", 0)
+// .filterBySuper(BaseAdapter.class)
+// .filterByField("TAG", "java.lang.String")
+// .firstOrNull();
+ Class MMBaseAdapterClass = conversationWithCacheAdapterClass.getSuperclass();
+ hp.MMBaseAdapterClassName = MMBaseAdapterClass.getName();
+ log("MMBaseAdapterClassName: " + hp.MMBaseAdapterClassName);
+ for (Method m: MMBaseAdapterClass.getDeclaredMethods()) {
+ if (m.getParameterTypes().length == 1 && m.getParameterTypes()[0] == int.class
+ && !"getItem".equals(m.getName()) && !"getItemId".equals(m.getName())) {
+ hp.MMBaseAdapter_getItemInternal = m.getName();
+ log(hp.MMBaseAdapter_getItemInternal);
+ break;
+ }
+ }
+ } catch (Error | Exception e) {
+ log("Search ConversationWithCacheAdapter Classes Failed! " + e);
+ //throw e;
+ }
}
private static int getVersionNum(String version) {
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index a830cee..a34725a 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -36,4 +36,7 @@
生成配置成功
生成配置失败
正在生成配置…
+ 私密好友
+ 启用私密好友
+ 私密好友清单
diff --git a/app/src/main/res/xml/pref_setting.xml b/app/src/main/res/xml/pref_setting.xml
index a163f6e..2cf1a62 100644
--- a/app/src/main/res/xml/pref_setting.xml
+++ b/app/src/main/res/xml/pref_setting.xml
@@ -102,6 +102,16 @@
+
+
+
+