【Unity】700MB→179MB!Unityでアプリ容量削減

はじめに

以前、Unityで簡単なiOSアプリを作りリリースした時にArchiveで作成したipaが130MBあったのでその対応に関しての記事です!

iOSのダウンロード制限について

ちなみにiOSではAppStoreに公開して100MBを超えているとWifiに接続しないとダウンロードできません。

問題点
アプリがWifi必須に制限されるとインストール率が大幅に低下します。

インストールすると容量が増える件

iOSはipaという圧縮ファイルでアプリを配布しており、インストール後はiOSのストレージに解凍されます。

問題点
アプリの容量が大きいとユーザーはアプリをアンインストールしたくなります。
ipaのサイズ130MB
解凍後のサイズ700MB

容量削減のために試したこと

容量削減のために試したこと一覧です。

Textureサイズを適切なものに変更

容量にはほぼ変化なしだがメモリ削減に効果あり。

UnityのProjectから画像素材を選択するとInspectorに下のような画面が表示されます。
そこで画像のサイズとクオリティを設定できます。

デフォルトでは2048という無駄に大きいサイズになっているはずなので画像素材のサイズより大きい適切なものに変更しましょう。(下では200x200pxの素材を256に変更)

素材の容量を削減

容量にやや効果ありですが、やりすぎると劣化します

ipaのサイズ130MB→124MB
解凍後のサイズ700MB→680MB

画像圧縮などで検索して以下のようなサービスで容量削減してください。

今回の場合、容量の原因は主に画像素材だったので、素材自体を圧縮してみました。

問題点
圧縮のしすぎは素材の劣化として現れます。アプリのクオリティを損なわない程度に調整してください。

AssetBundle化

iPhoneでの容量に大幅に効果あり

ipaのサイズ124MB→116MB
解凍後のサイズ680MB→179MB

今回の場合、連番画像が多くなっており、それをResources.Load()で取得しておりました。
しかし、Resourcesフォルダの多用はビルド時に使用している使用していないに関係なく無圧縮でビルドされることがわかりました。
また、画像素材の他にもビルド時に生成されたものがあり容量的によくないようです。
AssetBundleはUnityで使う素材を圧縮したもので、アプリで使用する時だけ解凍されます。

Resourcesをやめ、フォルダ名をResourceに変更しました。(フォルダ名はなんでも良い)
Resourceフォルダを選択すると、下にAssetBundle名を登録できますので自由につけました。(デフォルトはNone)

AssetBundleの運用
グループごとにフォルダを分けている場合でもフォルダ以下をAssetBundleにできますが、個別に名前をつけたほうが差し替えなどに都合がよくなります。

AssetBunldeの作成

以下のコードをUnityのProjectの「Assets/Editor」に追加します。

using UnityEngine;
using System.Collections;
using UnityEditor;
using System.IO;

public class ExportAssetbundle  {

	[MenuItem("Export/AssetBundle/iOS")]
	static void iOS_Export() {
		Directory.CreateDirectory (Application.streamingAssetsPath);
		BuildPipeline.BuildAssetBundles(Application.streamingAssetsPath+"/iOS", BuildAssetBundleOptions.ChunkBasedCompression, BuildTarget.iOS);
	}

	[MenuItem("Export/AssetBundle/Android")]
	static void Android_Export() {
		Directory.CreateDirectory (Application.streamingAssetsPath);
		BuildPipeline.BuildAssetBundles(Application.streamingAssetsPath+"/Android", BuildAssetBundleOptions.ChunkBasedCompression, BuildTarget.Android);
	}
}

追加するとUnityのメニューに「Export/AssetBundle」が追加されます。

UnityのProjectのAssetsに「StreamingAssets/iOS」を追加してメニューのiOSを選択するとAssetBundleの作成が開始されます。
作成されたAssetBundleは「Assets/StreamingAssets/iOS」に追加されます。

AssetBundleの読み込みはAssetBundle.LoadFromFile()メソッドで読み込めます。
しかし、AssetBundleは1度しか読み込めません(読み込むとエラーが出ます)
なので自分は以下のようにstaticのメソッドで一度読み込んだらキャッシュから読み出すようにしています。
AssetBundleが読み込めない時は、上の手順では「Assets/StreamingAssets/iOS」にAssetBundleを作成したので問題はないはずですがLoadFromFile()内のパスを確認してください。

private static Dictionary<string, AssetBundle> assetBundleCache = new Dictionary<string, AssetBundle>();
private static AssetBundle readAssetBundleAssetBundle(string key) {
	AssetBundle assetBundle = null;
	if (!string.IsNullOrEmpty(key)) {
		if (assetBundleCache != null) {
			if (assetBundleCache.ContainsKey (key)) {
				assetBundle = assetBundleCache [key];
			}
		}
		if (assetBundle == null) {
			assetBundle = AssetBundle.LoadFromFile(Application.streamingAssetsPath+"/iOS/"+key);
			if (assetBundleCache.ContainsKey(key)) {
				assetBundleCache[key] = assetBundle;
			} else {
				assetBundleCache.Add(key, assetBundle);
			}
		}
	}
	return assetBundle;
}

読み込んだAssetBundleから素材を取り出すにはLoadAsset()を使用します。
上のreadAssetBundleAssetBundleメソッドを使ってAssetBundleを取得した後、LoadAssetでSpriteを取得しています。
Resouces.Loadでは「Resouces/Chara/chara_1.png」を読み込む場合、”Chara/chara_1.png”を引数としていましたが、LoadAssetではフォルダ階層を無視し、拡張子が必要です。”chara_1.png”が引数になります。

AssetBundle assetBundle = readAssetBundleAssetBundle(AssetBundle名);
if (assetBundle != null) {
	sprite = assetBundle.LoadAsset<Sprite>(素材ファイル名);
}

AssetBundleで素材を読み込むのなら、AssetBundle化した素材たちはAssetsより上などプロジェクトの外で管理しておきましょう。

ダウンロードで素材を取得

ストアからダウンロード時のサイズに効果あり

ipaのサイズ124MB→116MB
解凍後のサイズ680MB→179MB

上の3つの対策をしてiPhoneでの容量は大幅に減らせましたが、ipaのサイズが100MBを超えているため素材は初回にダウンロードすることにしました。
このアプリでは一応、設定値などを起動時に通信していたのでその通信にAssetBundleも含めたいと思います。サーバーを利用していない場合はAWSのS3やFirebaseのFireStoreなど簡易的なストレージを使用するのがおすすめです。

サーバーにはAssetBundleのパスと最終更新日を用意し、最終更新日がアプリ内の最終更新日付より新しくなったら再取得するようにしました。

作成したAssetBundleにはフォルダに登録したAssetBundle名のファイル以外に「.manifest」や「iOS」「iOS.manifest」などが作成されますが削除してビルドしても実機で動かす際には問題なかったので使用しませんでした。

AssetBundleの取得はUnityWebRequestクラスで行います。

結論

  • 画像は256色にする
  • Resourcesフォルダの多用はしない
  • それでも重い時はAssetBundle化
  • ipaの容量が100MB超えたらサーバーからダウンロードさせる

AssetBundleはPrefabなども可能なのでサーバーがあればアプリを更新せずにレイアウトの変更も可能に!

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です