你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發基礎 >> watchOS 2 教程(四): Watch Connectivity

watchOS 2 教程(四): Watch Connectivity

編輯:IOS開發基礎

apple-watch-4.png

本文是投稿文章,作者Swift_波
開始

打開 Watch\Interface.storyboard,從對象庫拖動一個 Interface Controller 到 storyboard 畫板中。選中控制器,打開屬性檢查器做如下修改:

  • 設置 Identifier 為 BoardingPass;

  • 設置 Insets 為 Custom;

  • 設置 Top inset 為 6。

因為這個界面非常像 check-in 界面,設計界面有時候有些重復的工作,這時候你要靈活一點。

在文檔大綱中點開 CheckIn Scene,選擇那個包括起點和終點標簽的組,之後 Edit\Copy:

909589-ac05fb33d9896317 (1).png

點擊 storyboard 中那個新的控制器的任何地方,選擇 Edit\Paste。這個只在直接往控制器裡面粘貼時候有用,而往文檔大綱中粘貼沒有用,但是我也不知道為什麼。

新的控制器應該是這樣:

26.png

下一步,從對象庫拖動一個 Image 放到新的控制器中,確保它與你剛才粘貼的組同級,而不是子節點:

27.png

image 控件有兩個目的;最初它顯示動畫圖片序列來告訴用戶發生什麼事情,之後當手表從手機獲取到登機牌,image 會顯示它。

下載壓縮文件,解壓縮文件,然後拖動文件夾到 Watch\Assets.xcassets 目錄中。

確保拖動的是文件夾而不是其中的文件。這會在 asset catalog 中創建一個新的叫 Activity 的組,它包含一些圖片集合:

28.png

當你正在從配對的手機中請求登機牌的時候,用這個圖片序列顯示不確定進度指示器。

重新打開 Watch\Interface.storyboard 然後選擇之前那個 image。使用你的老朋友屬性檢查器做如下修改:

  • 設置 Image 為 Activity。自動補全有可能會建議例如 Activity1,所以確保你輸入的是 Activity;

  • 設置 Animate 為 Yes;

  • 設置 Duration 為1;

  • 選中 Animate on Load;

  • 設置 Horizontal alignment 為 Center;

  • 設置 Vertical alignment 為 Center;

  • 設置 Width 為 Fixed,值為66;

  • 設置 Height 為 Fixed,值為66;

當修改完成,你的屬性檢查器應該像這樣:

29.png

控制器應該像這樣:

30.png

可以看到 Image 的預覽圖片是一個又大又模糊的問題標記,不要擔心;因為沒有叫 Activity 的圖片,所以 IB 不能實時預覽動畫圖片-但是請相信我,運行時就沒這問題了。

設計完登機牌界面。現在創建 WKInterfaceController 的子類來做後續的工作。

創建控制器

在項目導航中右擊 Watch Extension 組,選擇 New File...。當對話框彈出來後選擇 watchOS\Source\WatchKit Class 然後點擊 Next。命名新的類為 BoardingPassInterfaceController,確保它是 WKInterfaceController 的子類並且語言設置為 Swift:

31.png

點擊 Next,之後 Create。

當新的文件在代碼編輯器中打開了,刪除三個空的方法,只剩下重要代碼和類定義。

之後,在類的頂部添加如下 outlets:

@IBOutlet var originLabel: WKInterfaceLabel!
@IBOutlet var destinationLabel: WKInterfaceLabel!
@IBOutlet var boardingPassImage: WKInterfaceImage!

這裡僅僅為剛才創建的圖片控件和兩個標簽增加連線。只要一瞬間你就能連接他們。

在連線下面增加如下代碼:

var flight: Flight? {
  didSet {
    if let flight = flight {
      originLabel.setText(flight.origin)
      destinationLabel.setText(flight.destination)
    }
  }
}

這又是我們的老朋友 flight 和它的屬性觀察器! 雖然你知道即將發生什麼,但是讓我們來回顧一下,你添加了一個可選的 Flight 類型屬性,包括一個屬性觀察器。當觀察器觸發,嘗試解包 flight,當解包成功使用 flight 來配置兩個標簽。

