這裡首先說明一下:這篇文章由於一些限制,我也沒有能夠進行實驗測試,只是盡可能的解釋書中的一些知識,可能會有錯誤,等以後有條件了,我會實驗這篇文章中的內容。但是作為了解內容還是不錯的。
在iOS 9之前在iPhone上native和web之間,基本上算是獨立的的兩部分內容。但是Apple正在努力縮小兩者之間的距離,使其越來越近。在iOS 9退出了universal links和web markup,使你能夠提供deep links直接進入你的app和在Spotlight和Safari中能夠搜索出來你的內容。
這一章書中提供了兩個工程,一個是APP端的,一個是Server端的,因為這個需要Server端修改一些東西。APP可以通過地址:https://itunes.apple.com/us/app/rwdevcon-tutorial-conference/id958625272?mt=8進行下載。APP截圖如下:
在真正開始前,先回顧一下universal link的前輩:deep links。通過這個回顧,了解一下deep links存在的一些問題。
在iOS 9之前我們可以給APP設置URL scheme,在Info.plist裡面添加CFBundleURLTypes key。一般格式類似://。 另外應該也看到過Apple自己的URL scheme,類似tel://、sms://等。
一旦設置了URL scheme,就能夠通過openURL(_:)方法調用起來該APP,調用的時候後面可以帶著一些參數。然後在我們自己的程序裡面可以再AppDelegate的application(_:handleOpenURL:)中進行對應的處理。這套系統已經存在很久了,但是現在暴露出來一些問題:
* 安全 UIApplication有一個方法canOpenURL(_:),可以用來檢測用戶是否能夠打開某個URL secheme,本來蘋果的設計是好的,但是不幸的是現在好多開發商使用這個來檢測用戶手機安排了什麼APP,這樣就收集了用戶的APP列表,涉及到了用戶的隱私。
沖突 由於URL scheme是每個APP開發商自己定義的,很有可能兩個APP開發商定義相同,這時候如果使用openURL(_:),iPhone將不會知道應該怎麼處理。 No fallback:如果 iOS 試圖打開沒有注冊的 URL scheme,會靜默失敗,然後用戶並不知道發生了什麼。canOpenURL(_:)這個方法在iOS9中有了限制,如果想使用這個方法必須首先把所有的地址添加到info.plist中,不能按照原來由服務器下發來檢測APP安裝了。
iOS使用universal links來解決這些問題。使用universal links來代替URL scheme。universal links使用標准的HTTP和HTTPS鏈接。
這裡舉了一個例子:你有一個域名clownapp.com,你可以注冊http://clownapp.com作為你的universal link。如果用戶安裝了你的clownapp。當他在Safari或者web view中點擊鏈接http://clownapp.com/clowns/fizbo的時候,將會直接進入到你的APP的fizbo的profile頁面。如果你沒有安裝這個將會直接跳轉到你的網站上的fizbo的profile頁面。如果你使用openURL(_:)打開,也會與這個動作一樣。
PS: 這裡我運行書中的例子,在模擬器的Safari中打不開。可能是我的原因
Universal links與deep links有如下的有點:
* 唯一 由於使用的是域名,能夠保證唯一性
* 安全 將你的app與你的域名綁定,上傳一個安全簽名到你的網站服務器。同樣其他的APP也不會輕易的知道手機上是否安裝了你的APP。
簡單 由於跳轉到APP和服務器的鏈接統一了,所以不用考慮在APP和手機上需要使用兩套不同的鏈接了。這裡原文如下There’s also no way for other apps to tell whether your app is installed.這裡不是沒有方式,只是說沒有原來那麼容易。使用URL scheme白名單的方式還是能夠檢測。
為了使App能夠處理對應的鏈接,首先需要讓App知道應該處理什麼鏈接。這裡使用的鏈接是rwdecon.com。按照下圖添加對應的鏈接:
這裡可能會出現選擇賬戶,這時候就選擇你對應的就好了,如果沒有賬戶可以進入到Account添加。
你需要在服務器的根目錄下面,添加文件名為apple-app-site-association(沒有後綴)的一個文件,然後在裡面添加上如下的內容:
{
"applinks": {
"apps": [],
"details": [
{
"appID": "KFCNEC27GU.com.razeware.RWDevCon",
"paths": [
"/videos/\*"
]
}
]
}
}
其中的appId是由team ID和bundle ID拼成的。Paths 數組包含了一個你的App應該處理的 URLs 白名單,這個 paths 數組還支持 基本的模式匹配,例如 *,? 等,如 /videos/*/year/201?/videoName。
這個文件需要上傳到服務器的根目錄,並且能夠通過HTTPS訪問到,並且沒有重定向。
這部分代碼沒有試驗
上面已經添加對應的universal links,下面需要在App中處理對應的鏈接了。這裡需要解析對應的鏈接,然後做一些相關的業務邏輯。在Session.swift添加下面的方法,這個方法主要是用來解析對應的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
}
在AppDelegate.swift添加如下方法:
extension AppDelegate {
// 輔助方法
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)
}
}
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
}
}
下面有兩個鏈接,可以給自己寫一封郵件帶上下面的兩個鏈接,第一個是能夠正常打開視頻播放的,第二個直接打開網站首頁。PS:我沒有試驗成功
good link
http://www.rwdevcon.com/videos/talk-tammy-coron-possible.html
bad link
http://www.rwdevcon.com/videos/tim-cook-keynote.html
Search 包含三種不同的 API:NSUserActivity,CoreSpotlight,web markup。前兩種已經介紹過了,現在來看第三種。
你可以使用 web markup 在搜索結果中得到你 app 應用裡面的內容。如果你有一個網站,內容與 APP 的內容一致,你可以使用基本的 markup、Smart App Banners、native App能夠處理universal links來修改你的網站,使其能夠更好的被搜索、展示。
蘋果有自己的爬蟲,如果你的網站使用web markup,蘋果的爬蟲能夠收集到對應的信息,然後保存到自己的服務器上,然後其他用戶在搜索的時候能夠搜索到對應的內容,不管用戶是否安裝了你的App,這樣也能夠幫助你獲取一部分用戶。
蘋果的爬蟲會到處去爬數據,但是不一定能夠很快的發現你的網站,這裡有個方法能夠幫助蘋果爬蟲發現你的網站。
1. 在iTunes Connect中,在設置Support URL的地方,設置Marketing URL,指向你已經使用markup的網站。
2. 保證你填寫的URL能夠被蘋果的爬蟲訪問到。
3. 檢查你Robots.txt文件,保證蘋果的爬蟲能夠正常的爬取你的網站。PS:關於Robots.txt自行百度吧。
添加了Smart App Banners後,打開網站的時候會在頂部出現一個banner,對於已經安裝App的用戶,會顯示一個OPEN按鈕方便用戶打開對應的App,對於未安裝App的用戶,將會出現一個view按鈕,點擊將會進入App store下載該App。效果圖類似如下:
實現這個效果的方式,在你想要添加banner的網頁上添加如下代碼:
這裡的name是App在store中的名字,下面的content包含兩部分內容:
* app-id 在store上的app id
* app- argument 包含跳轉回 App 的 URL,iOS 9 之前這個參數是自定義的 URL scheme deep link,現在 Apple 推薦使用 HTTP/HTTPS universal links
Smart App Banners 僅僅支持 Safari
你能使用Applebot支持的開放的mobile links,比如:Twitter Cards和App Links,但是這兩種標記我自己也沒有試驗,所以只是貼出來代碼:
// Twitter Cards 具體 https://dev.twitter.com/cards/mobile
// App Links 具體http://applinks.org
蘋果爬蟲爬到你的內容並不保證會顯示在 Spotlight 的搜索結果中,因為他還會和其他搜索結果內容進行競爭。
Apple 並沒有公布具體的評級算法,只是確保你的內容會被考慮。而當用戶明顯地點擊或搜索結果與你的內容高度相關,那麼就會優先被 Apple 考慮。
最後,Apple 建議為 markup 添加一些結構化的數據,來使其更好地以富文本的形式顯示在 Spotlight 中。
上面的og後面的屬性,我也沒有找到出處,有誰清楚麻煩留言說明一下。謝謝
關於web markup相關的詳細的東西可以看蘋果的文檔https://developer.apple.com/library/ios/documentation/General/Conceptual/AppSearch/WebContent.html
最後說明一下:這篇文章由於一些資源問題,我沒有做什麼測試,可能有地方不對,如果哪裡錯誤了,請指出來,謝謝。
突然感覺這是最沒底的一篇文章。