前言
通常来说,手机APP相当于是一座座信息孤岛,APP之间不能相互通信;但有些场景的确需要,让别的APP来唤醒自己,例如支付宝为别的APP提供支付,又或者需要在一个营销网页中打开APP的指定页面, 这时就可以利用定义自己的URL Schemes页面跳转协议
来实现。
一.什么是URL Schemes
1.URL Schemes单词理解
- URL, 我们都很清楚,
https://www.apple.com
就是一个URL,我们叫它链接或者网址。 - Schemes, 表示的是一个 URL 中的一个位置——最初始的位置,即 ://之前的那段字符。比如
https://www.apple.com
这个网址的 Schemes 是 https。
2.简单理解
例如微信打开扫一扫的功能的Schemes是:weixin://dl/scan
;我们可以理解,在以本地应用为主的 iOS 上,我们可以像定位一个网页一样,用一种特殊的 URL 来定位一个应用甚至应用里某个具体的功能。而定位这个应用的,就是这个应用URL 的 Schemes 部分。
3.APP和网页的对比
你可以完全按照理解一个网页的 URL (也就是它的网址)的方式来理解一个 iOS 应用的 URL,拿苹果的网站和 iOS 上的微信来做个简单对比:
网页(苹果) | iOS 应用(微信) | |
---|---|---|
网站首页/打开应用 | https://www.apple.com |
weixin:// |
子页面/具体功能 |
https://www.apple.com/mac (Mac页面) |
weixin://dl/moments (朋友圈) |
在这里,https://www.apple.com
和 weixin://
都声明了这是谁的地盘。然后在 https://www.apple.com
后面加上 /mac
就跳转到从属于 https://www.apple.com
的一个网页(Mac 页)上;同样,在 weixin://
后面加上 dl/moments
就进入了微信的一个具体的功能——朋友圈。
二.iOS中如何使用URL Schemes
1.注册URL Schemes
为自己的项目Bank注册一个URL Schemes,支持被唤醒。
Identifier
是自定义的 URL schemes 的名字,一般采用反转域名的方法保证该名字的唯一性,比如 com.lwin.www,不过在iOS中打开一个应用程序只需要拿到这个应用程序的协议头URL Schemes
即可,所以我们只需配置应用程序的协议头即可。一个应用是可以有多个URL Schemes的。
2.使用
a.唤醒应用
在另外一个APP唤起Bank
- (IBAction)open:(id)sender {
if(![[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:@"LBSAPP://"]]) {
return;
}
//不带参数
NSString * wslUrlScheme = @"LBSAPP://product";
//如果参数含有特殊字符或汉字,需要转码,否则这个URL不合法,就会唤起失败;参数字符串的格式可以自定义,只要便于自己到时候解析就行;
NSString * parameterStr = [@"?name=手机&id=1" stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
//LBSAPP://product?name=手机&id=1
NSURL * url = [NSURL URLWithString:[wslUrlScheme stringByAppendingString:parameterStr]];
//iOS 10以下
// [[UIApplication sharedApplication] openURL:url];
//iOS 10以上
[[UIApplication sharedApplication] openURL:url options:nil completionHandler:^(BOOL success) {
}];
}
如果点击调用时控制台报错:
-canOpenURL: failed for URL: "LBSAPP://" - error: "This app is not allowed to query for scheme lbsapp"
这是因为在iOS9以后,如果使用 canOpenURL:方法,该方法所涉及到的URL Schemes必须在"Info.plist"中将它们列为白名单,否则不能使用。
b.被唤醒之后的处理
- 在AppDelegate里面的UIApplicationDelegate代理方法做监听。
#import "AppDelegate.h"
#import "ViewController.h"
#import "SchemesManager.h"
@interface AppDelegate ()
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
self.window.rootViewController = [[ViewController alloc] init];;
[self.window makeKeyAndVisible];
//第三方应用打开本应用启动
if(launchOptions[UIApplicationLaunchOptionsURLKey] != nil){
[self application:application handleOpenURL:launchOptions[UIApplicationLaunchOptionsURLKey]];
}
// Override point for customization after application launch.
return YES;
}
/**
iOS 9.0 以下 程序运行过程中调用
*/
- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url{
return [SchemesManager handleOpenURL:url];
}
/**
iOS 9.0 以下 程序运行过程中调用
*/
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(nullable NSString *)sourceApplication annotation:(id)annotation{
return [SchemesManager handleOpenURL:url];
}
/**
iOS 9.0 之后
三方唤起本程序后执行的方法
return YES 表示允许唤起本程序 程序运行过程中调用
*/
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey, id> *)options{
return [SchemesManager handleOpenURL:url];
}
@end
2.可以单独写一个工具类来处理URL Schemes。
#import "SchemesManager.h"
#import <UIKit/UIKit.h>
@implementation SchemesManager
+ (BOOL)handleOpenURL:(NSURL *)url {
NSMutableString *str = [NSMutableString string];
[str appendFormat:@"URL scheme:%@ \n\n", [url scheme]];
[str appendFormat:@"URL host:%@ \n\n", [url host]];
[str appendFormat:@"URL absoluteString:%@ \n\n", [url absoluteString]];
NSURLComponents *comp = [NSURLComponents componentsWithURL:url resolvingAgainstBaseURL:YES];
if(comp) {
[str appendString:@"queryItems:\n"];
NSArray<NSURLQueryItem *> *queryItems = [comp queryItems];
for (int i=0; i<queryItems.count; i++) {
NSURLQueryItem *item = queryItems[i];
[str appendFormat:@"%@=%@ ", item.name, item.value];
if(i<queryItems.count-1) {
[str appendString:@","];
}
}
}
UIAlertView *alertView=[[UIAlertView alloc] initWithTitle:@"分享" message:str delegate:self cancelButtonTitle:nil otherButtonTitles:@"分享完成", nil];
[alertView show];
return YES;
}
+ (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
//返回URL scheme = bank234280的主应用
NSURL * url = [NSURL URLWithString:@"bank234280://success"];
[[UIApplication sharedApplication] openURL:url options:nil completionHandler:^(BOOL success) {
}];
}
@end
3.注意
如果使用了Scene,需要在SceneDelegate的代理方法
- (void)scene:(UIScene *)scene openURLContexts:(NSSet<UIOpenURLContext *> *)URLContexts
去处理URL Schemes :
@implementation SceneDelegate
- (void)scene:(UIScene *)scene openURLContexts:(NSSet<UIOpenURLContext *> *)URLContexts {
UIOpenURLContext *urlCtx = [URLContexts allObjects].firstObject;
[SchemesManager handleOpenURL:urlCtx.URL];
}
@end