watchOS Watch Connectivity

# はじめに

この記事は、岩手県立大学アドベントカレンダー2016 10日目の記事です。

watchOSアプリを改修するにあたりwatchOS 1で利用可能だったフレームワークのいくつかがwatchOS 2やwatchOS 3で利用不可能だということに気づきました。
例えば、SystemConfiguration.frameworkやCFNetwork.frameworkなどです。

これらのフレームワークの機能を使う方法を考えました。

# Watch Connectivity

Watch Connectivity framework(WatchConnectivity.framework)は、iPhone(iOSアプリ)とApple Watch(watchOSアプリ)の間でデータの送受信を提供します。
データの送受信をOSが決めるBackground transfersとデータをすぐに転送するInteractive messagingがあります。

# 実装

今回は、Interactive messagingを実装します。
実行環境は以下のとおりです。

* Xcode 8.1
* iPhone 7(iOS 10.1.1)
* Apple Watch(watchOS 3.1)

watchOS側の実装は以下のようになります。

```swift:InterfaceController.swift
import WatchKit
import Foundation
import WatchConnectivity

class InterfaceController: WKInterfaceController, WCSessionDelegate {
    override func awake(withContext context: Any?) {
        super.awake(withContext: context)
    }
    
    override func willActivate() {
        super.willActivate()
        
        if WCSession.isSupported() {
            // Watch Connectivityをサポートしているとき
            let session = WCSession.default()
            session.delegate = self
            session.activate()
            if session.isReachable {
                // iPhoneと通信可能のとき
                session.sendMessage([:], replyHandler: {(replay) -> Void in
                    
                    let buttonAction = WKAlertAction(title:"OK", style: .default) { () -> Void in
                    }
                    self.presentAlert(withTitle: "タイトル", message: replay.description, preferredStyle: .alert, actions: [buttonAction])
                }){(error) -> Void in
                    print(error)
                }
            }
        }
    }
    
    override func didDeactivate() {
        super.didDeactivate()
    }
    
    func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {
    }
   
}
```

次にiOS側の実装です。

```swift:AppDelegate.swif
import UIKit
import WatchConnectivity

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, WCSessionDelegate {

    @available(iOS 9.3, *)
    public func sessionDidDeactivate(_ session: WCSession) {
    
    }

    @available(iOS 9.3, *)
    public func sessionDidBecomeInactive(_ session: WCSession) {
        
    }

    var window: UIWindow?


    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        if WCSession.isSupported() {
            let session = WCSession.default()
            session.delegate = self
            session.activate()            
        }        
        return true
    }

    func applicationWillResignActive(_ application: UIApplication) {
    }

    func applicationDidEnterBackground(_ application: UIApplication) {
    }

    func applicationWillEnterForeground(_ application: UIApplication) {
    }

    func applicationDidBecomeActive(_ application: UIApplication) {
    }

    func applicationWillTerminate(_ application: UIApplication) {
    }

    func session(_ session: WCSession, didReceiveMessage message: [String : Any], replyHandler: @escaping ([String : Any]) -> Void) {
        if session.isReachable {
          // Apple Watchに結果を送信する
          replyHandler(["Hello":"World"])
        }
    }
    
    func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {
    }
}
```

# 実行結果

watchOSアプリを起動します。

![スライド45.jpg](https://qiita-image-store.s3.amazonaws.com/0/3862/f55627fc-0558-7bb0-80e0-15b57b17b5e9.jpeg)


アラートが表示されデータが送受信できたことがわかります。
このときiOSアプリは起動していなくてもデータの送受信可能です。

この仕組みを使えばwatchOSで用意されていないフレームワークの機能をiOSアプリで処理してwatchOSアプリに結果を渡すことができそうです。