Help us understand the problem. What is going on with this article?

Apple Watchで最寄り駅を取得する

More than 1 year has passed since last update.

はじめに

昔最寄り駅を取得するAPIを作ったんですけど、割と応用範囲が広そうなので今日届いたApple Watch Series 3で最寄り駅を取得するアプリを作ってみました。

蛇足ですが最寄り駅を取得するAPIの初版を作った時のセッションを貼っておきます。オタク特有の早口
https://youtu.be/zJ92TUjhdEw?t=15780

最寄り駅クソAPIについて

https://sapi.tinykitten.me/
でホストしてます。
Swagger
https://sapi.tinykitten.me/swaggerui
GitHub
https://github.com/TinyKitten/StationAPI
どうでもいいけどgoaで作ってます。goとgoaはいいぞ。

リポジトリ

こ↑こ↓
https://github.com/TinyKitten/NearStationSwift

実装

プロジェクト作成

これはポチポチするだけです。猿でもできます。いや猿に失礼か。
スクリーンショット 2018-10-27 1.10.16.png
スクリーンショット 2018-10-27 1.10.24.png

Info.plistに位置情報許可の設定を追加

まずiOS App側とWatchKit Extension側のInfo.plistに「Privacy - Location When In Use Usage Description」を追加してください。
スクリーンショット 2018-10-27 1.04.53.png
っていうかこれを知らない人はこの記事あまり読むとは思えないんですけど。

位置情報を取得する共通コードを書く

書くって言いながら借りパクですけど

【Swift 3】Apple Watchで位置情報取得して表示する

こちらの記事のLocationManager.swiftをお借りしました。謝謝。
今回はCommonグループの中に突っ込みました。
スクリーンショット 2018-10-27 1.07.24.png
ファイルを開いて右パネル(インスペクタ)のTarget MembershipにiOSアプリプロジェクトとWatchKit Extensionプロジェクトのチェックボックスをオンにしておかないと「あんたはうちのファイルではありません!」と親に捨てられたときのような悲しみを味わうことになるかと思うので忘れずに変えておいてください。
スクリーンショット 2018-10-27 1.07.44.png

最寄り駅を取得する共通コードを書く

Network.swift
//
//  Network.swift
//  NearStation WatchKit Extension
//
//  Created by TinyKitten on 2018/10/25.
//  Copyright © 2018 TinyKitten. All rights reserved.
//

import Foundation
import RxSwift
import Alamofire

class Network: NSObject {
    func getStation(lat: Float, lon: Float) -> Observable<[String: Any]> {
        return Observable.create { observer in
            let urlTemplate = "https://sapi.tinykitten.me/v1/station/near?lat=%f&lon=%f"
            let url = String(format: urlTemplate, lat, lon)
            Alamofire.request(url)
            .responseJSON(completionHandler: { res in
                if res.data != nil && res.error == nil {
                    let json = try! JSONSerialization.jsonObject(with: res.data!, options: JSONSerialization.ReadingOptions.allowFragments)
                    observer.onNext(json as! [String : Any])
                } else {
                    observer.onError(res.error!)
                }
            })
            return Disposables.create()
        }
    }
}

ひゃー。なんとも手抜き。
RxSwiftAlamofireを使ってます。ほんとはWebSocketを使いたかったんですけどそこまで凝視することもないだろうしwatchOS対応が怪しそうだったのでHTTPで通信することにしました。SwiftyJSONはなんか非対応っぽかったので使ってません。

iOS側コードを実装

iOS側で位置情報を許可しないとWatchでも位置情報取れない?みたいなので先にiOS側で最寄り駅を表示するコードを書いちゃいましょう。

ViewController.swift
//
//  ViewController.swift
//  NearStation
//
//  Created by TinyKitten on 2018/10/25.
//  Copyright © 2018 TinyKitten. All rights reserved.
//

import UIKit
import CoreLocation

class ViewController: UIViewController {

    @IBOutlet weak var stationNameLabel: UILabel!

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        LocationManager.Singleton.sharedInstance.startUpdatingLocation()

