我将把它作为一个答案,如果有人发现任何新东西或苹果将来添加此功能,我会很高兴错了。
TLDR:不再!
由于 Apple 从 wifi 菜单栏中删除了“创建网络...”选项,创建 ad-hoc 网络的唯一方法是通过网络共享。我跟着https://www.makeuseof.com/how-to-create-a-secure-ad-hoc-network-in-macos/在How to Create a Secure Ad Hoc Network部分下做了一个网络:
sudo networksetup -createnetworkservice AdHoc lo0
sudo networksetup -setmanual AdHoc 192.168.1.88 255.255.255.255
在“系统偏好设置”中,通过 WiFi 从 AdHoc 共享您的网络连接。
打开之后,我检查了 CWInterface.interfaceMode(),它处于 HostAP 模式。纯属猜测,但我认为 IBSS 已被完全删除,它在开发人员文档中被标记为已弃用。 -3930 是 kCWOperationNotPermittedErr,所以我不能 100% 确定这是准确的,但这是可能的。
CoreWLAN中有设置HostAP模式的私有接口:
https://github.com/onmyway133/Runtime-Headers/blob/master/macOS/10.13/CoreWLAN.framework/CWInterface.hhttps://medium.com/swlh/calling-ios-and-macos-hidden-api-in-style-1a924f244ad1https://gist.github.com/wolever/4418079
在最后一个链接中将objc_msgsend 替换为NSInvocation 后,objc_msgsend 似乎已被删除:
#import <CoreWLAN/CoreWLAN.h>
#import <objc/message.h>
int main(int argc, char* argv[]) {
@autoreleasepool {
int ch;
NSString *ssid = nil, *password = nil;
while((ch = getopt(argc, argv, "s:p:h")) != -1) {
switch(ch) {
case 's':
ssid = [NSString stringWithUTF8String:optarg];
break;
case 'p':
password = [NSString stringWithUTF8String:optarg];
break;
case '?':
case 'h':
default:
printf("USAGE: %s [-s ssid] [-p password] [-h] command\n", argv[0]);
printf("\nOPTIONS:\n");
printf(" -s ssid SSID\n");
printf(" -p password WEP password\n");
printf(" -h Print help\n");
printf("\nCOMMAND:\n");
printf(" status Print interface mode\n");
printf(" start Start Host AP mode\n");
printf(" stop Stop Host AP mode\n");
return 0;
}
}
NSString *command = nil;
if(argv[optind]) {
command = [NSString stringWithUTF8String:argv[optind]];
}
CWInterface *iface = [[CWWiFiClient sharedWiFiClient] interface];
if(!command || [command isEqualToString:@"status"]) {
NSString *mode = nil;
switch(iface.interfaceMode) {
case kCWInterfaceModeStation:
mode = @"Station";
break;
case kCWInterfaceModeIBSS:
mode = @"IBSS";
break;
case kCWInterfaceModeHostAP:
mode = @"HostAP";
break;
case kCWInterfaceModeNone:
default:
mode = @"None";
}
printf("%s\n", [mode UTF8String]);
} else if([command isEqualToString:@"stop"]) {
// Stop Host AP mode
if(getuid() != 0) {
printf("this may need root (trying anyway)...\n");
}
SEL selector = @selector(stopHostAPMode);
NSMethodSignature *signature = [iface methodSignatureForSelector: selector];
NSInvocation *invocation =
[NSInvocation invocationWithMethodSignature:signature];
invocation.target = iface;
invocation.selector = selector;
[invocation invoke];
printf("Done?");
//objc_msgSend(iface, @selector(stopHostAPMode));
} else if([command isEqualToString:@"start"]) {
if(!ssid) {
printf("error: an ssid must be specified\n");
return 1;
}
// known security types:
// 2: no securiry
// 16: wep
// Note: values [-127..127] have been tried, and all but these return errors.
unsigned long long securityType = 2;
if(password) {
if([password length] < 10) {
printf("error: password too short (must be >= 10 characters)\n");
return 1;
}
securityType = 16;
}
NSSet *chans = [iface supportedWLANChannels];
//printf("chan count: %lu\n", [chans count]);
NSEnumerator *enumerator = [chans objectEnumerator];
CWChannel *channel;
while ((channel = [enumerator nextObject])) {
//printf("channel: %lu\n", [channel channelNumber]);
if ([channel channelNumber] == 11)
break;
}
printf("Found Channel: %d\n", channel.channelNumber);
// Start Host AP mode
NSError *error = nil;
NSError **errorptr = &error;
SEL selector = @selector(startHostAPModeWithSSID:securityType:channel:password:error:);
NSMethodSignature *signature = [iface methodSignatureForSelector: selector];
NSInvocation *invocation =
[NSInvocation invocationWithMethodSignature:signature];
invocation.target = iface;
invocation.selector = selector;
NSString * ssidstr = @"Test";
NSString * pass = @"barbarbarr";
NSData * ssidArg = [ssidstr dataUsingEncoding:NSUTF8StringEncoding];
[invocation setArgument: &ssidArg atIndex:2];
[invocation setArgument: &securityType atIndex:3];
[invocation setArgument: &channel atIndex:4];
[invocation setArgument: &pass atIndex:5];
[invocation setArgument: &errorptr atIndex:6];
[invocation invoke];
BOOL success;
[invocation getReturnValue:&success];
if (!success) {
printf("startHostAPModeWithSSID error: %s\n", [(*errorptr).localizedDescription UTF8String]);
return 1;
} else {
printf("Success?\n");
return 0;
}
}
return 0;
}
}
./hostap stop 确实成功地将我从网络共享启动的 hostap 模式中踢了出来,但 ./hostap start 失败并显示 -3903 kCWNotSupportedErr。
此外,在没有其他设置的情况下使用startHostAPMode: 确实成功,但是 wifi 菜单显示WiFi: Internet Sharing,所以我认为这是一个专用于网络共享的私有 api,可能需要其他配置才能正常工作。你可能会继续沿着这条路走下去,但它看起来并不是很有希望。最好的办法是仅使用网络共享,或者如果您真的想要脚本化方法,则可能会使用 AppleScript 研究脚本系统偏好设置。