現在僅僅需要在控制器第一次打開的時候設置 flight 屬性。添加如下代碼到 BoardingPassInterfaceController:

override func awakeWithContext(context: AnyObject?) {
  super.awakeWithContext(context)
  if let flight = context as? Flight { self.flight = flight }
}

另一個老朋友;嘗試解包轉換 context 為 Flight 對象!如果轉換成功使用它來設置 self.flight,相應的觸發屬性觀察器來配置界面。

我保證這就是練習的樣板代碼。:]

現在,打開 Watch\Interface.storyboard 選擇登機牌控制器。在 Identity Inspector 中,修改 Custom Class\Class 為 BoardingPassInterfaceController:

32.png

在文檔大綱中右擊 BoardingPass 打開 outlets 和 actions 彈出框。連接 boardingPassImage 到 image:

34.png

最後,連接 destinationLabel 到 文本為 SFO 的標簽,連接 originLabel 到文字是 MAN 的標簽。

當完成這些操作,是時候更新 ScheduleInterfaceController 代碼, 一旦用戶登記了就打開登機牌界面。

打開登機牌界面

打開 ScheduleInterfaceController.swift 找到 table(_:didSelectRowAtIndex:)。替換這句代碼:

let controllers = ["Flight", "CheckIn"]

為下面這句代碼:

let controllers = flight.checkedIn ? ["Flight", "BoardingPass"] : ["Flight", "CheckIn"]

這裡僅僅判斷用戶是否登記過選中的航班,如果登記過就顯示航班詳情和登機牌界面。如果沒有,代替顯示航班詳情和登記界面。

編譯運行。點擊第一個航班,往左清掃,點擊 Check In。再次點擊相同的航班,往左清掃,你會看到登機牌界面,顯示不確定進度指示器:

e32re32.gif

是時候深入學習新的 Watch Connectivity 框架並且使用它請求真實的登機牌數據。

請求登機牌

打開 BoardingPassInterfaceController.swift 導入 Watch Connectivity 框架:

import

WatchConnecivity

下一步,在上面定義的 flight 的下面添加如下屬性:

var session: WCSession? {
  didSet {
    if let session = session {
      session.delegate = self
      session.activateSession()
    }
  }
}

這裡添加一個新的類型為 WCSession 的可選屬性。在手表和手機兩個設備間的所有連接操作都是由它處理的;你自己並不需要實例化這個類,而是使用框架提供的單例。你已經添加屬性觀察器了,當它觸發了,嘗試解包 session。當解包成功設置 session 的代理,之後激活它。

即使你不實現類的任何代理方法,你任然需要在激活前設置 session 的代理,不然情況會變得未知。

Xcode 可能會警告 BoardingPassInterfaceController 沒有遵循 WCSessionDelegate 協議,所以在 BoardingPassInterfaceController.swift 的底部添加如下空的擴展:

extension BoardingPassInterfaceController: WCSessionDelegate {

}

下一步,往 BoardingPassInterfaceController 添加如下幫助方法:

private func showBoardingPass() {
  boardingPassImage.stopAnimating()
  boardingPassImage.setWidth(120)
  boardingPassImage.setHeight(120)
  boardingPassImage.setImage(flight?.boardingPass)
}

它會在兩處調用 - 如果航班已經有登機牌了在 flight 的屬性觀察器中調用,還有另外一處是你發給你的 iPhone 的消息回調。實現非常簡單-停止圖片動畫,增加圖片大小,之後設置顯示到登機牌的圖片。

首先更新屬性觀察器,往 flight 屬性觀察器中的 if 代碼塊的底部增加如下代碼

if let _ = flight.boardingPass {
  showBoardingPass()
}

只有當 flight 存在一個登機牌的時候調用 showBoardingPass() 方法。

最後一部分代碼是往 iPhone 發送請求。在 awakeWithContext(_:) 代碼的下面添加如下代碼:

