iOS 的原生程序和 web 技术从来都是两个阵营,没有什么交集。但 Apple 近些年来让二者关系更近了。iOS 9 用 universal links 和 web markup 让二者走的更近,他让你提供直接进入你 app 的 deep link,以及可以展示在 Spotlight 和 Safari 搜索框中的 web 内容
前面已经熟悉了 deep links ,本节介绍一种新技术,开始前,再来回顾下 Deep links
在 iOS 9 之前,Apps 之间通讯的方式主要是通过注册自定义的 url scheme
(在 Info.plist 中使用 CFBundleURLTypes key )
例如你的一个社交类 App 注册了自定义的 clownapp://
或 clown://
,此时你就能从其他地方构造 clownapp://home/feed
这样的结构,一旦链接被打开,iOS 会打开你的 app 并通过 URL 传递一个 URL(通过 application(_:handleOpenURL:)
)此时,你的 app 就可以对这个 URL 做出解释,并做出相应的回应
Apple 从 iOS 3.0 就开始这么做了,随着时间的推移,也产生了一些问题,这么做有如下缺点:
canOpenURL(_:)
这个方法可用来收集已安装应用程序列表 幸运的是 iOS 9 使用 universal links 解决了这些问题。universal links 使用 基础的 HTTP 和 HTTPS links
你可以将 http://clownapp.com/ clowns/*
注册为唯一的 app link,如果用户安装了你的 app,然后在 Safari 或 web 上点击了 http://clownapp.com/clowns/fizbo
这个链接,就会跳转到你的 APP 的 Fizbo
的用户界面上,如果没装你的 App,那么 iOS 会跳转到 App 的主页上。你会发现和使用 openURL(_:) 基本上没有区别
Universal links 相对 deep links 有如下优势:
为了将 website 和 app 绑定,并且证明这就是你的 website,这里会有两种绑定:
在此之后,你只需要简单地在 app 中添加一些代码来处理即将到来的链接就好
让你的 APP 了解关于你域名的信息通常在 Capabilities tab 下的 Associated Domains 添加相关域名
这会告诉你的 app 将要响应的域名,确保域名以 applinks
开头(只有team agent 或 a team administrator 才能打开 Associated Domains )
接下来创建一个从 website 到 app 的连接,你可以在你的 website 上放置一个 JSON 文件,如下:
{ "applinks": { "apps": [], "details": [ { "appID": "KFCNEC27GU.com.razeware.RWDevCon", "paths": [ "/videos/*" ] } ] } }
在服务器上放置一个包含 app 信息的 json,名字必须是 apple-app-site-association ,且不能带扩展名,json 也不行。 apple-app-site-association 之前被用在 iOS 8 上来实现 web 和 app 之间的 Handoff
这个 applinks
部分决定了哪些 apps 可以处理 website 上特定的 URL paths
,而 details 部分包含了一个字典:
/videos/ */year/201?/videoName
一旦这个 Json 文件准备完毕,你必须上传到 website 的根目录下才能正常工作,而且不能有任何的重定向,而且必须可以通过 Https 访问到
这里还有额外的两点需要考虑下:
apple-app-site- association
进行签名 链接 你的 App 接受到 universal link,你需要做出针对性的回应,简单说就是解析 URL,决定哪些内容需要显示,然后导航到相关的界面上。
class func sessionByWebPath(path: String, context: NSManagedObjectContext) -> Session? { let fetch = NSFetchRequest(entityName: "Session") fetch.predicate = NSPredicate(format: "webPath = %@", path) do { let results = try context.executeFetchRequest(fetch) return results.first as? Session } catch let fetchError as NSError { print("fetch error: /(fetchError.localizedDescription)") } return nil }
Session 类有个 webPath 的属性,包含着 rwdevcon.com
上 video
页面的 path
。这个方法找出与 path 相匹配的 Session 对象
接着写一个 help 方法,接受一个 video URL ,然后在 UINavigationController 上嵌入一个 AVPlayerViewController 进行播放
func presentVideoViewController(URL: NSURL) { let storyboard = UIStoryboard(name: "Main", bundle: nil) let navID = "NavPlayerViewController" let navVideoPlayerVC = storyboard.instantiateViewControllerWithIdentifier(navID) as! UINavigationController navVideoPlayerVC.modalPresentationStyle = .FormSheet if let videoPlayerVC = navVideoPlayerVC.topViewController as? AVPlayerViewController { videoPlayerVC.player = AVPlayer(URL: URL) let rootViewController = window?.rootViewController rootViewController?.presentViewController( navVideoPlayerVC, animated: true, completion: nil) } }
最后实现如下 UIApplicationDelegate
方法,当有来自于注册过的 universal HTTP link call 就会自动被 iOS 调用
func application(application: UIApplication, continueUserActivity userActivity: NSUserActivity, restorationHandler: ([AnyObject]?) -> Void) -> Bool { //1 系统用 NSUserActivityTypeBrowsingWeb 表示对应的 universal HTTP links if userActivity.activityType == NSUserActivityTypeBrowsingWeb { let universalURL = userActivity.webpageURL! //2 提取出 url 的不同部分 if let components = NSURLComponents(URL: universalURL, resolvingAgainstBaseURL: true), let path = components.path { if let session = Session.sessionByWebPath(path, context: coreDataStack.context) { //3 找到 session,然后播放 video let videoURL = NSURL(string: session.videoUrl)! presentVideoViewController(videoURL) return true } else { //4 无法理解就打开网站首页 let app = UIApplication.sharedApplication() let url = NSURL(string: "http://www.rwdevcon.com")! app.openURL(url) } } } return false }
application(_:continueUserActivity:restorationHandler:)
也被用做 iOS 8 的 Handoff,之前的 App Search 我们也用到了这个方法
现在在你的设备上,打开邮件客户端,如果里面有这些链接:
点击第一个,就会打开 app 播放相关视频
而点击第二个则会用 Safari 打开网站主页
注意到顶部 banner 下的东东了吗?那叫做 Smart App Banner ,稍后会提到
The RWDevCon app 干净利落地处理了他能够识别的 universal links,不能识别的则用 Safari 来打开。除了通过链接来触发,你还可以通过直接载入一个 URL,一个 WKWebView,一个 UIWebView 或使用 openURL(_:) 来触发你的 App 来处理 universal link。
Search 包含三种不同的 API:NSUserActivity,CoreSpotlight,web markup。前两种已经介绍过了,现在来看第三种。
你可以使用 web markup 在搜索结果中得到你 app 应用里面的内容。如果你有一个网站,内容与 APP 的内容一致,你可以使用基本的 markup、Smart App Banners、universal links 来标记你的 web pages。
优化你的网站标记,苹果会派机器人去爬你的网站,即使用户没有安装应用,也能搜索相关内容。
苹果爬虫不保证什么时候会去爬你的网站,但你可以做下面的事情来保证网站更容易被发现:
Support URL
和 Marketing URL
为包含 web markup 的域名 一旦苹果的爬虫找到并索引了你的 website,Apple 建议添加 Smart App Banners
到你的网站的索引中
Smart App Banners
最早出现在 iOS 6,他啊可以在网页顶部显示一个 banner,推广你的 App,对于已经安装 App 的用户,这个 banner 可以很容易地提供一个前往 App 指定界面的 deep link
如果 iOS 检测到 APP 已安装,banner 会变成 OPEN,否则会显示 View,点击会跳转到 App Store
现在到网站的 Video 目录下,用文本编辑器打开 talk-ray-wenderlich- teamwork.html
,添加:
<meta name="apple-itunes-app" content="app-id=958625272, app- argument=http://www.rwdevcon.com/videos/talk-ray-wenderlich- teamwork.html">
属性 name 一定要是 apple- itunes-app
,这个类型的标记代表 Smart App Banner
tag,反过来会告诉 Safari 显示 Smart App Banner
内容属性包含两个重要的参数:
Smart App Banners 仅仅支持 Safari
Applebot 仅仅支持两种方式的 mobile links: Twitter Cards 和 Facebook App Links
使用了 Twitter Cards:
<meta name="twitter:app:name:iphone" content="RWDevCon"> <meta name="twitter:app:id:iphone" content="958625272"> <meta name="twitter:app:url:iphone" content="http://www.rwdevcon.com/ videos/talk-ray-wenderlich-teamwork.html">
使用了 Facebook's App Links:
<meta property="al:ios:app_name" content="RWDevCon"> <meta property="al:ios:app_store_id" content="958625272"> <meta property="al:ios:url" content="http://www.rwdevcon.com/videos/talk- ray-wenderlich-teamwork.html">
现在打开 Safari,输入 http://www.rwdevcon.com/videos/talk-jake-gundersen- opportunity.html.
你会发现 Smart App Banner 与之前的不太一样,变得更窄了,而且按钮变成了 OPEN,这种特殊的 banner 仅仅会 URL 匹配时才会展示。在其他未匹配状态,banner 还是会变成正常尺寸
点击这个 Smart App Banner,Safari 会打开 App 然后播放相关 video,前面的 application(_:continueUserActivity:restorationHandler:)
方法中已经实现了这一功能
苹果爬虫爬到你的内容并不保证会显示在 Spotlight 的搜索结果中,因为他还会和其他搜索结果内容进行竞争。
Apple 并没有公布具体的评级算法,只是确保你的内容会被考虑。而当用户明显地点击或搜索结果与你的内容高度相关,那么就会优先被 Apple 考虑。
最后,Apple 建议为 markup 添加一些结构化的数据,来使其更好地以富文本的形式显示在 Spotlight 中。在 /videos/talk-ray-wenderlich-teamwork.html
上添加下面代码:
<meta property="og:image" content="http://www.rwdevcon.com/assets/images/ videos/talk-ray-wenderlich-teamwork.jpg" /> <meta property="og:image:secure_url" content="https://www.rwdevcon.com/ assets/images/videos/talk-ray-wenderlich-teamwork.jpg" /> <meta property="og:image:type" content="image/jpeg" /> <meta property="og:image:width" content="640" /> <meta property="og:image:height" content="340" /> <meta property="og:video" content="http://www.rwdevcon.com/videos/Ray- Wenderlich-Teamwork.mp4" /> <meta property="og:video:secure_url" content="https://www.rwdevcon.com/ videos/Ray-Wenderlich-Teamwork.mp4" /> <meta property="og:video:type" content="video/mp4" /> <meta property="og:video:width" content="1280" /> <meta property="og:video:height" content="720" /> <meta property="og:description" content="Learn how teamwork lets you dream bigger, through the story of an indie iPhone developer who almost missed out on the greatest opportunity of his life." />
这将会使爬虫更好地查找和处理信息, og
代表 Open Graph
Open Graph 协议可以让网页成为一个“富媒体对象”。用了 Meta Property = og 标签,就是你同意了网页内容可以被其他社会化网站引用等,目前这种协议被 Fackbook 等 SNS 网站所采用。
在你的网站上添加 rich markup 主要目的在于:装饰 Spotlight 的搜索结果,使其展示更多的信息
注意 YouTube 是能够获取这些『富文本标记』
你在网站上都做好了 markup 标记,下一步验证是否能被 Apple 正确的支持也很简单。Apple 提供了在线 验证工具