推しのガチイベを応援するために星集め・捨て星のタイミングを通知してくれるツールを作った話

この記事は「もなふわすい~とる~む Advent Calendar 2021」x日目の記事です。(元は5日の週が空いていたので、当日まで埋まらなければ代打で投稿予定の記事だった。)


▽ 概要及び開発の経緯

我が唯一の推しである巻乃もなかさんがガチイベに参加した際には、応援したい気持ちから全枠3周フルを確実にこなすべく、公開されたタイムテーブルを参照して「星集め」と「捨て星」のタイミングをSlackリマインダーに登録しスマホから通知を受け取れるようにしてました。

※スマホから通知を受け取れるようにしておけば、常時装備しているAppleWatchからも通知を受け取れるようになるので失念する確率が大幅に減るため

とは言え、いちいちこれを手入力するのはぶっちゃけ結構手間です。
なので以下のようなツールを実装しました。

ちなみにこちらはFlutter on DesktopでmacOS向けに実装してます。
今回は幾つかの技術情報や選定理由などを備忘録ついでに解説していければと思います。

▼ 環境

[✓] Flutter (Channel stable, 2.5.3, on macOS 12.0.1 21A559 darwin-x64, locale ja-JP)
[✓] Xcode - develop for iOS and macOS
[✓] Android Studio (version 2020.3)

プロジェクトはGitHubで公開してます。
mao-test-h/flutter_gachieve_timetable_reminder

▽ 話すこと

  • Flutter on Desktopについて

  • 実装する上でのTips   

    • SlackAPIでリマインダーを登録するには

    • 設定の保存機能

  • 実装を終えて

    • Flutter on Desktopを触ってみた所感

    • 今後の課題

▽ 話さないこと

  • Flutter 基礎

    • プロジェクトの作成やビルド手順

    • 状態管理手法など

▽ Flutter on Desktopについて

こちらはFlutter 2系統からサポートされた新機能であり、ざっくり言えば「Flutterでデスクトップアプリ」を作成することができます。

Flutter on Desktop

