Keycloak OIDCでの認証時に発生したCORSエラー。犯人はトレイリングスラッシュでした。

"Keycloak - Identity and Access Management for Modern Applications - Second Edition"を読んでいます。

邦題『実践Keycloak』の2nd Edition版ですね。

この本のChapter 2のワークを進める上で一瞬ハマりかけました。

エラーログを読んで冷静になったらすぐに解決できたのですが、理解のおさらいも兼ねて思考過程をメモしておきます。

Keycloakはもちろん、OAuth、OIDC、CORS等には入門したばかりなので、違うこと言ってる可能性がかなりあると思いますが、これも勉強のうちということで…。

利用したサンプルアプリケーションについて

本書で用意されていたサンプルアプリケーションについて前提整理のためにざっくり書いておきます。

概要

  • Node.jsで実装されたSPA
  • KeycloakをIdPとしたOIDC Authorization Code Flowを利用したユーザーログイン機能を実装
  • ログイン処理後、Keycloakより返されたID TokenやAccess Tokenを画面に表示できる
  • KeycloakにてClient登録済み
  • 登録したURL等は以下

想定される挙動(一部Keycloakのライブラリが内部的に実行していると思われる)

  1. サンプルアプリケーションにてログインボタンを押す
  2. KeycloakへAuthorization Code Requestが送られる
  3. Keycloakのログイン画面が表示される
  4. Keycloakでユーザーがログインする
  5. サンプルアプリケーションのValid redirect URIsとして登録した http://localhost:8000/にリダイレクト。パラメータにAuthorization codeを含む
  6. サンプルアプリケーションがAuthorization code含めたリクエストをKeycloakのToken Endpointに送信する
  7. KeycloakからID TokenとAccess Tokenがサンプルアプリケーションに返される
  8. サンプルアプリケーションはID TokenとAccess Tokenを画面に表示する

CORS policyによるアクセス拒否

サンプルアプリケーションの仕様ではログイン後に取得したID TokenやAccess Tokenが画面に表示されるはずが何も表示されませんでした。

ChromeのDeveloper Toolを開いてConsoleのログを見るとエラー文が。

Access to XMLHttpRequest at 'http://localhost:8080/realms/myrealm/protocol/openid-connect/token' from origin 'http://localhost:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

