Search code examples
objective-cmacosbashcocoacorewlan

Mac OS X 10.10 Reorder preferred networks


What is the best way to programmatically change the order of "preferred" networks in OS X? Objective-C preferred...

I can use CoreWLAN to gather the list, and even add to it, but as far as re-ordering I am at a loss. I can create a copy of the preference file, edit it and change the order of precedence, and then use a bash script to write over the existing configuration, but that seems a but messy.

I am aware of the networksetup -addpreferredwirelessnetworkatindex command, but it does not work correctly in 10.10 (works fine for 10.9 systems) - it adds but does not set order properly.

SystemConfiguration framework? Something else?

Thanks!


Solution

  • I was looking for a way to accomplish this after transitioning a user from an open wireless network to a WPA2E network using EAP-TTLS. Since the user connects to the open network first, it remains higher in the Preferred Networks list.

    Here is what I came up with:

    CWInterface *interface = [CWInterface interfaceWithName:[
        [CWInterface interfaceNames] anyObject]
    ];
    CWMutableConfiguration *config = [CWMutableConfiguration
        configurationWithConfiguration:interface.configuration
    ];
    NSMutableArray *networks = [NSMutableArray arrayWithArray:
        [config.networkProfiles array]
    ];
    
    //Remove URI_Open (if present) and
    //move URI_Secure (if present) to index 0
    for (CWNetworkProfile *profile in [networks copy]) {
        if ([[profile ssid] isEqualToString:@"URI_Secure"]) {
            [networks removeObject:profile];
        } else if ([[profile ssid] isEqualToString:@"URI_Open"]) {
            CWNetworkProfile *tmp = profile;
            [networks removeObject:tmp];
            [networks insertObject:tmp atIndex:0];
        }
    }
    
    config.networkProfiles = [NSOrderedSet orderedSetWithArray:networks];
    
    SFAuthorization *auth = [SFAuthorization authorization];
    BOOL authResult = [auth obtainWithRight:"system.preferences"
        flags:(
            kAuthorizationFlagExtendRights |
            kAuthorizationFlagInteractionAllowed |
            kAuthorizationFlagPreAuthorize
         ) error:nil
    ];
    
    NSError *error = nil;
    [interface commitConfiguration:config authorization:auth error:&error];
    

    Some notes/disclaimers:

    • I do not use OS X regularly. I have one test Mac in my office. It has 10.7.5 installed.
    • This is the first thing I have ever written in Objective-C. It is the result of a single afternoon; as such it is probably broken and ugly. YMMV.
    • Question specified 10.10. I used interfaceWithName and interfaceNames, which are deprecated in 10.10. I am not sure what the proper replacement is, but I suspect CWWifiClient.
    • My approach was based loosely on this ruby program.
    • I removed error handling for brevity.
    • I did look into using networksetup or removing the open network right in the .mobileconfig, but neither seemed to work quite right.
    • Since I just pull the network profile list out into a mutable array, this is easily adaptable to any arbitrary sorting etc.