微信防撤回通知机制:WeChatTweak-macOS系统通知实现原理

微信防撤回通知机制:WeChatTweak-macOS系统通知实现原理

【免费下载链接】WeChatTweak-macOS A dynamic library tweak for WeChat macOS - 首款微信 macOS 客户端撤回拦截与多开 🔨 【免费下载链接】WeChatTweak-macOS 项目地址: https://gitcode.com/gh_mirrors/we/WeChatTweak-macOS

一、痛点直击:撤回消息的"数字消失术"

你是否经历过这样的场景:刚看到微信消息预览,还没来得及细读,屏幕上却弹出"对方已撤回一条消息"的提示?这种"数字消失术"不仅打断阅读体验,更可能导致重要信息的永久丢失。WeChatTweak-macOS作为首款针对微信macOS客户端的功能增强工具,通过底层消息拦截与系统通知整合,彻底解决了这一痛点。本文将深入剖析其防撤回通知机制的实现原理,帮助开发者理解Objective-C运行时特性在实际项目中的应用。

二、技术原理概览:消息拦截的"三道防线"

WeChatTweak-macOS的防撤回通知功能基于三大核心技术构建:

mermaid

2.1 关键技术组件对比

技术组件作用范围核心API风险等级
Method Swizzling运行时方法替换jr_swizzleMethod:withMethod:error:高(需精确匹配选择器)
消息数据篡改消息状态修改ModifyMsgData:msgData:中(依赖内部数据结构)
系统通知集成用户提醒机制deliverNotification:低(系统标准API)

三、深度解析:从消息拦截到通知展示的全流程

3.1 方法替换:防撤回的"第一道关卡"

WeChatTweak-macOS通过__attribute__((constructor))修饰的初始化函数,在程序启动时完成关键方法的替换:

static void __attribute__((constructor)) tweak(void) {
    // 拦截消息撤回处理方法
    [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];
}

技术点睛FFProcessReqsvrZZ是微信内部负责消息处理的核心类,通过替换其DelRevokedMsg:msgData:方法,实现对撤回指令的拦截。使用NSSelectorFromString而非直接使用选择器,是为了规避编译时检查。

3.2 消息状态篡改:让撤回"失效"的核心逻辑

在替换后的tweak_DelRevokedMsg:msgData:方法中,通过修改消息ID实现撤回拦截:

- (void)tweak_DelRevokedMsg:(NSString *)session msgData:(MessageData *)messageData {
    if (messageData.isSendFromSelf) {
        // 自己发送的消息允许撤回
        [self tweak_DelRevokedMsg:session msgData:messageData];
    } else {
        // 篡改消息ID,使系统认为是新消息
        messageData.mesSvrID = messageData.mesLocalID;
        [((FFProcessReqsvrZZ *)self) ModifyMsgData:session msgData:messageData];
        
        // 主线程更新UI
        dispatch_async(dispatch_get_main_queue(), ^{
            [((FFProcessReqsvrZZ *)self) notifyDelMsgOnMainThread:session msgData:messageData isRevoke:YES];
            [((FFProcessReqsvrZZ *)self) notifyAddMsgOnMainThread:session msgData:messageData];
        });
    }
}

关键洞察:微信通过比较mesSvrID(服务器ID)和mesLocalID(本地ID)来判断消息是否被撤回。将两者设为相等,使系统将撤回消息识别为正常消息,从而绕过删除逻辑。

3.3 系统通知构建:从消息数据到用户提醒

tweak_notifyAddRevokePromptMsgOnMainThread:msgData:方法中,完成系统通知的构建与分发:

