最近作ったアプリの話



先日、コナミ社の提供しているコナステのダウンロードコンテンツゲームを1クリックで起動できるアプリを作り、公開した。

Ks Game Launcher (Github)

作った理由として、インストール時に作成されたショートカットをクリックするとブラウザが起動し、ログインしていたらそこから起動ボタンを押して初めてクライアントのランチャーが立ち上がる……という起動方法がイマイチに感じたため。

また、過去に似たような理由(とサブ垢切り替えが面倒だったため)で作ったことがある拙生作 TSLoginManager と同等の仕組みで実装できると考えたため。また、久しぶりにクライアントアプリの開発言語を触りたかったから、というのもある。


今回は作ったときのメモとして、どんなことをやったか、どんな経緯だったかをこの記事に残してみる。メモなのでまとまっていない書き方になっている点はご容赦を。


昔話

.NETもC#もWindows Formsアプリも、実に10年ぶり。

TSLoginManager 開発当時は、開発コードのバージョン管理もしておらず、Githubの存在もあとから知って登録しつつも、Git自体をおそらく理解しておらず、ただただ自分の環境で作っていた。もしかしたらSubversionくらいは使っていただろうか。しかしもう記憶にない。

当初コードは公開していなかった。アカウントを管理する機能を持っていて、いくらかセキュリティを担保しなければならない認識はあったが、その作りは大変稚拙であった。

.NETなので、dnSpy、ILSpyなどのスパイツールを使えばデコンパイルしてコードを読むことができるが、そこまでする人は少ないだろうと考え、非公開にしておく方がリスクは少ないと思っていた。

しかし現在は基となるサービスも終了し、その役目を終えたと思っているため、現在は公開している


Ks Game Launcher

Ks Game Launcherという名前がTSLoginManagerに似ているのは単に私のセンスの問題である。はじめは "Konaste Game Launcher" としていた。しかし "コナステ" の名称はコナミ社の商標であり、製品名に勝手に使って良いものではない。
また、できる限り汎用性を持たせて作りたいが、元々特定のサービスに依存したものとなる為、その名称を含めない現在の名称を名乗ることにした。

基本機能について

アカウントの管理

メイン機能の一つとなるアカウントの管理。利用者の大切なアカウントを預かるため、雑な管理はできない。どのように管理するか悩みつつ探ってみると、Windows OSにはmacOSやiOSでいうキーチェーンのように認証情報を管理する機能、「資格情報マネージャー」があることを知った。ここに各アプリケーションで利用する認証情報を安全に保存できるため、こちらを利用することにした。保存されたアカウントのポータビリティについてはここでは考えない。

また、インストール型ゲーム、基本的に据え置き環境であるという性質上、ログインしているアカウント内のみで利用できることを想定し、共有PC環境での利用までは考慮しない。基本的に管理される範囲はOSの資格情報マネージャーに委託する。

ゲームの列挙

インストールされているゲームの列挙は、レジストリの特定の項目を確認することでできる。が、ここから取得できる情報も限られること、各ゲームごとに固有の設定情報、参照情報を持たせたいため、アプリ側にリストを持つようにした。
ただしそれをアプリの内部に持たせてしまうと、対象ゲームが追加された際にアプリ自体を更新しなければならなくなる。そのため、設定を完全に外に出し、初回起動時(ファイルがローカルに存在しない場合)にサーバーに取得しに行く方式にした。現在このリストファイルは静的ファイルを取得しているだけだが、動的管理、新規ゲームの追加に対応させるなどしてもいいかもしれない。

また、このリストのアップデートのメンテナンスも継続しなければならないとなると、後々私が開発に飽きてきたときに使えなくなってしまうため、ユーザー側で対象となり得るゲームの追加して扱える様に実装した。

OTPと二段階認証の話

コナミアカウントにはワンタイムパスワード(OTP)と二段階認証(便宜的に2FAと呼ぶ)の設定がある。どちらも似ているが性質(使い方)がやや異なる。

OTP

ログイン時に別途購入したハードウェアまたはソフトウェアトークンから発行された数桁の番号を入力してログインする。認証タイミングは通常ログインと同じタイミングで行われる。

2FA

ログイン認証後、新規デバイスあるいはログインから一定期間経過後のデバイスに対して、2つ目の認証を設ける。これはアカウントに紐付いたメールアドレス宛に数桁の数値を送り、それを入力させる。これによって登録メールアドレス所有者とログインを行う者が同一人物である事を認証しているようだ。

どちらも似て非なるものだが、認証時に発生するものである。
前者はオプションでログイン実行時に必ずダイアログを表示し、コードを入力させる。
後者はログイン試行後、アカウント認証フローから抜け出さず、コード入力を促されている場合にそのコードを入力させるダイアログを表示し、コードを入力させるようにした。

具体的には、アカウント認証後に通常はコンテンツページへ遷移するが、そこに遷移せず、アカウント認証ドメインFQDN内に留まり、所定のフォームが出力されているか否かを確認している。
この処理についてはコナミアカウント側での設定の存在を認識しつつも、自分のアカウントの使い勝手が悪くなること、そこまでセキュリティ要件を高める意味があまりない(使い方をしていたため)ことを理由に、検証、実装をサボってた。