CORS policyでサンプルアプリケーションのオリジン(http://localhost:8000)からのリクエストが許可されてないとのこと。

Web originsは設定しているはずだが…

前述した想定される挙動の「5. サンプルアプリケーションがAuthorization code含めたリクエストをKeycloakのToken Endpointに送信する」にてエラーが発生していると思われます。

サンプルアプリケーションはフロントエンドのJavascriptによってリクエストを送信しており、リクエスト先であるKeycloakのCORS policyによってオリジンが許可されている場合のみリクエストが成功します。

そしてKeycloakではClientのWeb originsにて設定された値をAccess-Control-Allow-Originに追加する模様。

事前の設定で追加しているはずなんだが…

おや…?

おやおや…?

Web originsの設定値にトレイリングスラッシュが入っていた

http://localhost:8000/Web originsに登録していたが、よくよくエラー文を見てみるとorigin 'http://localhost:8000' has been blocked by CORS policy と書かれています。

そう。犯人は末尾の/

本書を読み返してみると、確かに文中ではWeb originsの値のみ末尾の/が記載されていませんでした。読み間違いやらかしてたー。

1つだけ弁明させてもらうと、本書に添付されていた設定画面のスクショでは/がしっかり入っている値が表示されているのです。少し罠だと思いました。

そしてWeb originsの値をhttp://localhost:8000へと修正したら見事解決。

ちなみに末尾の/は「トレイリングスラッシュ」というらしいです。

gmotech.jp

オリジンにトレイリングスラッシュは含まない

となるとオリジンの定義が気になるところなので調べてみました。

developer.mozilla.org

定義としては

Web content's origin is defined by the scheme (protocol), hostname (domain), and port of the URL used to access it. Two objects have the same origin only when the scheme, hostname, and port all match.

とのこと。これだけではトレイリングスラッシュを含むかどうか判断しにくいなと思いましたが、オリジンの例を見てみるとどれも末尾に/がなく、オリジンというものはトレイリングスラッシュを含まないみたいですね。

These are not same origin because they use different hostnames:

よくよく考えたら HTTP requestは以下のような形式なので、オリジンにトレイリングスラッシュが入ったらおかしなことになりそうではありますね。

GET / HTTP/1.1
Host: example.com

Valid redirect URIsはトレイリングスラッシュが必要

ちなみに、Valid redirect URIs の方は逆にトレイリングスラッシュ必須なの?というのが気になったので検証してみると、想定挙動の「2. Keycloakのログイン画面が表示される」にてエラーが発生したため必須ぽいです。

このときのKeycloakへのリクエストURLを見てみると以下のようになっていて、redirect_uriの値には末尾に/(エンコードされて%2Fになっている)が設定されていることがわかります。

http://localhost:8080/realms/myrealm/protocol/openid-connect/auth?client_id=myclient&redirect_uri=http%3A%2F%2Flocalhost%3A8000%2F&state=以下略

コード実装上では以下のようになっており、redirect_uriはKeycloakライブラリが設定している模様。

var kc = new Keycloak({ realm: 'myrealm', clientId: 'myclient' });
~~略~~
 <button onclick="window.kc.login()">Login</button>

ここでのredirect_uriはおそらくアクセス元から生成していて、トレイリングスラッシュをつけるようになっているのではなかろうか。そしてKeycloakのClientに設定した Valid redirect URIsに一致するものがあるかチェックしてる気がします。

(ライブラリのソースも少し読んでみたがすぐにはわからなそうで断念したので憶測です)

そもそもブラウザは基本、トレイリングスラッシュがないURLの入力には自動でトレイリングスラッシュをつけるらしく、Keycloakライブラリが設定するredirect_uriにトレイリングスラッシュがついてるのもそういう流れなのかもしれないですねえ。

webmasters.stackexchange.com

参考

育休中にスマホゲームを開発してストアにリリースした

現在絶賛育休中なのですが、育児の合間にスマホ向けゲームを開発し、Google PlayApple Storeにリリースしました。

本当にちょっとしたゲームなのですが、企画からデザイン、シナリオ、実装すべて自分でつくったオリジナルゲームです。

生まれてはじめてゲームのリリースに成功したので、せっかくなので色々と振り返ってみようと思います。

リリースしたゲーム

『Macaron 〜マカロンとの4日間〜』というゲームをリリースしました。

本当に拙いちょっとしたゲームなのですが、ゲームプレイ自体は5分くらいで終わるのでよかったら遊んでみてください。

App Store

apps.apple.com

Google Play

play.google.com

開発に利用した主なツール

デザイン

Figmaを使いました。

個人利用の範囲では無料で使えるというのが一番の理由です。ちょっとした趣味で課金するにはAdobe税はハードルが高かった。

Figmaは使ったことがなかったのですが、Youtubeにあるチュートリアルをやったりゲームデザインのトレースをしたりして、なんとか簡単なデザインは作れるようになりました。

便利だったのはプロトタイプ機能で、Unityでの実装前に基本的な画面遷移やアニメーションの動きを確認できたのはとても良い体験でした。

ゲームエンジン

Unityを使いました。

理由としては2Dスマホゲーム開発の手軽さと、昔ほんの1年ほど仕事で触っていたこともあり比較的知見があったためです。

なんでスマホゲームかは気分です。なんかこう、スマホゲームってこう、自分のアイテム感ありません?

そういう意味ではSwitchもいいなーと思ったのですが、趣味で気軽に開発して基本無料で出すならスマホかなーと。

シナリオ管理

Google Spreadsheetを使いました。

一番の理由は加筆編集が手軽だからです。API経由でシナリオ読み込みもできるので、編集をすぐに反映できるのも良いポイントです。

ちなみにUnityへのシナリオ読み込みは下記で書いたスクリプトを応用してます。 mich0w0h.hatenablog.com

どのくらい時間をかけたか

111時間、約100時間ですね。

内訳は以下

  • デザイン: 14%
  • シナリオ: 6%
  • 開発、及びリリース作業: 80%

なぜゲームをつくったのか

正直よくわかりません。

シンプルにいうと結局は「やりたかったから」です。

「やりたかったから」の中にごちゃっと混ざっているものを雑多に書いてみるとこんな感じでしょうか

  • 作ったものが動くのが楽しい
  • シェルスクリプトとかでなく、見た目が好みのやつがこう、いい感じに動くのが良いというか
  • 自分だけの箱庭。なんにも気にせず自分で要件から好きに作れて好きに壊していいし好きに直して良い、育てる感じがぐっとくる
  • 物語性があり「これを自分が作った」と言える作品のようなものを作りたい
  • 小説や漫画だとなんだかすごく恥ずかしくなってしまったり、煮詰まりすぎて手が動かなくなったりしてしまい、ゲームがちょうど良いのでは?と思ったり
  • 妊娠期間が調子ダメすぎてガチで全てのことに手がつかなかったのでその憂さ晴らし
  • ゲーム開発は仕事でやるには大変すぎるが趣味で手抜きしながらやるには長く楽しめて良さそうかも

完成させられた要因

ゲームなど創作系の作品って完成させるの本当に難しいのです。さまざまな障壁により途中でやる気を喪失してしまう。

もかしたら全然余裕でできちゃうよって人も多いかも知れませんが、自分は何度も挫折してます。

なので今後のためにも、今回はなぜ形だけでもストアにゲームをリリースできたのか?を整理しておこうと思います。

もちろん全てあくまで仮説です。

全てに共通することととしては「とにかく一にも二にもやる気を保つこと」です。

デザインから先に作った

自分はデザイン経験はほぼなく、実装の方が比較的経験があるので、直感的には実装ファーストで作るのが良い作戦のように思われますがこれは罠でした。

自分、いい感じのデザイン素材じゃないと動かしてもテンション上がらないのですよね。

以前いらすとや素材だけを使って実装ファーストで開発に取り掛かったことがあるのですが、全然気が乗らずにすぐにやめてしまいました。

なので、今回は頑張ってFigmaをイチから学んでデザイン先行でゲームを作ったのですが、この作戦が大当たり。

割りと気に入った手作りのデザイン素材があると動かしてみたくなるし、実際に動くとものすごくテンションが上がります。

そういった報酬体験を積み重ねたおかげで手を動かし続けられたのは大きいかなと思います。

シンプルなゲームに徹した

実は今回の『Macaron 〜マカロンとの4日間〜』を開発する前に、脱出ゲームを作ろうとして挫折してます。

デザインファーストで、割と気に入ったデザインが作れたのにも関わらず、です。

脱出ゲームだと場面も数が必要ですし、デザイン素材もたくさん必要です。脱出要素の仕掛けを考えるのも一苦労です。しかもキャラクターも何体も出現させようとしてた(アホ)

結局は完成のビジョンが見えず心が折れてしまい、開発を中断したのでした。

『Macaron 〜マカロンとの4日間〜』ではこの反省を活かし、以下のようなシンプルなゲームプレイに徹し「見ててなんか可愛い」だけを目指すことにしました

  • キャラはマカロンのみ
  • 場面は一つだけ
  • プレイ方法はタップだけ

途中で「これもやってみたい」みたいな欲が出てきてもぐっと堪える。これ大切。完成させてからまず物を言いなさいと自分に言い聞かせます。

そのおかげで「あとこれだけやったら終わるぞ」という感覚のまま最後まで走り抜けることができたのだとと思います。

本当はストーリーとかも作らない予定でしたが、ある程度動きを作ったらマカロンを喋らせたくなってしまい、気が付いたらシナリオを書いていました…。

「今作っている箇所がとにかく動く」を最優先に実装

例えば、今は1つだけチャプターを実装しているが後から何個かチャプターが増えるとわかっていても、チャプター1個分のゲームプレイに最適化したコードを書くようにします。

ついつい先のことも考えてコードを書きたくなるのですが、そこをぐっと堪えます。

「動いた!」という脳への報酬をできる限り早く供給するためです。

機能を拡張するときというのは時間がかかったとしてもモチベが続きやすい感覚があります。

また、先々のことを考えてコードを書いたけど「よく考えたらこれいらなくね?」「時間かけた割にゲーム制作進捗なくない?」となったときのなんとも言えない悲しさはモチベに毒。

各工程に合った作業の仕方をする

個人開発なので企画、シナリオ、デザイン、実装その他全て自分ひとりで作ることになります。

各工程はそれぞれ別の脳を使う感覚があり、うまくやりくりしないと手が動かなくなったりします。

特に前段階の作業ほど腰が重くなりがちです。無から有を作るのはやはり大変です。

何度も失われそうなやる気に火をつけるため、色々なやり方を模索しました。

  • 企画はデザインと並行で考える。ビジュアルからインスピレーションを得るタイプ
  • 基本のゲームプレイで使用するデザイン及びアニメーションは実装前に作成しておく
  • シナリオは小刻みに書く。最初のチャプターのシナリオを書いたら実装に移り、実際に動いているゲームを見てインスピレーションを得て次のシナリオを書く
  • シナリオは思いついたときに書き、それ以外の時間は別のタスクをやる。答えがある系タスク推奨
  • 実装は他作業の気分転換に使う。他工程と比べたら要件決まってるし負荷がすごく軽い
  • メンタル荒れたときは作業せず離れ、回復に徹する。心身の健康が一番大切。

集中できる環境があった

まず、育休取得中です。

ゲーム開発は初めての体験も多く、やはり負荷は大きいです。

育児家事などにより、1日の作業時間自体は仕事の合間に進めるのと変わらない程度ではありましたが、慣れないかつ業務に直結しないゲーム開発となると、仕事しながらだったら続けられなかった気がします。

今回の経験でだいぶ雰囲気が掴めて次は仕事しながらでもいける感覚ができたので、育休はいいきっかけだったなーと思います。

肝心の育児家事はどうなんだというところですが、生後3ヶ月頃には夫と協力体制でかなり安定して回せるようになっており、細切れ時間ではありましたが心置きなく集中して開発に取り組むことができました。

安定育児体制に役立ったものたちはこちらの記事で紹介してます。 mich0w0h.hatenablog.com

この記事でも紹介してますが、結局一番は夫が育児担当をしてくれていることが大きいです。

自分は基本的に授乳だけやってあとは自分のペースで家事をしているので、ゲーム開発に集中しやすい状況でした。

夫よありがとう。

執念

自分は妊娠期間がクソで、安定期になっても何も思考が働かず無気力死体化、全ての娯楽が楽しめない本当に苦しい日々を過ごしてました。

個人開発なんてもってのほかです。

あの頃を思うと何かに取り組む気力があり、思考が働く状態にあるだけで本当に幸せだと思えます。あの苦しみを成仏させたい一心で開発の手が止まりそうなときも踏みとどまれました。

何かを完成まで持っていくのにはこういった執念は侮れません。

おわりに

趣味ゲーム開発はとても楽しかったですが、本当にちょっとしたゲームにも関わらず、やはりリリースまで持っていくのは大変でした。

完成したー!と思ってからがまた長いのよ…。 mich0w0h.hatenablog.com

ということで、拙いゲームですが良かったら遊んでください。(シナリオも自分で作ったので少し恥ずかしい気持ちもありますが…)

App Store

apps.apple.com

Google Play play.google.com

ぼやき

Apple Developer Programへの課金がお高い。Apple Storeリリースするのやめようか真剣に悩んだレベル。

Google Developerは買い切り3,816円、Apple Develperは年間12,980円 ※2023年10月時点

ストアのクオリティを担保するためなのはわかるが、趣味個人開発者には厳しい。

Unityで開発した趣味ゲームが完成してからGoogle Play及びApp Storeに提出するまでに対応したこと備忘録

先日Unityで開発したスマホ向けの趣味ゲームをめでたくストア(Google PlayApp Store両方)に公開したのですが、これがもう想像以上に大変でした。

Unity上でゲームが完成したぞ〜〜となってからが本当に長かった。

一言で言うなら初見殺しが多すぎる。

自分は普段ゲーム開発をしているわけではなく、ストアにスマホゲームを公開するのも人生初でした。(昔小さなゲーム会社で見習いエンジニアを少しだけやっていたことはあります)

ビルドはUnityの初期設定ままだと通らないのは当たり前。

また、ここ数年で様々な情報取得に対して各ストアはどんどん厳しくなっているらしく、世はまさに大プライバシー時代。

軽い気持ちで「広告ってどんな感じか気になるし実装してみよ〜」などとUnity Adsを導入した結果、Google PlayしかりApp Storeしかり、対応することが次から次へと降ってきました。

今後またUnityでゲームを開発するかはわかりませんが、もがいた時間の供養および備忘録として対応したことを残しておこうと思います。

なお、やったことはメモ程度に簡潔に書くので詳しく知りたいときは参考ページを参照することを推奨。

環境

環境変わるだけでビルド結果等々が変わることはまちまちなのでメモ

  • Unity: 2022.3.8f1 -> 2022.3.11f1 (Xcodeビルド不具合解消のため途中でアップデート)
  • Unity Ads(Advertisement Legacy): 4.4.2
  • Unity iOS 14 Advertising Support: 1.0.0
  • XCode: 15
  • PC: M2 MacBook Air
  • OS: macOS Ventura 13.5.2

Google Play及びApp Store共通

リリース用データをPlayer Settingにて設定

なぜやったか

  • アプリリリースに必須の項目
  • しかし初期値は設定されており、例えばCompay Nameは"Default Company"になったりしてしまい変えるのを忘れると後で焦る

やったこと

  • Company Name, Product Name, Versionの入力
    • Versionは修正ビルドごとにインクリメント
  • イコン画像の設定
    • アイコン用画像はInspector WindowにてTexture Type をEditor GUI and Legacy GUIに、CompressionNoneに設定
    • アイコンは512x512で作成すると後のストア登録のときにも使い回せて良さそう
    • Android用には一枚絵以外に、背景のみ、メインビジュアルのみのものをそれぞれ用意し、Adaptive iconsに設定した
  • Resolution and PresentationにてDefault Arientationを設定。今回のゲームは縦向き固定のゲームだったのでPortraitを選択
  • Bundle Identifier, Bundle Version Codeの設定
    • Bundle Version Codeはストアにアップロードするたびに値を増やさないとエラーになるらしいので注意

参考

プライバシーポリシーの用意

なぜやったか

  • 世はまさに大プライバシー時代
  • Google Play及びApp Store共にアプリを公開する際、プライバシーポリシーページのURLの入力が必須項目
  • また、アプリ内にプライバシーポリシーを明記もしくは明記したページへのリンクが必要
  • Prepare your app for review - Play Console Help

やったこと

  • プライバシーポリシーを記載したWebページを用意し、そのページへのリンクをゲーム内のタイトル画面に設置
  • 内容はUnity Ads用に用意された他ゲームのものを参考に作成
  • 新たにサイト開設とかはめんどかったのでgistで公開
  • https://gist.github.com/mich0w0h/8c6e333a00701e3bc4a129ed8e46ce46

参考

各ストアのData Collection Surveyに回答

なぜやったか

  • Unity Adsによってデータ収集が発生しており、世は大プライバシー時代なので回答必須

やったこと

メインシーンにてFPSを60FPSに指定

なぜやったか

  • 実機で動作テストしたらアニメーションがめっちゃカクカクしてた
  • モバイルの場合は初期値に30FPSが設定されるらしく、これが原因
  • FPSを上げると消費電力の上昇するというし、メインのゲームシーンでだけFPSを60に設定することにした

やったこと

参考

画像アセットのビルドサイズ削減

なぜやったか

  • Google Playにビルドを初回アップロードした際、アプリサイズが88MBくらいあった
  • 「このゲーム内容にしてはちょっと重すぎないか?」と思ってしまった
  • 2Dゲームにおける二大サイズ容量要因である画像とフォントに対してアプローチすることに(フォントについては次のセクションで記述)
  • 対応後は24MBになり、半分以下にサイズ削減できた
  • そのままでもリリースはできたので完全に自己満

やったこと

  • Sprite AssetをSpriteAltas化
    • 対象画像はInspector WindowにてCompressionNoneに設定する。Warningが出たので。
    • UIにSpriteを利用している際はTight PackingAllow Rotationをオフにする
  • TextureのInspector WindowにてMax Sizeをゲームの見た目を損ねない程度に減らす

参考

フォントアセットのビルドサイズ削減

なぜやったか

  • 前述の「画像アセットのビルドサイズ削減」と以下同文
  • 本セクションではTextMesh Proが主な対象

やったこと

  • Font Asset CreatorにてTextMesh Proアセット生成時にCustom Charactersで使用する文字を限定し、Altas Resolutionを見た目を損ねない程度に減らす

    • 使用する文字だけに絞ったら表示がバグったのである程度の文字数はあったほうが良さそう
  • Importするフォントの文字を利用している文字だけにする。Inspector WindowにてCharacter欄でCustom Setを、Custom Chars欄に使う文字列を入力

    • これは一応やってみたがTextMeshPro利用時にも効果があるのかはわからない
  • アンダーライン効果用の_(アンダースコア)や半角全角スペースなどは抜けやすいので注意
  • ゲーム表示に問題ないか一度全部チェックしたほうが安心

参考

Google Play向け

UnityのTarget API LevelをAPI level 34に変更

なぜやったか

  • UnityでAndroid向けにビルドする際、Gradleにて下記エラーが発生
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8 (省略)
cannot find symbol (省略)
symbol:   variable TIRAMISU location: class VERSION_CODES
  • 原因は上記variableがAndroid API 33以降でしか定義されてなく、存在しないvariableを参照していたこと
  • Unityのデフォルト値ではAPI levelが低かったため、設定変更が必要

やったこと

  • UnityにてPlayer Settings > Other Settings > Identification > Target API LevelにてAPI level 34を選択

UnityのAndroid向けビルド方法をIL2CPPに変更

なぜやったか

  • Google Playは64bit版アプリしか受け付けておらず、また64bit版アプリのビルドはIL2CPPでしかできない
  • Android向けビルドのデフォルトはMonoに設定されているため変更する必要がある

やったこと

  • UnityにてPlayer Settings > Other Settings > Configuration > Scripting BackendにてIL2CPPを選択

参考

Androidでのサウンド再生音遅延対策にCRI ADX2を導入

なぜやったか

  • ビルドを実機で動作確認してたら、SEの再生があまりにも遅かった
  • タップに反応してSEを鳴らす場合、さすがに違和感がありすぎたので対応
  • 対応後はマシにはなったが、まだちょっと遅延は残っているものの趣味ゲームだしと許容

やったこと

参考

AndroidのKeystoreを作る

なぜやったか

  • Google Playにアプリをアップロードする際に署名が必要
  • Unity上でその署名用のKeystoreを発行できる

やったこと

参考

App Store向け

リリースの際の手順は基本的にこれ通りに進めればいけた

本当にこのページがよくまとまっていてほぼこれ通りに進めればいけたので貼っておきます

marumaro7.hatenablog.com

いくつか注意点

  • XCodeでビルドしたプロジェクトを開いた際、Warningを解消していくと記事には書いてあるが、XCode15ではむしろWarningのまま放置しないとビルドが失敗した
  • XCodeAutomatically manage signingをオンにしているとDeveloperプロファイルを参照しようとし存在しないとエラーになる。オフにして手動でDistribution用に作成したプロファイルを選択することで解決
  • Archive作成時、double-quoted include "LifeCycleListener.h" in framework header, expected angle-bracketed insteadといったエラーが発生したがUnityを最新版LTSにアップデートすることで解消
  • ArchiveのValidate時に発生するInvalid Bundle. The bundle at '〇〇.app/Frameworks/UnityFramework.framework' contains disallowed file 'Frameworks’エラーはXCodeAlways EmbedSwiftStandartLibrariesを修正することで解決

参考

ATT許可申請

なぜやったか

  • 満を持してApp Store審査へアプリを提出したところリジェクトをくらった
  • 広告でユーザートラッキングしてるならApp Tracking Transparency(ATT)を実装してねとのこと
  • なにそれ…生粋のAndroidユーザーには未知の概念
  • どうやらiOS 14以降、ユーザーデータを収集する前にポップアップを表示してユーザーに認可をもらう必要があるらしい
  • その許可申請を用意されてるATT Frameworkで実装する必要があるとのこと

やったこと

参考

App Storeで表示されるdeveloper nameを変更したい

なぜやったか

  • ゲームがApp Storeにリリース成功したので見に行ったらdeveloper name(販売元名)が自分の本名になっていた
  • 自分としてはハンドルネームであるmich0w0hを表示したい
  • 個人開発者だとApple Account名が強制的にdeveloper nameにされてしまうらしい。えー。Google Playでは自分で設定できたのに。。。

やったこと

  • Apple Developerにてサポートに問い合わせしたがダメでした。
  • 開発用に別途Appleアカウントを開設するのが正解なのだろうか…
  • ちなみにAppleからの回答は下記
大変恐れ入りますが、個人として登録しているデベロッパが App Store で App を販売する際は、正式な個人名を使用します。

貴社の創立者または共同創立者である場合は、メンバーシップを個人から法人に移行するリクエストを送信いただけます。

参考

iPhoneでサイレントモード時にもゲームサウンドを鳴らす

なぜやったか

  • iPhoneでゲームプレイしたところサウンドが全く鳴らなかった
  • 試しにインスタを開いたところそちらでは音が鳴っていた
  • (当方iPhone実機を持っておらず、ストアリリース後に友人に頼んで動作検証してもらって発覚)
  • どうやらiPhoneの仕様でサイレントモードがオンの場合、音楽は鳴らすがその他の音(カメラのシャッター音など)は鳴らさないようになっているらしい
  • 通常サイレントモードに設定されているだろうし、それでせっかくのゲームサウンドが鳴らず無音のゲームだと思われたら寂しいので対応したい

やったこと

  • サイレントモードで音を鳴らすには「このゲームの音は音楽再生ですよ」とiOSに伝える必要がある
  • 具体的にはAudioSessionCategoryAVAudioSessionCategoryPlaybackにする
  • iOSAPIをUnityから呼び出すため一工夫が必要で、Objective-Cで書いたPluginを用意しそちらをスクリプトで呼び出すことになる
  • それ用のコードを公開している方がいたので、そちらを導入した
  • Unity Editor上でゲームを再生するとEntryPointNotFoundExceptionが発生するがこれは無視して良いらしい

参考

おわりに

リリース作業…大変だった…。

全てが未知だったので、予想外の作業や不具合がどんどん発生するし、環境依存すぎて解決方法が調べてもGPTに聞いても全然ヒットしないこともしばしばでした。

しかし大変だったけど後悔はしてません。終わってみれば色々なことを知れて楽しかったなーと思います。

今後またゲームをリリースするかわかりませんが、今回の経験を活かして次はもっとスムーズにできるはず…。

※ 公開したスマホゲームについては別途ブログ記事を書く予定です。

子が生後半年を過ぎたので育児お役立ち系の記事を書いてみる

2023年3月に子が爆誕し、つい先日2023年9月に生後半年へと成長しました。

いまだに自分が産んだ子だという実感はなく、突然やってきた謎の生き物を必要にかられて育てている感覚のまま半年が経ってしまいました。

良い区切りなのでなにか書こうと思い立ち、この半年の日々を助けてくれたものたちを感謝の正拳突きをしながら記すことにしました。

選定基準としては、圧倒的に私自身の精神衛生に貢献したかどうかが大きいです。おかげさまで現在わりと元気に過ごせています。

特に産後は体力死んでたりと身体が思っている以上に動かないことが多いので、何も使わずに過ごしたら終わってたと思います。

なお、過ごした季節が春夏だったので内容もそっち寄りのものが多いです。

思いついた順に書いているので各セクションにおける順番は適当です。

マスト

記憶を残したまま強くてニューゲームするとしても欠かしたくないやつらです。

夫が育休を取得する

  • これなに
    • 夫が育休を取得してくれた。ありがてぇ。
    • 半年の予定だったのが、気がついたらプラス3ヶ月錬金されており、計9ヶ月
    • 産後3ヶ月くらいまでは自分は母乳マシンと化し、その他の家事育児はすべて夫がやってくれた。感謝感激雨嵐。
    • 最近は家事全般と授乳は自分、育児全般と掃除は夫という分担
  • Good
    • 現在わりと元気に過ごせているのに一番貢献している
    • 日々事件を起こす怪物が家にいても、二人でギャーギャー言いながら共有できるので楽しい思い出に変わる(大変であるのは変わらないが)
  • Bad
    • 産後3ヶ月くらいまでは夫の負担が重く、大変そうだった
    • 収入が減る。育児によって支出増は必ず起こるのにな

赤ちゃん睡眠本を読みまくる

  • これなに
    • 産後の安寧は親の睡眠量が重要なファクターだと考え、結局は子が夜寝てくれるかが最重要だと考えた
    • 出産前に「赤ちゃん 睡眠」がテーマの本を図書館や本屋立ち読みを利用し10冊くらい読んだ
    • 一番簡潔にまとまってそうな1冊をピックし常に見返すバイブルとして購入
  • Good
    • 現在の弊子はいつもの時間に暗くした寝室に置くだけで寝て、夜中はお腹が空いたときだけ起きるように
    • やはり夜ぐっすり寝れるは正義。生活の安定感がぐっと増す
    • 抱っこソリューションをほぼ発動しないので腱鞘炎にならずにすんだ
  • Bad
    • 事前にいくら準備しようと、子をお迎えしてしばらくは想定外の要因で夜ギャン泣きは発生する
    • その度に得た知識を参考に原因特定、対応するの繰り返しでやっと安眠生活へ
    • ある程度成長するまで、数時間おきにミルクが必要であり深夜対応はゼロにはならない
    • 寝やすさは個体差があり、弊子はある程度寝てくれる子であった可能性はある

ドラム式洗濯乾燥機

ななめドラム洗濯乾燥機 NA-LX113AL 詳細(スペック) | 洗濯機/衣類乾燥機 | Panasonic

  • これなに
    • 衣服の洗濯から乾燥まで一気通貫してやってくれる最高のやつ
  • Good
    • みなさん聞き飽きているかもしれませんが、洗濯干さなくていいって本当に本当に最高
    • 赤子とはとにかく穴と言う穴から様々な液体を撒き散らす生物なので洗濯物量が増えるんですわ
  • Bad
    • 赤さん用の布類はだいたい乾燥機非対応と表示されている
    • 表示をガン無視して乾燥機にかけるため縮んだり伸びたり見栄えは悪くなる。使用はできたので気にしなければ無問題
    • ほこりフィルター手入れは簡単だけど頻度高いのでだるい。次買うとしたら自動清掃機能付きがいいなあ

食器洗い乾燥機

NP-TSP1-W 食器洗い乾燥機(タンク式)(ホワイト)|食器乾燥機【パナソニック公式通販】

  • これなに
    • 食器を自動で洗ってくれるいいやつ。いわゆる食洗機
    • 賃貸だったりと家の条件によってタンク式を使用
    • 哺乳瓶は煮沸等の消毒作業が巷でよく話題になるが、もうめんどくなって我が家では「食洗機洗浄を煮沸とする」となった(食洗機はわりと高熱の湯が出る)
  • Good
    • みなさん聞き飽きているかもしれませんが、水を入れてスイッチぽちーとすれば洗い物が完了するのは超良い
    • 哺乳瓶(食洗機対応)を複数個一気に洗えるのは神。ミルク間隔が約2-3時間の新生児期になくてはならない存在
  • Bad
    • タンク式なので毎回水汲むのがめんどい。次買うときは自動で給水するやつを買う
    • 寝る前に運転開始するとうるさい。リビングで寝ているので仕方ないところはある

電気ポット

VE電気まほうびんタイプ CV-GA型|商品情報|象印

  • これなに
    • 粉ミルク生成用に電気ポットを購入
    • 粉ミルクつくるときのお湯は殺菌のため「沸騰→約70度まで冷ます→ミルク入れる→人肌まで冷ます」の工程が必要で、それを手っ取り早く実現するために買った
  • Good
    • 「70度まで冷めたかを気にしなくて良いのが一番の効用」by ミルク担当の夫
    • 「ゆっくり給湯機能もなかなかに便利」 by 同上
    • 自分目線だと、産後から急に冷えやすい体質になったので白湯を手軽に飲めるのが嬉しい
  • Bad
    • とくになし

ぴよログ

育児記録アプリ ぴよログ

  • これなに
    • 育児管理アプリで調べると必ず出てくる定番アプリ
  • Good
    • 夫婦間で共有でき口頭で説明せずとも子の状況がだいたいわかる
    • 病院での診察時に「授乳回数は?💩の回数は?」と聞かれても自信を持って答えられる
    • 端末間共有が爆速すぎて逆に心配になる
  • Bad
    • 良いアプリなのでもっと稼げててほしいなと思う。キャッシュポイントは少なそうに見えたので

不思議おくるみ

Amazon.co.jp: 【手が出せる】 おくるみ スワドル モロー反射を防ぐ【助産師が推薦】Mughart

  • これなに
    • 特殊な形態のおくるみ?で見るとわかるがひょうたん型で着た様はわりと笑える
    • 生後1ヶ月くらまでは反射で手がビクつく動きをよくするのだが、夜に怪物が自らの反射動作で目を覚ましてしまう
    • おくるみが良いらしいと聞いて調べたらこれがAmazon上位にでてきたので買ってみた
  • Good
    • ダメ元で買ってみたが驚くほど効果があって、手の動きが抑えられるからかよく寝てくれた
    • 足元はチャックで開けるようになっており、股関節の発達を阻害しないかを気にしなくて良いし、着させたままオムツ替えができる
    • これを着た子の見た目がかなり滑稽でウケる
  • Bad
    • 使える時期が一瞬。諸説あるが寝返り動作をし始める頃にはおくるみは卒業したほうがよいらしいし、サイズ的にも生後2ヶ月頃には使えなくなった
    • 2000円ちょっとで数週間の安眠を買った感じ。こういったことの積み重ねで子の一人で寝る力は育つと思うし全然ペイできる

ナイキスポーツブラ

授乳期におすすめのNikeスポーツブラ.オンラインストア (通販サイト)

  • これなに
    • 授乳中に運動したくて「授乳中 スポーツブラ」で探して購入した
    • 授乳初期は特に胸の張りや重みがえげつなくて、通常のブラでは早歩きすら胸を抑えいなとキツかった
    • 自分は運動しないと気力活力が失われていくタイプなので死活問題だった
  • Good
    • 運動できるようになった
    • サイズ調整がわりと可能で胸の張りが落ち着いてきた現在でもちゃんと使えている
    • スポーツブラにしてはリーズナブル
    • 着てると強そうに見える
  • Bad
    • 洗濯するとパッドが丸まってしまうことがあり、毎度手で直すのがめんどくさい
    • 調子に乗って運動強度を急に上げすぎて高熱を出して倒れるのを3回はやってる(商品はなにも悪くない)

ベビーカー(レンタル)

コンビ ホワイトレーベル メチャカル ハンディ オート4キャス エッグショック HG|コンビ公式ブランドストア

  • これなに
    • 首すわり前でも使えるベビーカーを生後3ヶ月くらいのタイミングでレンタル開始
    • サービスは調べた中で最もリーズナブルだったDMMレンタルを利用。後にサービスクローズしてたので滑り込みだった
    • 安いしこれでいいかとコンビの少し前のモデルであるメチャカルを選択
  • Good
    • 自分はメンタル調子が悪いと一人では動けなくなり詰むのだが、ベビーカーによって「気分転換にみんなでお出かけ」ができるように。何度も救われました。
    • 月齢低いうちは対面で使えるのは安心
    • メチャカルと言うだけあってけっこう軽い
  • Bad
    • 対面利用だとかなり操作性悪く、曲がるのも直進するのも技巧が必要なのを感じた。背面に切り替えるとかなり改善する
    • 段差乗り越えがちょっと大変。操作性を考えたら三輪バギータイプがいいんだろうな

ジョイントマット

Amazon.co.jp: タンスのゲン ジョイントマット 43cm 厚み10mm

  • これなに
    • 子の可動範囲に敷いておくマット
    • 床の汚れ防止効果を期待して購入。防音効果もある
    • 必要な枚数だけパズルみたいに組み合わせて利用するタイプ。ちまちまするとめんどいので大判タイプを購入
  • Good
    • 子の可動範囲の変化に合わせて簡単に移動・増設ができる
    • 子が吐き散らかそうがよだれダラダラ垂らそうがニッコリして見守れる
    • クッション性があり子が足やら頭やらを打ち付けても割りと安心
  • Bad
    • 大きさが合わず床の端から端までカバーできないことも。切って調整はできるが将来的に部屋が変わったときに使いづらくなりそうで踏み切れず
    • つなぎ目のスキマからゴミが落ちていきやすく、マットの下は定期的に掃除しないとゴミ溜めと化しそう

ソニーノイキャンイヤホン

WF-1000XM4 | ヘッドホン | ソニー

  • これなに
    • 愛用しているソニーのノイキャンイヤホン
    • 授乳中や運動時に音楽やPodcastを聞くのに活用
  • Good
    • 授乳は軌道に乗るまでは最中に子から目が離せないが、拘束時間も長いので耳で気分転換できるのは本当によかった
    • 片手で簡単に音の再生/停止や音量調整ができるのもかなり重宝する
    • メンタル調子が怪しいときに運動で回復したくても調子が悪いがゆえに動き始められないとき、ノイキャンx音楽爆音だと走り出せることがありかなり助けられている
  • Bad
    • 特になし

電動搾乳機

ピジョン母乳アシスト さく乳器 電動handy fit+(ハンディフィット+) | 商品情報 | ピジョン株式会社

  • これなに
    • 電動で勝手に搾乳してくれるやつ
    • 母乳出るか出ないかわからんけど、いずれにせよトライするなら何かと使うだろうと産前に購入していた
  • Good
    • 疲労や体調不良で授乳はしたくないが母乳は出さないとやばいみたいな場面がかなり発生したので非常に重宝した
    • 手絞りはかなり力を使い手や腕が痛くなるわ疲れるわで大変なので、電動はありがたかった
    • 電動のおかげで搾乳しながらお絵描きしたりKindleで技術書見つつメモ書いたりとかができ大変効用が高かった
    • なんと電動部分以外の全パーツ食洗機対応(電動部分は洗う必要なし)。パーツごとの販売もしてたので全パーツ追加購入した
    • Type-C充電
  • Bad
    • 使用するまで必要かわからない系のグッズだが、即買いするのをためらわせる絶妙な価格
    • 母乳育児での頻出トラブルである乳頭負傷時には傷を悪化させないために手絞りが推奨されるため搾乳機の出番がない
    • 母乳育児が起動に乗ると出番はなくなってくる。断乳時での活躍に期待

chocoZAP

|chocoZAP(チョコザップ)|ライザップが作ったコンビニジム

  • これなに
    • 最近急激に勢力を伸ばしているコンビニジム。うちの近所にもできた
    • 夏で暑さがやばすぎるときの運動用に契約。夏の2ヶ月間ほぼ毎日使った
  • Good
    • アプリで登録したその瞬間から使い始められる
    • 着替えいらず持ち物いらずなのが本当に気軽にジムにいけていい
    • 準備がいらないので頑張って長居する圧力がなく、15分トレッドミルで早歩きして帰るとかができる
    • 真夏で暑すぎて運動できずメンタルが終わっていたところを救ってもらいました
  • Bad
    • 育児関係なかった。育児中のメンタル安定剤ということでいいか
    • トレッドミルは身体を痛めやすいのを感じた。可能なら外で歩く走るが身体には合ってそう
    • 危険な暑さを過ぎたら外で運動できるので使わない。ので、解約した。

夏のひんやりグッズ

チャイルドシートの暑さ対策してる?【西松屋のひんやりシート・100均グッズが大活躍!】 | 子育てパパの備忘録

わきの下専用 ちょいパットアイス スペアジェル2個付 通販 | 育児用品 | アカチャンホンポ Online Shop

  • これなに
    • 夏の暑さがやばすぎて5分外に出るのも無対策だと危険を感じたために購入
    • ベビーカーシートに保冷剤入れられるやつと、脇の下に保冷剤入れられるやつ
  • Good
    • ひんやりしてて気持ちよさそう
    • ある程度の暑さならこれで耐えられそうな安心感がある
    • 凍ってても固くならない保冷剤なので子が使っても痛くなさそう
  • Bad
    • 本当にやばい暑さのときはこれがあっても外に出るのは危険と感じるので、車でドアツードアが良いんだろうなと思う

便利

絶対これが必要!!って感じではないが普通に便利だったものたちです。

寝室環境自動化 by SwitchBot

SwitchBot 温湿度計 お部屋の温度・湿度を適切に管理 – SwitchBot (スイッチボット)

スマートリモコン SwitchBot ハブミニ – SwitchBot (スイッチボット)

  • これなに
    • 子の寝室環境をSwitchBotで自動化している
    • 正確には産後に私が死亡している間に夫がゴニョゴニョ設定してくれた
    • 空気清浄機、電気、エアコンらへんの操作をさせている
  • Good
    • エアコンつけるつけないに脳リソースを奪われなくなった
    • 一番ありがたいのはやはり空調のオンオフ。弊子は室温が適温でないとすぐ起きる
  • Badその他
    • 赤外線を操作するのでそれ以外で操作するものには使えない(もちろんSwitchBotシリーズは別)

キッズパーテーション

キッズパーテーション │ ベビーゲート

  • これなに
    • 子の可動範囲を制限する柵。曲線状に置けたりサークルにもなる
    • 子が順応無人に転がるようになってきたし、どうせハイハイするようになったら欲しくなるだろうと購入
    • 壁に固定するタイプではなく据え置きタイプ
  • Good
    • 子の水際対策としてきちんと機能してる
    • 置いてるだけでもちゃんと安定していて簡単には倒れなさそう
    • パーツを外して長さ調整が可能。引っ越しして部屋の状況が変わっても使える
  • Bad
    • 組み合わせるパーツの長さがもう少し短いともっと置く場所へフィットさせやすくなりそう

ウェットシートのふた

取り出しやすいウエットシートのフタ(くま) | 【公式】DAISO(ダイソー)ネットストア

  • これなに
    • おしりふきにつけてサッとシートを出せるようにするフタ。育児定番百均グッズ
  • Good
    • ふたを開ける煩わしさから開放される
    • おしりふきを出す場面は慌ててるときが多いので地味に助かるやつ
    • 粘着力が続くまでは付け替えて使うことも可能
  • Bad
    • 粘着力はだんだん弱まるが百均グッズだし定期的に買い替えるので問題なし

見守りカメラ

ベビーカメラ KX-HBC200 | 商品一覧 | ホームネットワーク(ペットカメラ・ベビーモニターなど) | Panasonic

  • これなに
    • 別の部屋にいるときに子の様子を確認するために購入。特に我が家はある程度過ぎたら親子別室で寝るつもりだったのでマストかなと
    • バイスが増えるのが嫌でスマホアプリで見れるタイプにしてみた
  • Good
    • 真っ暗な部屋でもしっかり子の様子が見える
    • アプリ状でタップすることでカメラの向きを簡単に調整できるのも良い
  • Bad
    • 強くてニューゲームするとしたら見守りカメラは欲しいが絶対にこれは選ばないだろうというくらいスマホアプリ機能が微妙。同じパナソニックが出している物理モニターに移すやつだったらマシだったのかもしれない。
    • 音検知機能は無駄音を検知しすぎて使えず、モニターを写しっぱなしにすると数分後には接続が切れる。夜に別部屋で寝ながら異常検知するのには使えない感じ。
    • いいお値段する。後に見つけたSwitchBotの見守りカメラがかなりお安かったのでこっちが良さそう

コープ生協定期便

コープデリ | 小学校入学前のお子さまをお持ちの方にうれしいおしらせ! 子育て割引

  • これなに
    • 買い物を楽にしようということでコープに加入してみた。これと西友ネットスーパーを駆使している。
    • 毎週月曜日に注文した品が届くシステム
  • Good
    • 冷凍離乳食シリーズが本当に便利。離乳食初期はもうこれでいいんじゃないかと思っている
    • 赤ちゃん割引で基本手数料も配達手数料も無料になる
    • コープの注文用スマホアプリが意外にも良かった。使ってて特に不便さを何も感じないというのはかなり良いアプリだと思われる
  • Bad
    • 生鮮系、特に肉魚類はスーパーよりもお高い
    • 西友の「みなさまのお墨付き」や「きほんのき」には一歩及ばない商品が多い気がする

ユラリズム

ユラリズム | ベビーカー・チャイルドシートのアップリカ | Aprica

  • これなに
    • 夫が帰省したときに買ってもらってた。夫の姉が激推ししてたらしい
    • 首すわり前から使えて食事用の椅子にまでなる
    • 名前の通り、ユラユラ揺れる
  • Good
    • 子が昼寝にまだ慣れてないときに寝るスイッチを入れさせるのに良かった
    • 子は普段床にいるからか、置いておくだけでも視界が変わるのか楽しそうにしている
    • 離乳食食べさせるときの椅子としても活躍中
  • Bad
    • 結構場所を取る。首すわり前用の最もリクライニングを下げている状態だと特にね

スマートウォッチ

Xiaomi Miスマートバンド6-世界一のポータブル | Xiaomi Japan

  • これなに
    • 愛用している時計
    • 授乳時間を測るのに活躍
  • Good
    • 授乳するときにショートカットからパッとストップウォッチをスタートできて便利
    • 夜の寝室でもそこまで明かりを出さないので子を刺激しすぎないのは良い
  • Bad
    • ほぼないが強いて言えば充電端子がType-Cでなく特殊な形状

Wi-Fi対応体重計でのSlack通知

Wi-Fi対応 体組成計 - Body+ | Withings

  • これなに
    • 愛用している体重計
    • 子の体重を毎日チェックするのに活用(大人が乗る→子を抱っこしながら乗る→差分を計算)
    • 計測した結果はWi-Fi経由でSlackに通知される
  • Good
    • 毎日チェックしていると子の体重がちゃんと増えてるのがわかって安心感がある
    • Slackに記録されるので計測時に頑張って数値を覚えて無くて良い
  • Bad
    • 子の体重単位を想定してない体重計なため、誤差は発生する。正確に測るというよりざっくり変化をウォッチする感じ

オーボール

オーボール ラトル | ラングスジャパン 公式オンラインショップ

  • これなに
    • ボール状のおもちゃ。おもちゃは基本これしかない
    • 定番おもちゃらしい
  • Good
    • オーボールを与えておけばしばらく一人で楽しそうにしているのでラク
    • 口に入れてても安心だし、サッと水洗いしやすくて良い。さすが支持を獲得している赤ちゃん用おもちゃはしっかりしてる
  • Bad
    • 特になし

スマホ入れるミニショルダー

Amazon.co.jp: [ジゼル] ショルダーバッグ レディース スマホポーチ

  • これなに
    • ベビーカー利用時にサッとスマホが出せると嬉しい場面が増えてきたので購入
    • 検診等で病院に行くと世のママはみんなスマホショルダー使ってるんじゃないかってくらいよく見かける
    • 自分は鍵付きの薄い財布も入れたかったのでケースタイプではなくポーチタイプにした
  • Good
    • ベビーカーで電車に乗るときにすぐに改札にスマホをかざせるのがとても良い
    • ちょっとしたお出かけもこれにスマホと鍵財布を入れて行けばいいので身軽になって良い
  • Bad
    • 特になし

日除け帽子

Amazon | [YUMISS] UVカット帽子 レディースハット

  • これなに
    • 夏は日差しかなり強いがベビーカーを押していると日傘がさせないため購入
  • Good
    • マジで日が顔に当たらない
    • 紐付きなので風が吹いても安定している
  • Bad
    • ファッション的な見た目はそんなに良くはない。すごい悪いわけでもないが

ルンバ(レンタルお試し中)

i2|ロボット掃除機 ルンバ | アイロボット公式サイト

  • これなに
    • 夫に誕生日欲しいものを聞いたら「掃除機」とのこと。確かに子は床を転げ回るは舐めまわるはしているので、床に落ちてるゴミが昔より気になるようになった
    • コードレスクリーナー等も調べたなかで「ルンバありでは?」となり試しにレンタルしている
    • 家の要件的にそこまですごくなくて良いのでエントリーモデルのi2を選択
  • Good
    • 出かけている間に自動で家のなかを掃除してくれる。特にリビングと寝室は全部自分で掃除すると疲れるので嬉しい
    • ちょっとした段差は乗り越えてくれる。いくつか心配なポイントがあったがしっかり乗り越えて掃除してくれた
    • 思ってたよりしっかりゴミを取ってくれているし、割りと購入に心が傾いている
  • Bad
    • よく言われるがルンバを行き渡らせるために物をどかす等の事前準備が少し手間
    • 凹凸のあるジョイントマット表面には小さいゴミがのこりがち
    • ドアの裏とかは結局自分で掃除するしかない

おわりに

とりあえず思いつく限りざっと書いてみました。

夫と共に試行錯誤しながら過ごしたおかげか、生後3ヶ月頃から徐々に生活が安定しはじめ、わりと充実した育休生活を過ごせています。

逆にそれまでは子の空腹になる間隔が短かかったり、昼夜の区別がついてなかったりと、どう頑張ろうと結局大変で夫婦共にぐったりしていた記憶があります。

ただ、こうやって思い返してみると、子のお世話より自らのお世話(気分が下降すると戻しにくい)の方ががずっと大変なのを感じています。まだ子が自我を主張し始める前だからかもですが、、、。

なんにせよ、子がいる生活は変化が目まぐるしいし試行錯誤もたくさん必要だしで、刺激的で楽しいです。

Unity C#でJWT生成しようとしたら署名部分の実装理解が大変そうで撤退

UnityでGoogle Spreadsheetのデータにアクセスするのに、Google Client Libraryを使った際の裏話です。

mich0w0h.hatenablog.com

UnityでVisual Studioを使わずにNugetパッケージを導入するのちょっと面倒そうだなーと思った過去の私(詳しくは上の記事参照)は、パッケージを使わずに自分で実装すればいいじゃんと思いました。

Googleのサービスアカウント方式でアクセストークンを入手するフローはなんとなくわかっていましたし、実際以下のようなNodeで実装した記事とかも見つけて、これをUnity C#に持ってくればいけるっしょ、と。

christina04.hatenablog.com

で、実際やってみて、ほぼほぼ実装できそうだったのですが、トークンリクエストで使用するJWT生成の最後の最後、署名部分でちょっとくじけました。

RSA暗号使っての署名はGCPから落とした秘密鍵を暗号化モジュールに読み込ませればできるっしょと思っていたのですが、C#だと自分でmodulus等の各パラメータをPEMから抽出して設定しなければならないみたいでした。自分が調べた範囲に限定されるので、もしかしたら他の手もあるかもです。

具体的な実装方法はは以下の記事等で紹介されています。 qiita.com

記事を読んでみるとわかるのですが、各パラメータを抽出するにはASN.1という規則で書かれたデータをバイナリにしたやつを読み取っていくことになります。ASN.1をバイナリ変換するフォーマットはDER (Distinguished Encoding Rule)というものが使われているそうです。うん、このバイナリ読み解き方が全然わからない。私はもっと軽い気持ちでこの実装に臨んでいたんですよね。

かと言って、なんとなくわかる範囲内で実装したかったので、コードのコピペは憚られます。

結局冒頭に貼った記事に着地し、思ったよりもUnityへの.NET Google Client Library導入が簡単だったため、自前実装作戦は撤退となりました。

ちなみに、後日気になって調べたところ、以下の記事がASN.1やDERについての説明としてわかりやすかったです。読み物としてもおもしろいです。「全然わからない」からは抜け出せました。 bearmini.hatenablog.com

今回は実装自体は撤退しましたが、今まではただ"-BEGIN PRIVATE KEY-"だけを認識していた秘密鍵の中身への解像度が上がりましたし、RSAの各パラメータについてももう少ししっかり理解したいなと思うなど、暗号について以前より興味を持つ良いきっかけになったかなと思います。

UnityでGoogle SpreadsheetへアクセスしたいVSCode民が色々頑張って成功した話

最近Unityで少しずつ手探りでゲームを作ってみています。ほんとーに少しずつです。

その過程で、シナリオデータを作って読み込みたい時期になってきました。

ひとまず、UnityからGoogle Spreadsheet上のデータを読み込めるようにしようということで、色々と模索して実装できたよという話をしたいと思います。

実装方法ですが、GoogleAPI Client Libraryを公開してくれているため、コード自体はかなり簡単に書けます。ただし、このClient LibraryはNuGetパッケージとして公開されていることから、Unityで使えるようにするためにひと苦労せねばなりませんでした。

特に私は、NuGetパッケージを今まで活用したことがなく、しかもVIsual StudioではなくVisual Studio Code(VSCode)で開発していたため、NuGetパッケージのインストール方法がよくわからず、その点でも混乱ポイントがありました。

というわけで、ちょぴっと頑張ったのでその軌跡をブログに残しておきたくなったワケです。

前提

以下の作業はすでに終わっているものとして話を進めます。

  • GCP上でサービスアカウントを作成しており、Sheet APIは有効化済み、Credentialsは手元に用意してある
  • データを読み取りたいスプシにてサービスアカウントへ権限を付与済み

また、Unityは2022.3.4f1を使用しています。

MicrosoftがUnity向けの手順ページを公開していた

NuGetでインストールしたいパッケージのページを見てみると、インストール用のコマンドが記載されています。例えばGoogle.Apis.Sheets.v4のページではこんな感じ

Visual Studio経由でのインストールだとPackage Manager Consoleを使ってコマンド一発でインストールできるみたいですが、こちらはVSCodeの民です。また、.NET CLIでのインストールも試みましたが、エラー続きで萎えたので撤退。UnityでしかC#使ったことないからそういうのわかんないんだわ。

どうしたものかと調べてみたところ、Microsoft公式がこんなページを用意してました。

learn.microsoft.com

お、それっぽいそれっぽい。ということで、こちらのページを参考にしつつ進めていきます。

Unityで.NET 4.xを有効にする

まずはUnityのPlayer Settingsにて.NET 4.xを有効にせよとのことで、Edit > Project Settings > Player > Other Settings を見てみます。公式の言うところによると以下のようにApi compatibility Levelで.NET 4.xを選択せよとのことでしたが、

実際に自分の環境で見てみると、.NET 4.xが選択肢にありません。

どうやら、既に.NET 4.xにApi compatibility Levelが切り替えられた状態だとこのような表記になるみたいです。特に自分では設定してないので、最近のUnityではデフォルトで.NET 4.xが設定されてるみたいですね。その場合、.NET Frameworkを選択することが.NET 4.xに該当するようなので、.NET Frameworkを選択します。

選択後は設定反映を確実にするためUnityを再起動します。

NuGetパッケージのdllを入手する

次に、NuGetパッケージのdllを入手します。

該当のNuGetパッケージのページにて"Download package"をクリックすると .nupkg形式のファイルがダウンロードされます。

このファイルの拡張子を.zipに書き換えて解凍せよとのこと。解凍して出てきたフォルダ内のlib/net45配下にほしいdllファイルがありました。こいつをUnityに持っていきます。

.nupkgってそんな風にして開けるんですね。これは自分では思いつかなかっただろうなあ。

今回のスプシ読み取り用途で必要だったパッケージは以下です。

※ 後ほど知ったのですが、VSCodeNuGet Package ManagerのExtentionがあるみたいです。これを使えばよかったのでは、、、

Unityにdllファイルを配置する

Assets/Plugins配下に入手したdllファイルたちをブチ込みます。

読み込み処理終了後、特にエラーが出てないことを確認しつつ、Unityを再起動。

すると、Client LibraryへのAutocompleteが発動するようになってました!やったね!

実装してみる

実際にちゃんと動くかを確認するため、スプシのデータを読み取るコードを書いてみます。

using UnityEngine;
using System.Collections.Generic;
using Google.Apis.Auth.OAuth2;
using Google.Apis.Services;
using Google.Apis.Sheets.v4;
using Google.Apis.Sheets.v4.Data;
using System.Threading.Tasks;

public static async Task LoadScenarioData(string spreadsheetId, string sheetName) {
        string credentialPath = "PATH_TO_FILE";    // credentialsのファイルへのパスを入れる
        string[] scopes = { SheetsService.Scope.SpreadsheetsReadonly };

        GoogleCredential credential = GoogleCredential.FromFile(credentialPath).CreateScoped(scopes);

        SheetsService service = new SheetsService(new BaseClientService.Initializer() {
            HttpClientInitializer = credential
        });

        SpreadsheetsResource.ValuesResource.GetRequest request = service.Spreadsheets.Values.Get(spreadsheetId, sheetName);

        ValueRange response = await request.ExecuteAsync();

        IList<IList<object>> values = response.Values;
        if (values != null && values.Count > 0) {
            foreach (var row in values) {
                foreach (var cell in row) {
                    Debug.Log(cell.ToString());
                }
            }
        }
    }

動作確認用にこんな感じのデータをスプシに用意。

そして、実行してみたところ、、、

// spreadsheetId, sheetNameには実際のスプシIDとシート名を入れる
await ScenarioLoader.LoadScenarioData(spreadsheetId, sheetName);

意図したとおりにログが出力されました!やったね!

おわりに

ということで、実装自体はライブラリを使うとめちゃくちゃ簡単にできたのですが、ライブラリを使えるようにするまでが少しだけ苦労しました。

UnityかつVSCodeという環境でNuGetを使うというのが混乱ポイントでしたね。わかる人にとっては全然大変じゃないのかもですが、わからないサイドの人間だったので、、、

こういうとき、.NET Frameworkについて知らなすぎる弊害を感じるので、どこかで抑えておきたいところです。

今回はスプシの値をただ読み取るだけで留めていますが、データをゲーム処理中に使いやすいような形式で出力したいところ。また、現状スプシ読み込みはUnity Editor上から実行する実装にしているので、Credentialsの置き場はそこまで気を遣わなくて良いのですが、ゲーム起動時にシナリオデータを更新したいとなったときは(なりそう)また考えないとなーと思っています。

番外: Unity Editorからボタンぽちーでスプシ読み込みを実行する

スプシ読み込み処理の呼び出しは、Unity Editor上のボタンをぽちーとすると実行されるようにしています。

具体的には、ヘッダー上にToots/Load Scenario Dataというメニューを作り、

そちらを選択すると、ウィンドウが開き、スプシIDとシート名を入力して"Load Scenario Data"ボタンを押すことで実行される仕組みです。

以下のようなコードで実装してます。これだけの記述で実装できちゃうので便利ですね。実はEditorWindowの実装を自分でするのは初めてだったので、想定通りに動かせたときは嬉しかったものです。

using UnityEngine;
using UnityEditor;

public class ScenarioLoaderEditor : EditorWindow {

    private string spreadsheetId = "";
    private string sheetName = "";

    [MenuItem("Tools/Load Scenario Data")]
    public static void ShowWindow() {
        GetWindow(typeof(ScenarioLoaderEditor), false, "Load Scenario Data");
    }

    private async void OnGUI() {
        GUILayout.Label("Google Spreadsheet Settings", EditorStyles.boldLabel);
    
        spreadsheetId = EditorGUILayout.TextField("Spreadsheet ID", spreadsheetId);
        sheetName = EditorGUILayout.TextField("Sheet Name", sheetName);

        if (GUILayout.Button("Load Scenario Data")) {
            await ScenarioLoader.LoadScenarioData(spreadsheetId, sheetName);
        }
    }
}

自宅Wi-Fi環境アップデートを検討し、結局そこまで変えなかったが色々楽しめたのでヨシとする

最近ネットワークの勉強を少しずつしていて、そろそろ実践的な何かもやりたいなーと思い始めてきました。そこで「自宅のネットワーク環境で何かできないかな」と思い始めるのは自然な流れでしょう。

ただ、うちは賃貸でそこまで広くないし、最近変なイキモノ*1が仲間に加わったこともあり、あまりケーブル等を増やしたくない気持ちになり、無線LANの範囲内で検討しようとなりました。

【目次】

まずは無線LANWi-Fi)について知らねば

