間違っている部分もありそうだけど、一応意図したとおり動いたのでまとめておく。
Unity 2019.1.7f1を使用し、Editor、Android実機で確認。
Window > Package Manager を開く。
Packagesタブの下の項目を[All packages]に。
Advanced >Show prview packages にチェック。
左下のLoading packages…が終わるまで待つ。結構長い。
Addressablesが表示されたらInstall.
インストールが終わったら、
Window > Asset Management >Addressables
Addressablesのビューが表示される。
[Create Addressables Settings]を実行。
ProjectビューにAddressableAssetDataが作成される。
ProjectビューのAddressableAssetSettingsを設定する。
Player Version Override = 自分はアプリのビルドバージョンに合わせている。
Build Remote Catalog = true
Profiles の下の+ボタンから、新しくプロファイルを作る。デフォルトを上書きしてもよい。
Profile Entries の RemoteLoadPathを、ファイルを置くサーバーに変更。
例: https://myservertesttest.com/[BuildTarget]
※/[BuildTarget]は消さない。
Addressablesビューに移動し、Profile: Defaultを上記で作ったプロファイルに変更。
Labelsに使いたいラベル名を書く。
ここでは「MyAsset」というラベルを1つ作っておく。
続いて、Projectビュー、AssetGroupTemplatesフォルダ内にある、Packed Assets(テンプレート)を設定する。
▼BundledAssetGroupSchema
Bundled Asset Provider Type = BundledAssetProvider
Build Path = LocalBuildPath
Load Path = LocalLoadPath
▼ContentUpdateGroupSchema
Static Content = true
イラストやから画像を借りてくる。
image1 https://www.irasutoya.com/2015/10/blog-post_65.html
image2 https://www.irasutoya.com/2018/09/blog-post_845.html
image3 https://www.irasutoya.com/2014/01/blog-post_3235.html
テスト用にフォルダやImageを作成していく。
Projectビューに AssetDataというフォルダを作り、image1を設置。
Addressablesビューにも同様のフォルダを作り、Projectビューからimage1をドラッグドロップ。
Addressablesビューで Build > Build Player Content を実行し、AssetBundleデータを作成。
HierarchyビューにUI > Imageを作成。
画面にimage1を表示するためのプログラムを書く。
public class ImageLoader : MonoBehaviour { { ImageLoad(); } void ImageLoad() { //画像のベースとなるImage Image image = GameObject.Find("Image").GetComponent<Image>(); //画像データをロード、アドレスはAddressablesビューのAsset Addressで確認出来る Addressables.LoadAssetAsync<Sprite>("Assets/AssetData/image1.png").Completed += spriteData => { image.sprite = spriteData.Result; image.preserveAspect = true; //アスペクト比を保つ }; } }
上記コードをCanvasあたりにアタッチする。
Addressablesビュー > Play Mode Script > Packed Play Mode に変更。
エディターでPlayする。
image1、赤ちゃんが表示される。
ロードするアドレスはそのままで、表示される画像をimage2に変更する。
Projectビュー、AssetDataフォルダ内
image1をimage1bakにリネーム。
image2をドラッグドロップし、image1にリネーム。
Addressablesビュー、AssetDataフォルダ内
既存のimage1を削除。
ProjectビューAssetData内のimage1を、Addressables側にドラッグドロップ。
Labelsから、MyAssetラベルを付ける。
Addressablesビュー > Build > Prepare For Content Update を実行。
フォルダが表示されるのでaddressables_content_state.binを開く。
更新されるデータを確認し、[Apply Changes]
Addressablesビュー内にContent Updateというフォルダが作成され、image1がそこに設置される。
Addressablesビュー > Build > Build For Content Update を実行。
Unityプロジェクトのフォルダに「ServerData」というフォルダが出来る。
その中の「Android」フォルダをサーバーにアップロードする。
(Projectタブ内には表示されないため、Windowsのエクスプローラーからアクセス)
エディターでPlayする。
データがサーバーからダウンロードされ、更新されたimage1の子供(image2)が表示される。
更新データがあるか確認し、あればダウンロード、更新した画像を表示。
無ければ既存の画像を表示させる。
先程のコードを以下のように修正する。
実装する時は
if (dataSize > 0)
の下あたりに、ダウンロードするかしないか、ユーザーに選択する表示を付けるのが普通かと思うが省略。
using System.Collections; using UnityEngine; using UnityEngine.AddressableAssets; using UnityEngine.UI; using UnityEngine.ResourceManagement.AsyncOperations; public class ImageLoader : MonoBehaviour { // Start is called before the first frame update void Start() { //ImageLoad(); Addressables.GetDownloadSizeAsync("MyAsset").Completed += updata => { long dataSize = updata.Result; if (dataSize > 0) { //更新データあり、ダウンロード //MyAssetラベルの付いたデータをダウンロードする AsyncOperationHandle download = Addressables.DownloadDependenciesAsync("MyAsset"); //ダウンロード中の処理 StartCoroutine(DownloadWait(download)); //ダウンロード完了時の処理 download.Completed += op => { if (AsyncOperationStatus.Succeeded == download.Status) { //ダウンロード成功 //更新した画像を表示 ImageLoad(); } else { //ダウンロード失敗 } }; } else { //更新データ無し、既存の画像を表示 ImageLoad(); } }; } IEnumerator DownloadWait(AsyncOperationHandle download) { while (!download.IsDone) { //ダウンロード中の処理を書く Debug.Log(download.PercentComplete); //※1.1.4ではPercentCompleteは機能していない yield return new WaitForSeconds(0.01f); } } void ImageLoad() { Image image = GameObject.Find("Image").GetComponent<Image>(); Addressables.LoadAssetAsync<Sprite>("Assets/AssetData/image1.png").Completed += spriteData => { image.sprite = spriteData.Result; image.preserveAspect = true; }; } }
ラベル名が一致する更新データのダウンロードサイズを取得している。
ラベル名など無しで、「更新データ全部のサイズ」というのは無理らしい。
Unityのフォーラムでそのうち実装するというコメントを見た気はする。
ラベルは複数付けられるので、今のところは共通のラベル名を全てのデータにつけておけばいいと思う。
※Addressablesのコード修正
AndroidではGetDownloadSizeAsync()が正しく機能していないため、Packages/Addressables内の、
AssetBundleProvider.csを以下のように修正する。 (NG) if (!loc.InternalId.Contains("://"))
↓
(OK) if (!loc.InternalId.StartsWith("http"))
参考 https://scrapbox.io/bexide-tech-blog/Addressables_0.6.8_%E4%B8%8D%E5%85%B7%E5%90%88%E3%81%BE%E3%81%A8%E3%82%81
実機検証のため、再度AssetBundleデータを作成していく。
Addressablesビュー内、Content Updateフォルダにあるimage1を、同ビュー内のAssetDataフォルダに移動する。
Content Updateフォルダは削除してよい。
Build > Build Player Contentを実行。
サーバーにあるAndroidフォルダ内のデータを削除。
Windowsエクスプローラーから、ServerData/Androidフォルダにあるcontentupdate…bundleを削除。
catalog….hash、catalog….jsonをサーバーにアップロード
Android実機を繋いでBuild and Run、image2の子供が表示される。
画像を更新する
Projectビュー、AssetDataフォルダ内
image1をimage2にリネーム。
image3をドラッグドロップし、image1にリネーム。
Addressablesビュー、AssetDataフォルダ内
image1を削除。
ProjectビューのAssetDataフォルダからimage1をドラッグドロップ。
LabelsからMyAssetラベルを付ける。
Addressablesビュー > Build > Prepare For Content Update。
[Apply Changes]を実行。
Build > Build For Content Updateを実行。
ServerData/Android内のファイル、hash、json、bundleをサーバーに上書きアップロード。
Android実機でアプリを起動する。
イラストが更新され、成長した子供がグレる。
名前長すぎ問題
Projectビュー内での階層が深くなりすぎるとAsset Addressが長くなり、Build Player Content実行時に下記のようなエラーが出る。
DirectoryNotFoundException: Could not find a part of the path “Temp/com.unity.addressables/AssetBundles\めっちゃ長い名前_assets_all.bundle” or “Library/com.unity.addressables/StreamingAssetsCopy/aa/Android/Android\ めっちゃ長い名前 _assets_all_69177449bd8240b183cef2c1236045cd.bundle”
その場合はAddressablesビュー内のファイル上で右クリック、[Simplify Entry Names]を実行する。
Assets/AssetDataXXXXXX……/image1.png
というアドレスであれば、
image1.png
のようにアドレスが短縮される。
アドレス短縮し、Buildしたら、コードに書いてるアドレスも直さないと当然エラーが出る。
エディターで、パーティクル等がピンクになってしまう
エディター上で、Packed Mode実行時はそうなる仕様。
FastModeにするか、Android実機で確認すれば大丈夫。
一括で画像を表示したい場合のサンプルコード
Addressables.LoadAssetsAsync(new List { "ラベル名" }, null, Addressables.MergeMode.Intersection).Completed += data => { List images = new List(); foreach(Sprite sprite in data.Result) images.Add(sprite); };
アプリ更新時
Player Version Overrideを変更する。
Content Updateフォルダがあれば、中身を所定のフォルダに移す。
(以前のアプリバージョンでデータの更新があった際のアップデータを、新しいアプリバージョンに含める。
そうしないと、当然ダウンロードするアップデータがどんどん増えてしまう。)
Build Player Content を実行。
(Build Pipeline CacheとDetaBuildersをクリアしてからの方がベターかも。)
サーバーにServerDataフォルダからファイル(hash、json)をアップロード。
(以前のデータは残しておかないと、古いバージョンのアプリを使用してるユーザーが困る。)
不具合が出て色々試してもどうにもならない時
・AddressablesのReimport。
・AddressableAssetDataフォルダを削除 > AddressablesのReimport > データを作り直す。
・上記+Reimport All。