mirror of
https://github.com/Sunnyyoung/WeChatTweak-macOS.git
synced 2025-07-07 16:16:07 +08:00
Add some features
1. Improve system notification 2. Add message list notification 3. Update screenshot 4. Update README
This commit is contained in:
parent
3b615b7547
commit
d2a215865a
|
@ -10,25 +10,29 @@
|
|||
|
||||

|
||||

|
||||

|
||||
|
||||
## 功能
|
||||
|
||||
- 阻止消息撤回
|
||||
- 消息列表通知
|
||||
- 系统通知
|
||||
- 正常撤回自己发出的消息
|
||||
- 客户端无限多开
|
||||
- 右键 Dock Icon 登录新的微信账号
|
||||
- 命令行执行:`open -n /Applications/WeChat.app`
|
||||
- 阻止退出登录(重新打开应用无需手机认证)
|
||||
- 重新打开应用无需手机认证
|
||||
|
||||
## 使用
|
||||
|
||||
- `sudo make install` 安装动态库
|
||||
- `sudo make install` 安装动态库
|
||||
- `sudo make uninstall` 卸载动态库
|
||||
|
||||
## 开发调试
|
||||
|
||||
**Requirement: Command Line Tools**
|
||||
|
||||
运行命令:`xcode-select --install` 安装 Command Line Tools。
|
||||
运行命令:`xcode-select --install` 安装 Command Line Tools
|
||||
|
||||
- `make build` 编译 dylib 动态库到当前目录下
|
||||
- `make debug` 编译 dylib 动态库并临时注入微信 macOS 客户端
|
||||
|
|
12
README.md
12
README.md
|
@ -10,25 +10,29 @@ A dynamic library tweak for WeChat macOS.
|
|||
|
||||

|
||||

|
||||