今までかすかにインプットしていたネットワーク関連知識はだいたい有線がベース。お恥ずかしながら無線LAN、つまりはWi-Fi環境のアレコレについては本当にナニモワカラナイ状態でした。

具体的には以下のレベルの認識。

  • SSID見つけてパスワード入れれば使える」
  • 「公衆無線LANは通信内容見えちゃうから扱いには気をつける」
  • 「2.4GHzと5GHzみたいなのがあるけど、5GHzのほうが繋がりやすい?らしい?」

わかってなさすぎて照れる。

そもそも自宅環境をいじるにしても何ができるかもわからないため、どこから手をつけるべきかもわからず。

そういう訳なので、それっぽい本を何冊か読んで基本知識をインプットすることにしました。

読んだ本は以下。

上二冊はWi-Fi関連用語を知るのに良く、しかし業務用LAN構築に寄った話だったので、三冊目の本が家庭用ルーターなど一般利用向けの具体的Tipsや用語をさらえて良かったです。

人任せにして放置していた自宅ネット環境の棚卸し

次にやったのは自宅のネット環境の棚卸しです。

何ができるかは回線やISPの契約内容、ルーターの機種によって変わるはずですが、それらを全く把握してませんでした。

ISPやらを契約したのは5年以上前、しかも同居人にすべてを任せっきり。そして同居人は当時をあまり覚えておらず。

