【Unity】iOS/Androidでアプリを休止してもダウンロードを続ける BackgroundDownload
今回はタイトルの通り「アプリを終了(もしくはサスペンド)してもダウンロードを継続する」機能を提供するアセットの機能と使い方についてです。
このアプローチを導入すると、アプリ開始時の「追加コンテンツダウンロード待ち」でアプリを起動しっぱなしで待たずとも良くなります。
アプリのバックグラウンドでダウンロード
通常のWebRequest系は非同期で動作しますが、基本的にダウンロード処理はアプリが動作していないと動きません。このため、多くの場合ダウンロード中に色々と工夫が加えられています(漫画を表示とか、ミニゲームとか)
今回のアプローチでは、アプリを休止もしくは停止した状態でもダウンロードを継続してくれます。つまり、このダウンロード時間を他の操作(例えばTwitterを見るとか!)に使うことが出来ます。
アプリのバックグラウンドでデータをダウンロード出来ると、コンテンツのダウンロード中に他のゲームで遊べるという例 pic.twitter.com/hJcFpTbj5M
— 椿 (@tsubaki_t1) 2018年12月16日
単純に消費電力の低下にも良いかもしれません。
電池消費のそれなりの割合はGPUと通信(4G)です。Unityは毎フレームGPUを動かすゲームエンジンなので、ゲーム画面でダウンロード待ち処理を行うと、GPUと通信でバッテリー消費量が増大しますし、端末も熱くなります。逆にGPUを止める(フレームレートを超落とす、CameraとCanvasを全て止める)と、Energy ImpactはLowに下がります。*1
さらにアプリをバックグラウンドに持っていけば、メインスレッド/ワーカースレッドも、GPUも動いていない状態になるので、もっと消費電力を下げる事が期待出来ます。
BackgroundDownloadの概要
BackgroundDownloadはiOS/Android/Windows Platform向けプラグインです。このプラグインはアプリのバックグラウンド*2でファイルのダウンロードを可能にします。
ダウンロードしたファイルはApplication.persistentDataPath以下に保存されます。BackgroundDownloadにはダウンロードしたbytesにアクセスするインターフェースが無いので、System.IO系のAPIでダウンロードしたファイルへアクセスする流れになります。

BackgroundDownloadはWindowsやMac、というよりUnity Editorで動作しません。
エディター上で動作をテストする場合は、BackgroundDownloadがダウンロードしたファイルを保存するフォルダに、ダウンロードすべきファイルを置いて*3動作確認をする流れになるんじゃないかなと思います。
導入
- GitHub - Unity-Technologies/BackgroundDownload: Plugins for mobile platforms to enable file downloads in background の
BackgroundDownloadフォルダとPluginsフォルダをUnityプロジェクトに入れます。
iOSなら、コレで解決します。
Androidの場合、Manifestを少し弄る必要があります。
- Manifestを用意
<receiver android:name="com.unity3d.backgrounddownload.CompletionReceiver">~</receiver>を<application>の中に追記<uses-permission android:name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION" />と<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />を追加
要するに、下の項目を自身のManifestへ移植します。特にjava.lang.SecurityExceptionが出た場合、マニフェストが正常に設定されていません。

使い方
後は使うだけです。
APIは非常に簡単で、BackgroundDownloadConfigにダウンロードしたいファイルや設定を詰めてBackgroundDownload.Startを呼ぶだけです。
コルーチンで簡単に観測出来ますが、BackgroundDownload.backgroundDownloads[0]で他の機構から観測するのも良さそうな感じがします。
BackgroundDownloadConfig config = new BackgroundDownloadConfig
{
filePath = saveFilePath,
url = new Uri(downloadFileURL),
policy = BackgroundDownloadPolicy.UnrestrictedOnly
};
using (var download = BackgroundDownload.Start(config))
{
yield return download;
Debug.Log(download.status);
}
BackgroundDownloadConfigでは、一応、AddRequestHeaderでヘッダー情報を追加したり、ダウンロードが使用できるネットワークの指定*4が可能です。
ダウンロード完了時や、ダウンロード進行度を通知で出したい
現状、プラグイン自体を書き換える必要があります。

補足
Q: iOS でバックグランドのダウンロードは5分かそこらでOSから強制的に落とされる?
A:backgroundTaskではなくNSURLSessionDownloadTaskを使用しているので、多分そういうことは起こらないQ:沢山のファイルをダウンロードしようとすると、セッションの限界に到達しない?
A:ダウンロード処理は最大4つ並列で処理され、他はキューィングされる。
https://t.co/9u63zFYcut 大量のファイルをダウンロードした場合でも、ちゃんと4つずつダウンロードするの図 pic.twitter.com/bFSGGkH2Oz
— 椿 (@tsubaki_t1) 2018年12月17日
感想
毎回長時間のダウンロードを待たされる身としては非常に良い機能に見えますが、コレ自体はかなり昔から実現可能なアプローチであり、その上でコレを利用していないゲームが過半数を占めるということは、何か問題があるのかもしれません。(例えばバックグラウンドにした後にプレイヤーが帰ってこない等のサービス的な問題とか、技術的な要因とか)
何にせよ簡単に出来るようになったのは有り難い。