- (void)tweak_notifyAddRevokePromptMsgOnMainThread:(NSString *)session msgData:(MessageData *)messageData {
    // 获取本地消息数据
    MessageData *localMessage = [((FFProcessReqsvrZZ *)self) GetMsgData:session localId:messageData.mesLocalID];
    
    if (!localMessage || localMessage.mesSvrID != messageData.mesLocalID) {
        [self tweak_notifyAddRevokePromptMsgOnMainThread:session msgData:messageData];
    } else {
        // 创建系统通知
        NSUserNotification *userNotification = [[NSUserNotification alloc] init];
        MMServiceCenter *serviceCenter = [objc_getClass("MMServiceCenter") defaultCenter];
        
        // 判断是群聊还是单聊
        if ([session rangeOfString:@"@chatroom"].location == NSNotFound) {
            // 单聊通知处理
            ContactStorage *contactStorage = [serviceCenter getService:objc_getClass("ContactStorage")];
            WCContactData *contact = [contactStorage GetContact:session];
            userNotification.informativeText = messageData.msgContent;
        } else {
            // 群聊通知处理
            GroupStorage *groupStorage = [serviceCenter getService:objc_getClass("GroupStorage")];
            WCContactData *groupContact = [groupStorage GetGroupContact:session];
            NSString *groupName = groupContact.m_nsNickName.length ? 
                                 groupContact.m_nsNickName : 
                                 [NSBundle.tweakBundle localizedStringForKey:@"Tweak.Title.Group"];
            userNotification.informativeText = [NSString stringWithFormat:@"%@: %@", groupName, messageData.msgContent];
        }
        
        // 主线程分发通知
        dispatch_async(dispatch_get_main_queue(), ^{
            WeChatTweakNotificationType notificationType = WeChatTweak.notificationType;
            if (notificationType == WeChatTweakNotificationTypeReceiveAll || 
                (notificationType == WeChatTweakNotificationTypeInherited && isChatStatusNotifyOpen)) {
                [[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification:userNotification];
            }
        });
    }
}

3.4 UI层修改:消息气泡的视觉标记

通过替换MMMessageCellView的三个关键方法,实现撤回消息的特殊标记:

// 添加撤回标记文本框
- (instancetype)tweak_initWithFrame:(NSRect)arg1 {
    MMMessageCellView *view = (MMMessageCellView *)[self tweak_initWithFrame:arg1];
    NSTextField *revokeTextField = [[NSTextField alloc] init];
    revokeTextField.hidden = YES;
    revokeTextField.tag = 9527; // 使用特殊标记值
    revokeTextField.stringValue = [NSBundle.tweakBundle localizedStringForKey:@"Tweak.Message.RecalledMark"];
    revokeTextField.font = [NSFont systemFontOfSize:7.0];
    revokeTextField.textColor = [NSColor lightGrayColor];
    [view addSubview:revokeTextField];
    return view;
}

// 根据消息状态显示标记
- (void)tweak_populateWithMessage:(MMMessageTableItem *)tableItem {
    [self tweak_populateWithMessage:tableItem];
    BOOL recalled = tableItem.message.mesSvrID && tableItem.message.mesSvrID == tableItem.message.mesLocalID;
    [((MMMessageCellView *)self).subviews enumerateObjectsUsingBlock:^(__kindof NSView * _Nonnull view, NSUInteger index, BOOL * _Nonnull stop) {
        if (view.tag != 9527) return;
        *stop = YES;
        view.hidden = !recalled;
    }];
    // 设置背景色标记
    ((MMMessageCellView *)self).layer.backgroundColor = recalled ? WeChatTweak.maskColor.CGColor : nil;
}

实现细节:通过tag = 9527标记自定义文本框,避免与微信原有视图冲突。当检测到消息被篡改(mesSvrID == mesLocalID)时,显示"已撤回"标记并更改气泡背景色。

四、通知分发流程:从消息拦截到用户提醒的完整链条

mermaid

五、实战应用:基于WeChatTweak的功能扩展思路

5.1 通知类型扩展

WeChatTweak当前支持两种通知模式,开发者可通过扩展WeChatTweakNotificationType枚举添加更多模式:

typedef NS_ENUM(NSUInteger, WeChatTweakNotificationType) {
    WeChatTweakNotificationTypeReceiveAll,       // 接收所有撤回通知
    WeChatTweakNotificationTypeInherited,        // 继承微信通知设置
    WeChatTweakNotificationTypeOnlyImportant,    // 仅重要联系人通知(扩展)
    WeChatTweakNotificationTypeCustomFilter      // 自定义过滤规则(扩展)
};

5.2 通知内容增强

可通过添加富文本支持和操作按钮增强通知功能:

userNotification.hasActionButton = YES;
userNotification.actionButtonTitle = @"查看详情";
userNotification.otherButtonTitle = @"忽略";
userNotification.contentImage = [NSImage imageNamed:@"revoke_icon"];

六、风险与应对:内部API依赖的稳定性挑战

潜在风险影响范围应对策略
微信版本更新导致类名变更全部功能失效实现动态类名探测机制
消息数据结构变化防撤回功能失效添加数据结构兼容性检查
方法签名变更部分功能异常实现方法参数动态适配

稳定性建议:通过objc_getClassNSSelectorFromString动态获取类和方法,避免直接依赖微信内部符号;添加运行时类型检查,确保在内部API变更时能够优雅降级。

七、总结与展望

WeChatTweak-macOS的防撤回通知机制通过Objective-C运行时特性,实现了对闭源应用的功能增强。其核心价值不仅在于解决用户痛点,更为macOS应用逆向开发提供了典范:

  1. 技术层面:展示了Method Swizzling在实际项目中的安全应用
  2. 架构层面:构建了"拦截-篡改-通知"的三层处理模型
  3. 用户体验:平衡了功能实现与原生应用体验的一致性

未来版本可考虑添加的功能方向:

  • 撤回消息的历史记录管理
  • 自定义通知音效与样式
  • 基于NSPasteboard的快速回复功能

掌握这些技术不仅能帮助开发者构建类似工具,更能深入理解macOS应用的内部工作机制。建议开发者在使用此类技术时,始终遵守软件使用协议和相关法律法规,仅在个人学习研究范围内使用。

如果觉得本文对你有帮助,请点赞、收藏、关注三连,下期将带来"WeChatTweak多开功能的实现原理"深度解析!

【免费下载链接】WeChatTweak-macOS A dynamic library tweak for WeChat macOS - 首款微信 macOS 客户端撤回拦截与多开 🔨 【免费下载链接】WeChatTweak-macOS 项目地址: https://gitcode.com/gh_mirrors/we/WeChatTweak-macOS

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值