|
||||
|
||||
## Feature
|
||||
|
||||
- Prevent message revoked
|
||||
- Message list notification
|
||||
- System notification
|
||||
- Revoke message you sent
|
||||
- Multiple WeChat Instance
|
||||
- Right click on the Dock icon to login another WeChat account
|
||||
- Run command: `open -n /Applications/WeChat.app`
|
||||
- Prevent logout (Auto login without authority)
|
||||
- Auto login without authentication
|
||||
|
||||
## Usage
|
||||
|
||||
- `sudo make install` Inject the dylib to `WeChat`
|
||||
- `sudo make uninstall` Uninstall the injection
|
||||
- `sudo make install` Inject the dylib
|
||||
- `sudo make uninstall` Uninstall the dylib
|
||||
|
||||
## Development
|
||||
|
||||
**Requirement: Command Line Tools**
|
||||
|
||||
Run `xcode-select --install` to install Command Line Tools.
|
||||
Run `xcode-select --install` to install Command Line Tools
|
||||
|
||||
- `make build` Build the dylib file to the same dicrectory
|
||||
- `make debug` Build the dylib file and run `WeChat` with dynamic injection
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 105 KiB |
Binary file not shown.
Before Width: | Height: | Size: 174 KiB After Width: | Height: | Size: 78 KiB |
BIN
Screenshot/0x03.png
Normal file
BIN
Screenshot/0x03.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 163 KiB |
Binary file not shown.
|
@ -3,30 +3,94 @@
|
|||
#import <objc/message.h>
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "JRSwizzle.h"
|
||||
#import "WeChatTweakHeaders.h"
|
||||
|
||||
@implementation NSString (WeChatTweak)
|
||||
|
||||
- (NSString *)tweak_sessionFromMessage {
|
||||
NSRange begin = [self rangeOfString:@"<session>"];
|
||||
NSRange end = [self rangeOfString:@"</session>"];
|
||||
NSRange range = NSMakeRange(begin.location + begin.length,end.location - begin.location - begin.length);
|
||||
return [self substringWithRange:range];
|
||||
}
|
||||
|
||||
- (NSUInteger)tweak_newMessageIDFromMessage {
|
||||
NSRange begin = [self rangeOfString:@"<newmsgid>"];
|
||||
NSRange end = [self rangeOfString:@"</newmsgid>"];
|
||||
NSRange range = NSMakeRange(begin.location + begin.length,end.location - begin.location - begin.length);
|
||||
return [[self substringWithRange:range] longLongValue];
|
||||
}
|
||||
|
||||
- (NSString *)tweak_replaceMessageFromMessage {
|
||||
NSRange begin = [self rangeOfString:@"<replacemsg><![CDATA["];
|
||||
NSRange end = [self rangeOfString:@"]]></replacemsg>"];
|
||||
NSRange range = NSMakeRange(begin.location + begin.length,end.location - begin.location - begin.length);
|
||||
return [self substringWithRange:range];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation NSObject (WeChatTweak)
|
||||
|
||||
#pragma mark - Constructor
|
||||
|
||||
static void __attribute__((constructor)) tweak(void) {
|
||||
[objc_getClass("MessageService") jr_swizzleMethod:NSSelectorFromString(@"onRevokeMsg:") withMethod:@selector(tweak_onRevokeMsg:) error:nil];
|
||||
[objc_getClass("CUtility") jr_swizzleClassMethod:NSSelectorFromString(@"HasWechatInstance") withClassMethod:@selector(tweak_HasWechatInstance) error:nil];
|
||||
class_addMethod(objc_getClass("AppDelegate"), @selector(applicationDockMenu:), method_getImplementation(class_getInstanceMethod(objc_getClass("AppDelegate"), @selector(tweak_applicationDockMenu:))), "@:@");
|
||||
class_addMethod(objc_getClass("AppDelegate"), @selector(applicationDockMenu:), method_getImplementation(class_getInstanceMethod(objc_getClass("AppDelegate"), @selector(tweak_applicationDockMenu:))), "@:@");
|
||||
[objc_getClass("AppDelegate") jr_swizzleMethod:NSSelectorFromString(@"applicationDidFinishLaunching:") withMethod:@selector(tweak_applicationDidFinishLaunching:) error:nil];
|
||||
[objc_getClass("AppDelegate") jr_swizzleMethod:NSSelectorFromString(@"applicationShouldTerminate:") withMethod:@selector(tweak_applicationShouldTerminate:) error:nil];
|
||||
[objc_getClass("MessageService") jr_swizzleMethod:NSSelectorFromString(@"onRevokeMsg:") withMethod:@selector(tweak_onRevokeMsg:) error:nil];
|
||||
[objc_getClass("CUtility") jr_swizzleClassMethod:NSSelectorFromString(@"HasWechatInstance") withClassMethod:@selector(tweak_HasWechatInstance) error:nil];
|
||||
}
|
||||
|
||||
#pragma mark - No Revoke Message
|
||||
|
||||
- (void)tweak_onRevokeMsg:(NSString *)message {
|
||||
NSRange begin = [message rangeOfString:@"<replacemsg><![CDATA["];
|
||||
NSRange end = [message rangeOfString:@"]]></replacemsg>"];
|
||||
NSRange subRange = NSMakeRange(begin.location + begin.length,end.location - begin.location - begin.length);
|
||||
NSString *informativeText = [message substringWithRange:subRange];
|
||||
// Decode message
|
||||
NSString *session = [message tweak_sessionFromMessage];
|
||||
NSUInteger newMessageID = [message tweak_newMessageIDFromMessage];
|
||||
NSString *replaceMessage = [message tweak_replaceMessageFromMessage];
|
||||
|
||||
// Prepare message data
|
||||
MessageData *localMessageData = [((MessageService *)self) GetMsgData:session svrId:newMessageID];
|
||||
MessageData *promptMessageData = ({
|
||||
MessageData *data = [[objc_getClass("MessageData") alloc] init];
|
||||
data.messageType = 10000;
|
||||
data.msgStatus = 4;
|
||||
data.toUsrName = localMessageData.toUsrName;
|
||||
data.fromUsrName = localMessageData.fromUsrName;
|
||||
data.msgCreateTime = localMessageData.msgCreateTime;
|
||||
if ([localMessageData isSendFromSelf]) {
|
||||
data.mesLocalID = localMessageData.mesLocalID;
|
||||
data.msgContent = replaceMessage;
|
||||
} else {
|
||||
data.mesLocalID = localMessageData.mesLocalID + 1;
|
||||
data.msgContent = [NSString stringWithFormat:@"[已拦截]\n%@", replaceMessage];
|
||||
}
|
||||
data;
|
||||
});
|
||||
|
||||
// Prepare notification information
|
||||
NSUserNotification *userNotification = [[NSUserNotification alloc] init];
|
||||
if ([session rangeOfString:@"@chatroom"].location == NSNotFound) {
|
||||
userNotification.informativeText = replaceMessage;
|
||||
} else {
|
||||
GroupStorage *groupStorage = [[objc_getClass("MMServiceCenter") defaultCenter] getService:objc_getClass("GroupStorage")];
|
||||
WCContactData *groupContact = [groupStorage GetGroupContact: session];
|
||||
NSString *groupName = groupContact.m_nsNickName.length ? groupContact.m_nsNickName : @"群组";
|
||||
userNotification.informativeText = [NSString stringWithFormat:@"%@: %@", groupName, replaceMessage];
|
||||
}
|
||||
|
||||
// Dispatch notification
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
NSUserNotification *userNotification = [[NSUserNotification alloc] init];
|
||||
userNotification.informativeText = informativeText;
|
||||
[[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification:userNotification];
|
||||
// Delete message if is revoke from myself
|
||||
if ([localMessageData isSendFromSelf]) {
|
||||
[((MessageService *)self) DelMsg:session msgList:@[localMessageData] isDelAll:NO isManual:YES];
|
||||
[((MessageService *)self) AddRevokePromptMsg:session msgData: promptMessageData];
|
||||
} else {
|
||||
[[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification:userNotification];
|
||||
[((MessageService *)self) AddRevokePromptMsg:session msgData: promptMessageData];
|
||||
[((MessageService *)self) notifyAddMsgOnMainThread:session msgData: promptMessageData];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -51,7 +115,7 @@ static void __attribute__((constructor)) tweak(void) {
|
|||
[task launch];
|
||||
}
|
||||
|
||||
#pragma mark - No Logout
|
||||
#pragma mark - Auto auth
|
||||
|
||||
- (void)tweak_applicationDidFinishLaunching:(NSNotification *)notification {
|
||||
[self tweak_applicationDidFinishLaunching:notification];
|
||||
|
|
44
WeChatTweakHeaders.h
Normal file
44
WeChatTweakHeaders.h
Normal file
|
@ -0,0 +1,44 @@
|
|||
#import <Foundation/Foundation.h>
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@interface MessageData: NSObject
|
||||
|
||||
@property(nonatomic) unsigned int messageType;
|
||||
@property(nonatomic) unsigned int msgStatus;
|
||||
@property(retain, nonatomic) NSString *toUsrName;
|
||||
@property(retain, nonatomic) NSString *fromUsrName;
|
||||
@property(retain, nonatomic) NSString *msgContent;
|
||||
@property(nonatomic) unsigned int msgCreateTime;
|
||||
@property(nonatomic) unsigned int mesLocalID;
|
||||
|
||||
- (BOOL)isSendFromSelf;
|
||||
|
||||
@end
|
||||
|
||||
@interface WCContactData : NSObject
|
||||
|
||||
@property(retain, nonatomic) NSString *m_nsNickName;
|
||||
|
||||
@end
|
||||
|
||||
@interface GroupStorage: NSObject
|
||||
|
||||
- (id)GetGroupContact:(id)arg1;
|
||||
|
||||
@end
|
||||
|
||||
@interface MMServiceCenter : NSObject
|
||||
|
||||
+ (id)defaultCenter;
|
||||
- (id)getService:(Class)arg1;
|
||||
|
||||
@end
|
||||
|
||||
@interface MessageService: NSObject
|
||||
|
||||
- (id)GetMsgData:(id)arg1 svrId:(unsigned long long)arg2;
|
||||
- (void)DelMsg:(id)arg1 msgList:(id)arg2 isDelAll:(BOOL)arg3 isManual:(BOOL)arg4;
|
||||
- (void)AddRevokePromptMsg:(id)arg1 msgData:(id)arg2;
|
||||
- (void)notifyAddMsgOnMainThread:(id)arg1 msgData:(id)arg2;
|
||||
|
||||
@end
|
Loading…
Reference in New Issue
Block a user