ルーターはリモートワークの波が来たタイミングで新調したのですが、それも同居人と家電量販店のスタッフにお任せ。そして同居人は当時をあまり覚えておらず。

そういう訳で、ホコリ被った契約書を引っ張り出しプラン確認するところからやりました。一度もログインせずに放置されていた管理用サイトを見つけ出したり、ルーター機種名をググったりと現状把握に労力を投下しました。

そして判明したのが下記です。

種別 名称
回線 フレッツ 光ネクスト マンションタイプ
ISP @nifty
ルーター NEC Atermシリーズ

Wi-Fiへの接続デバイスと帯域もチェックしました。

バイス 帯域
PC 1 5GHz
PC 2 5GHz
PC 3 5GHz
PC 4 5GHz
Smartphone 1 5GHz
Smartphone 2 5GHz
Tablet 1 5GHz
Tablet 2 2.4GHz
Nintendo Switch 5GHz
Fire TV Stick 5GHz
空気清浄機 5GHz
SwitchBot Hub Mini 2.4GHz
デスクライト 2.4GHz
Webカメラ 2.4GHz

IoT系は2.4GHz縛りのものが結構多いことをここで知りました*2。2.4GHz帯は閉じるのもありなのかなーとか思っていたのですが、とんでもないですね。

また、このタイミングで初期値のまま放置していた(オイ)パスワード等の値の刷新したり、これまた初期設定のまま放置していたWi-Fi電波の暗号化方式をよりセキュアな方式に変更するなどしました。

