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);