読者です 読者をやめる 読者になる 読者になる

Nobollel開発者ブログ

Nobollelのエンジニアが、UnityやCocos2d-xの旬な情報・技術を紹介します。

Unityで実機上のアプリバージョンを取得する (iOS/Android)

Unity iOS Android

Unityで実機上のアプリバージョンを取得する (iOS/Android)

こんにちは、Nobollelエンジニアの古屋です。今回は、Unity iOS/Android実機でバージョンを取得する方法を紹介します。


一応、アプリバージョンはApplication.versionから取得できます。

Debug.Log("version=" + Application.version);

しかし、これは表示用のバージョンで、厳密なバイナリバージョン (Androidならバージョンコード) が別にあります。ログにバージョンを乗せたいときなど厳密なバージョンの方を知りたいことも多いです。この記事ではこれらを実行時に取得する方法について書いていきます。

iOSのビルド番号を取得する

そもそも「ビルド番号」というのは、Unity上で設定するこれ↓

f:id:nobollel:20161209125706p:plain

もしくはXcode上のこれ↓のことです。

f:id:nobollel:20161209125911p:plain

(正式名称がよくわかりませんが、Unityのエディタスクリプトのプロパティ名がbuildNumberなので、便宜上ビルド番号と呼んでいます)

「Version」がApp Store上に表示されるバージョンなのに対して、「Build」はアップロードする各バイナリのユニークなバージョンです。たとえば、表示上のバージョンを変えずにバイナリをストアに再アップロードする場合は、Buildの数字を上げる必要があります。

ビルド番号の取得には、ネイティブコードの実装が必要です:

IOSVersion.mm (Plugins/iOS以下に配置)

extern "C" {
    char *GetBundleVersion() {
        NSString *bundleVersion = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"];
        const char *s = [bundleVersion UTF8String];
        return strcpy((char *)malloc(strlen(s) + 1), s);
    }
}

[NSBundle mainBundle]infoDictionaryからバージョン情報を取り出して返すだけのネイティブコードです。CFBundleVersionというキーがビルド番号に該当します。

プラグインが返す文字列はヒープ上に確保されている必要がある (ここiOS Tipsを参照) ので、mallocしたポインタにstrcpyして返しています。


次はC#側のコードです:

IOSVersion.cs

#if UNITY_IOS
using System.Runtime.InteropServices;
#endif

#if UNITY_EDITOR
using UnityEditor;
#endif

public static class IOSVersion {
    public static string GetBuildNumber() {
#if UNITY_EDITOR
        return PlayerSettings.iOS.buildNumber;
#elif UNITY_IOS
        return GetBundleVersion();
#else
        return null;
#endif
    }

#if UNITY_IOS
    [DllImport("__Internal")]
    static extern string GetBundleVersion();
#endif
}

C#側では、さきほどのネイティブの関数2つをラップしているだけです。エディタ上ではプラグインが動作しないのでPlayerSettingsから値を取得して返し、iOS以外のプラットフォームではnullを返します。

Androidのバージョンコードを取得する

Androidでは、iOSのビルド番号に相当するものとしてバージョンコードがあります。こちらはネイティブコードを書かなくても、AndroidJavaObjectを使って実装できます。

AncroidVersion.cs

#if UNITY_ANDROID
using UnityEngine;
#endif

#if UNITY_EDITOR
using UnityEditor;
#endif

public static class AndroidVersion {
    public static int GetVersionCode() {
#if UNITY_EDITOR
        return PlayerSettings.Android.bundleVersionCode;
#elif UNITY_ANDROID
        using (var packageInfo = GetPackageInfo()) {
            return packageInfo.Get<int>("versionCode");
        }
#else
        return 0;
#endif
    }

#if UNITY_ANDROID
    static AndroidJavaObject GetPackageInfo() {
        using (var unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer"))
        using (var currentActivity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity"))
        using (var context = currentActivity.Call<AndroidJavaObject>("getApplicationContext"))
        using (var packageManager = context.Call<AndroidJavaObject>("getPackageManager"))
        using (var packageManagerClass = new AndroidJavaClass("android.content.pm.PackageManager")) {
            string packageName = context.Call<string>("getPackageName");
            int activities = packageManagerClass.GetStatic<int>("GET_ACTIVITIES");
            return packageManager.Call<AndroidJavaObject>("getPackageInfo", packageName, activities);
        }
    }
#endif
}

GetPackageInfoは見た目ごちゃごちゃしていますが、アクティビティからPackageManagerを取ってきてgetPackageInfoしているだけです。戻り値のPackageInfoクラスがバージョン情報を持っており、そこからversionCodeを取得します。