速度改善検討したけどやめた。配線がVDSL方式だったからね

機器について、以前から地味に気になっていたことがありました。

我が家、ルーターと外へ繋がるケーブルの間にもう一つ機器があるのですよね。ネット繋がってるしいいかとずっと見て見ぬふりしてました。

自宅ネット環境棚卸しの際に、さすがに見ぬふりは貫けないなとその機器に貼ってある製品シールを読み、機器が"VDSL"というものだと知りました。

なんだそれ。ググります。

flets.com

これによって、我が家の回線は「VDSL方式」で光回線に接続していることがわかりました。マンションまでは光配線、マンション内から各部屋までは電話配線で接続しているとな。

マンションタイプ「サービスメニュー」と「配線方式」について | フレッツ 光ネクスト より

そして、この「VDSL方式」というのが曲者でした。

電話線部分がボトルネックになって、最大でも100Mbpsの通信速度しか望めないとのこと。おい、光はどこにいった。そしてこのマンション内の電話配線は各部屋で共有してるため、同時接続が多いほど遅くなりやすい。

この時点でWi-Fi環境アップデート計画のなかから「速度改善」という言葉が消えました。

とはいえ、実は通信速度に関しては特に困ったことはなかったので、別にいいかなという感じでもあります。

一応こちらのサイトで測定もしてみました。上り下りともに通常利用範囲ではやはり問題なさそうな数値ぽいですね。

