From ddf9e51acd6b1581209584deccedc6e794e195dd Mon Sep 17 00:00:00 2001 From: Sunny Young Date: Thu, 13 Jul 2023 14:55:03 +0800 Subject: [PATCH] Fix support for WeChat 3.8.1 --- README.md | 20 ++-- WeChatTweak/AntiRevoke.m | 104 +++++++----------- .../Supporting Files/WeChatTweakHeaders.h | 41 +++---- 3 files changed, 62 insertions(+), 103 deletions(-) diff --git a/README.md b/README.md index 606187e..cfc322c 100644 --- a/README.md +++ b/README.md @@ -57,21 +57,23 @@ ## FAQ -1. 功能失效? +- 功能失效? 请提交 **issue** 然后等待,或提交 **pull request** 一起发电。 -2. Issue 没有响应 or 回复? +- Issue 没有响应 or 回复? 开源项目,用爱发电,耐心等。 -3. 兼容旧版本客户端吗? +- 兼容旧版本客户端吗? 不,为了降低维护成本和保证更新速度,默认只支持**最新**版本客户端。 -4. 会封号吗? +- 会封号吗? 在**只使用该工具**的情况下**没有**出现过封号/风险提示,若有**使用过其他同类工具**则有可能会出现封号/风险提示,因此风险自负。 -5. 安装出现 `codesign_allocate helper tool cannot be found or used` 错误? +- 安装出现 `codesign_allocate helper tool cannot be found or used` 错误? 该错误为系统问题,暂未清楚原因,一般情况下重新执行安装操作即可。 -6. 安装完打开微信客户端提示 `没有权限打开应用程序`? - 先卸载,再重新安装一次即可,如仍无法解决请重启电脑。实在搞不定的,到 [issues](https://github.com/Sunnyyoung/WeChatTweak-macOS/issues?q=) 里找找类似问题并尝试解决。 -7. 截图失效? +- 安装完打开微信客户端提示 `没有权限打开应用程序`? + 先卸载,再重新安装一次即可,如仍无法解决请重启电脑。实在搞不定的,到 [issues](https://github.com/sunnyyoung/WeChatTweak-macOS/issues) 里找找类似问题并尝试解决。 +- 截图失效? 系统偏好设置 -> 隐私 -> 删除微信并重新添加 -> 重启微信客户端。 -8. 理性讨论。 +- 出现`“WeChat.app” cannot be opened because the developer cannot be verified.`怎么办? + 进入 `WeChat.app` 所在目录,通过右键菜单打开。 +- 理性讨论。 ## 参考 diff --git a/WeChatTweak/AntiRevoke.m b/WeChatTweak/AntiRevoke.m index b8b7fc3..f41188e 100644 --- a/WeChatTweak/AntiRevoke.m +++ b/WeChatTweak/AntiRevoke.m @@ -12,83 +12,56 @@ @implementation NSObject (AntiRevoke) static void __attribute__((constructor)) tweak(void) { - [objc_getClass("FFProcessReqsvrZZ") jr_swizzleMethod:NSSelectorFromString(@"processNewXMLMsg:sessionMsgList:") withMethod:@selector(tweak_processNewXMLMsg:sessionMsgList:) error:nil]; + [objc_getClass("FFProcessReqsvrZZ") jr_swizzleMethod:NSSelectorFromString(@"DelRevokedMsg:msgData:") withMethod:@selector(tweak_DelRevokedMsg:msgData:) error:nil]; + [objc_getClass("FFProcessReqsvrZZ") jr_swizzleMethod:NSSelectorFromString(@"notifyAddRevokePromptMsgOnMainThread:msgData:") withMethod:@selector(tweak_notifyAddRevokePromptMsgOnMainThread:msgData:) error:nil]; [objc_getClass("MMMessageCellView") jr_swizzleMethod:NSSelectorFromString(@"initWithFrame:") withMethod:@selector(tweak_initWithFrame:) error:nil]; [objc_getClass("MMMessageCellView") jr_swizzleMethod:NSSelectorFromString(@"populateWithMessage:") withMethod:@selector(tweak_populateWithMessage:) error:nil]; [objc_getClass("MMMessageCellView") jr_swizzleMethod:NSSelectorFromString(@"layout") withMethod:@selector(tweak_layout) error:nil]; } -- (void)tweak_processNewXMLMsg:(MessageData *)message sessionMsgList:(nullable id)sessionMsgList { - // - (id)GetMsgData:(id)arg1 svrId:(unsigned long long)arg2; - SEL GetMsgDataSelector = NSSelectorFromString(@"GetMsgData:svrId:"); - if (![self respondsToSelector:GetMsgDataSelector]) { - // Fallback to origin method - return [self tweak_processNewXMLMsg:message sessionMsgList:sessionMsgList]; - } - // Decode message - NSString *content = [[message.msgContent stringByReplacingOccurrencesOfString:@"\n" withString:@""] componentsSeparatedByString:@":"].lastObject; - NSDictionary *dictionary = [NSDictionary dictionaryWithXMLString:content]; - NSString *session = dictionary[@"revokemsg"][@"session"]; - NSString *newMessageID = dictionary[@"revokemsg"][@"newmsgid"]; - NSString *replaceMessage = dictionary[@"revokemsg"][@"replacemsg"]; - // Get message data - MessageData *messageData = ((id (*)(id, SEL, id, unsigned long long))objc_msgSend)(self, GetMsgDataSelector, session, newMessageID.longLongValue); +- (void)tweak_DelRevokedMsg:(NSString *)session msgData:(MessageData *)messageData { if (messageData.isSendFromSelf) { - // Fallback to origin method - [self tweak_processNewXMLMsg:message sessionMsgList:sessionMsgList]; + [self tweak_DelRevokedMsg:session msgData:messageData]; } else { - [self handleRevokedMessageIntoWithSession:session messageData:messageData replaceMessage:replaceMessage]; + messageData.mesSvrID = LONG_LONG_MAX; + [((FFProcessReqsvrZZ *)self) ModifyMsgData:session msgData:messageData]; + dispatch_async(dispatch_get_main_queue(), ^{ + [((FFProcessReqsvrZZ *)self) notifyDelMsgOnMainThread:session msgData:messageData isRevoke:YES]; + [((FFProcessReqsvrZZ *)self) notifyAddMsgOnMainThread:session msgData:messageData]; + }); } } -- (void)handleRevokedMessageIntoWithSession:(NSString *)session messageData:(MessageData *)messageData replaceMessage:(NSString *)replaceMessage { - MMRevokeMsgService *service = [[objc_getClass("MMServiceCenter") defaultCenter] getService:objc_getClass("MMRevokeMsgService")]; - [service.db insertRevokeMsg:({ - RevokeMsgItem *item = [[objc_getClass("RevokeMsgItem") alloc] init]; - item.svrId = @(messageData.mesSvrID).stringValue; - item.createTime = UINT32_MAX; - item; - })]; - WeChat *wechat = [objc_getClass("WeChat") sharedInstance]; - if ([wechat respondsToSelector:NSSelectorFromString(@"chatsViewController")]) { - id chatsViewController = [wechat valueForKey:@"chatsViewController"]; - if ([chatsViewController respondsToSelector:NSSelectorFromString(@"chatDetailSplitViewController")]) { - id chatDetailSplitViewController = [chatsViewController valueForKey:@"chatDetailSplitViewController"]; - if ([chatDetailSplitViewController respondsToSelector:NSSelectorFromString(@"chatMessageViewController")]) { - id chatMessageViewController = [chatDetailSplitViewController valueForKey:@"chatMessageViewController"]; - if ([chatMessageViewController respondsToSelector:NSSelectorFromString(@"reloadTableView")]) { - dispatch_async(dispatch_get_main_queue(), ^{ - ((void (*)(id, SEL))objc_msgSend)(chatMessageViewController, NSSelectorFromString(@"reloadTableView")); - }); - } - } - } - } - // Prepare notification information - MMServiceCenter *serviceCenter = [objc_getClass("MMServiceCenter") defaultCenter]; - NSUserNotification *userNotification = [[NSUserNotification alloc] init]; - BOOL isChatStatusNotifyOpen = YES; - if ([session rangeOfString:@"@chatroom"].location == NSNotFound) { - ContactStorage *contactStorage = [serviceCenter getService:objc_getClass("ContactStorage")]; - WCContactData *contact = [contactStorage GetContact:session]; - isChatStatusNotifyOpen = [contact isChatStatusNotifyOpen]; - userNotification.informativeText = replaceMessage; +- (void)tweak_notifyAddRevokePromptMsgOnMainThread:(NSString *)session msgData:(MessageData *)messageData { + MessageData *localMessage = [((FFProcessReqsvrZZ *)self) GetMsgData:session localId:messageData.mesLocalID]; + if (!localMessage || localMessage.mesSvrID != LONG_LONG_MAX) { + [self tweak_notifyAddRevokePromptMsgOnMainThread:session msgData:messageData]; } else { - GroupStorage *groupStorage = [serviceCenter getService:objc_getClass("GroupStorage")]; - WCContactData *groupContact = [groupStorage GetGroupContact:session]; - isChatStatusNotifyOpen = [groupContact isChatStatusNotifyOpen]; - NSString *groupName = groupContact.m_nsNickName.length ? groupContact.m_nsNickName : [NSBundle.tweakBundle localizedStringForKey:@"Tweak.Title.Group"]; - userNotification.informativeText = [NSString stringWithFormat:@"%@: %@", groupName, replaceMessage]; - } - // Dispatch notification - dispatch_async(dispatch_get_main_queue(), ^{ - // Deliver notification - WeChatTweakNotificationType notificationType = WeChatTweak.notificationType; - if (notificationType == WeChatTweakNotificationTypeReceiveAll || (notificationType == WeChatTweakNotificationTypeInherited && isChatStatusNotifyOpen)) { - [[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification:userNotification]; + MMServiceCenter *serviceCenter = [objc_getClass("MMServiceCenter") defaultCenter]; + NSUserNotification *userNotification = [[NSUserNotification alloc] init]; + BOOL isChatStatusNotifyOpen = YES; + if ([session rangeOfString:@"@chatroom"].location == NSNotFound) { + ContactStorage *contactStorage = [serviceCenter getService:objc_getClass("ContactStorage")]; + WCContactData *contact = [contactStorage GetContact:session]; + isChatStatusNotifyOpen = [contact isChatStatusNotifyOpen]; + userNotification.informativeText = messageData.msgContent; + } else { + GroupStorage *groupStorage = [serviceCenter getService:objc_getClass("GroupStorage")]; + WCContactData *groupContact = [groupStorage GetGroupContact:session]; + isChatStatusNotifyOpen = [groupContact isChatStatusNotifyOpen]; + NSString *groupName = groupContact.m_nsNickName.length ? groupContact.m_nsNickName : [NSBundle.tweakBundle localizedStringForKey:@"Tweak.Title.Group"]; + userNotification.informativeText = [NSString stringWithFormat:@"%@: %@", groupName, messageData.msgContent]; } - }); + // Dispatch notification + dispatch_async(dispatch_get_main_queue(), ^{ + // Deliver notification + WeChatTweakNotificationType notificationType = WeChatTweak.notificationType; + if (notificationType == WeChatTweakNotificationTypeReceiveAll || (notificationType == WeChatTweakNotificationTypeInherited && isChatStatusNotifyOpen)) { + [[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification:userNotification]; + } + }); + } } - (instancetype)tweak_initWithFrame:(NSRect)arg1 { @@ -111,8 +84,7 @@ static void __attribute__((constructor)) tweak(void) { - (void)tweak_populateWithMessage:(MMMessageTableItem *)tableItem { [self tweak_populateWithMessage:tableItem]; - MMRevokeMsgService *service = [[objc_getClass("MMServiceCenter") defaultCenter] getService:objc_getClass("MMRevokeMsgService")]; - BOOL recalled = tableItem.message ? (tableItem.message.messageType != MessageDataTypePrompt && tableItem.message.msgStatus == 4 && [service.db getRevokeMsg:@(tableItem.message.mesSvrID).stringValue] != NULL) : NO; + BOOL recalled = tableItem.message.mesSvrID == LONG_LONG_MAX; [((MMMessageCellView *)self).subviews enumerateObjectsUsingBlock:^(__kindof NSView * _Nonnull view, NSUInteger index, BOOL * _Nonnull stop) { if (view.tag != 9527) { return ; diff --git a/WeChatTweak/Supporting Files/WeChatTweakHeaders.h b/WeChatTweak/Supporting Files/WeChatTweakHeaders.h index 649346a..59e5c58 100644 --- a/WeChatTweak/Supporting Files/WeChatTweakHeaders.h +++ b/WeChatTweak/Supporting Files/WeChatTweakHeaders.h @@ -119,34 +119,6 @@ typedef NS_ENUM(unsigned int, MessageDataType) { @end -@interface MMSessionMgr: NSObject - -- (void)loadSessionData; -- (void)loadBrandSessionData; - -@end - -@interface RevokeMsgItem : NSObject - -@property (nonatomic, assign) unsigned int createTime; -@property (nonatomic, retain) NSString *svrId; -@property (nonatomic, retain) NSString *content; - -@end - -@interface MMRevokeMsgDB : NSObject - -- (BOOL)insertRevokeMsg:(id)msg; -- (id)getRevokeMsg:(NSString *)svrId; - -@end - -@interface MMRevokeMsgService : NSObject - -@property (nonatomic, strong) MMRevokeMsgDB *db; - -@end - @protocol MASPreferencesViewController @property(readonly, nonatomic) NSString *toolbarItemLabel; @@ -207,6 +179,19 @@ typedef NS_ENUM(unsigned int, MessageDataType) { @end +@interface FFProcessReqsvrZZ : NSObject + +- (id)GetMsgData:(id)arg2 localId:(long long)arg3; +- (id)GetMsgData:(id)arg2 svrId:(long long)arg3; +- (void)AddLocalMsg:(id)arg2 msgData:(id)arg3; +- (void)ModifyMsgData:(id)arg2 msgData:(id)arg3; +- (void)notifyAddMsgOnMainThread:(id)arg2 msgData:(id)arg3; +- (void)notifyModMsgOnMainThread:(id)arg2 msgData:(id)arg3; +- (void)notifyDelMsgOnMainThread:(id)arg2 msgData:(id)arg3 isRevoke:(BOOL)arg4; +- (void)notifyUIAndSessionOnMainThread:(id)arg2 withMsg:(id)arg3; + +@end + @interface NSDictionary (XMLDictionary) + (id)dictionaryWithXMLString:(id)arg1;