テラシュールブログ

旧テラシュールウェアブログUnity記事。主にUnityのTipsやAR・VR、ニコニコ動画についてのメモを残します。

【Unity】iOS/Androidでアプリを休止してもダウンロードを続ける BackgroundDownload

今回はタイトルの通り「アプリを終了(もしくはサスペンド)してもダウンロードを継続する」機能を提供するアセットの機能と使い方についてです。

このアプローチを導入すると、アプリ開始時の「追加コンテンツダウンロード待ち」でアプリを起動しっぱなしで待たずとも良くなります

アプリのバックグラウンドでダウンロード

通常のWebRequest系は非同期で動作しますが、基本的にダウンロード処理はアプリが動作していないと動きません。このため、多くの場合ダウンロード中に色々と工夫が加えられています(漫画を表示とか、ミニゲームとか)

今回のアプローチでは、アプリを休止もしくは停止した状態でもダウンロードを継続してくれます。つまり、このダウンロード時間を他の操作(例えばTwitterを見るとか!)に使うことが出来ます。

単純に消費電力の低下にも良いかもしれません。

電池消費のそれなりの割合はGPUと通信(4G)です。Unityは毎フレームGPUを動かすゲームエンジンなので、ゲーム画面でダウンロード待ち処理を行うと、GPUと通信でバッテリー消費量が増大しますし、端末も熱くなります。逆にGPUを止める(フレームレートを超落とす、CameraとCanvasを全て止める)と、Energy ImpactLowに下がります。*1

さらにアプリをバックグラウンドに持っていけば、メインスレッド/ワーカースレッドも、GPUも動いていない状態になるので、もっと消費電力を下げる事が期待出来ます。

f:id:tsubaki_t1:20181216131027p:plain
レンダリングを止めてGPUを抑えた時の消費電力

BackgroundDownloadの概要

github.com

BackgroundDownloadiOS/Android/Windows Platform向けプラグインです。このプラグインはアプリのバックグラウンド*2でファイルのダウンロードを可能にします。

ダウンロードしたファイルはApplication.persistentDataPath以下に保存されます。BackgroundDownloadにはダウンロードしたbytesにアクセスするインターフェースが無いので、System.IO系のAPIダウンロードしたファイルへアクセスする流れになります。

f:id:tsubaki_t1:20181217002109j:plain
ダウンロードと利用は完全に分かれている

BackgroundDownloadWindowsMac、というよりUnity Editorで動作しません。
エディター上で動作をテストする場合は、BackgroundDownloadがダウンロードしたファイルを保存するフォルダに、ダウンロードすべきファイルを置いて*3動作確認をする流れになるんじゃないかなと思います。

導入

  1. GitHub - Unity-Technologies/BackgroundDownload: Plugins for mobile platforms to enable file downloads in backgroundBackgroundDownloadフォルダとPluginsフォルダをUnityプロジェクトに入れます。

iOSなら、コレで解決します。

Androidの場合、Manifestを少し弄る必要があります。

  1. Manifestを用意
  2. <receiver android:name="com.unity3d.backgrounddownload.CompletionReceiver"></receiver><application>の中に追記
  3. <uses-permission android:name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION" /><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />を追加

要するに、下の項目を自身のManifestへ移植します。特にjava.lang.SecurityExceptionが出た場合、マニフェストが正常に設定されていません。

f:id:tsubaki_t1:20181217002559j:plain
自身のManifestファイルに移植すべき項目

使い方

後は使うだけです。

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が可能です。

gist.github.com

ダウンロード完了時や、ダウンロード進行度を通知で出したい

現状、プラグイン自体を書き換える必要があります。

f:id:tsubaki_t1:20181217003856j:plain
Androidの通知にダウンロード進捗を表示

補足

  • Q : iOS でバックグランドのダウンロードは5分かそこらでOSから強制的に落とされる?
    A:backgroundTaskではなくNSURLSessionDownloadTaskを使用しているので、多分そういうことは起こらない
  • Q:沢山のファイルをダウンロードしようとすると、セッションの限界に到達しない?
    A:ダウンロード処理は最大4つ並列で処理され、他はキューィングされる。

感想

毎回長時間のダウンロードを待たされる身としては非常に良い機能に見えますが、コレ自体はかなり昔から実現可能なアプローチであり、その上でコレを利用していないゲームが過半数を占めるということは、何か問題があるのかもしれません。(例えばバックグラウンドにした後にプレイヤーが帰ってこない等のサービス的な問題とか、技術的な要因とか)

何にせよ簡単に出来るようになったのは有り難い。

*1:通常はHih ~ Very Highの間ぐらい

*2:アプリの裏側という意味、別スレッドという意味ではない

*3:ダウンロードに成功したという扱い

*4:iOS以外