同じマンションにネットをガンガン使うような家庭がそんなにないんでしょうかね。ルーターの性能的に、ルーター部分で速度が劣化してなさそうというのもありそうです。

最新のWi-Fi6対応ルーター導入したり、AP増設してメッシュWi-FiにしたりAP同士の電波チューニングだのも少しやってみたかった気はしますが、家の広さやネット利用状況等を踏まえると、そこまで頑張らなくても問題ないんですよね。そしてVDSLだし。

ということで、通信速度に関してはノータッチでいくことになりました。

IPoEがちょっと気になるお年頃だったが、PPPoEとの併用環境つくるのが面倒になったのでやめる

IPoE、PPPoE。これらの用語は書籍等で見かけたことはあったのですが、なんだか遠い世界の言葉のようであまり頭に入ってこなかった過去があります。

せっかく自宅環境を見直しているところなので、これらについても調べてみて、できれば設定してみたいなーと思っておりました。自分ごとになればもうちょい頭に入るかなと。

調べてみたところ、現在はPPPoEを利用しての接続をしており、契約中のISPはIPoEでの接続へ無料で切り替えられるとのこと。

csoption.nifty.com

IPoEのメリットとして速度改善が主に挙げられるようです。速度改善。光回線への接続がVDSL方式だからノータッチでいこうとしていた部分です。正直やる必要がない。

