iOS App跳轉設置頁面

齊云山航拍

引言

App跳轉到設置界面這個話題看似簡單,實則讓人又愛又恨,愛其應用簡單帶來無窮的方便,恨其反復無常難以覓其宗旨。

需求

從應用跳到系統設置里的設置界面有這個需求存在嗎?答案是肯定的。比如以下兩個例子:

  • 在沒有網的狀態下,你可能想提醒用戶去設置界面連接WiFi。如果不能跳到WiFi界面,只能在APP里面做出文字提示。這樣很多小白用戶可能不會看提示,只會覺得APP沒有做好。

  • 還有一種情況,做智能家居的APP,智能硬件設備自帶WiFi(局域網)。如果用戶沒有連接設備的WiFi進入APP時,需要提示用戶去設置界面連接WiFi。

以上這兩種情況只是舉個例子,這個小功能的用處還是很多的,大家可以自行探索。

實現

info里面設置

在項目中的info.plist中添加 URL types 并設置一項URL Schemes為prefs,如下圖:


info里面設置

實現代碼(iOS10以下可用)

 NSURL *url = [NSURL URLWithString:@"prefs:root=WIFI"];
 if ([[UIApplication sharedApplication] canOpenURL:url])
 {
    [[UIApplication sharedApplication] openURL:url];
 }

iOS10 新變化

作為UIApplication單例對象的方法 openURL: 在iOS開發中經常用來實現在當前應用打開外部鏈接的需求比如跳轉到其他應用,跳轉應用隱私設置界面;還有相關API canOpenURL: 進行跳轉前判斷.而這個古老(iOS2時出現)的 openURL 方法將被現今iOS10出現的新API openURL:options:completionHandler: 所替代.

新API的官方描述

首先來看官方文檔對iOS10的 What’s New in iOS UIKit部分對新API的描述

The new UIApplication method openURL:options:completionHandler:, which is executed asynchronously and calls the specified completion handler on the main queue (this method replaces openURL:).

這段話清楚地指明了新API的兩個特點:異步執行open操作和主線程執行回調.

新API的代碼描述

接下來再看看具體的接口代碼,可以看出判斷鏈接打開是否成功的方式也從以前的根據 openURL
調用return的布爾值變成了查詢completion的success參數;

old- (BOOL)openURL:(NSURL*)url 
new- (void)openURL:(NSURL*)url options:(NSDictionary<NSString *, id> *)options completionHandler:(void (^ __nullable)(BOOL success))completion

并且額外地提供了一個用來URL處理的options字典參數,沒有限定值時就要傳空字典,就像下方代碼一樣調用.

[[UIApplication sharedApplication] openURL:URL options:@{} completionHandler:nil];

options目前可傳入參數Key在UIApplication頭文件只有一個:UIApplicationOpenURLOptionUniversalLinksOnly,其對應的Value為布爾值,默認為False.如該Key對應的Value為True,那么打開所傳入的Universal Link時,只允許通過這個Link所代表的iOS應用跳轉的方式打開這個鏈接,否則就會返回success為false,也就是說只有安裝了Link所對應的App的情況下才能打開這個Universal Link,而不是通過啟動Safari方式打開這個Link的代表的網站.

[application openURL:URL options:@{UIApplicationOpenURLOptionUniversalLinksOnly : @YES} completionHandler:nil];

注意:雖然有了新的Api方法但是iOS 10在應用自身上(除非通知欄)已經不允許任何跳轉到系統設置的行為了,所以我們只能找替代方法了。

那么就有人提出疑問了,下面方法iOS10仍然可以跳轉啊。

   NSURL *url = [NSURL URLWithString:UIApplicationOpenSettingsURLString];
    
    if ([[UIApplication sharedApplication] canOpenURL:url]) {
        
        [[UIApplication sharedApplication] openURL:url];
    }

雖然可以正常跳轉但只會跳到自身應用界面的系統設置,并沒有達到我們的目的。

自身應用界面
既然官方的正常的途徑無法達到目的我們只能嘗試私有API啦
使用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。

