├── .gitignore ├── DingTalkAssistant.plist ├── GPS ├── WBGPSPickerViewController.h └── WBGPSPickerViewController.m ├── Makefile ├── MenuWindow ├── WBAssistantManager.h ├── WBAssistantManager.m ├── WBGlobalSettingViewController.h ├── WBGlobalSettingViewController.m ├── WBMenuView.h ├── WBMenuView.m ├── WBMenuViewController.h ├── WBMenuViewController.m ├── WBWindow.h └── WBWindow.m ├── README.md ├── Tweak.xm ├── WIFI ├── WBWifiListViewController.h ├── WBWifiListViewController.m ├── WBWifiModel.h ├── WBWifiModel.m ├── WBWifiStore.h └── WBWifiStore.m ├── XcodeProject └── DingTalkAssistant.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ │ └── buginux.xcuserdatad │ │ └── UserInterfaceState.xcuserstate │ └── xcuserdata │ └── buginux.xcuserdatad │ └── xcschemes │ ├── DingTalkAssistant.xcscheme │ └── xcschememanagement.plist └── control /.gitignore: -------------------------------------------------------------------------------- 1 | _ 2 | obj 3 | *.deb 4 | .theos/ 5 | .DS_Store 6 | -------------------------------------------------------------------------------- /DingTalkAssistant.plist: -------------------------------------------------------------------------------- 1 | { Filter = { Bundles = ( "com.laiwang.DingTalk" ); }; } 2 | -------------------------------------------------------------------------------- /GPS/WBGPSPickerViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // WBGPSPickerViewController.h 3 | // DingTalkAssistant 4 | // 5 | // Created by buginux on 2017/7/28. 6 | // Copyright © 2017年 buginux. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface WBGPSPickerViewController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /GPS/WBGPSPickerViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // WBGPSPickerViewController.m 3 | // DingTalkAssistant 4 | // 5 | // Created by buginux on 2017/7/28. 6 | // Copyright © 2017年 buginux. All rights reserved. 7 | // 8 | 9 | #import "WBGPSPickerViewController.h" 10 | 11 | @interface WBGPSPickerViewController () 12 | 13 | @end 14 | 15 | @implementation WBGPSPickerViewController 16 | 17 | - (void)viewDidLoad { 18 | [super viewDidLoad]; 19 | 20 | self.title = @"GPS 设置"; 21 | 22 | self.view.backgroundColor = [UIColor whiteColor]; 23 | } 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | THEOS_DEVICE_IP = localhost 2 | THEOS_DEVICE_PORT = 2222 3 | 4 | include $(THEOS)/makefiles/common.mk 5 | 6 | TWEAK_NAME = DingTalkAssistant 7 | DingTalkAssistant_FILES = $(wildcard MenuWindow/*.m) $(wildcard WIFI/*.m) $(wildcard GPS/*.m) Tweak.xm 8 | DingTalkAssistant_FRAMEWORKS = SystemConfiguration 9 | 10 | include $(THEOS_MAKE_PATH)/tweak.mk 11 | 12 | after-install:: 13 | install.exec "killall -9 DingTalk" 14 | -------------------------------------------------------------------------------- /MenuWindow/WBAssistantManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // WBAssistantManager.h 3 | // FlowWindow 4 | // 5 | // Created by buginux on 2017/7/27. 6 | // Copyright © 2017年 buginux. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface WBAssistantManager : NSObject 12 | 13 | + (instancetype)sharedManager; 14 | 15 | - (void)showMenu; 16 | - (void)hideMenu; 17 | - (void)toggleMenu; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /MenuWindow/WBAssistantManager.m: -------------------------------------------------------------------------------- 1 | // 2 | // WBAssistantManager.m 3 | // FlowWindow 4 | // 5 | // Created by buginux on 2017/7/27. 6 | // Copyright © 2017年 buginux. All rights reserved. 7 | // 8 | 9 | #import "WBAssistantManager.h" 10 | #import "WBWindow.h" 11 | #import "WBMenuViewController.h" 12 | 13 | @interface WBAssistantManager () 14 | 15 | @property (nonatomic, strong) WBWindow *menuWindow; 16 | @property (nonatomic, strong) WBMenuViewController *menuViewController; 17 | 18 | @end 19 | 20 | @implementation WBAssistantManager 21 | 22 | + (instancetype)sharedManager { 23 | static WBAssistantManager *sharedManager = nil; 24 | static dispatch_once_t onceToken; 25 | dispatch_once(&onceToken, ^{ 26 | sharedManager = [[[self class] alloc] init]; 27 | }); 28 | return sharedManager; 29 | } 30 | 31 | - (instancetype)init { 32 | if (self = [super init]) { 33 | 34 | } 35 | return self; 36 | } 37 | 38 | - (WBWindow *)menuWindow { 39 | NSAssert([NSThread isMainThread], @"You must use %@ from the main thread only.", NSStringFromClass([self class])); 40 | if (!_menuWindow) { 41 | _menuWindow = [[WBWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; 42 | _menuWindow.eventDelegate = self; 43 | _menuWindow.rootViewController = self.menuViewController; 44 | } 45 | return _menuWindow; 46 | } 47 | 48 | - (WBMenuViewController *)menuViewController { 49 | if (!_menuViewController) { 50 | _menuViewController = [[WBMenuViewController alloc] init]; 51 | _menuViewController.delegate = self; 52 | } 53 | return _menuViewController; 54 | } 55 | 56 | - (void)showMenu { 57 | self.menuWindow.hidden = NO; 58 | } 59 | 60 | - (void)hideMenu { 61 | self.menuWindow.hidden = YES; 62 | } 63 | 64 | - (void)toggleMenu { 65 | if (self.menuWindow.isHidden) { 66 | [self showMenu]; 67 | } else { 68 | [self hideMenu]; 69 | } 70 | } 71 | 72 | #pragma mark - WBWindowEventDelegate 73 | 74 | - (BOOL)shouldHandleTouchAtPoint:(CGPoint)pointInWindow { 75 | return [self.menuViewController shouldReceiveTouchAtWindowPoint:pointInWindow]; 76 | } 77 | 78 | - (BOOL)canBecomeKeyWindow { 79 | return [self.menuViewController wantsWindowToBecomeKey]; 80 | } 81 | 82 | #pragma mark - WBMenuViewControllerDelegate 83 | 84 | - (void)menuViewControllerDidFinish:(WBMenuViewController *)menuViewController { 85 | [self hideMenu]; 86 | } 87 | 88 | @end 89 | -------------------------------------------------------------------------------- /MenuWindow/WBGlobalSettingViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // WBGlobalSettingViewController.h 3 | // DingTalkAssistant 4 | // 5 | // Created by buginux on 2017/7/28. 6 | // Copyright © 2017年 buginux. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @protocol WBGlobalSettingViewControllerDelegate; 12 | 13 | @interface WBGlobalSettingViewController : UITableViewController 14 | 15 | @property (nonatomic, unsafe_unretained) id delegate; 16 | 17 | /// We pretend that one of the app's windows is still the key window, even though the explorer window may have become key. 18 | /// We want to display debug state about the application, not about this tool. 19 | + (void)setApplicationWindow:(UIWindow *)applicationWindow; 20 | 21 | @end 22 | 23 | @protocol WBGlobalSettingViewControllerDelegate 24 | 25 | - (void)globalSettingViewControllerDidFinish:(WBGlobalSettingViewController *)viewController; 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /MenuWindow/WBGlobalSettingViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // WBGlobalSettingViewController.m 3 | // DingTalkAssistant 4 | // 5 | // Created by buginux on 2017/7/28. 6 | // Copyright © 2017年 buginux. All rights reserved. 7 | // 8 | 9 | #import "WBGlobalSettingViewController.h" 10 | #import "../GPS/WBGPSPickerViewController.h" 11 | #import "../WIFI/WBWifiListViewController.h" 12 | 13 | static UIWindow *s_applicationWindow = nil; 14 | 15 | @implementation WBGlobalSettingViewController 16 | 17 | - (void)viewDidLoad { 18 | [super viewDidLoad]; 19 | 20 | [self setupUI]; 21 | } 22 | 23 | - (void)setupUI { 24 | self.title = @"设置"; 25 | 26 | self.tableView.tableFooterView = [UIView new]; 27 | self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(doneButtonTapped:)]; 28 | } 29 | 30 | + (void)setApplicationWindow:(UIWindow *)applicationWindow { 31 | s_applicationWindow = applicationWindow; 32 | } 33 | 34 | - (void)doneButtonTapped:(UIButton *)sender { 35 | [self.delegate globalSettingViewControllerDidFinish:self]; 36 | } 37 | 38 | - (NSString *)titleForRowAtIndexPath:(NSIndexPath *)indexPath { 39 | if (indexPath.row == 0) { 40 | return @"GPS 设置"; 41 | } else { 42 | return @"WIFI 设置"; 43 | } 44 | } 45 | 46 | - (UIViewController *)viewControllerToPushForRowAtIndexPath:(NSIndexPath *)indexPath { 47 | if (indexPath.row == 0) { 48 | return [WBGPSPickerViewController new]; 49 | } else { 50 | return [WBWifiListViewController new]; 51 | } 52 | } 53 | 54 | #pragma mark - Table view data source 55 | 56 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 57 | return 2; 58 | } 59 | 60 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 61 | static NSString *CellIdentifier = @"Cell"; 62 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 63 | if (!cell) { 64 | cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]; 65 | cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; 66 | cell.textLabel.font = [UIFont systemFontOfSize:14.0]; 67 | } 68 | 69 | cell.textLabel.text = [self titleForRowAtIndexPath:indexPath]; 70 | 71 | return cell; 72 | } 73 | 74 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 75 | UIViewController *viewControllerToPush = [self viewControllerToPushForRowAtIndexPath:indexPath]; 76 | [self.navigationController pushViewController:viewControllerToPush animated:YES]; 77 | } 78 | 79 | @end 80 | -------------------------------------------------------------------------------- /MenuWindow/WBMenuView.h: -------------------------------------------------------------------------------- 1 | // 2 | // WBMenuView.h 3 | // FlowWindow 4 | // 5 | // Created by buginux on 2017/7/27. 6 | // Copyright © 2017年 buginux. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface WBMenuView : UIView 12 | 13 | @property (nonatomic, strong) UIButton *menuButton; 14 | @property (nonatomic, strong) UIButton *closeButton; 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /MenuWindow/WBMenuView.m: -------------------------------------------------------------------------------- 1 | // 2 | // WBMenuView.m 3 | // FlowWindow 4 | // 5 | // Created by buginux on 2017/7/27. 6 | // Copyright © 2017年 buginux. All rights reserved. 7 | // 8 | 9 | #import "WBMenuView.h" 10 | 11 | @implementation WBMenuView 12 | 13 | - (instancetype)initWithFrame:(CGRect)frame { 14 | if (self = [super initWithFrame:frame]) { 15 | [self commonInit]; 16 | } 17 | return self; 18 | } 19 | 20 | - (void)commonInit { 21 | self.backgroundColor = [UIColor colorWithWhite:0.0 alpha:0.2]; 22 | 23 | UIButton *menuButton = [UIButton buttonWithType:UIButtonTypeCustom]; 24 | [menuButton setTitle:@"菜单" forState:UIControlStateNormal]; 25 | [menuButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; 26 | menuButton.titleLabel.font = [UIFont systemFontOfSize:14.0]; 27 | [menuButton sizeToFit]; 28 | [self addSubview:menuButton]; 29 | self.menuButton = menuButton; 30 | 31 | UIButton *closeButton = [UIButton buttonWithType:UIButtonTypeCustom]; 32 | [closeButton setTitle:@"关闭" forState:UIControlStateNormal]; 33 | closeButton.titleLabel.font = [UIFont systemFontOfSize:14.0]; 34 | [closeButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; 35 | [closeButton sizeToFit]; 36 | [self addSubview:closeButton]; 37 | self.closeButton = closeButton; 38 | 39 | CGSize menuButtonSize = menuButton.frame.size; 40 | CGSize closeButtonSize = closeButton.frame.size; 41 | menuButton.frame = CGRectMake(8.0, 0.0, menuButtonSize.width, menuButtonSize.height); 42 | closeButton.frame = CGRectMake(CGRectGetMaxX(menuButton.frame) + 8.0, CGRectGetMinY(menuButton.frame), closeButtonSize.width, closeButtonSize.height); 43 | } 44 | 45 | - (CGSize)sizeThatFits:(CGSize)size { 46 | CGFloat width = CGRectGetMaxX(self.closeButton.frame) + 8.0; 47 | CGFloat height = CGRectGetHeight(self.menuButton.frame); 48 | return CGSizeMake(width, height); 49 | } 50 | 51 | 52 | @end 53 | -------------------------------------------------------------------------------- /MenuWindow/WBMenuViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // WBMenuViewController.h 3 | // FlowWindow 4 | // 5 | // Created by buginux on 2017/7/27. 6 | // Copyright © 2017年 buginux. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @protocol WBMenuViewControllerDelegate; 12 | 13 | @interface WBMenuViewController : UIViewController 14 | 15 | @property (nonatomic, unsafe_unretained) id delegate; 16 | 17 | - (BOOL)shouldReceiveTouchAtWindowPoint:(CGPoint)pointInWindowCoordinates; 18 | - (BOOL)wantsWindowToBecomeKey; 19 | 20 | @end 21 | 22 | @protocol WBMenuViewControllerDelegate 23 | 24 | - (void)menuViewControllerDidFinish:(WBMenuViewController *)menuViewController; 25 | 26 | @end 27 | -------------------------------------------------------------------------------- /MenuWindow/WBMenuViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // WBMenuViewController.m 3 | // FlowWindow 4 | // 5 | // Created by buginux on 2017/7/27. 6 | // Copyright © 2017年 buginux. All rights reserved. 7 | // 8 | 9 | #import "WBMenuViewController.h" 10 | #import "WBGlobalSettingViewController.h" 11 | #import "WBMenuView.h" 12 | 13 | @interface WBMenuViewController () 14 | 15 | @property (nonatomic, strong) WBMenuView *menu; 16 | 17 | /// Gesture recognizer for dragging a view in move mode 18 | @property (nonatomic, strong) UIPanGestureRecognizer *movePanGR; 19 | 20 | /// Only valid while a move pan gesture is in progress. 21 | @property (nonatomic, assign) CGRect menuFrameBeforeDragging; 22 | 23 | /// Tracked so we can restore the key window after dismissing a modal. 24 | /// We need to become key after modal presentation so we can correctly capture intput. 25 | /// If we're just showing the toolbar, we want the main app's window to remain key so that we don't interfere with input, status bar, etc. 26 | @property (nonatomic, strong) UIWindow *previousKeyWindow; 27 | 28 | /// Similar to the previousKeyWindow property above, we need to track status bar styling if 29 | /// the app doesn't use view controller based status bar management. When we present a modal, 30 | /// we want to change the status bar style to UIStausBarStyleDefault. Before changing, we stash 31 | /// the current style. On dismissal, we return the staus bar to the style that the app was using previously. 32 | @property (nonatomic, assign) UIStatusBarStyle previousStatusBarStyle; 33 | 34 | @end 35 | 36 | @implementation WBMenuViewController 37 | 38 | - (void)viewDidLoad { 39 | [super viewDidLoad]; 40 | 41 | [self setupMenu]; 42 | [self setupMenuActions]; 43 | 44 | // View moving 45 | self.movePanGR = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handleMovePan:)]; 46 | [self.view addGestureRecognizer:self.movePanGR]; 47 | } 48 | 49 | - (void)viewWillAppear:(BOOL)animated { 50 | [super viewWillAppear:animated]; 51 | 52 | } 53 | 54 | - (void)setupMenu { 55 | self.menu = [[WBMenuView alloc] init]; 56 | [self.menu sizeToFit]; 57 | 58 | CGRect frame = self.menu.frame; 59 | frame.origin.x = CGRectGetWidth([UIScreen mainScreen].bounds) - CGRectGetWidth(self.menu.frame); 60 | frame.origin.y = 100; 61 | self.menu.frame = frame; 62 | 63 | self.menu.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin; 64 | 65 | [self.view addSubview:self.menu]; 66 | } 67 | 68 | - (void)setupMenuActions { 69 | [self.menu.menuButton addTarget:self action:@selector(menuButtonTapped:) forControlEvents:UIControlEventTouchUpInside]; 70 | [self.menu.closeButton addTarget:self action:@selector(closeButtonTapped:) forControlEvents:UIControlEventTouchUpInside]; 71 | } 72 | 73 | - (void)menuButtonTapped:(UIButton *)sender { 74 | [self toggleSettingViewController]; 75 | } 76 | 77 | - (void)closeButtonTapped:(UIButton *)sender { 78 | [self.delegate menuViewControllerDidFinish:self]; 79 | } 80 | 81 | - (void)handleMovePan:(UIPanGestureRecognizer *)movePanGR { 82 | switch (movePanGR.state) { 83 | case UIGestureRecognizerStateBegan: 84 | self.menuFrameBeforeDragging = self.menu.frame; 85 | [self updateMenuPositionWithDragGesture:movePanGR]; 86 | break; 87 | 88 | case UIGestureRecognizerStateChanged: 89 | case UIGestureRecognizerStateEnded: 90 | [self updateMenuPositionWithDragGesture:movePanGR]; 91 | break; 92 | 93 | default: 94 | break; 95 | } 96 | } 97 | 98 | - (UIWindow *)statusWindow { 99 | NSString *statusBarString = [NSString stringWithFormat:@"%@arWindow", @"_statusB"]; 100 | return [[UIApplication sharedApplication] valueForKey:statusBarString]; 101 | } 102 | 103 | - (void)updateMenuPositionWithDragGesture:(UIPanGestureRecognizer *)movePanGR { 104 | CGPoint translation = [movePanGR translationInView:self.menu.superview]; 105 | CGRect newSelectedViewFrame = self.menuFrameBeforeDragging; 106 | newSelectedViewFrame.origin.x = newSelectedViewFrame.origin.x + translation.x; 107 | newSelectedViewFrame.origin.y = newSelectedViewFrame.origin.y + translation.y; 108 | self.menu.frame = newSelectedViewFrame; 109 | } 110 | 111 | - (void)toggleSettingViewController { 112 | BOOL menuModalShown = [[self presentedViewController] isKindOfClass:[UINavigationController class]]; 113 | menuModalShown = menuModalShown && [[[(UINavigationController *)[self presentedViewController] viewControllers] firstObject] isKindOfClass:[WBGlobalSettingViewController class]]; 114 | if (menuModalShown) { 115 | [self resignKeyAndDismissViewControllerAnimated:YES completion:nil]; 116 | } else { 117 | void (^presentBlock)() = ^{ 118 | WBGlobalSettingViewController *settingViewController = [[WBGlobalSettingViewController alloc] init]; 119 | settingViewController.delegate = self; 120 | [WBGlobalSettingViewController setApplicationWindow:[[UIApplication sharedApplication] keyWindow]]; 121 | UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:settingViewController]; 122 | [self makeKeyAndPresentViewController:navigationController animated:YES completion:nil]; 123 | }; 124 | 125 | if (self.presentedViewController) { 126 | [self resignKeyAndDismissViewControllerAnimated:NO completion:presentBlock]; 127 | } else { 128 | presentBlock(); 129 | } 130 | } 131 | } 132 | 133 | #pragma mark - Touch Handling 134 | 135 | - (BOOL)shouldReceiveTouchAtWindowPoint:(CGPoint)pointInWindowCoordinates { 136 | BOOL shouldReceiveTouch = NO; 137 | 138 | CGPoint pointInLocalCoordinates = [self.view convertPoint:pointInWindowCoordinates fromView:nil]; 139 | 140 | // Always if it's on the menu 141 | if (CGRectContainsPoint(self.menu.frame, pointInLocalCoordinates)) { 142 | shouldReceiveTouch = YES; 143 | } 144 | 145 | // Always if we have a modal presented 146 | if (!shouldReceiveTouch && self.presentedViewController) { 147 | shouldReceiveTouch = YES; 148 | } 149 | 150 | return shouldReceiveTouch; 151 | } 152 | 153 | #pragma mark - WBGlobalSettingViewControllerDelegate 154 | 155 | - (void)globalSettingViewControllerDidFinish:(WBGlobalSettingViewController *)controller { 156 | [self resignKeyAndDismissViewControllerAnimated:YES completion:nil]; 157 | } 158 | 159 | 160 | #pragma mark - Modal Presentation and Window Management 161 | 162 | - (void)makeKeyAndPresentViewController:(UIViewController *)viewController animated:(BOOL)animated completion:(void (^)(void))completion { 163 | // Save the current key window so we can restore it following dismissal. 164 | self.previousKeyWindow = [[UIApplication sharedApplication] keyWindow]; 165 | 166 | // Make our window key to correctly handle input. 167 | [self.view.window makeKeyWindow]; 168 | 169 | // Move the status bar on top of FLEX so we can get scroll to top behavior for taps. 170 | [[self statusWindow] setWindowLevel:self.view.window.windowLevel + 1.0]; 171 | 172 | // If this app doesn't use view controller based status bar management and we're on iOS 7+, 173 | // make sure the status bar style is UIStatusBarStyleDefault. We don't actully have to check 174 | // for view controller based management because the global methods no-op if that is turned on. 175 | self.previousStatusBarStyle = [[UIApplication sharedApplication] statusBarStyle]; 176 | [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleDefault]; 177 | 178 | // Show the view controller. 179 | [self presentViewController:viewController animated:animated completion:completion]; 180 | } 181 | 182 | - (void)resignKeyAndDismissViewControllerAnimated:(BOOL)animated completion:(void (^)(void))completion { 183 | UIWindow *previousKeyWindow = self.previousKeyWindow; 184 | self.previousKeyWindow = nil; 185 | [previousKeyWindow makeKeyWindow]; 186 | [[previousKeyWindow rootViewController] setNeedsStatusBarAppearanceUpdate]; 187 | 188 | // Restore the status bar window's normal window level. 189 | // We want it above FLEX while a modal is presented for scroll to top, but below FLEX otherwise for exploration. 190 | [[self statusWindow] setWindowLevel:UIWindowLevelStatusBar]; 191 | 192 | // Restore the stauts bar style if the app is using global status bar management. 193 | [[UIApplication sharedApplication] setStatusBarStyle:self.previousStatusBarStyle]; 194 | 195 | [self dismissViewControllerAnimated:animated completion:completion]; 196 | } 197 | 198 | - (BOOL)wantsWindowToBecomeKey { 199 | return self.previousKeyWindow != nil; 200 | } 201 | 202 | @end 203 | -------------------------------------------------------------------------------- /MenuWindow/WBWindow.h: -------------------------------------------------------------------------------- 1 | // 2 | // WBWindow.h 3 | // FlowWindow 4 | // 5 | // Created by buginux on 2017/7/27. 6 | // Copyright © 2017年 buginux. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @protocol WBWindowEventDelegate; 12 | 13 | @interface WBWindow : UIWindow 14 | 15 | @property (nonatomic, unsafe_unretained) id eventDelegate; 16 | 17 | @end 18 | 19 | @protocol WBWindowEventDelegate 20 | 21 | - (BOOL)shouldHandleTouchAtPoint:(CGPoint)pointInWindow; 22 | - (BOOL)canBecomeKeyWindow; 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /MenuWindow/WBWindow.m: -------------------------------------------------------------------------------- 1 | // 2 | // WBWindow.m 3 | // FlowWindow 4 | // 5 | // Created by buginux on 2017/7/27. 6 | // Copyright © 2017年 buginux. All rights reserved. 7 | // 8 | 9 | #import "WBWindow.h" 10 | 11 | @implementation WBWindow 12 | 13 | - (instancetype)initWithFrame:(CGRect)frame { 14 | if (self = [super initWithFrame:frame]) { 15 | self.backgroundColor = [UIColor clearColor]; 16 | // Some apps have windows at UIWindowLevelStatusBar + n. 17 | // If we make the window level too high, we block out UIAlertViews. 18 | // There's a balance between staying above the app's windows and staying below alerts. 19 | // UIWindowLevelStatusBar + 100 seems to hit that balance. 20 | self.windowLevel = UIWindowLevelStatusBar + 100.0; 21 | } 22 | return self; 23 | } 24 | 25 | - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event { 26 | BOOL pointInside = NO; 27 | 28 | if ([self.eventDelegate shouldHandleTouchAtPoint:point]) { 29 | pointInside = [super pointInside:point withEvent:event]; 30 | } 31 | 32 | return pointInside; 33 | } 34 | 35 | - (BOOL)shouldAffectStatusBarAppearance { 36 | return [self isKeyWindow]; 37 | } 38 | 39 | 40 | 41 | @end 42 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 钉钉打卡助手 2 | 3 | 开发中... 4 | -------------------------------------------------------------------------------- /Tweak.xm: -------------------------------------------------------------------------------- 1 | #import "MenuWindow/WBAssistantManager.h" 2 | #import "WIFI/WBWifiStore.h" 3 | #import "WIFI/WBWifiModel.h" 4 | #import 5 | 6 | %hook DTAppDelegate 7 | 8 | - (void)applicationDidBecomeActive:(id)arg1 { 9 | %orig; 10 | 11 | [[WBAssistantManager sharedManager] showMenu]; 12 | } 13 | 14 | %end 15 | 16 | CFArrayRef (*oldCNCopySupportedInterfaces)(); 17 | CFDictionaryRef (*oldCNCopyCurrentNetworkInfo)(CFStringRef interfaceName); 18 | Boolean (*oldSCNetworkReachabilityGetFlags)(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags *flags); 19 | 20 | CFArrayRef newCNCopySupportedInterfaces() { 21 | CFArrayRef result = NULL; 22 | 23 | WBWifiModel *wifi = [[WBWifiStore sharedStore] wifiHooked]; 24 | 25 | if(wifi && wifi.interfaceName) { 26 | NSArray *array = [NSArray arrayWithObject:wifi.interfaceName]; 27 | result = (CFArrayRef)CFRetain((__bridge CFArrayRef)(array)); 28 | } 29 | 30 | if(!result) { 31 | result = oldCNCopySupportedInterfaces(); 32 | } 33 | 34 | return result; 35 | } 36 | 37 | CFDictionaryRef newCNCopyCurrentNetworkInfo(CFStringRef interfaceName) { 38 | CFDictionaryRef result = NULL; 39 | 40 | WBWifiModel *wifi = [[WBWifiStore sharedStore] wifiHooked]; 41 | if(wifi) { 42 | NSDictionary *dictionary = @{ 43 | @"BSSID": (wifi.BSSID ? wifi.BSSID : @""), 44 | @"SSID": (wifi.SSID ? wifi.SSID : @""), 45 | @"SSIDDATA": (wifi.SSIDData ? wifi.SSIDData : @"") 46 | }; 47 | result = (CFDictionaryRef)CFRetain((__bridge CFDictionaryRef)(dictionary)); 48 | } 49 | 50 | if(!result) { 51 | result = oldCNCopyCurrentNetworkInfo(interfaceName); 52 | } 53 | 54 | return result; 55 | } 56 | 57 | Boolean newSCNetworkReachabilityGetFlags(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags *flags) { 58 | Boolean result = false; 59 | 60 | WBWifiModel *wifi = [[WBWifiStore sharedStore] wifiHooked]; 61 | if(wifi && wifi.flags > 0) { 62 | result = true; 63 | *flags = wifi.flags; 64 | } 65 | 66 | if(!result) { 67 | result = oldSCNetworkReachabilityGetFlags(target, flags); 68 | } 69 | 70 | return result; 71 | } 72 | 73 | %ctor { 74 | %init; 75 | 76 | MSHookFunction(&CNCopySupportedInterfaces, &newCNCopySupportedInterfaces, &oldCNCopySupportedInterfaces); 77 | MSHookFunction(&CNCopyCurrentNetworkInfo, &newCNCopyCurrentNetworkInfo, &oldCNCopyCurrentNetworkInfo); 78 | MSHookFunction(&SCNetworkReachabilityGetFlags, &newSCNetworkReachabilityGetFlags, &oldSCNetworkReachabilityGetFlags); 79 | } 80 | -------------------------------------------------------------------------------- /WIFI/WBWifiListViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // WBWifiListViewController.h 3 | // DingTalkAssistant 4 | // 5 | // Created by buginux on 2017/7/28. 6 | // Copyright © 2017年 buginux. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface WBWifiListViewController : UITableViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /WIFI/WBWifiListViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // WBWifiListViewController.m 3 | // DingTalkAssistant 4 | // 5 | // Created by buginux on 2017/7/28. 6 | // Copyright © 2017年 buginux. All rights reserved. 7 | // 8 | 9 | #import "WBWifiListViewController.h" 10 | #import "WBWifiStore.h" 11 | #import "WBWifiModel.h" 12 | 13 | @interface WBWifiListViewController () 14 | 15 | @property (nonatomic, strong) WBWifiStore *store; 16 | @property (nonatomic, strong) WBWifiModel *selectedWifi; 17 | 18 | @end 19 | 20 | @implementation WBWifiListViewController 21 | 22 | - (void)viewDidLoad { 23 | [super viewDidLoad]; 24 | self.title = @"WIFI 设置"; 25 | 26 | self.store = [WBWifiStore sharedStore]; 27 | [self.store fetchCurrentWifi]; 28 | [self.store fetchHistoryWifi]; 29 | for (WBWifiModel *wifi in self.store.historyWifiList) { 30 | if (wifi.selected) { 31 | self.selectedWifi = wifi; 32 | } 33 | } 34 | [self.tableView reloadData]; 35 | } 36 | 37 | 38 | - (NSString *)titleForSection:(NSInteger)section { 39 | if (section == 0) { 40 | return @"当前 Wifi"; 41 | } else { 42 | return @"历史 Wifi"; 43 | } 44 | } 45 | 46 | - (WBWifiModel *)wifiForRowAtIndexPath:(NSIndexPath *)indexPath { 47 | if (indexPath.section == 0) { 48 | return self.store.currentWifiList[indexPath.row]; 49 | } else if (indexPath.section == 1) { 50 | return self.store.historyWifiList[indexPath.row]; 51 | } 52 | return nil; 53 | } 54 | 55 | - (void)selectWifi:(WBWifiModel *)currentWifi { 56 | for (WBWifiModel *wifi in self.store.currentWifiList) { 57 | wifi.selected = (wifi == currentWifi); 58 | } 59 | for (WBWifiModel *wifi in self.store.historyWifiList) { 60 | wifi.selected = (wifi == currentWifi); 61 | } 62 | 63 | if (![self.store wifiHooked]) { 64 | UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"初次设置需重启后才会生效" message:nil preferredStyle:UIAlertControllerStyleAlert]; 65 | [alert addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:nil]]; 66 | [alert addAction:[UIAlertAction actionWithTitle:@"重启" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { 67 | exit(0); 68 | }]]; 69 | 70 | [self presentViewController:alert animated:YES completion:nil]; 71 | } 72 | 73 | self.selectedWifi = currentWifi; 74 | [self.store hookWifi:currentWifi]; 75 | [self.store appendHistoryWifi:currentWifi]; 76 | [self.store saveHistoryWifi]; 77 | [self.tableView reloadData]; 78 | } 79 | 80 | #pragma mark - UITableViewDataSource 81 | 82 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { 83 | NSInteger numberOfSection = 0; 84 | 85 | if ([self.store.currentWifiList count] > 0) { 86 | numberOfSection += 1; 87 | } 88 | 89 | if ([self.store.historyWifiList count] > 0) { 90 | numberOfSection += 1; 91 | } 92 | 93 | return numberOfSection; 94 | } 95 | 96 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 97 | if (section == 0) { 98 | return [self.store.currentWifiList count]; 99 | } else if (section == 1) { 100 | return [self.store.historyWifiList count]; 101 | } 102 | 103 | return 0; 104 | } 105 | 106 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 107 | static NSString *CellIdentifier = @"Cell"; 108 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 109 | 110 | if (!cell) { 111 | cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier]; 112 | cell.textLabel.font = [UIFont systemFontOfSize:14.0]; 113 | cell.detailTextLabel.font = [UIFont systemFontOfSize:12.0]; 114 | } 115 | 116 | WBWifiModel *wifi = [self wifiForRowAtIndexPath:indexPath]; 117 | cell.textLabel.text = wifi.wifiName; 118 | cell.accessoryType = wifi.selected ? UITableViewCellAccessoryCheckmark : UITableViewCellAccessoryNone; 119 | 120 | return cell; 121 | } 122 | 123 | - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { 124 | return [self titleForSection:section]; 125 | } 126 | 127 | #pragma mark - UITableViewDelegate 128 | 129 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 130 | [tableView deselectRowAtIndexPath:indexPath animated:YES]; 131 | 132 | WBWifiModel *selectedWifi = [self wifiForRowAtIndexPath:indexPath]; 133 | if ([self.selectedWifi isEqual:selectedWifi]) { 134 | return; 135 | } 136 | 137 | NSString *message = [NSString stringWithFormat:@"确定将钉钉的 WIFI 切换为 %@ 吗?", selectedWifi.wifiName]; 138 | UIAlertController *alert = [UIAlertController alertControllerWithTitle:message message:nil preferredStyle:UIAlertControllerStyleAlert]; 139 | 140 | __unsafe_unretained __typeof(self)weakSelf = self; 141 | UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:nil]; 142 | UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { 143 | [weakSelf selectWifi:selectedWifi]; 144 | }]; 145 | [alert addAction:cancelAction]; 146 | [alert addAction:okAction]; 147 | 148 | [self presentViewController:alert animated:YES completion:nil]; 149 | } 150 | 151 | @end 152 | -------------------------------------------------------------------------------- /WIFI/WBWifiModel.h: -------------------------------------------------------------------------------- 1 | // 2 | // WBWifiModel.h 3 | // DingTalkAssistant 4 | // 5 | // Created by buginux on 2017/7/29. 6 | // Copyright © 2017年 buginux. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @interface WBWifiModel : NSObject 13 | 14 | @property (nonatomic, strong) NSString *interfaceName; 15 | @property (nonatomic, copy) NSString *BSSID; 16 | @property (nonatomic, copy) NSData *SSIDData; 17 | @property (nonatomic, copy) NSString *SSID; 18 | @property (nonatomic, assign) SCNetworkReachabilityFlags flags; 19 | 20 | @property (nonatomic, assign) BOOL selected; 21 | @property (nonatomic, strong, readonly) NSString *wifiName; 22 | 23 | - (instancetype)initWithInterfaceName:(NSString *)ifname dictionary:(NSDictionary *)dictionary; 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /WIFI/WBWifiModel.m: -------------------------------------------------------------------------------- 1 | // 2 | // WBWifiModel.m 3 | // DingTalkAssistant 4 | // 5 | // Created by buginux on 2017/7/29. 6 | // Copyright © 2017年 buginux. All rights reserved. 7 | // 8 | 9 | #import "WBWifiModel.h" 10 | 11 | @interface WBWifiModel () 12 | 13 | @end 14 | 15 | @implementation WBWifiModel 16 | 17 | - (void)encodeWithCoder:(NSCoder *)aCoder { 18 | [aCoder encodeObject:self.interfaceName forKey:@"ifnam"]; 19 | [aCoder encodeInt32:self.flags forKey:@"flags"]; 20 | [aCoder encodeObject:self.SSID forKey:@"SSID"]; 21 | [aCoder encodeObject:self.BSSID forKey:@"BSSID"]; 22 | [aCoder encodeObject:self.SSIDData forKey:@"SSIDDATA"]; 23 | [aCoder encodeBool:self.selected forKey:@"selected"]; 24 | } 25 | 26 | - (instancetype)initWithCoder:(NSCoder *)aDecoder { 27 | if (self = [super init]) { 28 | _interfaceName = [[aDecoder decodeObjectForKey:@"ifnam"] copy]; 29 | _flags = [aDecoder decodeInt32ForKey:@"flags"]; 30 | _SSID = [[aDecoder decodeObjectForKey:@"SSID"] copy]; 31 | _BSSID = [[aDecoder decodeObjectForKey:@"BSSID"] copy]; 32 | _SSIDData = [[aDecoder decodeObjectForKey:@"SSIDDATA"] copy]; 33 | _selected = [aDecoder decodeBoolForKey:@"selected"]; 34 | } 35 | return self; 36 | } 37 | 38 | - (instancetype)initWithDictionary:(NSDictionary *)dictionary { 39 | if (self = [super init]) { 40 | _SSID = [[dictionary valueForKey:@"SSID"] copy]; 41 | _BSSID = [[dictionary valueForKey:@"BSSID"] copy]; 42 | _SSIDData = [[dictionary valueForKey:@"SSIDDATA"] copy]; 43 | } 44 | return self; 45 | } 46 | 47 | - (instancetype)initWithInterfaceName:(NSString *)ifname dictionary:(NSDictionary *)dictionary { 48 | if (self = [self initWithDictionary:dictionary]) { 49 | _interfaceName = ifname; 50 | } 51 | return self; 52 | } 53 | 54 | - (NSString *)wifiName { 55 | if ([self.SSID length] > 0) { 56 | return self.SSID; 57 | } 58 | 59 | if ([self.BSSID length] > 0) { 60 | return self.BSSID; 61 | } 62 | 63 | return @"未知 WIFI"; 64 | } 65 | 66 | - (BOOL)isEqualToWifi:(WBWifiModel *)wifi { 67 | if (!wifi) { 68 | return NO; 69 | } 70 | 71 | BOOL haveEqualSSID = (!self.SSID && !wifi.SSID) || [self.SSID isEqualToString:wifi.SSID]; 72 | BOOL haveEqualBSSID = (!self.BSSID && !wifi.BSSID) || [self.BSSID isEqualToString:wifi.BSSID]; 73 | 74 | return haveEqualSSID && haveEqualBSSID; 75 | } 76 | 77 | - (BOOL)isEqual:(id)object { 78 | if (self == object) { 79 | return YES; 80 | } 81 | 82 | if (![object isKindOfClass:[WBWifiModel class]]) { 83 | return NO; 84 | } 85 | 86 | return [self isEqualToWifi:object]; 87 | } 88 | 89 | - (NSUInteger)hash { 90 | return [self.SSID hash] ^ [self.BSSID hash]; 91 | } 92 | 93 | @end 94 | -------------------------------------------------------------------------------- /WIFI/WBWifiStore.h: -------------------------------------------------------------------------------- 1 | // 2 | // WBWifiStore.h 3 | // DingTalkAssistant 4 | // 5 | // Created by buginux on 2017/7/29. 6 | // Copyright © 2017年 buginux. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class WBWifiModel; 12 | @interface WBWifiStore : NSObject 13 | 14 | + (instancetype)sharedStore; 15 | 16 | @property (nonatomic, strong) NSMutableArray *currentWifiList; 17 | @property (nonatomic, strong) NSMutableArray *historyWifiList; 18 | 19 | - (void)fetchCurrentWifi; 20 | - (void)fetchHistoryWifi; 21 | - (void)appendHistoryWifi:(WBWifiModel *)wifi; 22 | - (void)saveHistoryWifi; 23 | 24 | - (void)hookWifi:(WBWifiModel *)wifi; 25 | - (WBWifiModel *)wifiHooked; 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /WIFI/WBWifiStore.m: -------------------------------------------------------------------------------- 1 | // 2 | // WBWifiStore.m 3 | // DingTalkAssistant 4 | // 5 | // Created by buginux on 2017/7/29. 6 | // Copyright © 2017年 buginux. All rights reserved. 7 | // 8 | 9 | #import "WBWifiStore.h" 10 | #import "WBWifiModel.h" 11 | #import 12 | #import 13 | 14 | static NSString * const kWifiHookedKey = @"WifiHookedKey"; 15 | static NSString * const kHistoryWifiKey = @"HistoryWifiKey"; 16 | 17 | @implementation WBWifiStore 18 | 19 | + (instancetype)sharedStore { 20 | static WBWifiStore *store = nil; 21 | static dispatch_once_t onceToken; 22 | dispatch_once(&onceToken, ^{ 23 | store = [[[self class] alloc] init]; 24 | }); 25 | return store; 26 | } 27 | 28 | - (instancetype)init { 29 | if (self = [super init]) { 30 | _currentWifiList = [[NSMutableArray alloc] init]; 31 | _historyWifiList = [[NSMutableArray alloc] init]; 32 | } 33 | return self; 34 | } 35 | 36 | - (void)fetchCurrentWifi { 37 | [self.currentWifiList removeAllObjects]; 38 | 39 | CFArrayRef arrayRef = CNCopySupportedInterfaces(); 40 | NSArray *interfaces = (__bridge NSArray *)(arrayRef); 41 | 42 | if ([interfaces count] > 0) { 43 | NSString *interfaceName = [interfaces firstObject]; 44 | 45 | CFDictionaryRef info = CNCopyCurrentNetworkInfo((__bridge CFStringRef)interfaceName); 46 | NSDictionary *dictionary = (__bridge NSDictionary *)(info); 47 | 48 | if (dictionary) { 49 | WBWifiModel *wifi = [[WBWifiModel alloc] initWithInterfaceName:interfaceName dictionary:dictionary]; 50 | wifi.flags = [self fetchCurrentNetworkStatus]; 51 | [self.currentWifiList addObject:wifi]; 52 | } 53 | } 54 | } 55 | 56 | - (void)fetchHistoryWifi { 57 | NSData *data = [[NSUserDefaults standardUserDefaults] objectForKey:kHistoryWifiKey]; 58 | 59 | if ([data length] > 0) { 60 | NSArray *array = [NSKeyedUnarchiver unarchiveObjectWithData:data]; 61 | 62 | if ([array count] > 0) { 63 | NSMutableArray *copyArray = [[NSMutableArray alloc] initWithArray:array]; 64 | self.historyWifiList = copyArray; 65 | } 66 | } 67 | } 68 | 69 | - (void)appendHistoryWifi:(WBWifiModel *)wifi { 70 | if (![self.historyWifiList containsObject:wifi]) { 71 | [self.historyWifiList addObject:wifi]; 72 | } 73 | } 74 | 75 | - (void)saveHistoryWifi { 76 | NSData *data = [NSKeyedArchiver archivedDataWithRootObject:self.historyWifiList]; 77 | 78 | if (data) { 79 | [[NSUserDefaults standardUserDefaults] setObject:data forKey:kHistoryWifiKey]; 80 | [[NSUserDefaults standardUserDefaults] synchronize]; 81 | } 82 | } 83 | 84 | - (SCNetworkReachabilityFlags)fetchCurrentNetworkStatus { 85 | struct sockaddr_in zeroAddress; 86 | bzero(&zeroAddress, sizeof(zeroAddress)); 87 | zeroAddress.sin_len = sizeof(zeroAddress); 88 | zeroAddress.sin_family = AF_INET; 89 | 90 | SCNetworkReachabilityRef defaultRouteReachability = SCNetworkReachabilityCreateWithAddress(NULL, (struct sockaddr *)&zeroAddress); 91 | SCNetworkReachabilityFlags flags; 92 | 93 | BOOL didRetrieveFlags = SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags); 94 | CFRelease(defaultRouteReachability); 95 | 96 | if (!didRetrieveFlags) { 97 | NSLog(@"Error. Could not receover network reachability flags."); 98 | return 0; 99 | } 100 | 101 | return flags; 102 | } 103 | 104 | - (void)hookWifi:(WBWifiModel *)wifi { 105 | if (!wifi) { 106 | return; 107 | } 108 | 109 | NSData *data = [NSKeyedArchiver archivedDataWithRootObject:wifi]; 110 | 111 | if ([data length] > 0) { 112 | [[NSUserDefaults standardUserDefaults] setObject:data forKey:kWifiHookedKey]; 113 | [[NSUserDefaults standardUserDefaults] synchronize]; 114 | [self fetchCurrentWifi]; 115 | } 116 | } 117 | 118 | - (WBWifiModel *)wifiHooked { 119 | WBWifiModel *wifi = nil; 120 | 121 | NSData *data = [[NSUserDefaults standardUserDefaults] objectForKey:kWifiHookedKey]; 122 | if ([data length] > 0) { 123 | wifi = [NSKeyedUnarchiver unarchiveObjectWithData:data]; 124 | } 125 | 126 | return wifi; 127 | } 128 | 129 | @end 130 | -------------------------------------------------------------------------------- /XcodeProject/DingTalkAssistant.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | A29D798F1F2B6E8700595835 /* WBWifiListViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = A29D798E1F2B6E8700595835 /* WBWifiListViewController.m */; }; 11 | A29D79961F2B757000595835 /* WBGPSPickerViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = A29D79951F2B757000595835 /* WBGPSPickerViewController.m */; }; 12 | A29D79B11F2C5DBD00595835 /* WBWifiStore.m in Sources */ = {isa = PBXBuildFile; fileRef = A29D79B01F2C5DBD00595835 /* WBWifiStore.m */; }; 13 | A29D79B41F2C5DCF00595835 /* WBWifiModel.m in Sources */ = {isa = PBXBuildFile; fileRef = A29D79B31F2C5DCF00595835 /* WBWifiModel.m */; }; 14 | /* End PBXBuildFile section */ 15 | 16 | /* Begin PBXCopyFilesBuildPhase section */ 17 | A21AED281F2A2AFD0004944A /* CopyFiles */ = { 18 | isa = PBXCopyFilesBuildPhase; 19 | buildActionMask = 2147483647; 20 | dstPath = "include/$(PRODUCT_NAME)"; 21 | dstSubfolderSpec = 16; 22 | files = ( 23 | ); 24 | runOnlyForDeploymentPostprocessing = 0; 25 | }; 26 | /* End PBXCopyFilesBuildPhase section */ 27 | 28 | /* Begin PBXFileReference section */ 29 | A21AED2A1F2A2AFD0004944A /* libDingTalkAssistant.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libDingTalkAssistant.a; sourceTree = BUILT_PRODUCTS_DIR; }; 30 | A29D798D1F2B6E8700595835 /* WBWifiListViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WBWifiListViewController.h; path = ../../WIFI/WBWifiListViewController.h; sourceTree = ""; }; 31 | A29D798E1F2B6E8700595835 /* WBWifiListViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = WBWifiListViewController.m; path = ../../WIFI/WBWifiListViewController.m; sourceTree = ""; }; 32 | A29D79941F2B757000595835 /* WBGPSPickerViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WBGPSPickerViewController.h; path = ../../GPS/WBGPSPickerViewController.h; sourceTree = ""; }; 33 | A29D79951F2B757000595835 /* WBGPSPickerViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = WBGPSPickerViewController.m; path = ../../GPS/WBGPSPickerViewController.m; sourceTree = ""; }; 34 | A29D79AF1F2C5DBD00595835 /* WBWifiStore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WBWifiStore.h; path = ../../WIFI/WBWifiStore.h; sourceTree = ""; }; 35 | A29D79B01F2C5DBD00595835 /* WBWifiStore.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = WBWifiStore.m; path = ../../WIFI/WBWifiStore.m; sourceTree = ""; }; 36 | A29D79B21F2C5DCF00595835 /* WBWifiModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WBWifiModel.h; path = ../../WIFI/WBWifiModel.h; sourceTree = ""; }; 37 | A29D79B31F2C5DCF00595835 /* WBWifiModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = WBWifiModel.m; path = ../../WIFI/WBWifiModel.m; sourceTree = ""; }; 38 | /* End PBXFileReference section */ 39 | 40 | /* Begin PBXFrameworksBuildPhase section */ 41 | A21AED271F2A2AFD0004944A /* Frameworks */ = { 42 | isa = PBXFrameworksBuildPhase; 43 | buildActionMask = 2147483647; 44 | files = ( 45 | ); 46 | runOnlyForDeploymentPostprocessing = 0; 47 | }; 48 | /* End PBXFrameworksBuildPhase section */ 49 | 50 | /* Begin PBXGroup section */ 51 | A21AED211F2A2AFD0004944A = { 52 | isa = PBXGroup; 53 | children = ( 54 | A21AED2C1F2A2AFD0004944A /* DingTalkAssistant */, 55 | A21AED2B1F2A2AFD0004944A /* Products */, 56 | ); 57 | sourceTree = ""; 58 | }; 59 | A21AED2B1F2A2AFD0004944A /* Products */ = { 60 | isa = PBXGroup; 61 | children = ( 62 | A21AED2A1F2A2AFD0004944A /* libDingTalkAssistant.a */, 63 | ); 64 | name = Products; 65 | sourceTree = ""; 66 | }; 67 | A21AED2C1F2A2AFD0004944A /* DingTalkAssistant */ = { 68 | isa = PBXGroup; 69 | children = ( 70 | A29D79901F2B750C00595835 /* GPS */, 71 | A29D798C1F2B6E5A00595835 /* WIFI */, 72 | A2753E1C1F2A33C800C2293B /* MenuWindow */, 73 | ); 74 | path = DingTalkAssistant; 75 | sourceTree = ""; 76 | }; 77 | A2753E1C1F2A33C800C2293B /* MenuWindow */ = { 78 | isa = PBXGroup; 79 | children = ( 80 | ); 81 | path = MenuWindow; 82 | sourceTree = ""; 83 | }; 84 | A29D798C1F2B6E5A00595835 /* WIFI */ = { 85 | isa = PBXGroup; 86 | children = ( 87 | A29D798D1F2B6E8700595835 /* WBWifiListViewController.h */, 88 | A29D798E1F2B6E8700595835 /* WBWifiListViewController.m */, 89 | A29D79AF1F2C5DBD00595835 /* WBWifiStore.h */, 90 | A29D79B01F2C5DBD00595835 /* WBWifiStore.m */, 91 | A29D79B21F2C5DCF00595835 /* WBWifiModel.h */, 92 | A29D79B31F2C5DCF00595835 /* WBWifiModel.m */, 93 | ); 94 | name = WIFI; 95 | sourceTree = ""; 96 | }; 97 | A29D79901F2B750C00595835 /* GPS */ = { 98 | isa = PBXGroup; 99 | children = ( 100 | A29D79941F2B757000595835 /* WBGPSPickerViewController.h */, 101 | A29D79951F2B757000595835 /* WBGPSPickerViewController.m */, 102 | ); 103 | name = GPS; 104 | sourceTree = ""; 105 | }; 106 | /* End PBXGroup section */ 107 | 108 | /* Begin PBXNativeTarget section */ 109 | A21AED291F2A2AFD0004944A /* DingTalkAssistant */ = { 110 | isa = PBXNativeTarget; 111 | buildConfigurationList = A21AED331F2A2AFD0004944A /* Build configuration list for PBXNativeTarget "DingTalkAssistant" */; 112 | buildPhases = ( 113 | A21AED261F2A2AFD0004944A /* Sources */, 114 | A21AED271F2A2AFD0004944A /* Frameworks */, 115 | A21AED281F2A2AFD0004944A /* CopyFiles */, 116 | ); 117 | buildRules = ( 118 | ); 119 | dependencies = ( 120 | ); 121 | name = DingTalkAssistant; 122 | productName = DingTalkAssistant; 123 | productReference = A21AED2A1F2A2AFD0004944A /* libDingTalkAssistant.a */; 124 | productType = "com.apple.product-type.library.static"; 125 | }; 126 | /* End PBXNativeTarget section */ 127 | 128 | /* Begin PBXProject section */ 129 | A21AED221F2A2AFD0004944A /* Project object */ = { 130 | isa = PBXProject; 131 | attributes = { 132 | LastUpgradeCheck = 0830; 133 | ORGANIZATIONNAME = buginux; 134 | TargetAttributes = { 135 | A21AED291F2A2AFD0004944A = { 136 | CreatedOnToolsVersion = 8.3.3; 137 | DevelopmentTeam = AMCXGTYG4X; 138 | ProvisioningStyle = Automatic; 139 | }; 140 | }; 141 | }; 142 | buildConfigurationList = A21AED251F2A2AFD0004944A /* Build configuration list for PBXProject "DingTalkAssistant" */; 143 | compatibilityVersion = "Xcode 3.2"; 144 | developmentRegion = English; 145 | hasScannedForEncodings = 0; 146 | knownRegions = ( 147 | en, 148 | ); 149 | mainGroup = A21AED211F2A2AFD0004944A; 150 | productRefGroup = A21AED2B1F2A2AFD0004944A /* Products */; 151 | projectDirPath = ""; 152 | projectRoot = ""; 153 | targets = ( 154 | A21AED291F2A2AFD0004944A /* DingTalkAssistant */, 155 | ); 156 | }; 157 | /* End PBXProject section */ 158 | 159 | /* Begin PBXSourcesBuildPhase section */ 160 | A21AED261F2A2AFD0004944A /* Sources */ = { 161 | isa = PBXSourcesBuildPhase; 162 | buildActionMask = 2147483647; 163 | files = ( 164 | A29D79961F2B757000595835 /* WBGPSPickerViewController.m in Sources */, 165 | A29D79B11F2C5DBD00595835 /* WBWifiStore.m in Sources */, 166 | A29D79B41F2C5DCF00595835 /* WBWifiModel.m in Sources */, 167 | A29D798F1F2B6E8700595835 /* WBWifiListViewController.m in Sources */, 168 | ); 169 | runOnlyForDeploymentPostprocessing = 0; 170 | }; 171 | /* End PBXSourcesBuildPhase section */ 172 | 173 | /* Begin XCBuildConfiguration section */ 174 | A21AED311F2A2AFD0004944A /* Debug */ = { 175 | isa = XCBuildConfiguration; 176 | buildSettings = { 177 | ALWAYS_SEARCH_USER_PATHS = NO; 178 | CLANG_ANALYZER_NONNULL = YES; 179 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 180 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 181 | CLANG_CXX_LIBRARY = "libc++"; 182 | CLANG_ENABLE_MODULES = YES; 183 | CLANG_ENABLE_OBJC_ARC = YES; 184 | CLANG_WARN_BOOL_CONVERSION = YES; 185 | CLANG_WARN_CONSTANT_CONVERSION = YES; 186 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 187 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 188 | CLANG_WARN_EMPTY_BODY = YES; 189 | CLANG_WARN_ENUM_CONVERSION = YES; 190 | CLANG_WARN_INFINITE_RECURSION = YES; 191 | CLANG_WARN_INT_CONVERSION = YES; 192 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 193 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 194 | CLANG_WARN_UNREACHABLE_CODE = YES; 195 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 196 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 197 | COPY_PHASE_STRIP = NO; 198 | DEBUG_INFORMATION_FORMAT = dwarf; 199 | ENABLE_STRICT_OBJC_MSGSEND = YES; 200 | ENABLE_TESTABILITY = YES; 201 | GCC_C_LANGUAGE_STANDARD = gnu99; 202 | GCC_DYNAMIC_NO_PIC = NO; 203 | GCC_NO_COMMON_BLOCKS = YES; 204 | GCC_OPTIMIZATION_LEVEL = 0; 205 | GCC_PREPROCESSOR_DEFINITIONS = ( 206 | "DEBUG=1", 207 | "$(inherited)", 208 | ); 209 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 210 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 211 | GCC_WARN_UNDECLARED_SELECTOR = YES; 212 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 213 | GCC_WARN_UNUSED_FUNCTION = YES; 214 | GCC_WARN_UNUSED_VARIABLE = YES; 215 | IPHONEOS_DEPLOYMENT_TARGET = 10.3; 216 | MTL_ENABLE_DEBUG_INFO = YES; 217 | ONLY_ACTIVE_ARCH = YES; 218 | SDKROOT = iphoneos; 219 | }; 220 | name = Debug; 221 | }; 222 | A21AED321F2A2AFD0004944A /* Release */ = { 223 | isa = XCBuildConfiguration; 224 | buildSettings = { 225 | ALWAYS_SEARCH_USER_PATHS = NO; 226 | CLANG_ANALYZER_NONNULL = YES; 227 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 228 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 229 | CLANG_CXX_LIBRARY = "libc++"; 230 | CLANG_ENABLE_MODULES = YES; 231 | CLANG_ENABLE_OBJC_ARC = YES; 232 | CLANG_WARN_BOOL_CONVERSION = YES; 233 | CLANG_WARN_CONSTANT_CONVERSION = YES; 234 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 235 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 236 | CLANG_WARN_EMPTY_BODY = YES; 237 | CLANG_WARN_ENUM_CONVERSION = YES; 238 | CLANG_WARN_INFINITE_RECURSION = YES; 239 | CLANG_WARN_INT_CONVERSION = YES; 240 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 241 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 242 | CLANG_WARN_UNREACHABLE_CODE = YES; 243 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 244 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 245 | COPY_PHASE_STRIP = NO; 246 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 247 | ENABLE_NS_ASSERTIONS = NO; 248 | ENABLE_STRICT_OBJC_MSGSEND = YES; 249 | GCC_C_LANGUAGE_STANDARD = gnu99; 250 | GCC_NO_COMMON_BLOCKS = YES; 251 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 252 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 253 | GCC_WARN_UNDECLARED_SELECTOR = YES; 254 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 255 | GCC_WARN_UNUSED_FUNCTION = YES; 256 | GCC_WARN_UNUSED_VARIABLE = YES; 257 | IPHONEOS_DEPLOYMENT_TARGET = 10.3; 258 | MTL_ENABLE_DEBUG_INFO = NO; 259 | SDKROOT = iphoneos; 260 | VALIDATE_PRODUCT = YES; 261 | }; 262 | name = Release; 263 | }; 264 | A21AED341F2A2AFD0004944A /* Debug */ = { 265 | isa = XCBuildConfiguration; 266 | buildSettings = { 267 | DEVELOPMENT_TEAM = AMCXGTYG4X; 268 | OTHER_LDFLAGS = "-ObjC"; 269 | PRODUCT_NAME = "$(TARGET_NAME)"; 270 | SKIP_INSTALL = YES; 271 | }; 272 | name = Debug; 273 | }; 274 | A21AED351F2A2AFD0004944A /* Release */ = { 275 | isa = XCBuildConfiguration; 276 | buildSettings = { 277 | DEVELOPMENT_TEAM = AMCXGTYG4X; 278 | OTHER_LDFLAGS = "-ObjC"; 279 | PRODUCT_NAME = "$(TARGET_NAME)"; 280 | SKIP_INSTALL = YES; 281 | }; 282 | name = Release; 283 | }; 284 | /* End XCBuildConfiguration section */ 285 | 286 | /* Begin XCConfigurationList section */ 287 | A21AED251F2A2AFD0004944A /* Build configuration list for PBXProject "DingTalkAssistant" */ = { 288 | isa = XCConfigurationList; 289 | buildConfigurations = ( 290 | A21AED311F2A2AFD0004944A /* Debug */, 291 | A21AED321F2A2AFD0004944A /* Release */, 292 | ); 293 | defaultConfigurationIsVisible = 0; 294 | defaultConfigurationName = Release; 295 | }; 296 | A21AED331F2A2AFD0004944A /* Build configuration list for PBXNativeTarget "DingTalkAssistant" */ = { 297 | isa = XCConfigurationList; 298 | buildConfigurations = ( 299 | A21AED341F2A2AFD0004944A /* Debug */, 300 | A21AED351F2A2AFD0004944A /* Release */, 301 | ); 302 | defaultConfigurationIsVisible = 0; 303 | defaultConfigurationName = Release; 304 | }; 305 | /* End XCConfigurationList section */ 306 | }; 307 | rootObject = A21AED221F2A2AFD0004944A /* Project object */; 308 | } 309 | -------------------------------------------------------------------------------- /XcodeProject/DingTalkAssistant.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /XcodeProject/DingTalkAssistant.xcodeproj/project.xcworkspace/xcuserdata/buginux.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/buginux/DingTalkAssistant/fd9cb634e63c71b81dddaa211f6f2fde048e0552/XcodeProject/DingTalkAssistant.xcodeproj/project.xcworkspace/xcuserdata/buginux.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /XcodeProject/DingTalkAssistant.xcodeproj/xcuserdata/buginux.xcuserdatad/xcschemes/DingTalkAssistant.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 34 | 35 | 45 | 46 | 52 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 70 | 71 | 72 | 73 | 75 | 76 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /XcodeProject/DingTalkAssistant.xcodeproj/xcuserdata/buginux.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | DingTalkAssistant.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | A21AED291F2A2AFD0004944A 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /control: -------------------------------------------------------------------------------- 1 | Package: com.swiftyper.dingtalkassistant 2 | Name: DingTalkAssistant 3 | Depends: mobilesubstrate 4 | Version: 0.0.1 5 | Architecture: iphoneos-arm 6 | Description: An awesome MobileSubstrate tweak! 7 | Maintainer: buginux 8 | Author: buginux 9 | Section: Tweaks 10 | --------------------------------------------------------------------------------