🌤️

Apple WeatherKit を使ってお天気 Mac アプリを作った

2022/07/18に公開

はじめに

WeatherKit 使って自分用にお天気情報アプリを作ったので、適当な備忘録になります。
ついでに SwiftUI / Combine も初めて。

梅雨時に作ったので・・・画面映えしない・・・。

準備編

  • Apple の Certificates, Identifiers & Profiles Identifiers -> Capabilities で WheatherKit を有効にする

  • Signing & CapabilitiesApp Sandbox -> Incoming Connections(Sever) / Outgoing Connections(Cliet) にチェック入れる(Mac アプリのみかも

Location にチェックしているのはアプリの方で現在地の天気を計測する機能を実装している為であり、必須ではありません

Apple DeveloprForm に投稿してくれてました。私もハマったので助かりました!
サンキュー海外ニキ!
https://developer.apple.com/forums/thread/708019

実装編

実装は正直、ほとんどサンプル通りに作っただけですね・・・。
sample : https://developer.apple.com/documentation/weatherkit/fetching_weather_forecasts_with_weatherkit

一応コード書いておきます。
でも、サンプルの WeatherData でいいと思う・・・。

@MainActor
final class WeatherRepository {
    private let service = WeatherService.shared
    
    @Published var currentWeather: CurrentWeather?
    @Published var dailyForecasts: Forecast<DayWeather>?
    @Published var hourlyForecasts: Forecast<HourWeather>?
    
    @discardableResult
    func weather(location: CLLocation) async -> CurrentWeather? {
        let currentWeather = await Task.detached(priority: .userInitiated) {
            let forcast = try? await self.service.weather(
                for: location,
                including: .current)
            return forcast
        }.value
        self.currentWeather = currentWeather
        return currentWeather
    }
    
    @discardableResult
    func dailyForecast(location: CLLocation) async -> Forecast<DayWeather>? {
        let dayWeather = await Task.detached(priority: .userInitiated) {
            let forcast = try? await self.service.weather(
                for: location,
                including: .daily)
            return forcast
        }.value
        self.dailyForecasts = dayWeather
        return dayWeather
    }
    
    @discardableResult
    func hourlyForecast(location: CLLocation) async -> Forecast<HourWeather>? {
        let hourWeather = await Task.detached(priority: .userInitiated) {
            let forcast = try? await self.service.weather(
                for: location,
                including: .hourly)
            return forcast
        }.value
        self.hourlyForecasts = hourWeather
        return hourWeather
    }
}

weather function

CurrentWeather を取得できます。現在の天気情報ですね。

dailyForecast function

日次の天気情報を取得できます。
(今回は使ってないです)

hourlyForecast function

時間ごとの天気情報を取得できます。

まあ、実装はこれだけですね。あとは各 Publisher を sink しておけばいいです。
WeatherKit の実装自体はサンプル通りに作れば特に問題ないかと思います。

おまけ

天気の状態を表す WeatherCondition はとても細かく状態を表してくれます。今回、私のアプリではもうちょっと大雑把でも良かったので、 Translator をかまして粒度を大きくしました。
それと Apple が提供する Weather のデータには isDaylight というプロパティもあるので、これを使って昼夜みたいな分岐も用意しました。

// 自作アプリで使う Condition みたいな感じ.
enum WeatherType {
    case fine
    case fineNight
    case partlyCloudy
    case partlyCloudyNight
    case rain
    case cloudiness
    case heavyRain
    case snow
    case heavySnow
    case tropicalStorm
    case thunderStorm
}
struct WeatherConditionTranslatorInput {
    let condition: WeatherCondition
    let isNight: Bool
}

struct WeatherConditionTranslator: Translator {
    func translate(_  input: WeatherConditionTranslatorInput) -> WeatherType {
        switch(input.condition) {
        case .clear: return input.isNight ? .fineNight : .fine
        case .mostlyClear: return input.isNight ? .fineNight : .fine
        case .cloudy: return .cloudiness
        case .mostlyCloudy: return .cloudiness
        case .partlyCloudy: return input.isNight ? .partlyCloudyNight : .partlyCloudy
        case .rain: return .rain
        case .drizzle: return .rain
        case .freezingDrizzle: return .snow
        case .heavyRain: return .heavyRain
        case .freezingRain: return .heavyRain
        case .sleet: return .snow
        case .snow: return .snow
        case .blowingSnow: return .heavySnow
        case .heavySnow: return .heavySnow
        case .tropicalStorm: return .tropicalStorm
        case .strongStorms: return .tropicalStorm
        case .thunderstorms: return .thunderStorm
        default: return .cloudiness
        }
    }
}

ご紹介

技術書典で Flutterで作るアプリとゲームの融合 〜電卓騎士の開発Tips〜 を公開しています。
この書籍は Flutter でのちょっと変わった電卓の Tips を色々記載しています。無料ですので良かったら DL してください。

アプリ自体も無料で公開しています。

Discussion