UnityでiOS向けの開発とかやってると、容量の都合などでコンテンツの追加配信などでAssetBundleは避けられない道です。
ただ、AssetBundle化したいファイル全てにいちいちInspectorからAssetBundleとnameとか設定するのは正直めんどくさい...
今ではAssetBundleManagerやら、AssetBundleBrowserとか色々公式から便利なツールが出てきているので、そっちを使ってもいいのですが、暗号化処理とかを挟むために自前で実装する必要があるようなこともあるので、その際に役立つやり方を忘れないように残しておきます。
#はじめに
AssetBundle周りは改善が繰り返されていて、バージョンによってまるっきりやり方が違ったり(これからもどんどん変更されていったり)するみたいなのですが、自分の環境はUnity 2017.3とmacOS high Sierraでやっていくので、Windowsの方はBuildTargetなどは適宜変更してください。
#やり方
##変換したいリソースを置く場所を決める
ProjectのAssets内に"Resources"というフォルダとその中に"PlaceFileHere"みたいなパッとわかる適当な名前のフォルダを作ります。そして、Editerの拡張を書くので、Assets以下に"Editor"というフォルダも作っておきます。
最終的にはAssets/Resources/PlaceFileHere/
とAssets/Editor/
って感じ。
##Editer拡張を書いていく
Editorフォルダの中にC#スクリプトを作成、名前をCreateAssetBundles.cs
みたいな感じにします。
そしてこのScriptの中にiOSとAndroidとUnityEditer向けにビルドするコードを書いていきます。
using UnityEditor;
using System.IO;
using System.Collections.Generic;
using UnityEngine;
public class CreateAssetBundles
{
private const string sourceDirectory = "Assets/Resources/PlaceFileHere/";
private const string iOSPath = "iOS/";
private const string editerPath = "UnityEditer/";
private const string androidPath = "Android/";
[MenuItem("Assets/Build AssetBundles")]
static void BuildAssetBundles()
{
//sourceディレクトリの全てのファイル・フォルダを取得(サブフォルダの内部までは見ない)
//sourceフォルダに入れたものは全てAssetBundle化対象
string[] srcFilesPath = Directory.GetFileSystemEntries(sourceDirectory);
foreach (string srcFilePath in srcFilesPath)
{
//ファイルの名前を取得し、AssetBundleの名前に設定する
string fileName = Path.GetFileNameWithoutExtension(srcFilePath);
AssetImporter importer = AssetImporter.GetAtPath(srcFilePath);
if (importer != null)
{
importer.SetAssetBundleNameAndVariant(fileName, "");
}
}
//無いフォルダは作る
string assetBundleDirectory = "Assets/AssetBundles/";
if (!Directory.Exists(assetBundleDirectory + iOSPath))
{
Directory.CreateDirectory(assetBundleDirectory + iOSPath);
}
if (!Directory.Exists(assetBundleDirectory + editerPath))
{
Directory.CreateDirectory(assetBundleDirectory + editerPath);
}
if (!Directory.Exists(assetBundleDirectory + androidPath))
{
Directory.CreateDirectory(assetBundleDirectory + androidPath);
}
//各OS向けにビルド
BuildPipeline.BuildAssetBundles(assetBundleDirectory + iOSPath, BuildAssetBundleOptions.None, BuildTarget.iOS);
//Windowsの方はBuildTarget.StandaloneWindowsにでも変更してください
BuildPipeline.BuildAssetBundles(assetBundleDirectory + editerPath, BuildAssetBundleOptions.None, BuildTarget.StandaloneOSX);
BuildPipeline.BuildAssetBundles(assetBundleDirectory + androidPath, BuildAssetBundleOptions.None, BuildTarget.Android);
//sourceディレクトリのAssetBundle対象化を解除
foreach (string srcPath in srcFilesPath)
{
AssetImporter importer = AssetImporter.GetAtPath(srcPath);
if (importer != null)
{
importer.SetAssetBundleNameAndVariant("", "");
}
}
}
}
基本的には、Directory.GetFileSystemEntries(string path)
でフォルダ内のすべてのファイルやフォルダを取得して、AssetImporter
のSetAssetBundleNameAndVariant(stiring name,string Variant)
でAssetBundleの対象にし、あとはBuildPipeline.BuildAssetBundles()
で各OS向けのAssetBundleを生成していく感じです。
最後にAssetBundle対象化の解除を行なっています。
余計なファイルがAssetBundleの対象にされることのないようやっておくといいかなと。
##あとは実行するだけ
Assets > Build AssetBundlesを実行すれば、ビルドされてフォルダに出力されるはずです。
Buildする際に各プラットフォームにSwitchするからか、クソほど時間がかかるのでじっくり待ちましょう。
#終わりに
そんなに大変ってわけでもないですし、AssetBundle間の依存関係がややこしいようなものを変換したい方以外の人にはオススメです。
チーム開発で非プログラマの方にAssetBundle化してもらうとこまでやってもらう場合なんかも役にたつかもしれませんね。
各プラットフォームに向けてビルドしてるので当たり前ですが、iOS向けをEditorとかで読み込もうとすると表示がおかしくなったりするのでプラットフォームにあったものを使いましょう。
BuildPipeline.BuildAssetBundles()
の返戻値のManifestを使うと変換後のファイルにさらなる変更(暗号化とか)を行えます。気が向いたらそういうのも含めた記事も書くかも。