Apple Watchのアプリを何も分からんけどリリースしてみた話

2023/09/02に公開

前置き

  • 以前からスマホアプリ以外のアプリを身近なデバイスで使いたいな〜と思っていた
  • Apple製品を比較的愛用しているのもあり、Apple Watchを購入したので、何か作ってみようと思った
  • しかしタイトルの通り、何も分からんからはじまったので、今後誰かの参考のために残すことに
  • どんな感じでリリースしたかの前に、前提知識として以降、少しつらつら書いていきますので、そこは知ってるよ!という方は読み飛ばしていただければと思います。リリースの対象アプリは以降で説明しているいわゆるiPhoneと連携するタイプとなります
  • また、iOSアプリのリリース経験がある方向けとなります

Apple Watchアプリのタイプ

そもそもApple Watchのアプリは大きく2タイプあります。

タイプ1. 独立して動作するタイプ

こちらは分かりやすい方のタイプで、iOSアプリ同様、Apple Watch上で独立して動作するアプリとなります。
しかし、購入者にとってはご存知の通り、Apple Watchには携帯電話通信機能の有無がモデルによって異なる(GPS+Cellular/GPSのみ)という特徴があります。これは利用者の環境がインターネットに直接アクセスできるかできないかという大きな違いがあるため、もしこちらのタイプでアプリを作るとしたら、以下の2パターンで作ることになるのかなと思っています。

  1. ネット環境不要で動くアプリ
    • watch上で動くゲーム
    • センサーを利用した可視化アプリ
    • GPSを利用した何かしらのアプリ
  2. ネット環境を考慮されているアプリ
    • iPhoneアプリっぽいもの

タイプ2. iPhoneと連携するタイプ

こちらのタイプは、iPhoneが近くに存在すれば、iPhone⇔Watch間でデータのやりとりができるため、iPhoneと連携を前提としたアプリとなります。

実際にApp Storeのストアで色々ダウンロードしてみると分かりますが、iPhone側のWatchアプリで、インストール済みのアプリなどを見てみると、
タイプ1はこういった表示
独立して動作するタイプ
タイプ2はこういった表示になっているのかなと思ってます。
iPhoneと連携するタイプ

リリース(App Store申請)時のApple Watchアプリの扱い

WatchOS = iOSプラットフォームとして扱われます。
これは実際にApp Store Connectを触ってみると、普通に書いてあります。

要は、iOSアプリをリリースしたことがある人にとっては、同じノリでリリースできるということを意味しています。(多分)
リリース前は、Watchアプリは独立して別に申請したりするのかな?と思っていました。
しかし実態としては、iOSアプリとして扱い、連携するiOSアプリ+Watchアプリを同時に申請するような形となっていました。

前提知識は以上となります。
前置きの最後として、今回リリースするにあたって、どういったアプリに対して連携するものを作ったかを参考に載せておきます。

今回のリリースアプリについて

既にリリースしている、シンプルな買い物メモアプリを対象としました。

このアプリでは買い物のメモ(じゃがいも、牛乳 など)をリストに上げて、買い物中にリストのものをカゴへ入れたらリストから削除する。みたいな使い方を想定しています。
ただ、スマホ持ちながらだとちょっと不便と感じることもあったので、以下のようにできたら利便性が上がりそうと考え、Apple Watchアプリ制作の対象に決めました。

  1. iPhoneで買い物リストを作成
  2. Apple Watchで買い物リストを閲覧
  3. Apple Watch上で、買い物リストから削除

開発環境

  • Flutter3.10.5
  • Dart3.0.5

Apple Watchアプリ対応

WatchOS対応アプリの作り方自体は、先人の方々の記事がたくさんあるので、そちらを参考にしました。
私の場合は以下のnoifujiさんの記事を参考にさせていただきました。(感謝感謝です!🙏)
Watch OSアプリと連携するFlutterアプリの作り方

実装について

既にアプリが存在し、Watchアプリの部分だけ作成する場合、ポイントだけ書くと以下の通りです。

  1. Flutter
    a. flutter_watch_os_connectivityflutter pub addする
    b. Watch側へMap型でデータを渡す

    bool isReachable = await _flutterWatchOsConnectivity.getReachability();
    
    if (isReachable) {
      var sendMap = Map<String, String>();
      for (var i = 0; i < _hogeList.length; i++) {
        sendMap[i.toString()] = "hogehoge";
      }
    
      await _flutterWatchOsConnectivity.sendMessage(sendMap);
    }
    

    c. 受信もMap型で

    _flutterWatchOsConnectivity.messageReceived.listen((message) async {
      final recieveData = message.data; // Map<String, String>
      final item = recieveData['hoge']; // Map<String, dynamic>
      // TODO: なんかする
    });
    
  2. Xcode
    a. 確認用のシミュレータをインストールする
    b. watchOSのAppをExisting iOS Appとして作成する(独立して動くタイプだと、ここでNew Companion iOS Appとして作成しそう)

  3. Swiftベースのコードで以下をうまく使ってデータのやり取りをする
    a. データ受信

    func session(_ session: WCSession, didReceiveMessage message: [String : Any]) {
      print("didReceiveMessage: \(message)")
    
      for item in message.keys.sorted() {
        // TODO: なんかする
      }
    
      // 再描画
      DispatchQueue.main.async {}
    }
    
    1. データ送信
    func send(message: [String : Any]) {
      if WCSession.default.isReachable {
        WCSession.default.sendMessage(message, replyHandler: nil, errorHandler: nil)
      }
    }
    

    Swiftのコードを自分は書けなかったのですが、Xcode側でpreviewとして表示しつつ、コード自体はVSCodeを用いて、GitHubCopilotを活用することで、難なく実装ができました❤️

リリースについて

Archive周り

基本的にはiOSアプリのリリースと同じでした。
自分が引っかかったものは以下の箇所でした

  1. iOS側とwatchOS側のバージョンビルドナンバーを一致させる
  2. Build Settings > Architectures > Supported PlatformswatchOSにする
  3. Display Nameを短めに設定。
    設定しないとこういうダサい感じになる
  4. ArchiveはRunnerを選択した状態でOK(watchOS Appを選択しても同じっぽい?)

申請周り

スクショはiOSアプリと違って、Ultraのサイズだけ作成してアップロードすれば、全て他のサイズもカバーしてくれそうでした。
注意点として、角の丸みを考慮して作成する必要性があります。

アップロード後にビルドを選択し、含まれるアセットにAppアイコンApple Watchが表示されてると大丈夫そうです!

感想

  • スマホで動くのと違ってまた違う感動!
  • 他にも何か作ってみたいなーと思う一方、Android側はどうしようかが悩みどころ……

Discussion