        let center = NotificationCenter.default
        center.addObserver(self,
                           selector: #selector(type(of: self).fetchStation(notification:)),
                           name: NSNotification.Name(rawValue: LMLocationUpdateNotification),
                           object: nil)
    }


    @objc func fetchStation(notification: Notification) {
        let infoDic: Dictionary = notification.userInfo!
        let location: CLLocation? = infoDic[LMLocationInfoKey] as? CLLocation
        let coordinate = location!.coordinate

        let lat = (coordinate.latitude.description as NSString).floatValue
        let lon = (coordinate.longitude.description as NSString).floatValue

        Network().getStation(lat: lat, lon: lon)
            .subscribe(
                onNext: { data in
                    let white = UIColor(red: 255.0, green: 255.0, blue: 255.0, alpha: 1.0)
                    self.stationNameLabel.textColor = white
                    let stationName = data["station_name"] as! String
                    self.stationNameLabel.text = stationName + "駅"
            },
                onError: { error in
                    let red = UIColor(red: 255.0, green: 0.0, blue: 0.0, alpha: 1.0)
                    self.stationNameLabel.textColor = red
                    self.stationNameLabel.text = "エラーが発生しました"
            }
        )
    }
}

位置情報が変わったらリクエストしに行って表示を書き換える感じですね。
Storyboardはこんな感じ。ただ出すだけ。
スクリーンショット 2018-10-27 1.24.03.png
実際デバッグしてみるとこうなるかと。
IMG_1524.PNG
やったぜ。

Apple Watch側で最寄り駅を表示する

iOSで表示できればもうApple Watchでもそんなに変わりはありません。

InterfaceController.swift
//
//  InterfaceController.swift
//  NearStation WatchKit Extension
//
//  Created by TinyKitten on 2018/10/25.
//  Copyright © 2018 TinyKitten. All rights reserved.
//

import WatchKit
import Foundation

class InterfaceController: WKInterfaceController {

    @IBOutlet weak var stationNameLabel: WKInterfaceLabel!

    override func awake(withContext context: Any?) {
        super.awake(withContext: context)

        // Configure interface objects here.
        self.stationNameLabel.setAttributedText(NSAttributedString(string: "読み込み中...", attributes: [NSAttributedString.Key.font: UIFont.systemFont(ofSize: 24.0, weight: UIFont.Weight.bold)]))

        LocationManager.Singleton.sharedInstance.startUpdatingLocation()

        let center = NotificationCenter.default
        center.addObserver(self,
                           selector: #selector(type(of: self).fetchStation(notification:)),
                           name: NSNotification.Name(rawValue: LMLocationUpdateNotification),
                           object: nil)
    }

    override func willActivate() {
        // This method is called when watch view controller is about to be visible to user
        super.willActivate()
    }

    override func didDeactivate() {
        // This method is called when watch view controller is no longer visible
        super.didDeactivate()
    }

    @objc func fetchStation(notification: Notification) {
        let infoDic: Dictionary = notification.userInfo!
        let location: CLLocation? = infoDic[LMLocationInfoKey] as? CLLocation
        let coordinate = location!.coordinate

        let lat = (coordinate.latitude.description as NSString).floatValue
        let lon = (coordinate.longitude.description as NSString).floatValue

        let net = Network()
        net.getStation(lat: lat, lon: lon)
            .subscribe(
                onNext: { data in
                    let stationName = data["station_name"] as! String
                    let white = UIColor(red: 255.0, green: 255.0, blue: 255.0, alpha: 1.0)
                    self.stationNameLabel.setTextColor(white)
                    self.stationNameLabel.setAttributedText(NSAttributedString(string: stationName + "駅", attributes: [NSAttributedString.Key.font: UIFont.systemFont(ofSize: 24.0, weight: UIFont.Weight.bold)]))
            },
                onError: { error in
                    let red = UIColor(red: 255.0, green: 0.0, blue: 0.0, alpha: 1.0)
                    self.stationNameLabel.setTextColor(red)
                    self.stationNameLabel.setAttributedText(NSAttributedString(string: "エラーが発生しました。", attributes: [NSAttributedString.Key.font: UIFont.systemFont(ofSize: 24.0, weight: UIFont.Weight.bold)]))
            }
        )
    }
}

ちょっと変わってるのがテキストと色の書き換えが代入ではなくメソッドになっているのと、Storyboardで太文字にする方法が見当たらなかったのでコードで太文字にしているところです。
スクリーンショット 2018-10-27 1.28.13.png
\パン/ヨッシャwwwキタァァァァァァァアアアアアwwwwwwwwwww(高い声で)ウワヤッタァァァァァァアアアアアア

こんなもの作ってどうするんでしょうね。

おしまい。

編集履歴

  • 2018/10/28 サンプルプログラムにバグを発見したため修正
  • 2018/10/29 khskさんからの編集リクエストをマージしました卍 ををになっていた
Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away