mirror of
https://github.com/Sunnyyoung/WeChatTweak-macOS.git
synced 2025-05-23 23:06:08 +08:00
Fix support for WeChat 3.8.1
This commit is contained in:
parent
f72f4c3f77
commit
ddf9e51acd
20
README.md
20
README.md
|
@ -57,21 +57,23 @@
|
||||||
|
|
||||||
## FAQ
|
## FAQ
|
||||||
|
|
||||||
1. 功能失效?
|
- 功能失效?
|
||||||
请提交 **issue** 然后等待,或提交 **pull request** 一起发电。
|
请提交 **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=) 里找找类似问题并尝试解决。
|
先卸载,再重新安装一次即可,如仍无法解决请重启电脑。实在搞不定的,到 [issues](https://github.com/sunnyyoung/WeChatTweak-macOS/issues) 里找找类似问题并尝试解决。
|
||||||
7. 截图失效?
|
- 截图失效?
|
||||||
系统偏好设置 -> 隐私 -> 删除微信并重新添加 -> 重启微信客户端。
|
系统偏好设置 -> 隐私 -> 删除微信并重新添加 -> 重启微信客户端。
|
||||||
8. 理性讨论。
|
- 出现`“WeChat.app” cannot be opened because the developer cannot be verified.`怎么办?
|
||||||
|
进入 `WeChat.app` 所在目录,通过右键菜单打开。
|
||||||
|
- 理性讨论。
|
||||||
|
|
||||||
## 参考
|
## 参考
|
||||||
|
|
||||||
|
|
|
@ -12,60 +12,32 @@
|
||||||
@implementation NSObject (AntiRevoke)
|
@implementation NSObject (AntiRevoke)
|
||||||
|
|
||||||
static void __attribute__((constructor)) tweak(void) {
|
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(@"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(@"populateWithMessage:") withMethod:@selector(tweak_populateWithMessage:) error:nil];
|
||||||
[objc_getClass("MMMessageCellView") jr_swizzleMethod:NSSelectorFromString(@"layout") withMethod:@selector(tweak_layout) error:nil];
|
[objc_getClass("MMMessageCellView") jr_swizzleMethod:NSSelectorFromString(@"layout") withMethod:@selector(tweak_layout) error:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)tweak_processNewXMLMsg:(MessageData *)message sessionMsgList:(nullable id)sessionMsgList {
|
- (void)tweak_DelRevokedMsg:(NSString *)session msgData:(MessageData *)messageData {
|
||||||
// - (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);
|
|
||||||
if (messageData.isSendFromSelf) {
|
if (messageData.isSendFromSelf) {
|
||||||
// Fallback to origin method
|
[self tweak_DelRevokedMsg:session msgData:messageData];
|
||||||
[self tweak_processNewXMLMsg:message sessionMsgList:sessionMsgList];
|
|
||||||
} else {
|
} else {
|
||||||
[self handleRevokedMessageIntoWithSession:session messageData:messageData replaceMessage:replaceMessage];
|
messageData.mesSvrID = LONG_LONG_MAX;
|
||||||
}
|
[((FFProcessReqsvrZZ *)self) ModifyMsgData: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(), ^{
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
((void (*)(id, SEL))objc_msgSend)(chatMessageViewController, NSSelectorFromString(@"reloadTableView"));
|
[((FFProcessReqsvrZZ *)self) notifyDelMsgOnMainThread:session msgData:messageData isRevoke:YES];
|
||||||
|
[((FFProcessReqsvrZZ *)self) notifyAddMsgOnMainThread:session msgData:messageData];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
- (void)tweak_notifyAddRevokePromptMsgOnMainThread:(NSString *)session msgData:(MessageData *)messageData {
|
||||||
// Prepare notification information
|
MessageData *localMessage = [((FFProcessReqsvrZZ *)self) GetMsgData:session localId:messageData.mesLocalID];
|
||||||
|
if (!localMessage || localMessage.mesSvrID != LONG_LONG_MAX) {
|
||||||
|
[self tweak_notifyAddRevokePromptMsgOnMainThread:session msgData:messageData];
|
||||||
|
} else {
|
||||||
MMServiceCenter *serviceCenter = [objc_getClass("MMServiceCenter") defaultCenter];
|
MMServiceCenter *serviceCenter = [objc_getClass("MMServiceCenter") defaultCenter];
|
||||||
NSUserNotification *userNotification = [[NSUserNotification alloc] init];
|
NSUserNotification *userNotification = [[NSUserNotification alloc] init];
|
||||||
BOOL isChatStatusNotifyOpen = YES;
|
BOOL isChatStatusNotifyOpen = YES;
|
||||||
|
@ -73,13 +45,13 @@ static void __attribute__((constructor)) tweak(void) {
|
||||||
ContactStorage *contactStorage = [serviceCenter getService:objc_getClass("ContactStorage")];
|
ContactStorage *contactStorage = [serviceCenter getService:objc_getClass("ContactStorage")];
|
||||||
WCContactData *contact = [contactStorage GetContact:session];
|
WCContactData *contact = [contactStorage GetContact:session];
|
||||||
isChatStatusNotifyOpen = [contact isChatStatusNotifyOpen];
|
isChatStatusNotifyOpen = [contact isChatStatusNotifyOpen];
|
||||||
userNotification.informativeText = replaceMessage;
|
userNotification.informativeText = messageData.msgContent;
|
||||||
} else {
|
} else {
|
||||||
GroupStorage *groupStorage = [serviceCenter getService:objc_getClass("GroupStorage")];
|
GroupStorage *groupStorage = [serviceCenter getService:objc_getClass("GroupStorage")];
|
||||||
WCContactData *groupContact = [groupStorage GetGroupContact:session];
|
WCContactData *groupContact = [groupStorage GetGroupContact:session];
|
||||||
isChatStatusNotifyOpen = [groupContact isChatStatusNotifyOpen];
|
isChatStatusNotifyOpen = [groupContact isChatStatusNotifyOpen];
|
||||||
NSString *groupName = groupContact.m_nsNickName.length ? groupContact.m_nsNickName : [NSBundle.tweakBundle localizedStringForKey:@"Tweak.Title.Group"];
|
NSString *groupName = groupContact.m_nsNickName.length ? groupContact.m_nsNickName : [NSBundle.tweakBundle localizedStringForKey:@"Tweak.Title.Group"];
|
||||||
userNotification.informativeText = [NSString stringWithFormat:@"%@: %@", groupName, replaceMessage];
|
userNotification.informativeText = [NSString stringWithFormat:@"%@: %@", groupName, messageData.msgContent];
|
||||||
}
|
}
|
||||||
// Dispatch notification
|
// Dispatch notification
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
|
@ -90,6 +62,7 @@ static void __attribute__((constructor)) tweak(void) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
- (instancetype)tweak_initWithFrame:(NSRect)arg1 {
|
- (instancetype)tweak_initWithFrame:(NSRect)arg1 {
|
||||||
MMMessageCellView *view = (MMMessageCellView *)[self tweak_initWithFrame:arg1];
|
MMMessageCellView *view = (MMMessageCellView *)[self tweak_initWithFrame:arg1];
|
||||||
|
@ -111,8 +84,7 @@ static void __attribute__((constructor)) tweak(void) {
|
||||||
|
|
||||||
- (void)tweak_populateWithMessage:(MMMessageTableItem *)tableItem {
|
- (void)tweak_populateWithMessage:(MMMessageTableItem *)tableItem {
|
||||||
[self tweak_populateWithMessage:tableItem];
|
[self tweak_populateWithMessage:tableItem];
|
||||||
MMRevokeMsgService *service = [[objc_getClass("MMServiceCenter") defaultCenter] getService:objc_getClass("MMRevokeMsgService")];
|
BOOL recalled = tableItem.message.mesSvrID == LONG_LONG_MAX;
|
||||||
BOOL recalled = tableItem.message ? (tableItem.message.messageType != MessageDataTypePrompt && tableItem.message.msgStatus == 4 && [service.db getRevokeMsg:@(tableItem.message.mesSvrID).stringValue] != NULL) : NO;
|
|
||||||
[((MMMessageCellView *)self).subviews enumerateObjectsUsingBlock:^(__kindof NSView * _Nonnull view, NSUInteger index, BOOL * _Nonnull stop) {
|
[((MMMessageCellView *)self).subviews enumerateObjectsUsingBlock:^(__kindof NSView * _Nonnull view, NSUInteger index, BOOL * _Nonnull stop) {
|
||||||
if (view.tag != 9527) {
|
if (view.tag != 9527) {
|
||||||
return ;
|
return ;
|
||||||
|
|
|
@ -119,34 +119,6 @@ typedef NS_ENUM(unsigned int, MessageDataType) {
|
||||||
|
|
||||||
@end
|
@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 <NSObject>
|
@protocol MASPreferencesViewController <NSObject>
|
||||||
|
|
||||||
@property(readonly, nonatomic) NSString *toolbarItemLabel;
|
@property(readonly, nonatomic) NSString *toolbarItemLabel;
|
||||||
|
@ -207,6 +179,19 @@ typedef NS_ENUM(unsigned int, MessageDataType) {
|
||||||
|
|
||||||
@end
|
@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)
|
@interface NSDictionary (XMLDictionary)
|
||||||
|
|
||||||
+ (id)dictionaryWithXMLString:(id)arg1;
|
+ (id)dictionaryWithXMLString:(id)arg1;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user