override func didAppear() {
  super.didAppear()
  // 1
  if let flight = flight where flight.boardingPass == nil && WCSession.isSupported() {
    // 2
    session = WCSession.defaultSession()
    // 3
    session!.sendMessage(["reference": flight.reference], replyHandler: { (response) -> Void in
      // 4
      if let boardingPassData = response["boardingPassData"] as? NSData, boardingPass = UIImage(data: boardingPassData) {
        // 5
        flight.boardingPass = boardingPass
        dispatch_async(dispatch_get_main_queue(), { () -> Void in
          self.showBoardingPass()
        })
      }
    }, errorHandler: { (error) -> Void in
      // 6
      print(error)
    })
  }
}

下面一步步講解以上代碼怎麼回事:

  1. 假如存在有效航班,沒有登機牌,並且支持 Watch Connecivity,會繼續進入發送消息的模塊。在嘗試與配對的手機做任何連接前你應該經常檢查是否支持 Watch Connectivity。

  2. 設置 session 值為默認的 WCSession 單例。這會相應的觸發屬性觀察器,在激活 session 之前 設置它的代理。

  3. 往配對的 iPhone app 發送消息。一個包括航班信息的字典被轉發到 iPhone app,並且提供回調和錯誤處理。

  4. iPhone app 處理接收的消息然後返回數據給手表端。手表端從返回數據中提取登機牌的圖片信息來創建一個 UIImage 對象。

  5. 如果操作成功了,設置 UIImage 為航班登機牌的圖片,之後回到主線程調用 showBoardingPass() 來顯示給用戶。回調和錯誤處理是在後台線程中執行,所以如果你需要像現在這樣更新界面,確保是在主線程中更新。

  6. 如果消息發送失敗簡單的打印錯誤到命令行。

這些是手表 app 端處理。現在需要相應的更新 iPhone app 端了。

回應請求

首先,導入 Watch Connectivity 框架:

import WatchConnectivity

之後,在 window 下面添加如下代碼:

var session: WCSession? {
  didSet {
    if let session = session {
      session.delegate = self
      session.activateSession()
    }
  }
}

操作與 BoardingInterfaceController 中命名一樣。簡單的一個類型 WCSession 的可選屬性,包括屬性觀察器,當觸發了觀察器,嘗試解包 session。如果解包成功設置 session 的代理並且激活它。

下一步,在 AppDelegate.swift 文件中添加如下擴展:

extension AppDelegate: WCSessionDelegate {
  func session(session: WCSession, didReceiveMessage message: [String : AnyObject], replyHandler: ([String : AnyObject]) -> Void) {
    if let reference = message["reference"] as? String, boardingPass = QRCode(reference) {
      replyHandler(["boardingPassData": boardingPass.PNGData])
    }
  }
}

這裡實現了 WCSessionDelegate 方法負責接收消息。從手表傳過來的字典中提取航班信息,之後用 Alexander Schuch 寫的牛逼的 QRCode 庫來生成二維碼,如果生成成功,調用回調函數,傳遞圖片信息到手表 app。

最後,設置 session。添加如下代碼到application(_:didFinishLaunchingWithOptions:) 方法中:

if WCSession.isSupported() {
  session = WCSession.defaultSession()
}

這裡確保支持 Watch Connectivity ,之後設置 session 為框架提供的默認的 WCSession 單例。

你現在能夠與 iPhone app 進行雙向對話了。

編譯運行。按照如上步驟來登記航班然後查看登機牌。這次登機牌應該等段時間之後才能出現:

r43r2.gif

祝賀!你已經完成了使用 Watch Connectivity 向 iPhone app 請求登機牌;棒極了。

下一步做什麼?

這是系列教程的完整示例項目

在本教程中,你學習如何在 watch app 和配對的 iPhone app 間發送實時消息,如何在兩個設備間傳遞圖片信息。

如果你喜歡這個系列想要更多的學習關於 watchOS 2 開發知識,來看看我們的 watchOS 2 by Tutorials 書,它會教你很多開發 watchOS 2 apps 的技巧。

系列閱讀:

watchOS 2教程(一):開始吧

watchOS 2 教程(二):列表

watchOS 2 教程(三):動畫

watchOS 2 教程(四): Watch Connectivity(本篇)

  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved