Unity : Android アプリで他のアプリケーションのバージョンを取得する方法

複数のAndroidアプリと連携してごにょごにょするみたいなサービスを作っているときに他の連携アプリのバージョンを確認してそのアプリのバージョンが最新でなかったら警告を表示... みたいなことをしたい時に使えるtips

参考にした記事

インストールされているアプリのバージョンをチェックし、ストアに誘導する #C# - Qiita 他アプリのContextを取得するには | Android-Note

それとAndroid公式ドキュメント https://developer.android.com/reference/android/content/Context#CONTEXT_IGNORE_SECURITY

スクリプト

適当なスクリプトを用意して以下のコードをコピペしてStart()メソッドなどで呼び出す
実際に使うときはパッケージ名の com.example.sample をバージョンを取得したいアプリのパッケージ名にする

#if UNITY_ANDROID
    private string GetOtherApplicationVersionName()
    {

        using AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
        using AndroidJavaObject context = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity").Call<AndroidJavaObject>("getApplicationContext");
        using AndroidJavaObject otherAppContext = context.Call<AndroidJavaObject>("createPackageContext","com.example.sample", 2);
        using AndroidJavaObject packageManager = otherAppContext.Call<AndroidJavaObject>("getPackageManager");
        using AndroidJavaObject packageInfo = packageManager.Call<AndroidJavaObject>( "getPackageInfo", otherAppContext.Call<string>("getPackageName"), packageManager.GetStatic<int>("GET_ACTIVITIES") );

        string versionName = packageInfo.Get<string>("versionName");
        Debug.Log($"other application version : {versionName}");
        return versionName;
    }

#endif

解説

まず現在起動しているアプリのコンテキストを取得

AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
AndroidJavaObject context = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity").Call<AndroidJavaObject>("getApplicationContext");

次に、そのコンテキストから createPackageContext を呼び出し、バージョン情報を取得したいパッケージ名を指定、第二引数に Context.CONTEXT_IGNORE_SECURITY の値である 2 を指定
これは要求するコンテキストのセキュリティ制限を無視して常にロードできるようにする引数なので利用は慎重にとのこと

AndroidJavaObject otherAppContext = context.Call<AndroidJavaObject>("createPackageContext","com.example.sample", 2);

後は自分のアプリバージョンを取得する時と同様に packageManager から packageInfo を取得して versionName を取得するだけ

AndroidJavaObject packageManager = otherAppContext.Call<AndroidJavaObject>("getPackageManager");
AndroidJavaObject packageInfo = packageManager.Call<AndroidJavaObject>( "getPackageInfo", otherAppContext.Call<string>("getPackageName"), packageManager.GetStatic<int>("GET_ACTIVITIES") );

string versionName = packageInfo.Get<string>("versionName");

地味に引っかかったポイント

AndroidJavaObjectのCallメソッドでメソッド呼び出すときにその引数が int だったら int の値を渡す必要がある
最初 "Context.CONTEXT_IGNORE_SECURITY" の文字列を渡したら以下のエラーが出たからしばらく時間がかかった

AndroidJavaException: java.lang.NoSuchMethodError: no non-static method with name='createPackageContext' signature='(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object;' in class Ljava.lang.Object;

解決のヒントは↓のページで 渡すのはJavaの定数ではなく実際の値 ってアドバイスから forum.unity.com

Context.CONTEXT_IGNORE_SECURITY は 2 (0x00000002 ) が設定されているのでそのまま 2 を引数として渡した

AndroidJavaObject otherAppContext = context.Call<AndroidJavaObject>("createPackageContext","com.example.sample", 2);

Unity : エディタ拡張でUnityエディタを再起動する方法

Unityエディタ拡張でエディタを再起動したいときに検索したコードだとUnityエディタを閉じた後にUnityHubが起動するだけで肝心のプロジェクトが起動するところまでいかなかったのでいろいろ試した

最初に試したこと

よくあるのはこんな感じのコード

static void Restart()
{
    Process.Start(EditorApplication.applicationPath);
    EditorApplication.Exit(0);
}

現在起動しているエディタのパスを指定して起動した後にエディタを閉じるというもの

2023/08/28 現在ではこのコードではエディタを閉じたのちにUnityHubが起動するのみでプロジェクトまでは開いてくれなかった

解決策

以下のフォーラムにて対処方法が記述されていた
Is there an API to restart the editor via script? - Unity Forum

static void Restart()
{
    EditorApplication.OpenProject(Directory.GetCurrentDirectory());
}

Unity の CsReference 覗いてみたところエディタの再起動は以下のようなコードになっていた
https://github.com/Unity-Technologies/UnityCsReference/blob/62633e3912ab891be4c6f5ef4500e69f59d85ed4/Editor/Mono/Inspector/PlayerSettingsEditor/PlayerSettingsEditor.cs#L2916

Environment.CurrentDirectory と Directory.GetCurrentDirectory() はどちらもカレントディレクトリのパスを返すプロパティ or メソッド
どちらを使うかはほぼ好みに分かれるけど Environment.CurrentDirectory の方は setter でカレントディレクトリを移動出来てしまうので取得オンリーの Directory.GetCurrentDirectory() を採用した

パスフレーズの作り方

ほぼ自分用メモ

パスフレーズとは?

本人認証等で用いられるパスワードの一種。 一般的には文字数が多いものをパスフレーズと言うらしい。 一般的なパスワードよりも文字数 ( アルファベット大・小文字、数字、記号などを含む ) を多くしたものだが用途や中身が特別パスワードと異なるわけではない。 いくつかの単語をつなげたものなのでパスフレーズという言葉が使われている

例. トップガンのセリフ「I feel the need for speed」をつなげて Ifeeltheneedforspeed など、ただし映画のセリフなどは予測されやすいものなので利用はお勧めできない。

おすすめのパスフレーズの作り方

パスフレーズの作り方で調べると大体先頭に出てくるダイスウェア パスフレーズ  ↓のページに概念とか作り方とかが紹介されている。 Diceware Passphrase Home Page (Japanese)

前準備
ダイスウェア単語一覧をダウンロードしておく。

サイコロを用意する、手元にない場合は適当な乱数メーカー等を使って乱数を作成する。

パスフレーズ作成
1. サイコロを5回 or 5個のサイコロを振る
1. 出てきた5桁の数値をメモする
1. 単語一覧から5桁の数値に該当する単語を見つけ、メモする
1. 1 ~ 3を任意の回数繰り返し、単語をつなげてパスフレーズにする

長ければ長いほど堅牢ではあるがその分入力に手間がかかる、無難なのは6単語くらいで作るパスフレーズ

あとがき

パスフレーズを自分で考えるとどうしても似たような傾向になったり覚えやすいものを作ったりしてしまうがダイスウェアパスフレーズなら記憶と毎回の入力の手間だけで安全性の高いパスフレーズが作れるのでお勧めしたい。
特にGithubsshキー等のパスフレーズなどセキュリティ的に堅牢にしておきたい時など。

サイコロ振るのが面倒だったらツール作るのもいいかも。

Unity Project を UPM で公開する方法

個人的な備忘録。

一次資料 ( Unity マニュアル )

Unity の Package Manager - Unity マニュアル
Git URL からのインストール - Unity マニュアル
パッケージレイアウト - Unity マニュアル

参考にした先達の資料

zenn.dev
tips.hecomi.com

Unity プロジェクトを作成

今回は Unity プロジェクトの中身をパッケージとして公開したいのでマニュアルで紹介されていた構成をAssets/MatsumotoPackageExampleフォルダ以下に構成。

package.json を記述

パッケージマニフェストはマニュアルにあるものをほぼコピペ
パッケージマニフェスト - Unity マニュアル

必須要素

プロパティ 説明
name パッケージ名
version パッケージバージョン

必要要素

プロパティ 説明
description パッケージの概要
displayName Projectウィンドウ、UPMウィンドウでの表示名
unity パッケージと互換性のあるUnityの最も低いバージョン、省略すると全てのUnityバージョンと互換性が有るものとみなす

任意要素についてはマニュアルを参照。
下のマニフェストは必要最低限の要素を記述したもの。
注意点として name のパラメータは全て小文字でないとダメです。

  • 会社名やウェブサイト名が数字で始まっていても、<domain-name-extension>.<company-name> (例えば、com.example や net.example) で開始します。

  • UI に表示したい場合は 50 文字以下にしてください。UI にパッケージ名を表示する必要がない場合は 214 文字以下に制限してください。

  • 小文字、数字、ハイフン (-)、アンダースコア (_)、ピリオド (.) のみを使用してください。

  • ネストされた名前空間を示すために、名前空間に追加のピリオドのサフィックスを加えてください。例えば、 “com.unity.2d.animation” や “com.unity.2d.ik” など。

{
  "name": "com.matsumoto.example",
  "version": "0.0.1",
  "displayName": "MatsumotoPackageExample",
  "unity": "2021.3",
  "author": {
    "name": "Matsumoto",
    "email": "unity@example.com",
    "url": "https://www.unity3d.com"
  },
  "repository": {
    "type": "git",
    "url": "https://github.com/RyusukeMatsumoto7C9-B-2/UnityPackageLaern"
  },
  "license": "MIT License"
}

Github URL でインポートテスト

マニュアルにあるレイアウト例はリポジトリの直下に各種ファイルがある状態 ( UnityProject ではない状態 )での公開でのレイアウトなので今回の方法ではそのままリポジトリのURLを公開する形だとエラーが出てインポートできない。
UnityProject で開発を進めそれをパッケージとして公開したい場合はAssetsフォルダ以下 ( できればもう一つフォルダを挟む、今回の例では MatsumotoPackageExample ) に package.json を配置し、そのフォルダまでの URL を利用することでインポートできる。

リポジトリの URL + ?path=package.json があるフォルダまでのパス
↓例

https://github.com/RyusukeMatsumoto7C9-B-2/UnityPackageLaern.git?path=Assets/MatsumotoPackageExample

これでUnityProjectをGithubのURLでPackageManagerからインポートすることができるようになる。

動作確認

実際にプロジェクトにインポートして正常にパッケージをインポートできているか確認。
利用する URL は↓を利用する。

https://github.com/RyusukeMatsumoto7C9-B-2/UnityPackageLaern.git?path=Assets/MatsumotoPackageExample

PackageManager を開き add package from git URL から URL を記入。

成功すると PackageManager の画面で正常に MatsumotoPackageExample が表示される。

Packages フォルダ以下に展開されているのも確認できる。

おまけ : サンプルを追加してみる

パッケージのサンプルの作成 - Unity マニュアル

Samples フォルダ以下に SamplesHoge を作成。

作成後、 Samplesフォルダを Samples~ に名称を変更し、非表示にする。

その後 package.json を編集、versionの更新と一番下にサンプルを追加した。

{
  "name": "com.matsumoto.example",
  "version": "0.0.3",
  "displayName": "MatsumotoPackageExample",
  "description": "This is an example package",
  "unity": "2021.3",
  "author": {
    "name": "Matsumoto",
    "email": "unity@example.com",
    "url": "https://www.unity3d.com"
  },
  "repository": {
    "type": "git",
    "url": "https://github.com/RyusukeMatsumoto7C9-B-2/UnityPackageLaern"
  },
  "license": "MIT License",
  "samples": [
    {
      "displayName": "HogeSample",
      "description": "HogeSample",
      "path": "Samples~/SamplesHoge"
    }
  ]
}

Github でリリースを作成する

0.0.4 のタグを作成、Githubでリリースも0.0.4で作成( .unitypackage もここで公開すれば UPM、unitypackage両方での導入が可能になり親切 )

リポジトリのURLの末尾に0.0.4のタグ名 #0.0.4 を追加してUPMがバージョン0.0.4を参照するようにして Add 。

https://github.com/RyusukeMatsumoto7C9-B-2/UnityPackageLaern.git?path=Assets/MatsumotoPackageExample#0.0.4

無事 0.0.4 のバージョンがインポートされた。

Samples に先ほど作成した HogeSample が表示されているのでインポートを押下する。

すると Assets/Samples/MatsumotoPackageExample フォルダが追加され 0.0.4 の HogeSample が追加されているのが確認できる。

今回作業したリポジトリ

最後に、参考になるかはわからないですが今回作業したリポジトリ
コミットログはいろいろ迷走していたので結構汚いです。

github.com

JSTQB FL 合格しました

先日 JSTQB FL を受験し、合格しました。

