diff --git a/Podfile b/Podfile index 55d2a04..61136f4 100644 --- a/Podfile +++ b/Podfile @@ -3,4 +3,6 @@ inhibit_all_warnings! target 'WeChatTweak' do pod 'JRSwizzle' + pod 'GCDWebServer' + pod 'YYModel' end diff --git a/Podfile.lock b/Podfile.lock index e41c919..695a91d 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -1,12 +1,20 @@ PODS: + - GCDWebServer (3.4.1): + - GCDWebServer/Core (= 3.4.1) + - GCDWebServer/Core (3.4.1) - JRSwizzle (1.0) + - YYModel (1.0.4) DEPENDENCIES: + - GCDWebServer - JRSwizzle + - YYModel SPEC CHECKSUMS: + GCDWebServer: 1db60034fe0e78a4a8524bd6c7cd97cd3c589870 JRSwizzle: dd5ead5d913a0f29e7f558200165849f006bb1e3 + YYModel: 2a7fdd96aaa4b86a824e26d0c517de8928c04b30 -PODFILE CHECKSUM: 19c0de41a7724720f663ad47eb3832778049a284 +PODFILE CHECKSUM: af44d62b300e2c55cb63386ec4be3227b93c7761 COCOAPODS: 1.3.1 diff --git a/README-Chinese.md b/README-Chinese.md index 8877d20..f52c77f 100644 --- a/README-Chinese.md +++ b/README-Chinese.md @@ -1,15 +1,22 @@ # WeChatTweak-macOS -[![license](https://img.shields.io/github/license/mashape/apistatus.svg)](LICENSE) +[![License](https://img.shields.io/github/license/mashape/apistatus.svg)](LICENSE) [![README](https://img.shields.io/badge/README-English-blue.svg)](README.md) [![README](https://img.shields.io/badge/README-中文-blue.svg)](README-Chinese.md) +[![README](https://img.shields.io/badge/Telegram-WeChatTweak-brightgreen.svg)](https://t.me/joinchat/B0vW8kPU5OrwdC1qRbaqRA) 微信 macOS 客户端 Tweak 动态库。 ## 截图 +### 整体预览 + ![](Screenshot/0x01.png) +### Alfred workflow + +![](Screenshot/0x02.png) + ## 功能 - 阻止消息撤回 @@ -21,15 +28,17 @@ - 命令行执行:`open -n /Applications/WeChat.app` - 重新打开应用无需手机认证 - UI界面设置面板 +- 支持 Alfred workflow ## 使用 - `sudo make install` 安装或者更新动态库 - `sudo make uninstall` 卸载动态库 +- open `WeChat.workflow` 安装 Alfred workflow ## 文档 -获取更多信息, 请到 [wiki](https://github.com/Sunnyyoung/WeChatTweak-macOS/wiki)。 +获取更多信息, 请到 [Wiki](https://github.com/Sunnyyoung/WeChatTweak-macOS/wiki)。 ## 依赖 @@ -40,6 +49,7 @@ - [微信 macOS 客户端无限多开功能实践](https://blog.sunnyyoung.net/wei-xin-macos-ke-hu-duan-wu-xian-duo-kai-gong-neng-shi-jian/) - [微信 macOS 客户端拦截撤回功能实践](https://blog.sunnyyoung.net/wei-xin-macos-ke-hu-duan-lan-jie-che-hui-gong-neng-shi-jian/) +- [让微信 macOS 客户端支持 Alfred](https://blog.sunnyyoung.net/rang-wei-xin-macos-ke-hu-duan-zhi-chi-alfred/) ## License diff --git a/README.md b/README.md index 8dcd4a6..962f71c 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,22 @@ # WeChatTweak-macOS -[![license](https://img.shields.io/github/license/mashape/apistatus.svg)](LICENSE) +[![License](https://img.shields.io/github/license/mashape/apistatus.svg)](LICENSE) [![README](https://img.shields.io/badge/README-English-blue.svg)](README.md) [![README](https://img.shields.io/badge/README-中文-blue.svg)](README-Chinese.md) +[![README](https://img.shields.io/badge/Telegram-WeChatTweak-brightgreen.svg)](https://t.me/joinchat/B0vW8kPU5OrwdC1qRbaqRA) A dynamic library tweak for WeChat macOS. ## Screenshot +### Overview + ![](Screenshot/0x01.png) +### Alfred workflow + +![](Screenshot/0x02.png) + ## Feature - Prevent message revoked @@ -21,15 +28,17 @@ A dynamic library tweak for WeChat macOS. - Run command: `open -n /Applications/WeChat.app` - Auto login without authentication - UI Interface settings panel +- Alfred workflow support ## Quick Start - `sudo make install` Install or Upgrade the dylib - `sudo make uninstall` Uninstall the dylib +- open `WeChat.workflow` Install Alfred workflow ## Documentation -For more informations, please go to the [wiki](https://github.com/Sunnyyoung/WeChatTweak-macOS/wiki). +For more informations, please go to the [Wiki](https://github.com/Sunnyyoung/WeChatTweak-macOS/wiki). ## Dependency @@ -40,6 +49,7 @@ For more informations, please go to the [wiki](https://github.com/Sunnyyoung/WeC - [微信 macOS 客户端无限多开功能实践](https://blog.sunnyyoung.net/wei-xin-macos-ke-hu-duan-wu-xian-duo-kai-gong-neng-shi-jian/) - [微信 macOS 客户端拦截撤回功能实践](https://blog.sunnyyoung.net/wei-xin-macos-ke-hu-duan-lan-jie-che-hui-gong-neng-shi-jian/) +- [让微信 macOS 客户端支持 Alfred](https://blog.sunnyyoung.net/rang-wei-xin-macos-ke-hu-duan-zhi-chi-alfred/) ## License diff --git a/Screenshot/0x02.png b/Screenshot/0x02.png new file mode 100644 index 0000000..8c39d87 Binary files /dev/null and b/Screenshot/0x02.png differ diff --git a/WeChat.alfredworkflow b/WeChat.alfredworkflow new file mode 100644 index 0000000..34f42e8 Binary files /dev/null and b/WeChat.alfredworkflow differ diff --git a/WeChatTweak.framework/Versions/A/WeChatTweak b/WeChatTweak.framework/Versions/A/WeChatTweak index e3eb3e7..c81310c 100755 Binary files a/WeChatTweak.framework/Versions/A/WeChatTweak and b/WeChatTweak.framework/Versions/A/WeChatTweak differ diff --git a/WeChatTweak.xcodeproj/project.pbxproj b/WeChatTweak.xcodeproj/project.pbxproj index df307c0..f120c7b 100644 --- a/WeChatTweak.xcodeproj/project.pbxproj +++ b/WeChatTweak.xcodeproj/project.pbxproj @@ -7,6 +7,8 @@ objects = { /* Begin PBXBuildFile section */ + 7D14E5A41F6447DB00D75132 /* AlfredManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 7D14E5A21F6447DB00D75132 /* AlfredManager.h */; }; + 7D14E5A51F6447DB00D75132 /* AlfredManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 7D14E5A31F6447DB00D75132 /* AlfredManager.m */; }; 7DF8422C1F40583F00D42D79 /* WeChatTweak.h in Headers */ = {isa = PBXBuildFile; fileRef = 7DF8422A1F40583F00D42D79 /* WeChatTweak.h */; settings = {ATTRIBUTES = (Public, ); }; }; 7DF842341F4058AB00D42D79 /* WeChatTweak.m in Sources */ = {isa = PBXBuildFile; fileRef = 7DF842331F4058AB00D42D79 /* WeChatTweak.m */; }; 7DF842521F4058C600D42D79 /* TweakPreferecesController.h in Headers */ = {isa = PBXBuildFile; fileRef = 7DF8424F1F4058C600D42D79 /* TweakPreferecesController.h */; }; @@ -38,6 +40,8 @@ /* Begin PBXFileReference section */ 153504EC5C9196C0D85213CF /* libPods-WeChatTweak.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-WeChatTweak.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + 7D14E5A21F6447DB00D75132 /* AlfredManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AlfredManager.h; sourceTree = ""; }; + 7D14E5A31F6447DB00D75132 /* AlfredManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AlfredManager.m; sourceTree = ""; }; 7DF842271F40583F00D42D79 /* WeChatTweak.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = WeChatTweak.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 7DF8422A1F40583F00D42D79 /* WeChatTweak.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WeChatTweak.h; sourceTree = ""; }; 7DF8422B1F40583F00D42D79 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -75,6 +79,15 @@ name = Frameworks; sourceTree = ""; }; + 7D14E5A11F6447B900D75132 /* Manager */ = { + isa = PBXGroup; + children = ( + 7D14E5A21F6447DB00D75132 /* AlfredManager.h */, + 7D14E5A31F6447DB00D75132 /* AlfredManager.m */, + ); + name = Manager; + sourceTree = ""; + }; 7DF8421D1F40583F00D42D79 = { isa = PBXGroup; children = ( @@ -98,6 +111,7 @@ children = ( 7DF8422A1F40583F00D42D79 /* WeChatTweak.h */, 7DF842331F4058AB00D42D79 /* WeChatTweak.m */, + 7D14E5A11F6447B900D75132 /* Manager */, 7DF842551F4058C900D42D79 /* Controller */, 7DF842561F4058D300D42D79 /* Category */, 7DF842631F40594400D42D79 /* Resources */, @@ -162,6 +176,7 @@ files = ( 7DF8422C1F40583F00D42D79 /* WeChatTweak.h in Headers */, 7DF8425B1F4058DD00D42D79 /* NSBundle+WeChatTweak.h in Headers */, + 7D14E5A41F6447DB00D75132 /* AlfredManager.h in Headers */, 7DF842601F40590500D42D79 /* WeChatTweakHeaders.h in Headers */, 7DF842521F4058C600D42D79 /* TweakPreferecesController.h in Headers */, 7DF8425D1F4058DD00D42D79 /* NSString+WeChatTweak.h in Headers */, @@ -277,6 +292,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 7D14E5A51F6447DB00D75132 /* AlfredManager.m in Sources */, 7DF8425E1F4058DD00D42D79 /* NSString+WeChatTweak.m in Sources */, 7DF842531F4058C600D42D79 /* TweakPreferecesController.m in Sources */, 7DF842341F4058AB00D42D79 /* WeChatTweak.m in Sources */, diff --git a/WeChatTweak/AlfredManager.h b/WeChatTweak/AlfredManager.h new file mode 100644 index 0000000..e462e50 --- /dev/null +++ b/WeChatTweak/AlfredManager.h @@ -0,0 +1,23 @@ +// +// AlfredManager.h +// WeChatTweak +// +// Created by Sunnyyoung on 2017/9/10. +// Copyright © 2017年 Sunnyyoung. All rights reserved. +// + +#import +#import +#import +#import +#import +#import + +@interface AlfredManager : NSObject + ++ (instancetype)sharedInstance; + +- (void)startListener; +- (void)stopListener; + +@end diff --git a/WeChatTweak/AlfredManager.m b/WeChatTweak/AlfredManager.m new file mode 100644 index 0000000..10ace71 --- /dev/null +++ b/WeChatTweak/AlfredManager.m @@ -0,0 +1,102 @@ +// +// AlfredManager.m +// WeChatTweak +// +// Created by Sunnyyoung on 2017/9/10. +// Copyright © 2017年 Sunnyyoung. All rights reserved. +// + +#import "AlfredManager.h" +#import "WeChatTweakHeaders.h" + +@interface AlfredManager() + +@property (nonatomic, strong, nullable) GCDWebServer *server; + +@end + +@implementation AlfredManager + ++ (instancetype)sharedInstance { + static dispatch_once_t onceToken; + static AlfredManager *shared; + dispatch_once(&onceToken, ^{ + shared = [[AlfredManager alloc] init]; + }); + return shared; +} + +- (void)startListener { + if (self.server != nil) { + return; + } + self.server = [[GCDWebServer alloc] init]; + // Search contancts + [self.server addHandlerForMethod:@"GET" path:@"/wechat/search" requestClass:[GCDWebServerRequest class] processBlock:^GCDWebServerResponse * _Nullable(__kindof GCDWebServerRequest * _Nonnull request) { + NSString *keyword = [request.query[@"keyword"] lowercaseString] ? : @""; + NSArray *contacts = ({ + MMServiceCenter *serviceCenter = [objc_getClass("MMServiceCenter") defaultCenter]; + ContactStorage *contactStorage = [serviceCenter getService:objc_getClass("ContactStorage")]; + GroupStorage *groupStorage = [serviceCenter getService:objc_getClass("GroupStorage")]; + NSMutableArray *array = [NSMutableArray array]; + [array addObjectsFromArray:[contactStorage GetAllFriendContacts]]; + [array addObjectsFromArray:[groupStorage GetAllGroups]]; + array; + }); + NSArray *results = ({ + NSMutableArray *results = [NSMutableArray array]; + for (WCContactData *contact in contacts) { + BOOL isFriend = contact.m_uiBrandSubscriptionSettings == 0; + BOOL containsNickName = [contact.m_nsNickName.lowercaseString containsString:keyword]; + BOOL containsUsername = [contact.m_nsUsrName.lowercaseString containsString:keyword]; + BOOL containsAliasName = [contact.m_nsAliasName.lowercaseString containsString:keyword]; + BOOL containsRemark = [contact.m_nsRemark.lowercaseString containsString:keyword]; + BOOL containsNickNamePinyin = [contact.m_nsFullPY.lowercaseString containsString:keyword]; + BOOL containsRemarkPinyin = [contact.m_nsRemarkPYFull.lowercaseString containsString:keyword]; + BOOL matchRemarkShortPinyin = [contact.m_nsRemarkPYShort.lowercaseString isEqualToString:keyword]; + if (isFriend && (containsNickName || containsUsername || containsAliasName || containsRemark || containsNickNamePinyin || containsRemarkPinyin || matchRemarkShortPinyin)) { + [results addObject:contact]; + } + } + results; + }); + return [GCDWebServerDataResponse responseWithJSONObject:[results yy_modelToJSONObject]]; + }]; + // Start chat + [self.server addHandlerForMethod:@"GET" path:@"/wechat/start" requestClass:[GCDWebServerRequest class] processBlock:^GCDWebServerResponse * _Nullable(__kindof GCDWebServerRequest * _Nonnull request) { + WCContactData *contact = ({ + NSString *session = request.query[@"session"]; + WCContactData *contact = nil; + if (session != nil) { + MMServiceCenter *serviceCenter = [objc_getClass("MMServiceCenter") defaultCenter]; + if ([session rangeOfString:@"@chatroom"].location == NSNotFound) { + ContactStorage *contactStorage = [serviceCenter getService:objc_getClass("ContactStorage")]; + contact = [contactStorage GetContact:session]; + } else { + GroupStorage *groupStorage = [serviceCenter getService:objc_getClass("GroupStorage")]; + contact = [groupStorage GetGroupContact:session]; + } + } + contact; + }); + dispatch_async(dispatch_get_main_queue(), ^{ + [[objc_getClass("WeChat") sharedInstance] startANewChatWithContact:contact]; + [[objc_getClass("WeChat") sharedInstance] showMainWindow]; + [[NSApplication sharedApplication] activateIgnoringOtherApps: YES]; + }); + return [GCDWebServerResponse responseWithStatusCode:200]; + }]; + [self.server startWithOptions:@{GCDWebServerOption_Port: @(48065), + GCDWebServerOption_BindToLocalhost: @(YES)} error:nil]; +} + +- (void)stopListener { + if (self.server == nil) { + return; + } + [self.server stop]; + [self.server removeAllHandlers]; + self.server = nil; +} + +@end diff --git a/WeChatTweak/WeChatTweak.m b/WeChatTweak/WeChatTweak.m index 65476f3..429708a 100755 --- a/WeChatTweak/WeChatTweak.m +++ b/WeChatTweak/WeChatTweak.m @@ -11,6 +11,7 @@ #import "NSBundle+WeChatTweak.h" #import "NSString+WeChatTweak.h" #import "TweakPreferecesController.h" +#import "AlfredManager.h" @implementation NSObject (WeChatTweak) @@ -41,12 +42,11 @@ static void __attribute__((constructor)) tweak(void) { data.msgStatus = 4; data.toUsrName = localMessageData.toUsrName; data.fromUsrName = localMessageData.fromUsrName; + data.mesLocalID = localMessageData.mesLocalID; data.msgCreateTime = localMessageData.msgCreateTime; if ([localMessageData isSendFromSelf]) { - data.mesLocalID = localMessageData.mesLocalID; data.msgContent = replaceMessage; } else { - data.mesLocalID = localMessageData.mesLocalID; data.msgContent = [NSString stringWithFormat:@"[已拦截]\n%@", replaceMessage]; } data; @@ -77,7 +77,6 @@ static void __attribute__((constructor)) tweak(void) { [((MessageService *)self) AddLocalMsg:session msgData:promptMessageData]; } else { [((MessageService *)self) AddLocalMsg:session msgData:promptMessageData]; - [((MessageService *)self) notifyAddMsgOnMainThread:session msgData:promptMessageData]; } // Deliver notification if (![localMessageData isSendFromSelf]) { @@ -125,6 +124,7 @@ static void __attribute__((constructor)) tweak(void) { [accountService AutoAuth]; } } + [[AlfredManager sharedInstance] startListener]; } - (NSApplicationTerminateReply)tweak_applicationShouldTerminate:(NSApplication *)sender { diff --git a/WeChatTweak/WeChatTweakHeaders.h b/WeChatTweak/WeChatTweakHeaders.h index 8f34bee..c8efe3c 100644 --- a/WeChatTweak/WeChatTweakHeaders.h +++ b/WeChatTweak/WeChatTweakHeaders.h @@ -9,6 +9,22 @@ #import #import +@interface WeChat : NSObject + ++ (instancetype)sharedInstance; +- (void)lock:(id)block; +- (void)showMainWindow; +- (void)startANewChatWithContact:(id)contact; + +@end + +@interface MMSearchResultItem : NSObject + +@property(nonatomic) unsigned long long type; // 0 is single chat, 1 is group chat +@property(readonly, nonatomic) NSString *identifier; + +@end + @interface MessageData: NSObject @property(nonatomic) unsigned int messageType; @@ -25,7 +41,14 @@ @interface WCContactData : NSObject +@property(nonatomic) unsigned int m_uiBrandSubscriptionSettings; @property(retain, nonatomic) NSString *m_nsNickName; +@property(retain, nonatomic) NSString *m_nsUsrName; +@property(retain, nonatomic) NSString *m_nsAliasName; +@property(retain, nonatomic) NSString *m_nsRemark; +@property(retain, nonatomic) NSString *m_nsFullPY; +@property(retain, nonatomic) NSString *m_nsRemarkPYShort; +@property(retain, nonatomic) NSString *m_nsRemarkPYFull; - (BOOL)isChatStatusNotifyOpen; @@ -33,20 +56,22 @@ @interface ContactStorage : NSObject -- (id)GetContact:(id)arg1; +- (WCContactData *)GetContact:(NSString *)session; +- (NSArray *)GetAllFriendContacts; @end @interface GroupStorage: NSObject -- (id)GetGroupContact:(id)arg1; +- (WCContactData *)GetGroupContact:(NSString *)session; +- (NSArray *)GetAllGroups; @end @interface MMServiceCenter : NSObject + (id)defaultCenter; -- (id)getService:(Class)arg1; +- (id)getService:(Class)name; @end