iOS 9 by Tutorials 笔记(三)

iOS 的原生程序和 web 技术从来都是两个阵营,没有什么交集。但 Apple 近些年来让二者关系更近了。

Chapter 3:Your App on the Web

iOS 9 用 universal links 和 web markup 让二者走的更近,他让你提供直接进入你 app 的 deep link,以及可以展示在 Spotlight 和 Safari 搜索框中的 web 内容

Linking to your app

前面已经熟悉了 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(_:) 这个方法可用来收集已安装应用程序列表
  • 冲突:如果存在同名的 custom URL scheme 就会有冲突
  • No fallback:如果 iOS 试图打开没有注册的 URL scheme,会静默失败

幸运的是 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 有如下优势:

  • 唯一
  • 安全:将你的域名与 App 绑定,你要上传一个 安全签名文件到 web 服务器上,这样其他的 App 就无法查询你的 App 是否被安装了
  • 简单:universal link 其实就是个简单的 Http 链接,即使用户没装你的 App,或不是 iOS 9 也能通过浏览器打开

为了将 website 和 app 绑定,并且证明这就是你的 website,这里会有两种绑定:

  • 你要告诉你的 app 关于你的域名信息
  • 你要告诉你的域名关于你 app 的信息

在此之后,你只需要简单地在 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 部分包含了一个字典:

  • appID 由 teamID + bundleID 组成
  • Paths 数组包含了一个你的 app 应该处理的 URLs 白名单,这个 paths 数组还支持 基本的模式匹配,例如 *,? 等,如 /videos/ */year/201?/videoName

一旦这个 Json 文件准备完毕,你必须上传到 website 的根目录下才能正常工作,而且不能有任何的重定向,而且必须可以通过 Https 访问到

这里还有额外的两点需要考虑下:

  1. 由于 Handoff 等特性要照顾 iOS 8,那么可以使用 openssl 来对 apple-app-site- association 进行签名 链接
  2. 上传之前先检查下 Json 文件有无语法错误

Handling universal links in your app

你的 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.comvideo 页面的 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。

Working with web markup

Search 包含三种不同的 API:NSUserActivity,CoreSpotlight,web markup。前两种已经介绍过了,现在来看第三种。

你可以使用 web markup 在搜索结果中得到你 app 应用里面的内容。如果你有一个网站,内容与 APP 的内容一致,你可以使用基本的 markup、Smart App Banners、universal links 来标记你的 web pages。

优化你的网站标记,苹果会派机器人去爬你的网站,即使用户没有安装应用,也能搜索相关内容。

Making your website discoverable

苹果爬虫不保证什么时候会去爬你的网站,但你可以做下面的事情来保证网站更容易被发现:

  1. iTunes Connect 中设置 Support URLMarketing URL 为包含 web markup 的域名
  2. 确保这些域名可以访问到你的 web markup
  3. 检查 robots.txt,确保苹果的爬虫可以正常工作

Embedding universal links using Smart App Banners

一旦苹果的爬虫找到并索引了你的 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

内容属性包含两个重要的参数:

  • app-id:对应着你 App 的 Apple ID,不同于 登录 iCloud 的 Apple ID,这个 ID 是唯一的一串 number,所有 App Store 上的应用都有着唯一的 ID
  • app-argument:包含跳转回 App 的 URL,iOS 9 之前这个参数是自定义的 URL scheme deep link,现在 Apple 推荐使用 HTTP/HTTPS universal links

Smart App Banners 仅仅支持 Safari

Applebot 仅仅支持两种方式的 mobile links:Twitter CardsFacebook 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:)方法中已经实现了这一功能

Semantic markup using Open Graph

苹果爬虫爬到你的内容并不保证会显示在 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 是能够获取这些『富文本标记』

Validating your markup

你在网站上都做好了 markup 标记,下一步验证是否能被 Apple 正确的支持也很简单。Apple 提供了在线 验证工具


-EOF-

如果感觉此文对你有帮助,请随意打赏支持作者 😘

chengway

认清生活真相之后依然热爱它!

Subscribe to Talk is cheap, Show me the world!

Get the latest posts delivered right to your inbox.

or subscribe via RSS with Feedly!