私自身、今までこういった簡単なマルチプラットフォーム向けのGUIツールを実装する際にはUnity(with C#)などを用いて実装することが多かったのですが、今回は技術評価も兼ねて触ってみることにしました。

▼ 有効にするには

Flutter on Desktopは現時点ではまだβリリースの機能であり、デフォルトでは有効にはなっておりません。
有効にするには以下のコマンドを実行する必要があります。

# macOS
$ flutter config --enable-macos-desktop

# Windows
$ flutter config --enable-windows-desktop

# Linux
$ flutter config --enable-linux-desktop

他にもWindowsの場合にはVisual Studio 2019及び“Desktop development with C++”と言ったコンポーネントが必要だったりと、OS毎に一定の要件も求められます。(macOSの場合にはモバイルと同じ要件が求められるので、モバイルさえビルドできればそのままでも行けるはず)

詳細についてはドキュメントを御覧ください。
Desktop support for Flutter

※ macOSの注意点

macOS向けアプリにはデフォルトで幾つかの制約があり、例えば以下の機能を有効にしたい場合には権限を設定する必要があります。

  • インターネットアクセス

  • カメラの利用

  • ストレージアクセス

後者2つはまだしも、前者の「インターネットアクセス」は他のプラットフォームだと特に意識しなくても実行できる環境が多いので、ネットワーク通信を行うアプリは注意する必要があります。
macOS-specific support

▽ 実装する上でのTips

▼ SlackAPIでリマインダーを登録するには

SlackAPIからリマインダーを登録するには以下の「reminders.add」と言うAPIを利用します。

今回は”Required”と付いた必須パラメータ及び”user”だけを指定してリクエストを飛ばすようにしてます。(ちなみにトークンはPOSTリクエストのbodyでは無く、ヘッダーに入れて渡している。トークンの取得手順については後述)

  /// Slack APIのリクエスト
  Future<bool> _callSlackApi(String text, String timeStr) async {

        // JSON形式でリクエスト
    // Bearerトークンに渡している`_slackToken`にはAPIトークンが入る 
    final requestHeader = {
      HttpHeaders.contentTypeHeader: 'application/json ',
      HttpHeaders.authorizationHeader: 'Bearer $_slackToken',
    };

    try {
      // 通信モジュールにはdioを利用
      // https://pub.dev/packages/dio
      var dio = Dio();
      final Response<String> response = await dio.post(
        'https://slack.com/api/reminders.add',
        data: {
          'text': text,
          'time': timeStr,
          'user': _slackMemberId,
        },
        options: Options(
          headers: requestHeader,
        ),
      );

      var body =
          convert.jsonDecode(response.data.toString()) as Map<String, dynamic>;
      return body['ok'] as bool;
    } on DioError catch (e) {
      debugPrint(e.toString());
      return false;
    }
  }

例えばリクエストに以下のパラメータを渡すと、Slackには↓のように登録されます。

  • text : “もなふわテスト“

  • time : “yyyy-MM-dd HH:mm“

    • e.g. 2022-07-07 07:07

  • user : 自身のメンバーID

    • ※メンバーIDはSlackからプロフィールを開き、「その他」の項目から参照可能

2022年7月7日 AM7時7分に登録されている

※ Slack APIのトークンを取得するには?

リクエスト or ヘッダーに渡すトークンは api.slack.com からアプリを作成して取得する必要があります。

手順については記事の最後の「補足: Slack APIのトークン取得手順」と言う章に記載しているので、こちらを御覧ください。

▼ 設定の保存機能

経験上、もなふわすい〜とる〜むのタイテは日によって大幅に変わることは無く、連日同じタイテである可能性があります。

例として肉寿司イベのタイテを引用すると、10/26 ~ 11/2まで同じタイテであることが確認できる。

このことから前回入力したデータはそのまま使い回せると思い、入力情報を保存する機能を実装しています。

データの保存には shared_preferences がFlutter on Desktopでも活用できたので、こちらを利用してNSUserDefaultsに保存するようにしています。
(Unityユーザー向けに言うとPlayerPrefsみたいなもので保存していると思ってもらえれば良いかも)

  /// 保存
  Future onSave() async {
    // 入力されたデータをJSON形式で保存
    // → 日付などは`DateTime`型から文字列に変換している
    final lives = <JsonLive>[];
    for (var i = 0; i < _timeTable.length; ++i) {
      final live = _timeTable[i];
      final startLiveTimeStr = sendTimeFormatter.format(live.startLiveTime);
      lives.add(JsonLive(startLiveTimeStr, live.diffMinute));
    }


    final liveDateStr = sendTimeFormatter.format(_liveDate);
    final timeTable = JsonTimeTable(lives, liveDateStr);
    final jsonStr = convert.jsonEncode(timeTable.toJson());
    debugPrint('保存します: $jsonStr}');

        // JSONをそのまま文字列として保存している
    final prefs = await SharedPreferences.getInstance();
    prefs.setString(_persistenceKey, jsonStr);
  }

▽ 実装を終えて

▼ Flutter on Desktopを触ってみた所感

まだβリリースの段階ではありますが、触ってみた感じだと今回の範囲であれば普通に問題なく動いてくれたと言う印象はありました。

例えばこちらの記事を見るにまだパフォーマンス周りとかは評価はできない段階かもですが、逆に言うとそこまで気にしない開発用のツールと言った類のものなら導入も有りなんじゃないかな?とも思いました。

現にFlutterのhot reload/hot restartと言った機能はイテレーションの面では非常に強力なので、使って行きたさはあります。

ちなみに今回は以下のパッケージを導入してますが、どれも見た感じだとFlutter on Desktopに対応しており、そのまま活用することが可能でした。
(Dartで完結するパッケージならまだしも、shared_preferencesと言った明らかにネイティブに関わるプラグインも対応されているのは嬉しかった)

とは言え、恐らくは全部が全部対応されているわけではないかと思われるので、要件によっては自分でネイティブプラグインを書く必要もあるんじゃないかな〜とは思います。

▼ 今後の課題

これはアプリそのものの課題ですが、もし「これ自分も使いたい」と言う方が居たとした場合、どうやって公開すべきか?と言うのがあります…。
(今回は自分用に作ったと言うのが大きいので、そこまで公開を前提にしていない。あわよくば使いたい上でビルド出来るなら使ってねぐらい)

今回はデスクトップ向けで出力したが、Webアプリ向けに出してGitHub Pagesで公開とかがいいのかな…?


補足: Slack APIのトークン取得手順

Slack APIのトークンの取得手順についても纏めておく。
ほぼ以下の参考サイトの通りの手順通りだが、幾つか補足を加えつつ記載。
【Slack】APIトークンを取得する方法

※ちなみに2021-12-7 時点での情報となります。今後のSlackのアップデートで画面や手順などが変わるかもしれないのでご了承下さい。

1. Slack APIにアクセスし、アプリを作成

先ずはapi.slack.comにアクセスし、[Create an app]を開く。

するとリンク先で以下のダイアログが自動で表示されるので、[From scratch]を選択。

アプリ名とワークスペースの指定を求められるので入力すること。

今回は”monafuwa_test”で作成

2. APIをリクエストするのに必要な権限を設定

「Building Apps for Slack」が開かれたら、先ずは[Permissions]を開く。

※ ひょっとしたら「A new way to configure your app is coming」と言った感じに新規設定画面への切り替えをサジェストされるかもしれないが、この記事中では従来の設定画面ベースで解説していく。

リンク先に飛んだら「Scopes」までスクロールを行い、[User Token Scopes]側に今回必要なOAuth Scopeの追加を行う。

[Add an OAuth Scope]より追加可能

APIを叩くのに必要なスコープについてはAPIのドキュメントに記載されており今回利用する「リマインダーの追加」のページを見ると「Required scopes」には[reminders:write]が求められているのでこちらを追加。

3. ワークスペースにアプリをインストール

ここまで完了したら同ページ内にある「OAuth Tokens for Your Workspace」まで移動し、[Install to Workspace]を実行。

恐らくは許可を求める画面が開かれると思うので、そのまま許可することでワークスペースにアプリが紐付けられてトークンが手に入る。

こんな感じにトークンが手に入る。(黒塗りにしてます)

後はこちらの「User OAuth Token」をコピーして”slack_info.json”のtokenに入力すればOK。

この記事が気に入ったらサポートをしてみませんか?