でもやってみたいんだもん。ということで、リサーチを継続しました。

IPoEとPPPoEについてはこの記事がとてもわかりやすかったです。

www.ntt.com

そして、IPoEに切り替える前提条件として、利用しているルーターIPv4 over IPv6に対応している必要があることがわかりました。IPoEってIPv6にのみ対応しているプロトコルだったのですね。なので、IPv4にしか対応していないサービスにアクセスするにはIPv4パケットをカプセル化し、ネットワーク上でIPoEプロトコル利用時はIPv6パケットとして流し、IPv4のみ対応のサービスに渡すときはカプセル化を解除してIPv4パケットとして送る必要があるのだと把握しました(たぶん)

それがIPv4 over IPv6で、こちら側ではルーターカプセル化の処理をしてくれるのでしょう(たぶん)。あちら側はISPルーターとかが頑張ってくれるのだろうか。

確認してみたところ、現在利用しているAtermルーターIPv4 over IPv6に対応していたので、ヨシ!とISPである@niftyにてIPoE接続サービスの申し込みをしてやろうと意気込みました。

意気込んでいた、のですが。

@niftyの以下のページにて、気になる記述を見つけてしまいました。

@nifty v6サービス | @nifty

特定ポートを使用するサービスはPPPoE接続が必要となります。IPoE接続とPPPoE接続を併用してご利用ください。 例:一部オンラインゲームやWebカメラ(監視カメラ)、固定IPサービス、@niftyフォン、オンラインレセプトサービスなど