受験した動機としては所属している会社でテスト周りを触るようになったのと、自社のプロダクトの品質をより高めていきたいと思っていたので、 その為にまずはソフトウェアテストの基本的な知識、用語を身に着ける必要があると感じたからです。

勉強方法としては以下の手順で進めて行きました。

  1. シラバスを一通り読む ( わからないことがあってもいったん流しておいて全編目を通す )
  2. テス友で模擬テスト20問 ( 完全ランダム設定 )を行い、苦手な知識のある章を割り出す
  3. 割り出した苦手な章の部分を再度読み直し、テス友で模擬テスト ( 章を選択 )
  4. 以降 2 ~ 3 を繰り返す

シラバスはそのままだと個人的に読みづらかったので以下のNotionページにコピペしました ( 文言の前後等あり ) aboard-amethyst-d92.notion.site   

勉強時にはノートにとらずとにかく音読することを意識しました、ノートに書くより音読を何度も繰り返したほうがより覚えるのが早いのかなと体感ですが感じました。
( あとノートに書くと手が疲れる )

FL はあくまで基礎レベルなので今後業務を通して理解を深めていき AL にも挑戦していこうと思います。

Unity HubでインストールしたAndroid SDK の別バージョンインストール方法

仕事で Android OS 10 以前のバージョンでビルドしたいときに詰まったのでメモ。

Unity Hub でインストールする Android SDK は GooglePlayが要求する最新の SDK バージョンをインストールするのでより古いバージョン or 新しいバージョンはインストールされていない
docs.unity3d.com

古いバージョンの SDK でビルドする場合そのバージョンがインストールされていない為、以下のエラーコードが出てビルドできないことが良くある。

Android SDK does not include your Target SDK of (version). Please use the Android SDK Manager to install your target SDK version. Restart Unity after SDK installation for the changes to take effect.    

これの解決には手動で Android Studio から目的の SDK をインストールする必要があるのでその手順を以下にメモ。

Unityでの下準備

1. SDK インストール先のディレクトリパスをコピー

Edit > Preference > External Tools を開き、Android SDK Tools Installed with Unity ( recommended ) の項目の Copy Path ボタンを押下し、パスをクリップボードにコピーする。

2. Unityを閉じる

Unityでの下準備はこれで完了なのでいったんUnityを閉じます。

Android Studio での作業

1. SDK Manager を開く

Tools > SDK Manager を選択し SDK Manager を起動。

2. インストール先のパスを指定

Android SDK Location の横にある Edit を押下し、先ほど Unity でコピーしたパスをペーストする。

Next ボタンを押下し、設定を適用。

3 任意の SDK バージョンをインストールする

ビルドに使いたい任意のバージョンをインストールする。

Unity でビルドする際に Target API Level を Automatic にしているとインストールされているバージョンの中で最新のものを利用するので任意のバージョンが最新になるようにする。
例えば API Level 26 を利用したいときは 27 以降をアンインストールする

原因は深くまで調べていないのでわからないが Unity でビルドする際に Target API Level を Automatic 以外でビルドしようとすると Gradle 周りでエラーが出てしまいビルドできなかったのでこの対応とした。

これで Unity Hub で自動インストールされたバージョン以外の API Level でビルドすることができる。

GameCI自動テストでHttpUtilityを利用しているとエラーでテストできない問題の対応

HttpUtility.UrlEncode メソッド (System.Web) | Microsoft Learn

Untiyのプロジェクトではエラーが出ないことがあり、スルーされてしまうコンパイルエラー
UnityではHttpUtilityの利用は非推奨となりURLエンコード等はUnityWebRequestを利用することが推奨されている

余談だが以前はWWWクラスにURLのエンコード、デコードのメソッドが用意されていたが現在はWWWクラスも非推奨となり、UnityWebRequestに追加されている
↓将来的にページが削除されそうなのでスクショで、現在はWWWクラスは非推奨

現在推奨されているのはUnityWebRequestクラス
Networking.UnityWebRequest - Unity スクリプトリファレンス

以下のような置き換えでよさそう HttpUtility.UrlEncode() -> UnityWebRequest.EscapeURL()
HttpUtility.UrlDecode() -> UnityWebRequest.UnEscapeURL()