ver1.0.0公開直後にこの問題についてのIssuesが飛んできたため、対応した。そりゃそうだよなぁ、身元不明のアプリにアカウント情報渡すなんて怖いし。

自動アップデートの話

可能ならソフトウェアを作りっぱなしで終わりにしたかった。
しかし色々足りておらず、結局アップデートが必要になる。アップデートの通知をする仕組みは以前は自前で実装し、運用していた。
また時前で定義して実装するのも面倒なので、macアプリでよく見かけるアップデート通知とインストールを促してくれるアレ(Sparkle)が.NETアプリでも使えないかなと探しているといくつか候補が見つかった。WinSparkleNetSparkleUpdater、そしてAutoUpdater.NET
このなかでAutoUpdater.NETを今回は活用することにした。理由としては単純で、ドキュメントを見て実装がとてもシンプルにできそうだったから。
どの製品もSparkleをリスペクトしたものなっていて、基本的にはSpakleでも採用されているRSSを使用したバージョン定義になっている。が、AutoUpdater.NETはちょっと異なりそう。

その他機能について

多言語対応

主に日本国内で遊ばれるゲームなので基本的には日本語だけでも問題ない。が、実は国外のユーザーでも結構ファンが多い。公式にはおそらく日本と韓国向けに提供されている。韓国語は分からないため、翻訳ツールで翻訳しても良いが、訳が正しいことを確認できないこと、日韓以外にも想定ファンやユーザーはいることから、まずは日本語と英語で対応。
その後それぞれの言語話者が必要に応じて翻訳してくれたら良いな。と、浅はかに妄想している。

翻訳者が翻訳しやすい環境を準備する

貢献者によって翻訳し、多言語対応させたい場合、Crowdinなどを使って簡単に翻訳が行える様に環境を整える方が良い。が、現状できていない。このアプリについても、そこまでの需要も現時点ではあまり感じられていない。

カスタムURLによる起動

「ゲームをワンクリックで起動できるようにする」が本来の目的ではあるが、ベースランチャーアプリであるが故に2クリックせねばならず、ワンクリック起動できていない。
そこで、各ゲームがインストール後に作成するゲームアイコンのショートカットを書き換えてワンクリック起動できればと考えた。それが「インターネットショートカット」と「カスタムURL」を使用した起動方法。
カスタムURLとはいうが、厳密にはOSに独自のスキーマを定義し、特定のアプリケーションを起動するようにする仕組みである。アプリで言ういわゆるディープリンクというものである。
アプリからOSに ksgamelauncher:// でこのアプリを起動するという情報をレジストリに登録することで、アプリを直接コールできるようにする。この引数で起動するアプリケーションを決定する。

カスタムURIで呼び出されると、アプリは

呼び出し先アプリパス.exe custom-scheme://any-string-of-uri-path

といった具合でコールされるため、アプリ側は引数のパーサーを書いてそれぞれ処理すれば良い。
パースされた中から起動するゲームを確定し、それを呼び出すようにする。


ログイン方法とセッション管理

ログインフローは、人間がブラウザで行うことをそのまま単に自動化したまでとなる。図で示すとこのようになる
目に見える形で自動化すると、このGistに書いたような動作となる。このGistではWindows 10で使用できるMicrosoft Power Automateを使用して同じ動作を作っている。こちらを使う方が動作が見えるためある程度安心できると思うが、複数ゲームで遊ぶ場合はそれぞれごとに作らなければならないのがやや面倒。またログインセッションが切れた際には手動で対応する必要が今のところある。

ログイン後のセッションについては、初期段階では維持していなかったが、1.0.1以降はユーザーデータとして保持し、極力再利用するようにした。



遭遇した問題点

カスタムURLから起動したときに起動元スレッドの問題で苦労した話


カスタムURLからの起動時は、アプリのUIなどを一切表示せずバックグラウンドですぐにログイン処理にまわすのだが、ログイン処理ではHTTP通信を行う為、非同期処理となる。非同期処理に入るとメインスレッド上で実行されたそれは、結果を待たずに終了してしまい、起動しないままとなってしまう問題があった。

回避するためにはメインスレッド上で実行しないことしかなく、本来は行いたくなかったが、カスタムURLから起動した際は、UIスレッドを一度起動し、ログイン処理を継続、完了後に即終了するという挙動で実装することにした。
この関係で、UIスレッドが起動したタイミングで一度タスクバーにアプリアイコンが表示されることになった。

WPFを知ったけど諦めた話

今回はWindowsFormsアプリとして作成した。モダンなWindowsアプリの場合、WPF(Windows Presentation Foundation)として作成し高DPIにも対応し、フォームのレイアウトもある程度自由に作る事ができる。
本来であればこの形式で作るべきだったが、作り始めたタイミングでWPFを選択せずに始めてしまったため、この移行にコストがかかること、そこまでの重要性が見いだせなかったため諦めることにした。

最近作ったアプリの話

先日、コナミ社の提供している コナステ のダウンロードコンテンツゲームを1クリックで起動できるアプリを作り、公開した。 Ks Game Launcher  ( Github ) 作った理由として、インストール時に作成されたショートカットをクリックするとブラウザが起動し、ログインし...