在iOS10之前,跳轉到系統設置界面的某個指定界面的方式如下:
//打開定位服務界面
NSURL*url=[NSURL URLWithString:@"prefs:root=Privacy&path=LOCATION"];
if ([[UIApplication sharedApplication] canOpenURL:url]) {
[[UIApplication sharedApplication] openURL:url];
};
跳轉到其他的界面的字段
About — prefs:root=General&path=About
Accessibility — prefs:root=General&path=ACCESSIBILITY
AirplaneModeOn— prefs:root=AIRPLANE_MODE
Auto-Lock — prefs:root=General&path=AUTOLOCK
Brightness — prefs:root=Brightness
Bluetooth — prefs:root=General&path=Bluetooth
Date& Time — prefs:root=General&path=DATE_AND_TIME
FaceTime — prefs:root=FACETIME
General— prefs:root=General
Keyboard — prefs:root=General&path=Keyboard
iCloud — prefs:root=CASTLE iCloud
Storage & Backup — prefs:root=CASTLE&path=STORAGE_AND_BACKUP
International — prefs:root=General&path=INTERNATIONAL
Location Services — prefs:root=LOCATION_SERVICES
Music — prefs:root=MUSIC
Music Equalizer — prefs:root=MUSIC&path=EQ
Music VolumeLimit— prefs:root=MUSIC&path=VolumeLimit
Network — prefs:root=General&path=Network
Nike + iPod — prefs:root=NIKE_PLUS_IPOD
Notes — prefs:root=NOTES
Notification — prefs:root=NOTIFICATIONS_ID
Phone — prefs:root=Phone
Photos — prefs:root=Photos
Profile — prefs:root=General&path=ManagedConfigurationList
Reset — prefs:root=General&path=Reset
Safari — prefs:root=Safari Siri — prefs:root=General&path=Assistant
Sounds — prefs:root=Sounds
SoftwareUpdate— prefs:root=General&path=SOFTWARE_UPDATE_LINK
Store — prefs:root=STORE
Twitter — prefs:root=TWITTER
Usage — prefs:root=General&path=USAGE
VPN — prefs:root=General&path=Network/VPN
Wallpaper — prefs:root=Wallpaper
Wi-Fi — prefs:root=WIFI
Setting—prefs:root=INTERNET_TETHERING
電池電量 Prefs:root=BATTERY_USAGE
通用設置 Prefs:root=General
存儲空間 Prefs:root=General&path=STORAGE_ICLOUD_USAGE/DEVICE_STORAGE
蜂窩數據 Prefs:root=MOBILE_DATA_SETTINGS_ID
Wi-Fi 設置 Prefs:root=WIFI
藍牙設置 Prefs:root=Bluetooth
定位設置 Prefs:root=Privacy&path=LOCATION
輔助功能 Prefs:root=General&path=ACCESSIBILITY
關于手機 Prefs:root=General&path=About
鍵盤設置 Prefs:root=General&path=Keyboard
顯示設置 Prefs:root=DISPLAY
聲音設置 Prefs:root=Sounds
App Store 設置 Prefs:root=STORE
墻紙設置 Prefs:root=Wallpaper
打開電話 Mobilephone://
世界時鐘 Clock-worldclock://
鬧鐘 Clock-alarm://
秒表 Clock-stopwatch://
倒計時 Clock-timer://
打開相冊 Photos://
(在項目中的info中添加 URL types,添加 URL Schemes 為 prefs)
但是在iOS10上,調用canOpenURL:打開系統設置界面時控制臺會報如下錯誤,并且無法跳轉:
-canOpenURL: failed for URL: "Prefs:root=Privacy&path=LOCATION" - error: "The operation couldn’t be completed. (OSStatus error -10814.)"
原因是iOS10只允許如下方式跳轉到設置里自己app的界面,對跳轉到其他界面做了限制:
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]];
(iOS10之后用:openURL:(NSURL*)url options:(NSDictionary<NSString *, id> *)options completionHandler:(void (^ __nullable)(BOOL success))completion
Options 參數:
UIApplication 的頭文件中列了一個可用在 options字典中的key:
- UIApplicationOpenURLOptionUniversalLinksOnly:可以設置布爾值,如果設置為true(YES),則只能打開應用里配置好的有效通用鏈接。如果應用程序沒有配置,或者用于禁止打開這個鏈接,則 completion handler 回調里的success為false(NO)。
為了覆寫程序的默認動作(默認這個key的值是NO),我們需要創建一個字典,將對應的key 設置為true(YES),然后將字典傳給 options 參數:
NSDictionary *options = @{UIApplicationOpenURLOptionUniversalLinksOnly : @YES};
[application openURL:URL options:options completionHandler:nil];
舉個例子,我把這個值設置為 true 并嘗試打開https://twitter.com/kharrison, 如果我沒有安裝 Twitter 應用,它將會執行失敗,而不是在Safari中打開這個鏈接。
(譯者注:在iOS 9 使用 openURL:方法打開這個鏈接時,會在首先調起Safari,然后在Safari中打開這個鏈接))
解決方法
可以使用MobileCoreServices.framework里的私有API:
- (BOOL)openSensitiveURL:(id)arg1 withOptions:(id)arg2;
頭文件參考:LSApplicationWorkspace.h
使用方法:
//注意首字母改成了大寫,prefs->Prefs
NSURL*url=[NSURL URLWithString:@"Prefs:root=Privacy&path=LOCATION"];
Class LSApplicationWorkspace = NSClassFromString(@"LSApplicationWorkspace");
[[LSApplicationWorkspace performSelector:@selector(defaultWorkspace)] performSelector:@selector(openSensitiveURL:withOptions:) withObject:url withObject:nil];
MobileCoreServices.framework不是私有庫,所以直接使用performSelector:即可調用私有API。
(app需要添加一個Prefs的URL Schemes,即添加到info.plist的LSApplicationQueriesSchemes項中)
注意
iOS10的系統URLScheme改成了首字母大寫,使用小寫的方式會無法打開。
使用私有API的app無法通過App Store審核。你也可以嘗試把私有類名和selector字符串混淆一下,繞過審核。例如這位仁兄用ASCII混淆的方法:
- (UIView *)statusBarView {
UIView *statusBar = nil;
NSData *data = [NSData dataWithBytes:(unsigned char []){0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x42, 0x61, 0x72} length:9];
NSString *key = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
id object = [UIApplication sharedApplication];
if ([object respondsToSelector:NSSelectorFromString(key)]) {
statusBar = [object valueForKey:key];
}
return statusBar;
}
不過,還是不建議使用私有API,因為它是不可靠的。也許某天蘋果就把它移除了。
但是還是都可以跳到設置頁面的: if([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]]) {
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString] options:@{} completionHandler:nil];}