バイス棚卸し時に出てきたのですが、我が家、Webカメラを使っているのです。具体的にはPanasonicのこちらのベビーカメラ。寝室にいる変なイキモノ*3の生息を確認するのに大活躍しています。

panasonic.jp

こちらのベビーカメラ、映像をスマホ等のアプリから見ることができるのですが、そのアプリの説明ページにて以下の記述を発見しました。

グローバルIPアドレス[IPv4][IPv6を用いたIPv4]が付与されているインターネット接続環境をご用意ください。

お、IPv4 over IPv6で通信すればいけるぽい?が、固定IPサービス等、特定ポートを指定して接続しなければならない状況は今後十分考えられるので、IPoEとPPPoEが併用できる環境にはしておきたいところ。

調べてみたところ、やはり似たような状況でIPoEとPPPoEの併用環境を組んでいる人はいました。

note.com

qiita.com

qiita.com

薄々そうなんだろうなーと思ってはいたのですが、併用するにはもう一つルーター機器を用意する必要がありそうでした。それかYAMAHAルータ RTX830を買う。

ここまでかな、と。

通信速度に困っているわけでもないしVDSLだしで、新しくルーターを買うもしくは一部サービス接続不可な状況にしてまでIPoEに切り替えたいか?と言われれば正直微妙なところです。また、この時点で「IPoEとかPPPoEとかよくわからないから実際に検討することで理解を深めたい」といった欲望はだいぶ満たされていました。

引っ越し等で自宅環境が変わったら、再度検討することとします。

まとめ

結局自宅Wi-Fi環境アップデート大作戦は、色々と検討したもののほとんど何も変えずに終わることとなりました。が、以下の点でやってみてよかったです。

  • よくわかってなかった自宅のネットワーク関連の契約状況が把握できた
  • 各機器やサービスの管理ページを把握できたので、設定変更等が気軽にできるようになった
  • 初期設定のまま放置されていたアレコレを再設定するいいきっかけになった。セキュリティ強度の向上
  • Wi-Fi関連の用語が以前よりだいぶわかるようになった

実際にはWi-Fi環境というより、電波を飛ばす前のネットワーク環境について見ていることが多かった気もしますが、まあいいでしょう。

総じて楽しい体験ができたなと想います。

今回はこれまでとしますが、どこかのタイミングで自宅ネットワークで色々やってみたいものですね。

*1:世で言うところの0歳児です

*2:例によってこれらも同居人が設定したため知らなかった

*3:[再掲]世で言うところの0歳児です