什么是URL Schemes?
URL Schemes是蘋果給出的用來跳轉(zhuǎn)到系統(tǒng)應(yīng)用或者跳轉(zhuǎn)到別人的應(yīng)用的一種機制。同時還可以在應(yīng)用之間傳數(shù)據(jù)。
通過對比網(wǎng)頁鏈接來理解 iOS 上的 URL Schemes,應(yīng)該就容易多了。URL Schemes 有兩個單詞:
URL,我們都很清楚,http://www.apple.com就是個 URL,我們也叫它鏈接或網(wǎng)址;
Schemes,表示的是一個 URL 中的一個位置——最初始的位置,即 ://之前的那段字符。比如 http://www.apple.com這個網(wǎng)址的 Schemes是 http。根據(jù)我們上面對 URL Schemes 的使用,
我們可以很輕易地理解,在以本地應(yīng)用為主的 iOS 上,我們可以像定位一個網(wǎng)頁一樣,用一種特殊的 URL 來定位一個應(yīng)用甚至應(yīng)用里某個具體的功能。而定位這個應(yīng)用的,就應(yīng)該是這個應(yīng)用的 URL 的 Schemes 部分,也就是開頭兒那部分。
調(diào)用方法
1.注冊APP URL Schemes
2.打開APP方法:
調(diào)用APP
URL Schemes://
OC調(diào)用方法:
簡單調(diào)用:
NSURL *url = [NSURL URLWithString:@"myurltest:"];
[[UIApplication sharedApplication] openURL:url];
考慮到交互友好可以使用下面這種方法:
NSURL *url = [NSURL URLWithString:@"weixin://"];
//先判斷是否能打開該url
if ([[UIApplication sharedApplication] canOpenURL:url]) { //打開url
[[UIApplication sharedApplication] openURL:url];
}else { //給個提示或者做點別的事情
NSLog(@"U四不四灑,沒安裝WXApp,怎么打開啊!");
}
先判斷本機是否安裝,若果安裝就打開APP,否則提示沒有安裝。這里你也可以做成沒有安裝的話就直接跳轉(zhuǎn)到APPStore.
更重要的是,假如點擊之后沒效果,很有可能被蘋果拒絕哦。
除了OC代碼打開的方式,平時測試過程你也可以直接通過safari 地址欄上輸入
URL Schemes://
來打開應(yīng)用。
這里給出一個操作DEMO
3.APP 回調(diào)處理
蘋果一共給了3個openURL的回調(diào)。
- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url NS_DEPRECATED_IOS(2_0, 9_0, "Please use application:openURL:options:") __TVOS_PROHIBITED;
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(nullable NSString *)sourceApplication annotation:(id)annotation NS_DEPRECATED_IOS(4_2, 9_0, "Please use application:openURL:options:") __TVOS_PROHIBITED;
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<NSString*, id> *)options NS_AVAILABLE_IOS(9_0); // no equiv. notification. return NO if the application can't open for some reason
為什么會有3個呢?這3個回調(diào)又有什么區(qū)別?(為方面講解,分別設(shè)置ABC3個回調(diào))
3個回調(diào)的功能基本一樣,都是在別人通過URL Schemes打開應(yīng)用的時候會執(zhí)行的。不同之處:
A回調(diào)是在iOS2.0的時候推出的,參數(shù)只有url。
B回到是在iOS4.2的時候推出的,參數(shù)有url sourceApplication annotation.
C回調(diào)是iOS9.0的時候推出的,參數(shù)有url options。
這幾個回調(diào)是有優(yōu)先級的。C>B>A。也就是說,如果你3個回調(diào)都實現(xiàn)了,那么程序只會執(zhí)行C回調(diào)。其他回調(diào)是不會執(zhí)行的。(當然,iOS9以下只會執(zhí)行B回調(diào))。
所以只要在被打開的App 的 appdelegate這個類里面實現(xiàn):
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(nullable NSString *)sourceApplication annotation:(id)annotation
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<NSString*, id> *)options
這兩個方法即可。
使用URL Schems傳遞數(shù)據(jù)
URL Schemes除了可以用來打開APP之外,還可以用來在兩個App之間傳遞少量的數(shù)據(jù)。
這里寫一個demo來說明URL的組成結(jié)構(gòu)
NSURL *url = [NSURL URLWithString:@"http://www.baidu.com/s?tn=baiduhome_pg&bs=NSRUL&f=8&rsv_bp=1&rsv_spt=1&wd=NSurl&inputT=2709"];
NSLog(@"Scheme: %@", [url scheme]);
NSLog(@"Host: %@", [url host]);
NSLog(@"Port: %@", [url port]);
NSLog(@"Path: %@", [url path]);
NSLog(@"Relative path: %@", [url relativePath]);
NSLog(@"Path components as array: %@", [url pathComponents]);
NSLog(@"Parameter string: %@", [url parameterString]);
NSLog(@"Query: %@", [url query]);
NSLog(@"Fragment: %@", [url fragment]);
NSLog(@"User: %@", [url user]);
NSLog(@"Password: %@", [url password]);
輸出結(jié)果:
2012-08-29 15:52:23.781 NSurl[3560:f803] Scheme: http
2012-08-29 15:52:32.793 NSurl[3560:f803] Host: www.baidu.com
2012-08-29 15:52:39.102 NSurl[3560:f803] Port: (null)
2012-08-29 15:52:42.590 NSurl[3560:f803] Path: /s
2012-08-29 15:52:52.516 NSurl[3560:f803] Relative path: /s
2012-08-29 15:53:05.576 NSurl[3560:f803] Path components as array: (
"/",
s
)
2012-08-29 15:53:32.861 NSurl[3560:f803] Parameter string: (null)
2012-08-29 15:53:37.528 NSurl[3560:f803] Query: tn=baiduhome_pg&bs=NSRUL&f=8&rsv_bp=1&rsv_spt=1&wd=NSurl&inputT=2709
2012-08-29 15:53:52.942 NSurl[3560:f803] Fragment: (null)
2012-08-29 15:53:54.539 NSurl[3560:f803] User: (null)
2012-08-29 15:53:57.808 NSurl[3560:f803] Password: (null)
我們需要的是query 里面的參數(shù)內(nèi)容,可以用[url query]方法取出,取出的內(nèi)容為NSstring 類型需要做字符串處理才能拿到對應(yīng)的數(shù)據(jù)。
為了讓程序結(jié)構(gòu)更加清晰我們這時更希望取出來的為字典類型。這樣就少了字符串處理過程,同時也增加了我們程序的可讀性。
這里貼上處理函數(shù):
//
// NSMutableDictionary+URLParams.m
// TrainStaff
//
// Created by 逸信Mac on 2016/12/3.
// Copyright ? 2016年 eshine-ios. All rights reserved.
//
#import "NSMutableDictionary+URLParams.h"
@implementation NSMutableDictionary (URLParams)
/**
* 截取URL中的參數(shù)
*
* @return NSMutableDictionary parameters
*/
+(NSMutableDictionary *)getURLParameters:(NSString *)urlStr
{
// 查找參數(shù)
NSRange range = [urlStr rangeOfString:@"?"];
if (range.location == NSNotFound) {
return nil;
}
// 以字典形式將參數(shù)返回
NSMutableDictionary *params = [NSMutableDictionary dictionary];
// 截取參數(shù)
NSString *parametersString = [urlStr substringFromIndex:range.location + 1];
// 判斷參數(shù)是單個參數(shù)還是多個參數(shù)
if ([parametersString containsString:@"&"]) {
// 多個參數(shù),分割參數(shù)
NSArray *urlComponents = [parametersString componentsSeparatedByString:@"&"];
for (NSString *keyValuePair in urlComponents) {
// 生成Key/Value
NSArray *pairComponents = [keyValuePair componentsSeparatedByString:@"="];
NSString *key = [pairComponents.firstObject stringByRemovingPercentEncoding];
NSString *value = [pairComponents.lastObject stringByRemovingPercentEncoding];
// Key不能為nil
if (key == nil || value == nil) {
continue;
}
id existValue = [params valueForKey:key];
if (existValue != nil) {
// 已存在的值,生成數(shù)組
if ([existValue isKindOfClass:[NSArray class]]) {
// 已存在的值生成數(shù)組
NSMutableArray *items = [NSMutableArray arrayWithArray:existValue];
[items addObject:value];
[params setValue:items forKey:key];
} else {
// 非數(shù)組
[params setValue:@[existValue, value] forKey:key];
}
} else {
// 設(shè)置值
[params setValue:value forKey:key];
}
}
} else {
// 單個參數(shù)
// 生成Key/Value
NSArray *pairComponents = [parametersString componentsSeparatedByString:@"="];
// 只有一個參數(shù),沒有值
if (pairComponents.count == 1) {
return nil;
}
// 分隔值
NSString *key = [pairComponents.firstObject stringByRemovingPercentEncoding];
NSString *value = [pairComponents.lastObject stringByRemovingPercentEncoding];
// Key不能為nil
if (key == nil || value == nil) {
return nil;
}
// 設(shè)置值
[params setValue:value forKey:key];
}
return params;
}
@end
使用DEMO:
-(BOOL)application:(UIApplication *)application openURL:(nonnull NSURL *)url sourceApplication:(nullable NSString *)sourceApplication annotation:(nonnull id)annotation
{
NSString *schemeVal = [url scheme];
if([schemeVal isEqualToString:@"xyjtrain"]){
NSMutableDictionary *dic = [NSMutableDictionary getURLParameters:[url absoluteString]];
NSString *cookieVal = dic[@"cookie"];
if(NotNilAndNull(cookieVal)){
}
}
return NO;
}
iOS9中的適配
配置URL Schemes白名單
iOS9的時候蘋果加強了權(quán)限,只有在info.plist文件中加入了URL Schemes白名單才能使用canOpenURL:
方法來判斷是否能打開該url。該白名單的上限是50個。也就是說,你最多只能使用canOpenURL:
方法判斷50個URL Schemes。當然,平常我們都用不了那么多,就算是集成分享功能,50個肯定夠了。
備注:只是對canOpenURL:方法有限制,openURL:方法是沒有限制的。
我們需要在MyApp的info.plist里面將weixin
設(shè)置為白名單。
步驟:
點擊info.plist->右鍵->Open As->Source Code->添加下面的代碼
<key>LSApplicationQueriesSchemes</key>
<array>
<string>weixin</string>
</array>
問題
多個應(yīng)用設(shè)置相同的URL Scheme 會怎么樣?
這個URL Schemes并不是唯一的。也就是說,多個應(yīng)用之間設(shè)置的URL Schemes是可以相同的。
那么問題來了,假如兩個應(yīng)用的URL Schemes相同的話,使用openURL:方法會打開哪個應(yīng)用呢?
樓主親自用手機試了一下。
步驟是:
將MyApp安裝到手機上,點擊“打開微信”button,微信打開了。
然后將WXApp也安裝到手機上。再次點擊MyApp的“打開微信”button,結(jié)果打開的是WXApp。
結(jié)論:如果兩個應(yīng)用有URL Schemes是相同的,后安裝的應(yīng)用的URL Schemes會把早安裝的應(yīng)用的URL Schems覆蓋掉。
附上常用的URL Schemes:
QQ的url是 mqq://
微信是weixin://
淘寶taobao://
點評dianping:// dianping://search
微博 sinaweibo://
weico微博weico://
支付寶alipay://
美團 imeituan://
京冬openapp.jdmoble://
人人renren://
1號店wccbyihaodian://
有道詞典yddictproapp://
優(yōu)酷 youku://
/****6月2日更新****/
最近蘋果剛更新了IOS10.3,無意中發(fā)現(xiàn)了一個關(guān)于URL Scheme調(diào)整的問題,準確的說是URL Scheme命名的問題。官方對URL Scheme的命名做了規(guī)范限制:命名要小寫!但是到目前來看大寫小寫都是可以成功喚起的,也就是說無論大寫還是小寫跳轉(zhuǎn)都是沒有任何影響的