Skip to content

Commit 8ef5cd5

Browse files
committed
feat: enhance method loading and update supported versions
1 parent 5b1d9e4 commit 8ef5cd5

File tree

8 files changed

+173
-121
lines changed

8 files changed

+173
-121
lines changed

app/build.gradle.kts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,8 @@ android {
4545
applicationId = "com.wmods.wppenhacer"
4646
minSdk = 28
4747
targetSdk = 34
48-
versionCode = 153
49-
versionName = "1.5.3-DEV ($gitHash)"
48+
versionCode = 154
49+
versionName = "1.5.4-DEV ($gitHash)"
5050
multiDexEnabled = true
5151

5252
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
Lines changed: 20 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package com.wmods.wppenhacer;
22

33
import android.app.Activity;
4-
import android.util.Log;
54

65
import com.wmods.wppenhacer.xposed.core.WppCore;
76
import com.wmods.wppenhacer.xposed.core.components.AlertDialogWpp;
@@ -16,13 +15,11 @@
1615
import java.util.concurrent.TimeUnit;
1716

1817
import de.robv.android.xposed.XposedBridge;
19-
import okhttp3.OkHttpClient;
20-
2118
import io.noties.markwon.Markwon;
19+
import okhttp3.OkHttpClient;
2220

2321
public class UpdateChecker implements Runnable {
2422

25-
private static final String TAG = "WAE_UpdateChecker";
2623
private static final String LATEST_RELEASE_API = "https://api.github.com/repos/Dev4Mod/WaEnhancer/releases/latest";
2724
private static final String RELEASE_TAG_PREFIX = "debug-";
2825
private static final String TELEGRAM_UPDATE_URL = "https://t.me/waenhancher";
@@ -52,97 +49,75 @@ private static synchronized OkHttpClient getHttpClient() {
5249

5350
@Override
5451
public void run() {
55-
XposedBridge.log("[" + TAG + "] UpdateChecker.run() started");
5652
try {
57-
XposedBridge.log("[" + TAG + "] Starting update check...");
58-
53+
5954
var request = new okhttp3.Request.Builder()
6055
.url(LATEST_RELEASE_API)
6156
.build();
62-
57+
6358
String hash;
6459
String changelog;
6560
String publishedAt;
66-
61+
6762
try (var response = getHttpClient().newCall(request).execute()) {
6863
if (!response.isSuccessful()) {
69-
XposedBridge.log("[" + TAG + "] Update check failed: HTTP " + response.code());
7064
return;
7165
}
72-
66+
7367
var body = response.body();
74-
if (body == null) {
75-
XposedBridge.log("[" + TAG + "] Update check failed: Empty response body");
76-
return;
77-
}
78-
7968
var content = body.string();
8069
var release = new JSONObject(content);
8170
var tagName = release.optString("tag_name", "");
82-
83-
XposedBridge.log("[" + TAG + "] Latest release tag: " + tagName);
84-
71+
8572
if (tagName.isBlank() || !tagName.startsWith(RELEASE_TAG_PREFIX)) {
86-
XposedBridge.log("[" + TAG + "] Invalid or non-debug release tag");
8773
return;
8874
}
89-
75+
9076
hash = tagName.substring(RELEASE_TAG_PREFIX.length()).trim();
9177
changelog = release.optString("body", "No changelog available.").trim();
9278
publishedAt = release.optString("published_at", "");
93-
94-
XposedBridge.log("[" + TAG + "] Release hash: " + hash + ", published: " + publishedAt);
79+
9580
}
9681

9782
if (hash.isBlank()) {
98-
XposedBridge.log("[" + TAG + "] Empty hash, skipping");
9983
return;
10084
}
101-
85+
10286
var appInfo = mActivity.getPackageManager().getPackageInfo(BuildConfig.APPLICATION_ID, 0);
10387
boolean isNewVersion = !appInfo.versionName.toLowerCase().contains(hash.toLowerCase().trim());
10488
boolean isIgnored = Objects.equals(WppCore.getPrivString("ignored_version", ""), hash);
105-
89+
10690
if (isNewVersion && !isIgnored) {
107-
XposedBridge.log("[" + TAG + "] New version available, showing dialog");
108-
91+
10992
final String finalHash = hash;
11093
final String finalChangelog = changelog;
11194
final String finalPublishedAt = publishedAt;
112-
95+
11396
mActivity.runOnUiThread(() -> {
11497
showUpdateDialog(finalHash, finalChangelog, finalPublishedAt);
11598
});
116-
} else {
117-
XposedBridge.log("[" + TAG + "] No update needed (isNew=" + isNewVersion + ", isIgnored=" + isIgnored + ")");
11899
}
119-
} catch (java.net.SocketTimeoutException e) {
120-
XposedBridge.log("[" + TAG + "] Update check timeout: " + e.getMessage());
121-
} catch (java.io.IOException e) {
122-
XposedBridge.log("[" + TAG + "] Network error during update check: " + e.getMessage());
123100
} catch (Exception e) {
124-
XposedBridge.log("[" + TAG + "] Unexpected error during update check: " + e.getMessage());
125101
XposedBridge.log(e);
126102
}
127103
}
128104

129105
private void showUpdateDialog(String hash, String changelog, String publishedAt) {
130-
XposedBridge.log("[" + TAG + "] Attempting to show update dialog");
131106
try {
132107
var markwon = Markwon.create(mActivity);
133108
var dialog = new AlertDialogWpp(mActivity);
134-
109+
135110
// Format the published date
136111
String formattedDate = formatPublishedDate(publishedAt);
137-
112+
138113
// Build simple message with version and date
139114
StringBuilder message = new StringBuilder();
140115
message.append("📦 **Version:** `").append(hash).append("`\n");
141116
if (!formattedDate.isEmpty()) {
142117
message.append("📅 **Released:** ").append(formattedDate).append("\n");
143118
}
144119
message.append("\n### What's New\n\n").append(changelog);
145-
120+
146121
dialog.setTitle("🎉 New Update Available!");
147122
dialog.setMessage(markwon.toMarkdown(message.toString()));
148123
dialog.setNegativeButton("Ignore", (dialog1, which) -> {
@@ -154,10 +129,8 @@ private void showUpdateDialog(String hash, String changelog, String publishedAt)
154129
dialog1.dismiss();
155130
});
156131
dialog.show();
157-
158-
XposedBridge.log("[" + TAG + "] Update dialog shown successfully");
132+
159133
} catch (Exception e) {
160-
XposedBridge.log("[" + TAG + "] Error showing update dialog: " + e.getMessage());
161134
e.printStackTrace();
162135
}
163136
}
@@ -171,21 +144,21 @@ private String formatPublishedDate(String isoDate) {
171144
if (isoDate == null || isoDate.isEmpty()) {
172145
return "";
173146
}
174-
147+
175148
try {
176149
// Parse ISO 8601 date
177150
SimpleDateFormat isoFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US);
178151
Date date = isoFormat.parse(isoDate);
179-
152+
180153
if (date != null) {
181154
// Format to readable date
182155
SimpleDateFormat displayFormat = new SimpleDateFormat("MMM dd, yyyy", Locale.US);
183156
return displayFormat.format(date);
184157
}
185158
} catch (Exception e) {
186-
XposedBridge.log("[" + TAG + "] Error parsing date: " + e.getMessage());
159+
XposedBridge.log(e);
187160
}
188-
161+
189162
return "";
190163
}
191164
}

app/src/main/java/com/wmods/wppenhacer/xposed/core/WppCore.java

Lines changed: 15 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,10 @@
2626
import com.wmods.wppenhacer.xposed.utils.Utils;
2727

2828
import org.json.JSONObject;
29-
import org.luckypray.dexkit.query.enums.StringMatchType;
3029

3130
import java.io.File;
3231
import java.lang.reflect.Field;
3332
import java.lang.reflect.Method;
34-
import java.lang.reflect.Modifier;
3533
import java.util.Arrays;
3634
import java.util.Collections;
3735
import java.util.HashSet;
@@ -49,7 +47,6 @@ public class WppCore {
4947
static final HashSet<ActivityChangeState> listenerAcitivity = new HashSet<>();
5048
@SuppressLint("StaticFieldLeak")
5149
static Activity mCurrentActivity;
52-
private static Class<?> mGenJidClass;
5350
private static Method mGenJidMethod;
5451
private static Class bottomDialog;
5552
private static SharedPreferences privPrefs;
@@ -71,16 +68,12 @@ public class WppCore {
7168

7269
public static void Initialize(ClassLoader loader, XSharedPreferences pref) throws Exception {
7370
privPrefs = Utils.getApplication().getSharedPreferences("WaGlobal", Context.MODE_PRIVATE);
71+
72+
7473
// init UserJID
75-
var mSendReadClass = Unobfuscator.findFirstClassUsingName(loader, StringMatchType.EndsWith,
76-
"SendReadReceiptJob");
77-
var subClass = ReflectionUtils
78-
.findConstructorUsingFilter(mSendReadClass, (constructor) -> constructor.getParameterCount() == 8)
79-
.getParameterTypes()[0];
80-
mGenJidClass = ReflectionUtils
81-
.findFieldUsingFilter(subClass, (field) -> Modifier.isStatic(field.getModifiers())).getType();
82-
mGenJidMethod = ReflectionUtils.findMethodUsingFilter(mGenJidClass,
83-
(method) -> method.getParameterCount() == 1 && !Modifier.isStatic(method.getModifiers()));
74+
var companionField = FMessageWpp.UserJid.TYPE_JID.getDeclaredField("Companion");
75+
mGenJidMethod = ReflectionUtils.findMethodUsingFilter(companionField.getType(), m -> m.getParameterCount() == 1 && String.class.equals(m.getParameterTypes()[0]) && FMessageWpp.UserJid.TYPE_JID.equals(m.getReturnType()));
76+
8477
// Bottom Dialog
8578
bottomDialog = Unobfuscator.loadDialogViewClass(loader);
8679

@@ -183,7 +176,7 @@ public static Object getUserJidFromPhoneJid(Object userJid) {
183176
public static void initBridge(Context context) throws Exception {
184177
var prefsCacheHooks = UnobfuscatorCache.getInstance().sPrefsCacheHooks;
185178
int preferredOrder = prefsCacheHooks.getInt("preferredOrder", 1); // 0 for ProviderClient first, 1 for
186-
// BridgeClient first
179+
// BridgeClient first
187180

188181
boolean connected = false;
189182
if (preferredOrder == 0) {
@@ -257,7 +250,7 @@ public static void sendReaction(String s, Object objMessage) {
257250
try {
258251
var senderMethod = ReflectionUtils.findMethodUsingFilter(actionUser,
259252
(method) -> method.getParameterCount() == 3 && Arrays.equals(method.getParameterTypes(),
260-
new Class[] { FMessageWpp.TYPE, String.class, boolean.class }));
253+
new Class[]{FMessageWpp.TYPE, String.class, boolean.class}));
261254
senderMethod.invoke(getActionUser(), objMessage, s, !TextUtils.isEmpty(s));
262255
} catch (Exception e) {
263256
Utils.showToast("Error in sending reaction:" + e.getMessage(), Toast.LENGTH_SHORT);
@@ -357,7 +350,7 @@ public synchronized static Class getDataUsageActivityClass(@NonNull ClassLoader
357350
}
358351

359352
public synchronized static Class getTextStatusComposerFragmentClass(@NonNull ClassLoader loader) throws Exception {
360-
var classes = new String[] {
353+
var classes = new String[]{
361354
"com.whatsapp.status.composer.TextStatusComposerFragment",
362355
"com.whatsapp.statuscomposer.composer.TextStatusComposerFragment"
363356
};
@@ -370,7 +363,7 @@ public synchronized static Class getTextStatusComposerFragmentClass(@NonNull Cla
370363
}
371364

372365
public synchronized static Class getVoipManagerClass(@NonNull ClassLoader loader) throws Exception {
373-
var classes = new String[] {
366+
var classes = new String[]{
374367
"com.whatsapp.voipcalling.Voip",
375368
"com.whatsapp.calling.voipcalling.Voip"
376369
};
@@ -383,7 +376,7 @@ public synchronized static Class getVoipManagerClass(@NonNull ClassLoader loader
383376
}
384377

385378
public synchronized static Class getVoipCallInfoClass(@NonNull ClassLoader loader) throws Exception {
386-
var classes = new String[] {
379+
var classes = new String[]{
387380
"com.whatsapp.voipcalling.CallInfo",
388381
"com.whatsapp.calling.infra.voipcalling.CallInfo"
389382
};
@@ -442,8 +435,8 @@ public static String getSContactName(FMessageWpp.UserJid userJid, boolean saveOn
442435
}
443436
String name = null;
444437
var rawJid = userJid.getPhoneRawString();
445-
var cursor = mWaDatabase.query("wa_contacts", new String[] { "display_name" }, selection,
446-
new String[] { rawJid }, null, null, null);
438+
var cursor = mWaDatabase.query("wa_contacts", new String[]{"display_name"}, selection,
439+
new String[]{rawJid}, null, null, null);
447440
if (cursor.moveToFirst()) {
448441
name = cursor.getString(0);
449442
cursor.close();
@@ -458,8 +451,8 @@ public static String getWppContactName(FMessageWpp.UserJid userJid) {
458451
return "";
459452
String name = null;
460453
var rawJid = userJid.getPhoneRawString();
461-
var cursor2 = mWaDatabase.query("wa_vnames", new String[] { "verified_name" }, "jid = ?",
462-
new String[] { rawJid }, null, null, null);
454+
var cursor2 = mWaDatabase.query("wa_vnames", new String[]{"verified_name"}, "jid = ?",
455+
new String[]{rawJid}, null, null, null);
463456
if (cursor2.moveToFirst()) {
464457
name = cursor2.getString(0);
465458
cursor2.close();
@@ -486,9 +479,8 @@ public static Object getFMessageFromKey(Object messageKey) {
486479
public static Object createUserJid(@Nullable String rawjid) {
487480
if (rawjid == null)
488481
return null;
489-
var genInstance = XposedHelpers.newInstance(mGenJidClass);
490482
try {
491-
return mGenJidMethod.invoke(genInstance, rawjid);
483+
return mGenJidMethod.invoke(null, rawjid);
492484
} catch (Exception e) {
493485
XposedBridge.log(e);
494486
}

app/src/main/java/com/wmods/wppenhacer/xposed/core/devkit/Unobfuscator.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2383,9 +2383,15 @@ public static Class loadWaContactClass(ClassLoader classLoader) throws Exception
23832383

23842384
}
23852385

2386+
23862387
public static Method loadViewAddSearchBarMethod(ClassLoader classLoader) throws Exception {
2387-
return UnobfuscatorCache.getInstance().getMethod(classLoader, () -> findFirstMethodUsingStrings(classLoader,
2388-
StringMatchType.Contains, "HeaderFooterRecyclerViewAdapter/addHeaderViewItemIfNeeded/duplicate-item"));
2388+
return UnobfuscatorCache.getInstance().getMethod(classLoader, () -> {
2389+
for (var str : List.of("HeaderFooterRecyclerViewAdapter/addHeaderViewItemIfNeeded", "HeaderFooterRecyclerViewAdapter/addFooterViewItemAtPositionIfNeeded")) {
2390+
var method = findFirstMethodUsingStrings(classLoader, StringMatchType.Contains, str);
2391+
if (method != null) return method;
2392+
}
2393+
throw new RuntimeException("ViewAddSearchBar method not found");
2394+
});
23892395
}
23902396

23912397
public static Method loadMenuSearchMethod(ClassLoader classLoader) throws Exception {

app/src/main/java/com/wmods/wppenhacer/xposed/features/general/Others.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -652,7 +652,18 @@ private void hookSearchbar(String filterChats) throws Exception {
652652
XposedBridge.hookMethod(searchbar, new XC_MethodHook() {
653653
@Override
654654
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
655-
var view = (View) param.args[0];
655+
View view = null;
656+
if (param.args[0] instanceof View) {
657+
view = (View) param.args[0];
658+
} else {
659+
var auxFace = ((Method) param.method).getParameterTypes()[0];
660+
var method = ReflectionUtils.findMethodUsingFilter(auxFace, m -> m.getReturnType() == View.class);
661+
if (method != null) {
662+
var currentActivity = WppCore.getCurrentActivity();
663+
view = (View) method.invoke(param.args[0], currentActivity);
664+
}
665+
}
666+
656667
if ((view.getId() == searchBarID || view.findViewById(searchBarID) != null) && !Objects.equals(filterChats, "2")) {
657668
param.setResult(null);
658669
}

0 commit comments

Comments
 (0)