├── .gitignore ├── WeWorkHelper.plist ├── pngs ├── 1.png ├── 2.png └── 3.png ├── src ├── SuspensionView.h ├── HelperSettingController.h ├── AppDelegate.h ├── WWKMessageListController.h ├── WWKConversationLBSViewController.h ├── WindowInfoManager.h ├── WWKAttendanceBinaryCheckViewController.h ├── MainKeyMananer.h ├── WWKLocationItem.h ├── WWKAttendanceRamdonCheckViewController.h ├── SuspensionView.m ├── Tweak.xm ├── MainKeyMananer.m ├── WindowInfoManager.m └── HelperSettingController.m ├── control ├── Makefile └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .theos/ 2 | *.deb -------------------------------------------------------------------------------- /WeWorkHelper.plist: -------------------------------------------------------------------------------- 1 | { Filter = { Bundles = ( "com.tencent.ww" ); }; } 2 | -------------------------------------------------------------------------------- /pngs/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgfjx/weworkhelper/HEAD/pngs/1.png -------------------------------------------------------------------------------- /pngs/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgfjx/weworkhelper/HEAD/pngs/2.png -------------------------------------------------------------------------------- /pngs/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgfjx/weworkhelper/HEAD/pngs/3.png -------------------------------------------------------------------------------- /src/SuspensionView.h: -------------------------------------------------------------------------------- 1 | // 2 | // SuspensionView.h 3 | // hopper 4 | // 5 | // Created by mgfjx on 2017/2/3. 6 | // Copyright © 2017年 XXL. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface SuspensionView : UIView 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /control: -------------------------------------------------------------------------------- 1 | Package: com.mgfjx.weworkhelper 2 | Name: WeWorkHelper企业微信助手 3 | Depends: mobilesubstrate 4 | Version: 1.0.0 5 | Architecture: iphoneos-arm 6 | Description: 企业微信助手(2.7.5):可实现虚拟定位、远程打卡。打卡现场拍照改为从相册获取。声明:仅建议紧急情况使用,切勿长期迟到早退! 7 | Maintainer: mgfjx 8 | Author: mgfjx 9 | Section: Tweaks 10 | -------------------------------------------------------------------------------- /src/HelperSettingController.h: -------------------------------------------------------------------------------- 1 | // 2 | // HelperSettingController.h 3 | // test 4 | // 5 | // Created by mgfjx on 2019/3/17. 6 | // Copyright © 2019 mgfjx. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "MainKeyMananer.h" 11 | 12 | @interface HelperSettingController : UIViewController 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /src/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // test 4 | // 5 | // Created by mgfjx on 2018/7/3. 6 | // Copyright © 2018年 mgfjx. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /src/WWKMessageListController.h: -------------------------------------------------------------------------------- 1 | // 2 | // Generated by class-dump 3.5 (64 bit). 3 | // 4 | // class-dump is Copyright (C) 1997-1998, 2000-2001, 2004-2013 by Steve Nygard. 5 | // 6 | 7 | #import 8 | 9 | @interface WWKMessageListController : UIViewController 10 | 11 | - (void)xl_setLocationClicked:(id)sender ; 12 | 13 | @end 14 | 15 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | THEOS_DEVICE_IP = localhost 2 | THEOS_DEVICE_PORT = 2222 3 | 4 | ARCHS = armv7 arm64 5 | TARGET = iphone:latest:8.0 6 | 7 | FINALPACKAGE = 1 8 | 9 | include $(THEOS)/makefiles/common.mk 10 | 11 | TWEAK_NAME = WeWorkHelper 12 | WeWorkHelper_FILES = $(wildcard src/*.xm) $(wildcard src/*.m) 13 | 14 | include $(THEOS_MAKE_PATH)/tweak.mk 15 | 16 | after-install:: 17 | install.exec "killall -9 wework" 18 | -------------------------------------------------------------------------------- /src/WWKConversationLBSViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // Generated by class-dump 3.5 (64 bit). 3 | // 4 | // class-dump is Copyright (C) 1997-1998, 2000-2001, 2004-2013 by Steve Nygard. 5 | // 6 | 7 | #import 8 | #import "WWKLocationItem.h" 9 | 10 | @interface WWKConversationLBSViewController : UIViewController 11 | 12 | @property(retain, nonatomic) WWKLocationItem *selectionItem; 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /src/WindowInfoManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // WindowInfoManager.h 3 | // test 4 | // 5 | // Created by mgfjx on 2019/3/12. 6 | // Copyright © 2019 mgfjx. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @interface WindowInfoManager : NSObject 13 | 14 | + (instancetype)manager ; 15 | 16 | - (void)addToWindow:(UIWindow *)window ; 17 | 18 | @end 19 | 20 | @interface UIViewController (getName) 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /src/WWKAttendanceBinaryCheckViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // Generated by class-dump 3.5 (64 bit). 3 | // 4 | // class-dump is Copyright (C) 1997-1998, 2000-2001, 2004-2013 by Steve Nygard. 5 | // 6 | 7 | #import 8 | 9 | @interface WWKAttendanceBinaryCheckViewController : UIViewController 10 | 11 | //- (void)p_openCamera:(scoped_refptr_e21d2ae3)arg1; 12 | //- (void)p_openCamera_V27:(Promise_dd2761d8 *)arg1; 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /src/MainKeyMananer.h: -------------------------------------------------------------------------------- 1 | // 2 | // MainKeyMananer.h 3 | // test 4 | // 5 | // Created by mgfjx on 2019/3/17. 6 | // Copyright © 2019 mgfjx. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface MainKeyMananer : NSObject 12 | 13 | + (instancetype)manager ; 14 | 15 | @property (nonatomic, assign) BOOL on ; 16 | @property (nonatomic, assign) BOOL fakeLocation ; 17 | @property (nonatomic, assign) BOOL selectFromAlbum ; 18 | @property (nonatomic, assign) BOOL photoEdit ; 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /src/WWKLocationItem.h: -------------------------------------------------------------------------------- 1 | // 2 | // Generated by class-dump 3.5 (64 bit). 3 | // 4 | // class-dump is Copyright (C) 1997-1998, 2000-2001, 2004-2013 by Steve Nygard. 5 | // 6 | 7 | #import 8 | #import 9 | 10 | @class NSString; 11 | 12 | @interface WWKLocationItem : NSObject 13 | @property(copy, nonatomic) NSString *detailAddressName; 14 | @property(copy, nonatomic) NSString *addressName; 15 | @property(nonatomic) struct CLLocationCoordinate2D coordinate; 16 | 17 | @end 18 | 19 | -------------------------------------------------------------------------------- /src/WWKAttendanceRamdonCheckViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // Generated by class-dump 3.5 (64 bit). 3 | // 4 | // class-dump is Copyright (C) 1997-1998, 2000-2001, 2004-2013 by Steve Nygard. 5 | // 6 | 7 | #import 8 | #import "WWKConversationLBSViewController.h" 9 | 10 | @class NSString; 11 | 12 | @interface WWKAttendanceRamdonCheckViewController : UIViewController 13 | - (void)imagePickerController:(id)arg1 didFinishPickingMediaWithInfo:(id)arg2; 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /src/SuspensionView.m: -------------------------------------------------------------------------------- 1 | // 2 | // SuspensionView.m 3 | // hopper 4 | // 5 | // Created by mgfjx on 2017/2/3. 6 | // Copyright © 2017年 XXL. All rights reserved. 7 | // 8 | 9 | #import "SuspensionView.h" 10 | 11 | @interface SuspensionView (){ 12 | 13 | CGFloat contentOffsetX; 14 | CGFloat contentOffsetY; 15 | 16 | } 17 | 18 | @end 19 | 20 | @implementation SuspensionView 21 | 22 | - (instancetype)init{ 23 | self = [super init]; 24 | if (self) { 25 | 26 | // UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapHandler:)]; 27 | // [self addGestureRecognizer:tap]; 28 | 29 | UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panHandler:)]; 30 | [self addGestureRecognizer:pan]; 31 | 32 | } 33 | return self; 34 | } 35 | 36 | - (void)panHandler:(UIPanGestureRecognizer *)pan{ 37 | 38 | if (pan.state == UIGestureRecognizerStateBegan) { 39 | CGPoint origin = [pan locationInView:pan.view]; 40 | 41 | contentOffsetX = origin.x; 42 | contentOffsetY = origin.y; 43 | } 44 | 45 | if (pan.state == UIGestureRecognizerStateChanged) { 46 | CGPoint point = [pan locationInView:self.superview]; 47 | CGRect frame = pan.view.frame; 48 | CGFloat width = [UIScreen mainScreen].bounds.size.width; 49 | CGFloat height = [UIScreen mainScreen].bounds.size.height; 50 | CGFloat x = point.x - contentOffsetX; 51 | CGFloat y = point.y - contentOffsetY; 52 | CGFloat offset = self.bounds.size.width + 10; 53 | if (x + self.frame.size.width <= offset) { 54 | x = offset - self.frame.size.width; 55 | } 56 | if (x >= width - offset) { 57 | x = width - offset; 58 | } 59 | if (y + self.frame.size.height <= 64 + offset) { 60 | y = 64 + offset - self.frame.size.height; 61 | } 62 | if (y >= height - offset) { 63 | y = height - offset; 64 | } 65 | frame.origin = CGPointMake(x, y); 66 | pan.view.frame = frame; 67 | } 68 | 69 | } 70 | 71 | @end 72 | -------------------------------------------------------------------------------- /src/Tweak.xm: -------------------------------------------------------------------------------- 1 | #import "WindowInfoManager.h" 2 | #import "AppDelegate.h" 3 | #import "WWKAttendanceRamdonCheckViewController.h" 4 | #import "SuspensionView.h" 5 | #import 6 | #import "WWKAttendanceBinaryCheckViewController.h" 7 | #import 8 | #import "WWKConversationLBSViewController.h" 9 | #import "WWKMessageListController.h" 10 | #import "HelperSettingController.h" 11 | 12 | %hook AppDelegate 13 | 14 | - (_Bool)application:(id)arg1 didFinishLaunchingWithOptions:(id)arg2 { 15 | //[[WindowInfoManager manager] addToWindow:self.window]; 16 | return %orig; 17 | } 18 | 19 | 20 | %end 21 | 22 | %hook UIImagePickerController 23 | 24 | - (void)setSourceType:(UIImagePickerControllerSourceType)sourceType { 25 | if ([MainKeyMananer manager].on && [MainKeyMananer manager].selectFromAlbum) { 26 | sourceType = UIImagePickerControllerSourceTypePhotoLibrary; 27 | self.mediaTypes = @[(NSString*)kUTTypeImage]; 28 | } 29 | %orig; 30 | } 31 | 32 | - (void)setAllowsEditing:(BOOL)allowsEditing { 33 | if ([MainKeyMananer manager].on && [MainKeyMananer manager].photoEdit) { 34 | allowsEditing = YES; 35 | } 36 | %orig; 37 | } 38 | 39 | 40 | %end 41 | 42 | %hook WWKMessageListController 43 | 44 | - (void)viewDidAppear:(BOOL)animated { 45 | %orig; 46 | 47 | self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"助手设置" style:UIBarButtonItemStylePlain target:self action:@selector(xl_setLocationClicked:)]; 48 | 49 | } 50 | 51 | %new 52 | - (void)xl_setLocationClicked:(id)sender { 53 | 54 | HelperSettingController *vc = [%c(HelperSettingController) new]; 55 | [self.navigationController pushViewController:(UIViewController *)vc animated:YES]; 56 | } 57 | 58 | %end 59 | 60 | %hook CLLocation 61 | 62 | - (CLLocationCoordinate2D)coordinate { 63 | 64 | if ([MainKeyMananer manager].on && [MainKeyMananer manager].fakeLocation) { 65 | NSNumber *latitudeObj = [[NSUserDefaults standardUserDefaults] objectForKey:@"kXLLatitude"]; 66 | NSNumber *longitudeObj = [[NSUserDefaults standardUserDefaults] 67 | objectForKey:@"kXLLongitude"]; 68 | 69 | if(!latitudeObj || !longitudeObj){ 70 | return %orig; 71 | }else { 72 | CGFloat latitude = [latitudeObj floatValue]; 73 | CGFloat longitude = [longitudeObj floatValue]; 74 | CLLocationCoordinate2D coor = CLLocationCoordinate2DMake(latitude, longitude); 75 | return coor; 76 | } 77 | }else { 78 | return %orig; 79 | } 80 | } 81 | 82 | %end 83 | -------------------------------------------------------------------------------- /src/MainKeyMananer.m: -------------------------------------------------------------------------------- 1 | // 2 | // MainKeyMananer.m 3 | // test 4 | // 5 | // Created by mgfjx on 2019/3/17. 6 | // Copyright © 2019 mgfjx. All rights reserved. 7 | // 8 | 9 | #import "MainKeyMananer.h" 10 | 11 | @implementation MainKeyMananer 12 | 13 | static id singleton = nil; 14 | 15 | + (instancetype)allocWithZone:(struct _NSZone *)zone{ 16 | if (!singleton) { 17 | static dispatch_once_t onceToken; 18 | dispatch_once(&onceToken, ^{ 19 | singleton = [super allocWithZone:zone]; 20 | NSObject *obj = [[NSUserDefaults standardUserDefaults] objectForKey:@"kSwitchOn"]; 21 | if (!obj) { 22 | [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"kFakeLocation"]; 23 | [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"kSwitchOn"]; 24 | [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"kSelectFromAlbum"]; 25 | [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"kPhotoEdit"]; 26 | } 27 | }); 28 | } 29 | return singleton; 30 | } 31 | 32 | - (instancetype)init{ 33 | static dispatch_once_t onceToken; 34 | dispatch_once(&onceToken, ^{ 35 | singleton = [super init]; 36 | }); 37 | return singleton; 38 | } 39 | 40 | - (id)copyWithZone:(NSZone *)zone{ 41 | return singleton; 42 | } 43 | 44 | - (id)mutableCopyWithZone:(NSZone *)zone{ 45 | return singleton; 46 | } 47 | 48 | + (instancetype)manager{ 49 | return [[self alloc] init]; 50 | } 51 | 52 | - (BOOL)on { 53 | BOOL open = [[NSUserDefaults standardUserDefaults] boolForKey:@"kSwitchOn"]; 54 | return open; 55 | } 56 | 57 | - (void)setOn:(BOOL)on { 58 | [[NSUserDefaults standardUserDefaults] setBool:on forKey:@"kSwitchOn"]; 59 | } 60 | 61 | - (BOOL)fakeLocation { 62 | BOOL open = [[NSUserDefaults standardUserDefaults] boolForKey:@"kFakeLocation"]; 63 | return open; 64 | } 65 | 66 | - (void)setFakeLocation:(BOOL)fakeLocation { 67 | [[NSUserDefaults standardUserDefaults] setBool:fakeLocation forKey:@"kFakeLocation"]; 68 | } 69 | 70 | - (BOOL)selectFromAlbum { 71 | BOOL open = [[NSUserDefaults standardUserDefaults] boolForKey:@"kSelectFromAlbum"]; 72 | return open; 73 | } 74 | 75 | - (void)setSelectFromAlbum:(BOOL)selectFromAlbum { 76 | [[NSUserDefaults standardUserDefaults] setBool:selectFromAlbum forKey:@"kSelectFromAlbum"]; 77 | } 78 | 79 | - (BOOL)photoEdit { 80 | BOOL open = [[NSUserDefaults standardUserDefaults] boolForKey:@"kPhotoEdit"]; 81 | return open; 82 | } 83 | 84 | - (void)setPhotoEdit:(BOOL)photoEdit { 85 | [[NSUserDefaults standardUserDefaults] setBool:photoEdit forKey:@"kPhotoEdit"]; 86 | } 87 | 88 | @end 89 | -------------------------------------------------------------------------------- /src/WindowInfoManager.m: -------------------------------------------------------------------------------- 1 | // 2 | // WindowInfoManager.m 3 | // test 4 | // 5 | // Created by mgfjx on 2019/3/12. 6 | // Copyright © 2019 mgfjx. All rights reserved. 7 | // 8 | 9 | #import "WindowInfoManager.h" 10 | 11 | static WindowInfoManager *manager ; 12 | 13 | @interface WindowInfoManager () 14 | 15 | @property (nonatomic, strong) UIWindow *window ; 16 | @property (nonatomic, strong) UITextView *textView ; 17 | 18 | @end 19 | 20 | @implementation WindowInfoManager 21 | 22 | + (instancetype)manager { 23 | static dispatch_once_t onceToken; 24 | dispatch_once(&onceToken, ^{ 25 | manager = [WindowInfoManager new]; 26 | }); 27 | return manager; 28 | } 29 | 30 | - (void)addToWindow:(UIWindow *)superWindow { 31 | 32 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 33 | UIWindow *window = [[UIWindow alloc] initWithFrame:CGRectMake(0, 64, 150, 150)]; 34 | [superWindow addSubview:window]; 35 | [window makeKeyAndVisible]; 36 | self.window = window; 37 | 38 | UITextView *textView = [[UITextView alloc] initWithFrame:window.bounds]; 39 | textView.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.3]; 40 | textView.editable = NO; 41 | textView.textColor = [UIColor whiteColor]; 42 | [window addSubview:textView]; 43 | textView.layoutManager.allowsNonContiguousLayout = NO; 44 | self.textView = textView; 45 | 46 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appendText:) name:@"kNotificationVCLoad" object:nil]; 47 | }); 48 | 49 | } 50 | 51 | - (void)appendText:(NSNotification *)notification { 52 | 53 | NSString *text = (NSString *)notification.object; 54 | 55 | NSString *content = self.textView.text; 56 | self.textView.text = [NSString stringWithFormat:@"%@%@\n",content,text]; 57 | [self.textView scrollRangeToVisible:NSMakeRange(self.textView.text.length, 1)]; 58 | 59 | } 60 | 61 | @end 62 | 63 | 64 | #import 65 | 66 | @implementation UIViewController (getName) 67 | 68 | + (void)load { 69 | Method m1 = class_getInstanceMethod([self class], @selector(viewDidLoad)); 70 | Method m2 = class_getInstanceMethod([self class], @selector(ex_viewDidLoad)); 71 | method_exchangeImplementations(m1, m2); 72 | } 73 | 74 | - (void)ex_viewDidLoad { 75 | /* 76 | NSMutableString *string = [NSMutableString string]; 77 | for (UIViewController *vc in self.navigationController.viewControllers) { 78 | [string appendString:NSStringFromClass([vc class])]; 79 | [string appendString:@","]; 80 | } 81 | */ 82 | [[NSNotificationCenter defaultCenter] postNotificationName:@"kNotificationVCLoad" object:NSStringFromClass([self class])]; 83 | [self ex_viewDidLoad]; 84 | } 85 | 86 | @end 87 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # weworkhelper 2 | ##### 企业微信app虚拟定位、打卡照片实现从相册选择并添加编辑功能 3 | 4 | 安装方法:添加源地址 `https://evildriver.github.io`,里面有个`WeWorkHelper企业微信助手`安装就可以了;或者直接下载release版本直接使用`iFunBox`进行安装。 5 | 先上源码: 6 | 7 | ``` 8 | #import "WindowInfoManager.h" 9 | #import "AppDelegate.h" 10 | #import "WWKAttendanceRamdonCheckViewController.h" 11 | #import "SuspensionView.h" 12 | #import 13 | #import "WWKAttendanceBinaryCheckViewController.h" 14 | #import 15 | #import "WWKConversationLBSViewController.h" 16 | #import "WWKMessageListController.h" 17 | #import "HelperSettingController.h" 18 | 19 | %hook AppDelegate 20 | 21 | - (_Bool)application:(id)arg1 didFinishLaunchingWithOptions:(id)arg2 { 22 | //[[WindowInfoManager manager] addToWindow:self.window]; 23 | return %orig; 24 | } 25 | 26 | 27 | %end 28 | 29 | %hook UIImagePickerController 30 | 31 | //设置是否从相册选择 32 | - (void)setSourceType:(UIImagePickerControllerSourceType)sourceType { 33 | if ([MainKeyMananer manager].on && [MainKeyMananer manager].selectFromAlbum) { 34 | sourceType = UIImagePickerControllerSourceTypePhotoLibrary; 35 | self.mediaTypes = @[(NSString*)kUTTypeImage]; 36 | } 37 | %orig; 38 | } 39 | 40 | //设置是否可编辑 41 | - (void)setAllowsEditing:(BOOL)allowsEditing { 42 | if ([MainKeyMananer manager].on && [MainKeyMananer manager].photoEdit) { 43 | allowsEditing = YES; 44 | } 45 | %orig; 46 | } 47 | 48 | 49 | %end 50 | 51 | %hook WWKMessageListController 52 | //在首页添加助手设置入口 53 | - (void)viewDidAppear:(BOOL)animated { 54 | %orig; 55 | 56 | self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"助手设置" style:UIBarButtonItemStylePlain target:self action:@selector(xl_setLocationClicked:)]; 57 | 58 | } 59 | 60 | %new 61 | - (void)xl_setLocationClicked:(id)sender { 62 | 63 | HelperSettingController *vc = [%c(HelperSettingController) new]; 64 | [self.navigationController pushViewController:(UIViewController *)vc animated:YES]; 65 | } 66 | 67 | %end 68 | 69 | %hook CLLocation 70 | 71 | - (CLLocationCoordinate2D)coordinate { 72 | 73 | if ([MainKeyMananer manager].on && [MainKeyMananer manager].fakeLocation) { 74 | NSNumber *latitudeObj = [[NSUserDefaults standardUserDefaults] objectForKey:@"kXLLatitude"]; 75 | NSNumber *longitudeObj = [[NSUserDefaults standardUserDefaults] 76 | objectForKey:@"kXLLongitude"]; 77 | 78 | if(!latitudeObj || !longitudeObj){ 79 | return %orig; 80 | }else { 81 | CGFloat latitude = [latitudeObj floatValue]; 82 | CGFloat longitude = [longitudeObj floatValue]; 83 | CLLocationCoordinate2D coor = CLLocationCoordinate2DMake(latitude, longitude); 84 | return coor; 85 | } 86 | }else { 87 | return %orig; 88 | } 89 | } 90 | 91 | %end 92 | 93 | ``` 94 | `MainKeyMananer`主要是控制开关。 95 | ![image.png](./pngs/1.png) 96 | ![image.png](./pngs/2.png) 97 | ![image.png](./pngs/3.png) 98 | 注:地图选点用的是企业微信自带的类,但为了不影响原来界面,此类为runtime动态创建的继承于自带类的子类,贴一下部分代码: 99 | ``` 100 | void p_send(id self, SEL _cmd, id arg1) { 101 | Ivar ivar = class_getInstanceVariable([self class], "_selectionItem"); 102 | // 返回名为test的ivar变量的值 103 | WWKLocationItem *item = (WWKLocationItem *)object_getIvar(self, ivar); 104 | 105 | CLLocationCoordinate2D coor = item.coordinate; 106 | 107 | NSString *string = [NSString stringWithFormat:@"%lf,%lf", coor.latitude, coor.longitude]; 108 | 109 | [[NSUserDefaults standardUserDefaults] setObject:@(coor.latitude) forKey:@"kXLLatitude"]; 110 | [[NSUserDefaults standardUserDefaults] setObject:@(coor.longitude) forKey:@"kXLLongitude"]; 111 | 112 | [[NSNotificationCenter defaultCenter] postNotificationName:@"kNotificationVCLoad" object:string]; 113 | 114 | UIViewController *vc = (UIViewController *)self; 115 | [vc.navigationController popViewControllerAnimated:YES]; 116 | } 117 | 118 | void viewDidLoad(id self, SEL _cmd) { 119 | //调用父类的viewdidload方法 120 | SEL superSel = _cmd; 121 | Method sm = class_getInstanceMethod([self superclass], superSel); 122 | IMP imp = method_getImplementation(sm); 123 | imp(self, superSel); 124 | 125 | UIViewController *vc = (UIViewController *)self; 126 | 127 | vc.title = @"虚拟定位"; 128 | 129 | vc.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"确定" style:UIBarButtonItemStylePlain target:self action:@selector(p_send:)]; 130 | } 131 | 132 | //runtime添加继承类 133 | Class LocationSelectViewController = objc_allocateClassPair(NSClassFromString(@"WWKConversationLBSViewController"), "LocationSelectViewController", 0); 134 | { 135 | BOOL success = class_addMethod(LocationSelectViewController, @selector(p_send:), (IMP)p_send, "V@:"); 136 | if (success) { 137 | NSLog(@"添加方法成功"); 138 | } 139 | } 140 | 141 | { 142 | BOOL success = class_addMethod(LocationSelectViewController, @selector(viewDidLoad), (IMP)viewDidLoad, "V@:"); 143 | if (success) { 144 | NSLog(@"添加方法成功"); 145 | } 146 | } 147 | 148 | id vc = [LocationSelectViewController new]; 149 | [self.navigationController pushViewController:(UIViewController *)vc animated:YES]; 150 | ``` 151 | 152 | 如有问题,请留言。 -------------------------------------------------------------------------------- /src/HelperSettingController.m: -------------------------------------------------------------------------------- 1 | // 2 | // HelperSettingController.m 3 | // test 4 | // 5 | // Created by mgfjx on 2019/3/17. 6 | // Copyright © 2019 mgfjx. All rights reserved. 7 | // 8 | 9 | #import "HelperSettingController.h" 10 | #import 11 | #import "WWKLocationItem.h" 12 | #import 13 | #import 14 | 15 | #define CellHeight 50 16 | #define MainWidth [UIScreen mainScreen].bounds.size.width 17 | 18 | @interface HelperSettingController () 19 | 20 | @property (nonatomic, strong) UITableView *tableView ; 21 | 22 | @end 23 | 24 | @implementation HelperSettingController 25 | 26 | #pragma mark - LifeCycle 27 | 28 | void p_send(id self, SEL _cmd, id arg1) { 29 | Ivar ivar = class_getInstanceVariable([self class], "_selectionItem"); 30 | // 返回名为test的ivar变量的值 31 | WWKLocationItem *item = (WWKLocationItem *)object_getIvar(self, ivar); 32 | 33 | CLLocationCoordinate2D coor = item.coordinate; 34 | 35 | NSString *string = [NSString stringWithFormat:@"%lf,%lf", coor.latitude, coor.longitude]; 36 | 37 | [[NSUserDefaults standardUserDefaults] setObject:@(coor.latitude) forKey:@"kXLLatitude"]; 38 | [[NSUserDefaults standardUserDefaults] setObject:@(coor.longitude) forKey:@"kXLLongitude"]; 39 | 40 | [[NSNotificationCenter defaultCenter] postNotificationName:@"kNotificationVCLoad" object:string]; 41 | 42 | UIViewController *vc = (UIViewController *)self; 43 | [vc.navigationController popViewControllerAnimated:YES]; 44 | } 45 | 46 | void viewDidLoad(id self, SEL _cmd) { 47 | SEL superSel = _cmd; 48 | Method sm = class_getInstanceMethod([self superclass], superSel); 49 | IMP imp = method_getImplementation(sm); 50 | imp(self, superSel); 51 | 52 | UIViewController *vc = (UIViewController *)self; 53 | 54 | vc.title = @"虚拟定位"; 55 | 56 | vc.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"确定" style:UIBarButtonItemStylePlain target:self action:@selector(p_send:)]; 57 | } 58 | 59 | - (void)viewDidLoad { 60 | [super viewDidLoad]; 61 | 62 | self.title = @"助手设置"; 63 | self.view.backgroundColor = [UIColor whiteColor]; 64 | [self initViews]; 65 | 66 | } 67 | 68 | - (void)initViews { 69 | 70 | UITableView *table = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain]; 71 | table.delegate = self; 72 | table.dataSource = self; 73 | 74 | [self.view addSubview:table]; 75 | self.tableView = table; 76 | 77 | table.tableFooterView = [UIView new]; 78 | 79 | CGFloat value = 0.95; 80 | table.backgroundColor = [UIColor colorWithRed:value green:value blue:value alpha:1.0]; 81 | 82 | } 83 | 84 | #pragma mark - UITableViewDelegate, UITableViewDataSource 85 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { 86 | return 3; 87 | } 88 | 89 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 90 | if (section == 0) { 91 | return 1; 92 | }else if (section == 1){ 93 | if ([MainKeyMananer manager].fakeLocation) { 94 | return 2; 95 | }else{ 96 | return 1; 97 | } 98 | }else{ 99 | return 2; 100 | } 101 | } 102 | 103 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 104 | NSString *cellReuse = @"cell"; 105 | UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:cellReuse]; 106 | cell.selectionStyle = UITableViewCellSelectionStyleNone; 107 | 108 | if (indexPath.section == 0) { 109 | cell.textLabel.text = @"总开关"; 110 | } 111 | 112 | if (indexPath.section == 1) { 113 | if (indexPath.row == 0) { 114 | cell.textLabel.text = @"虚拟定位"; 115 | }else{ 116 | cell.textLabel.text = @"设置虚拟定位"; 117 | } 118 | } 119 | 120 | if (indexPath.section == 2) { 121 | if (indexPath.row == 0) { 122 | cell.textLabel.text = @"从相册选择照片"; 123 | }else{ 124 | cell.textLabel.text = @"编辑照片"; 125 | } 126 | } 127 | 128 | if (indexPath.section == 1 && indexPath.row == 1) { 129 | cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; 130 | }else{ 131 | UISwitch *sw = [[UISwitch alloc] init]; 132 | sw.frame = CGRectMake(MainWidth - sw.bounds.size.width - 10, 0, 0, 0); 133 | [cell.contentView addSubview:sw]; 134 | sw.center = CGPointMake(sw.center.x, CellHeight/2); 135 | [sw addTarget:self action:@selector(switchValueChange:) forControlEvents:UIControlEventValueChanged]; 136 | NSInteger tag = (indexPath.section + 1)*100 + indexPath.row; 137 | sw.tag = tag; 138 | 139 | [[NSNotificationCenter defaultCenter] postNotificationName:@"kNotificationVCLoad" object:[@(tag) stringValue]]; 140 | if (tag == 100) { 141 | sw.on = [MainKeyMananer manager].on; 142 | }else if (tag == 200){ 143 | sw.on = [MainKeyMananer manager].fakeLocation; 144 | }else if (tag == 300){ 145 | sw.on = [MainKeyMananer manager].selectFromAlbum ; 146 | }else if (tag == 301){ 147 | sw.on = [MainKeyMananer manager].photoEdit ; 148 | } 149 | 150 | } 151 | 152 | return cell; 153 | } 154 | 155 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 156 | if (indexPath.section == 1 && indexPath.row == 1) { 157 | //runtime添加继承类 158 | Class LocationSelectViewController = objc_allocateClassPair(NSClassFromString(@"WWKConversationLBSViewController"), "LocationSelectViewController", 0); 159 | { 160 | BOOL success = class_addMethod(LocationSelectViewController, @selector(p_send:), (IMP)p_send, "V@:"); 161 | if (success) { 162 | NSLog(@"添加方法成功"); 163 | } 164 | } 165 | 166 | { 167 | BOOL success = class_addMethod(LocationSelectViewController, @selector(viewDidLoad), (IMP)viewDidLoad, "V@:"); 168 | if (success) { 169 | NSLog(@"添加方法成功"); 170 | } 171 | } 172 | 173 | id vc = [LocationSelectViewController new]; 174 | [self.navigationController pushViewController:(UIViewController *)vc animated:YES]; 175 | } 176 | } 177 | 178 | - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section { 179 | return 20; 180 | } 181 | 182 | - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section { 183 | UIView *view = [UIView new]; 184 | CGFloat value = 0.95; 185 | view.backgroundColor = [UIColor colorWithRed:value green:value blue:value alpha:1.0]; 186 | return view; 187 | } 188 | 189 | - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { 190 | return CellHeight; 191 | } 192 | 193 | - (void)switchValueChange:(UISwitch *)sw { 194 | 195 | NSInteger tag = sw.tag; 196 | 197 | if (tag == 100) { 198 | [MainKeyMananer manager].on = sw.on; 199 | }else if (tag == 200){ 200 | [MainKeyMananer manager].fakeLocation = sw.on; 201 | [self.tableView reloadSections:[NSIndexSet indexSetWithIndex:1] withRowAnimation:UITableViewRowAnimationAutomatic]; 202 | }else if (tag == 300){ 203 | [MainKeyMananer manager].selectFromAlbum = sw.on; 204 | }else if (tag == 301){ 205 | [MainKeyMananer manager].photoEdit = sw.on; 206 | } 207 | 208 | [[NSNotificationCenter defaultCenter] postNotificationName:@"kNotificationVCLoad" object:[@(tag) stringValue]]; 209 | 210 | } 211 | 212 | @end 213 | --------------------------------------------------------------------------------