美文网首页MAC os开发
切换网络代理macos app开发

切换网络代理macos app开发

作者: 人仙儿a | 来源:发表于2020-02-29 22:45 被阅读0次

    前言

    因为每次在设置里手动切换代理太浪费时间了,所以这两天想做一个可以mac app, 可以打开或关闭网络代理,app不能有主窗口,只在菜单栏上有个按钮,这样比较简洁。

    截屏2020-02-29下午9.11.18.png

    步骤一:创建项目

    new project->macos->app。

    步骤二:去掉主窗口

    截屏2020-02-29下午9.22.39.png

    打开main.storyboard,打这两项删掉(直接按delete),再次run之后发现主窗口不显示了

    步骤三:添加菜单栏

    在AppDelegate.m里添加代码如下:

    @interface AppDelegate ()
    
    @property (nonatomic,strong) NSStatusItem *statusItem; //必须应用、且强引用,否则不会显示。
    
    @end
    
    @implementation AppDelegate
    
    - (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
        // Insert code here to initialize your application
        NSStatusBar *statusBar = [NSStatusBar systemStatusBar];
            
        NSStatusItem *statusItem = [statusBar statusItemWithLength: NSSquareStatusItemLength];
        [statusItem setHighlightMode:YES];
        [statusItem.button setImage: [NSImage imageNamed:@"abc"]]; //设置图标,请注意尺寸
        [statusItem.button setToolTip:@"代理切换"];
        
        NSMenu *subMenu = [[NSMenu alloc] initWithTitle:@"Load_TEXT"];
        [subMenu addItemWithTitle:@"打开"action:@selector(clickItem1) keyEquivalent:@"E"];
        [subMenu addItemWithTitle:@"关闭"action:@selector(clickItem2) keyEquivalent:@"R"];
        statusItem.menu = subMenu;
        
        self.statusItem = statusItem;
    }
    
    - (void)clickItem1{
    }
    
    - (void)clickItem2{
    }
    

    注意:图片是本地,选个大小适中的图片。
    运行后发现menu上显示app图标,说明成功了。

    步骤四:执行shell命令

    一. 切换网络代理命令

    切换网络代理命令会用到networksetup指令,
    打开自动代理配置命令:
    sudo networksetup -setautoproxyurl 网络名称 pac地址//设置自动代理的url
    sudo networksetup -setautoproxystate 网络名称 on//自动代理的状态改为 打开
    关闭自动代理配置命令:
    sudo networksetup -setautoproxystate 网络名称 off
    注意:“网络名称”一般都是“Wi-Fi”,也可能是其他的,但是不是你家wifi的名字...,看下图:

    截屏2020-02-29下午9.41.49.png
    二. 运行shell命令的几种方法
    1. c语言的system方法
     system(@"sudo networksetup -setautoproxystate Wi-Fi on".UTF8String);
    

    此方法只能运行非root权限命令

    2. NSTask

    可以运行root或非root权限命令。运行root命令时会弹用户名密码提示
    代码如下:

    - (NSString *)runNSTaskCmd:(NSString *)cmd
    {
        NSMutableArray *components = [[cmd componentsSeparatedByString:@" "] mutableCopy];
        NSString *launchPath = components[0];
        [components removeObjectAtIndex:0];
        
        // 初始化并设置shell路径
        NSTask *task = [[NSTask alloc] init];
        [task setLaunchPath: launchPath];
        // -c 用来执行string-commands(命令字符串),也就说不管后面的字符串里是什么都会被当做shellcode来执行
        NSArray *arguments = components;
        [task setArguments: arguments];
        
        // 新建输出管道作为Task的输出
        NSPipe *pipe = [NSPipe pipe];
        [task setStandardOutput: pipe];
        
        // 开始task
        NSFileHandle *file = [pipe fileHandleForReading];
        [task launch];
        
        // 获取运行结果
        NSData *data = [file readDataToEndOfFile];
        return [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding];
    }
    

    调用代码如下:

        [self runNSTaskCmd:@"/usr/sbin/networksetup -setautoproxystate Wi-Fi off"];
    
    3. 第三方库STPrivilegedTask Github地址
    - (void)runPrivilegedTask:(NSString*) cmdStr{
        STPrivilegedTask *privilegedTask = [[STPrivilegedTask alloc] init];
        
        NSMutableArray *components = [[cmdStr componentsSeparatedByString:@" "] mutableCopy];
        NSString *launchPath = components[0];
        [components removeObjectAtIndex:0];
        
        [privilegedTask setLaunchPath:launchPath];
        [privilegedTask setArguments:components];
        [privilegedTask setCurrentDirectoryPath:[[NSBundle mainBundle] resourcePath]];
        
        //set it off
        OSStatus err = [privilegedTask launch];
        if (err != errAuthorizationSuccess) {
            if (err == errAuthorizationCanceled) {
                NSLog(@"User cancelled");
                return;
            }  else {
                NSLog(@"Something went wrong: %d", (int)err);
                // For error codes, see http://www.opensource.apple.com/source/libsecurity_authorization/libsecurity_authorization-36329/lib/Authorization.h
            }
        }
        
        [privilegedTask waitUntilExit];
    }
    

    调用代码如下:

        [self runPrivilegedTask:@"/usr/sbin/networksetup -setautoproxystate Wi-Fi off"];
    

    其实NSTask或者是STPrivilegedTask的传的参数是一样的,不过内部原理不同(STPrivilegedTask使用了AuthorizationRef进行提权)。
    推荐使用NSTask,理由如下:
    NSTask除了在第一次使用时会弹权限提示窗口,后面即便杀掉app再启动时执行shell命令也不会弹权限提示窗口,总之只弹了一次,我很奇怪,这样难道不更不安全了吗?而STPrivilegedTask无论重不重启app,只要执行一次shell命令就会弹权限窗口,非常的烦。

    结语

    代码放在了 github上,欢迎大家指正~~

    相关文章

      网友评论

        本文标题:切换网络代理macos app开发

        本文链接:https://www.haomeiwen.com/subject/aafbhhtx.html