注意
  • iOS10的系統URLScheme改成了首字母大寫,使用小寫的方式會無法打開。
  • 使用私有API的app無法通過App Store審核。你也可以嘗試把私有類名和selector字符串混淆一下,繞過審核。例如 這位仁兄 用ASCII混淆的方法:
- (void)returnToSystemWIFISettingMenu{
    NSString * defaultWork = [self getDefaultWork];
    NSString * privateMethod = [self privateMethod];
    NSURL*url=[NSURL URLWithString:@"Prefs:root=WIFI"];

    Class LSApplicationWorkspace = NSClassFromString(@"LSApplicationWorkspace");

    [[LSApplicationWorkspace  performSelector:NSSelectorFromString(defaultWork)] performSelector:NSSelectorFromString(privateMethod) withObject:url     withObject:nil];
}

- (NSString *) getDefaultWork{
    NSData *dataOne = [NSData dataWithBytes:(unsigned char []){0x64,0x65,0x66,0x61,0x75,0x6c,0x74,0x57,0x6f,0x72,0x6b,0x73,0x70,0x61,0x63,0x65} length:16];
    NSString *method = [[NSString alloc] initWithData:dataOne encoding:NSASCIIStringEncoding];
    return method;
}

- (NSString *)privateMethod {
    NSData *dataOne = [NSData dataWithBytes:(unsigned char []){0x6f, 0x70, 0x65, 0x6e, 0x53, 0x65, 0x6e, 0x73, 0x69,0x74, 0x69,0x76,0x65,0x55,0x52,0x4c} length:16];
    NSString *keyone = [[NSString alloc] initWithData:dataOne encoding:NSASCIIStringEncoding];
    NSData *dataTwo = [NSData dataWithBytes:(unsigned char []){0x77,0x69,0x74,0x68,0x4f,0x70,0x74,0x69,0x6f,0x6e,0x73} length:11];
    NSString *keytwo = [[NSString alloc] initWithData:dataTwo encoding:NSASCIIStringEncoding];
    NSString *method = [NSString stringWithFormat:@"%@%@%@%@",keyone,@":",keytwo,@":"];
    return method;
}
不過,還是不建議使用私有API,因為它是不可靠的。
最后附上常用參數:
英文 參數 中文
About prefs : root=General&path=About 關于
Accessibility prefs:root=General&path=ACCESSIBILITY 輔助功能
Airplane Mode On 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 FaceTime
General prefs:root=General 通用
iCloud Storage & Backup prefs:root=CASTLE&path=STORAGE_AND_BACKUP 云存儲與備份
iCloud prefs:root=CASTLE iCloud云
International prefs:root=General&path=INTERNATIONAL International
Location Services prefs:root=LOCATION_SERVICES 位置服務
Music prefs:root=MUSIC 音樂
Music Equalizer prefs:root=MUSIC&path=EQ 音樂均衡器
Music Volume Limit prefs:root=MUSIC&path=VolumeLimit 音樂音量限制
Network prefs:root=General&path=Network 網絡
Nike + iPod prefs:root=NIKE_PLUS_IPOD Nike + iPod
Notes prefs:root=NOTES 備忘錄
Notification prefs:root=NOTIFICATIONS_ID 通知
Phone prefs:root=Phone 電話
Photos prefs:root=Photos 照片
Profile prefs:root=General&path=ManagedConfigurationList Profile
Reset prefs:root=General&path=Reset 重啟
Safari prefs:root=Safari 瀏覽器
Software Update prefs:root=General&path=SOFTWARE_UPDATE_LINK 軟件更新
Store prefs:root=STORE 應用商店
Twitter prefs:root=TWITTER Twitter
Usage prefs:root=General&path=USAGE 用量
VPN prefs:root=General&path=Network/VPN VPN
Wallpaper prefs:root=Wallpaper 壁紙
Wi-Fi prefs:root=WIFI 無線網絡
Internet_tethering prefs:root= INTERNET_TETHERING 網絡共享
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容