ストリーミングはほとんどのブラウザと
Developerアプリで視聴できます。
-
Appのバックグラウンド実行の最新情報
Appでバックグラウンド実行を活用することは、優れたユーザー体験を提供できる強力な方法です。このセッションでは、バックグラウンドでAppを実行する際(特にVoIPまたはサイレントプッシュを使用する場合)に従うべきベストプラクティスと、長時間実行する処理やメンテナンスのタスクを可能にするまったく新しいスケジューリングAPIについて紹介します。
リソース
- Background Tasks
- pushRegistry(_:didReceiveIncomingPushWith:for:completion:)
- Refreshing and Maintaining Your App Using Background Tasks
- プレゼンテーションスライド(PDF)
関連ビデオ
WWDC19
-
ダウンロード
(音楽)
(拍手) Software Battery Lifeチームの ロベルトです “Advances in App Background Execution”へようこそ
ユーザはAppが大好きです すばらしい体験が得られるからです フォアグラウンドで アクティブに使うものや バックグラウンドで 実行しなくてはならないものがあります バックグラウンド処理が必要なものの 例がこちらです ナビゲーションや補助的な通信 アップデートやダウンロードなど Appleでは これらをより快適に 使用できるAPIを設計しています 今日は バックグラウンド処理の概観を話し― ベストプラクティスを紹介します その後トーマスが― バックグラウンドタスクの 新しいフレームワークを紹介します
まずは概観から始めましょう まず始めに バックグラウンド処理とは何か? バックグラウンドと言えば スレッドやキューもありますが “処理”が意味するのは― バックグラウンドで動いているか コードを実行している状態です この図では3つ目のボックスです Appが動いているけど ユーザには見えない状態です
なぜこうなるのでしょう? おおまかに2通りあります 1つはAppのリクエスト Appがしたい作業があり システムにリクエストする場合です ダウンロードやアップデート フォアグラウンド作業の残りなどです もう1つは特定イベントのトリガーで 何かが起きて それに対処するためAppが動く場合です ユーザが外国地域に入るとか― 新しい健康データが 必要になった場合など
しかし何よりユーザ体験が重要です APIの設計には 重要な要素がたくさんあります 中でも3つに注目します パワー パフォーマンス プライバシーです
まずパワーから フォアグラウンドでも バックグラウンドでも アプリケーションが動くと パワーを使います 時間と共にバッテリーが消費されます 図で見てみましょう 左が朝で 右が夜を表しているとします 夜に充電すると仮定して― 緑の部分が充電を表します 明るい青がアプリケーションが フォアグラウンドで動く時間 暗い青が バックグラウンドで動く時間です 長く動くほどバッテリーが消費され― 短くなるほど消費は減ります APIの設計では― 節電できるよう 処理に必要な時間を考えていきます そしてAPIを効率的にし― 処理が済めば 完了ハンドラを呼ぶようにします 予定より早く終われば― システムに伝わりアプリケーションが 停止され 節電できます 次にパフォーマンス システムにはスムーズに 動いてほしいですし 起動の速さやUIの反応のよさが 欲しいですね バックグラウンドでは特に重要です なぜなら1日を見ると 動いているアプリケーションは― 1つではないからです フォアグラウンドでも バックグラウンドでも 複数が動いています 1つを操作中にバックグラウンドで 別のアプリケーションが動く時や 複数がバックグラウンドで 動いてる時もあります だからAPIの設計では スマートなCPUとメモリ制限が重要です APIを使う時は制限を意識し ユーザに影響しないようにすべきです システムがアプリケーションを停止し 次の起動が遅くなるのも避けたいです
最後にプライバシーです ユーザは個人情報にとても敏感です フォアグラウンドで動いている時は 個人情報へのアクセスに気づいていても バックグラウンドでは 違うかもしれません ケースごとに 必要なデータへのアクセスを設定し― 異なるAPIを設計する必要があります そしてユーザへの透明性を意識し― どのデータが使われるか知らせます この3つが重要な留意事項です パワー パフォーマンス プライバシー 先ほどの例も それぞれ異なるAPIにつながります 求められる動作を実現するのに それぞれ必要なものが違っています
概観は話したので いくつかベストプラクティスを紹介して APIの変更について話します
メッセージAppを例にしましょう 主な機能は メッセージの送信や通話だとしましょう スレッドのミュートや添付ファイルを ダウンロードする機能もあります これら4つを どのAPIで実現するか見てみましょう まずメッセージの送信 これはAppの核となる機能です メッセージは すぐに届いてほしいですね 1日後では困ります ただちに完了しなくてはなりません 大抵はできますが たまにうまくいかない時もあります 通信の混雑やserverの遅さで 時間がかかるかもしれません その間にユーザはスマホを置いて ロックしてしまうかも だから確実に 完了するようにしたいのです 後で見たら 送られてないという事態は避けたいです ここで使うAPIが― Background Task Completionです 停止する前にバックグラウンドで 動く時間をAppに与えます UIApplication.beginBackgroundTaskや ProcessInfo.performExpiringActivity を呼べばいいのです フォアグラウンドで始めた作業を 完了させます これにはファイルの保存など― ユーザ起動の リクエストが当てはまります それではコードを見てみましょう メッセージ送信の関数です
送信を確立後 beginBackgroundTaskを呼びます これでシステムに― アプリケーションが閉じられても タスクを完了させるよう伝えます
送信が済んだら― 完了ブロックで システムにタスクを終了させます “もういい”と システムに対し 終わったので切ってくれと伝えます 節電やパフォーマンス向上のためです 最後に1つ システムから時間を与えられたものの 通信が悪すぎて― 作業が終わらない時もあります その時は expirationHandlerが呼ばれます この場合は ユーザに通知バナーで知らせます “メッセージが送れませんでした”と
まとめると メッセージ送信は Background Task Completionsで確実に そしてユーザの操作で始めることです バックグラウンドになる前がいいですね システムがAppを停止するまで 限られた時間で送らねばなりません
では次に通話を見てみましょう
普段はメッセージで済ませていても― 直接 話して 手早く何かを伝えたい時もあるでしょう 使うAPIはVoIPプッシュ通知です これはアプリケーションを起動して― 通話できるよう 着信を知らせる特別なプッシュです
使うにはPKPushRegistryで― VoIPのプッシュタイプを 設定すればいいのです
今年からdidReceiveIncomingPush コールバックのCallKitで 着信を報告しないと Appが 終了させられるようになりました もし繰り返し 着信の報告をしなかった場合― VoIPプッシュで Appが起動しなくなることもあります ではコードを見ていきましょう didReceiveIncomingPushコールバック プッシュタイプはVoIPです PushPayloadの情報を CXCallUpdateオブジェクトに追加して 着信の報告はproviderを使います
メソッドが返るまでに 着信を報告しなければ― システムがアプリケーションを切ります 他にもいくつか助言があります PuchPayloadに発信者情報を含めれば すばやく表示できるので― UIをリッチにするには なるべく情報を含めてください
次にプッシュのapns-expirationを ゼロか小さい数字にしてください ユーザが何分も後に 着信のプッシュを受け取らずに済みます 例えば着信があり プッシュが送られるのに2分かかれば 着信の報告は要りません 2分後には もうおそらく電話は鳴っていません ゼロに設定すれば すぐに届けられなければ失敗になるので プッシュがあれば 今 現在のものだと分かります それからバナーのほうが好みなら 標準のプッシュを利用してください フルスクリーンでなくてもいいのです 内容の変更は Notification Service Extensionを 暗号化する場合などです 以上が通話についてです 次はスレッドのミュートについて 複数の友人やグループで やり取りする場合もあるでしょう スレッドがうるさくなり― 通知を切りたい時もあります でも内容が 要らなくなったわけではないですね 後でメッセージを見たいのですが ただ毎回 通知されるのが嫌なだけです デバイスにだけ コンテンツを知らせる方法が欲しい
そこでバックグラウンドプッシュです デバイスにだけ 新しいデータを知らせる仕組みです
content-availableを1に設定した プッシュを― alert sound badgeなしで送ります いつアプリケーションを起動して ダウンロードするか システムが 電力状況などを考えて判断します 図で見ればこんな感じでしょう ユーザがスレッドをミュートします 誰かがメッセージを送ると バックグラウンドプッシュが届きます その後どこかでアプリケーションが 起動され データをフェッチします ユーザがアプリケーションを開くと― スレッドで メッセージを見ることができます ここでも注意点があります apns-priority = 5に設定しなければ アプリケーションは起動しません
apns-push-typeはbackgroundに watchOSでは必須です 他のプラットフォームでも推奨します watchOSのプッシュについては― “Creating Independent Watch Apps”をご覧ください
まとめると― バックグラウンドプッシュで コンテンツをダウンロードすること バックグラウンドプッシュ後にAppが バックグラウンドで動けなかった場合は 開いた時に ダウンロードすればいいでしょう
では続いて過去の添付ファイルです
ユーザが新しいデバイスで― サインインしたとします アカウントで 最新メッセージなどはすぐ見るでしょう でも古いコンテンツは その場でダウンロードしたくありません わざわざフォアグラウンドでやり― パフォーマンスを低下させる 必要はありません 充電中で アイドル状態の時にやればいいのです Discretionary Background URL Sessionを使います ダウンロードを先延ばしさせ― システムに情報を渡して より賢くスケジュールを組ませます 通常どおり Background URL Sessionを設定して discretionary = trueにします
システムに 追加で渡せる情報を見てみましょう タイムアウト間隔 ダウンロードを 何度も試すのを防ぐのにいいでしょう 最早開始日 将来ダウンロードしてほしい場合にです そして想定ダウンロード容量サイズ ダウンロードが どれほどの作業かシステムに知らせます
ユーザに影響しないよう 過去の添付ファイルは できれば延期を この方針は他のアップロードや ダウンロードにも使えます 後でアップロードしたい分析とか 後で保存しておきたい写真などです メッセージAppの主な機能について まとめます メッセージの送信 通話 スレッドのミュート 過去の添付ファイルのダウンロード それぞれ異なるAPIを使います Background Task Completionで メッセージを確実に送信させます VoIPプッシュで通話を可能に バックグラウンドプッシュで Appにコンテンツに対処させ― Discretionary URL Sessionで 適切な時間にダウンロードさせます 他にも既存のモードで対処できない 事例があります 同僚のトーマスが― それらの事例で新しいモードと フレームワークを紹介します ありがとうございました (拍手) ありがとう ロベルト 使用事例を紹介しましょう serverとの同期や データベースのクリーンアップ― Cloudへのバックアップなど メンテナンスタイプのタスクで― ユーザの邪魔をせず バックグラウンドで済ませたいものです 現在のAppはこうした作業を よくバックグラウンドでしており― 1日でかなりの作業量になります ではこれを先延ばしして― 充電中かアイドル状態で やればどうでしょう そこで 新しいバックグラウンドモードと― フレームワークBackgroundTasksを 紹介します BackgroundTasksは 作業を後でやるよう予定を組みます iOS iPadOS tvOS そして MacのiPad Appで利用可能です 新しいモード Background Processing Tasksを紹介すると共に この機会を利用し 既存のAPIの改善にも取り組みました
では新しいモードについて このモードでは システムに都合のいい時間を探して― 何分かで アプリケーションに作業させます メンテ作業の他にも Core MLトレーニングなども含みます 詳しくはセッションで
CPU Monitorという機能は― バックグラウンドでCPUを使いすぎる アプリケーションを自動的に切ります 今回 初めて ハードウェアを最大限に生かすため― この機能を オフにできるようにしました
そして最後に フォアグラウンドで操作中 あるいは少し前に操作していた時に― リクエストされたタスクは実行されます
次に新API Background App Refreshについて 既存のAPIとポリシーは変わりません 30秒のランタイムで― 起動するたび 新しいコンテンツをフェッチします
アプリケーションの起動頻度や時間帯は ユーザの過去から分かります 朝と昼と夜にユーザが アプリケーションを使うとしましょう システムは学習し その少し前に アプリケーションを起動させて― 必要なコンテンツを入手します 頻繁に使わないアプリケーションなら 起動も少なくなるでしょう
これは新しいAPIなので― 以下に示す既存のものは廃止されます これらのAPIはiOS iPadOS― tvOSでは今後もサポートされますが Macではされません Macの場合は Background App Refreshの導入を
では仕組みを見てみましょう 拡張機能を持つアプリケーションが あるとします 基本的にやり取りするオブジェクトは BGTaskSchedulerです BGTaskSchedulerはインテリジェントで ダイナミックなスケジューラであり― 常にシステム状態を監視します バッテリー残量やアプリケーション 使用時間や通信状態などです
Appの作動中に後でバックグラウンドで 動くようリクエストできます そうするには TaskRequestオブジェクトを作成します タスクのタイプに対応したものです ここではAppをリフレッシュします BGAppRefreshTaskRequestを作成して スケジューラに送ります
複数のタスクを送ることもできます 今回はクリーンアップも行いましょう BGProcessingTaskRequestを作成し 送ります
拡張機能からもリクエストできます キーボードから ユーザのタイプ習性を学習したい場合 同じくリクエストを作成し送れます このように 複数のリクエストを受けられます それぞれ 特定のタスクに対応しています
スケジューラは Appのしたいタスクを把握します 必要なシステム状態とポリシーが 満たされれば― タスクを実行します Appをバックグラウンドで起動し― 対応するBGTaskオブジェクトを 届けます ここではBGAppRefreshTaskです これでリフレッシュや フェッチやUIのアップデートができます 終わればsetTaskCompletedを呼び タスクの完了を知らせAppを停止します
リクエストの設定や システムの状態やポリシーによっては 複数タスクを 同時にさせることもあります この場合はAppが起動され BGProcessingTaskが2つ届けられます そしてこの時 Appにはタスクではなく起動ごとに 限られた時間が割り振られます タスクがすべて 時間内に済むよう準備しましょう キーボードがリクエストしたタスクも アプリケーション本体に届きます 拡張機能ではなく 本体がBGTaskに対処するからです
作業が終わり すべてのタスクが 完了し報告されるとAppは停止します 以上がBackground Task APIです BGTaskRequestを作成し― スケジューラに送り システムに起動されるのを待ちます タスクをこなせば― setTaskCompletedを呼びます どうやって実装するか説明するため デモを見せます
(拍手)
これがAppです ColorFeedという名前です 写真でなく 最新の色のトレンドが見られます スクロールして― 時間ごとに 最新の色が何だったかが示されます このAppを ユーザの手を借りず最新の状態で― 保てるようにしたいと思います Background Tasksで BackgroundAppRefreshを実装します まず最初に info.plistに必要なキーを追加して BackgroundTasksと リフレッシュのサポートを宣言します そこでプロジェクトの設定を開きます
ターゲットをクリックし―
Signing & Capabilitiesタブへ
+を押して Background Modesの機能を追加します
新しいセクションで タスクに合ったモードを選びます 今回の場合は― 古いAPIと同じ Background Fetchをチェックします
次にinfo.plistファイルを開きます ここです
+を押して新しいキーを追加します
Permitted background task scheduler identifiers 文字列の配列です 各文字列は それぞれAppのしたいタスクを表します ユニークにすべきです リバースDNSで 他のフレームワークとの衝突を避けます
配列を拡張し +を押して文字列を追加します 名前はcom.colorfeed.refresh
保存します 次にAppがいつ起動されるか決める コードを実装 Appのデリゲートで行います
ファイルを開き BackgroundTasksをインポートします
次に― システムに 起動されたら何をしたいか伝えます そのためには 起動前に起動ハンドラを登録します didFinishLaunchingWithOption メソッド内でBGTaskScheduler.―
shared.register [forTaskWithIdentifierを呼びます そして先ほど info.plistに入れた識別子を渡します 次のパラメータはDispatchQueue これでハンドラを呼びます 別のキューを 指定することもできますし― nilを渡せば システムがキューを作成してくれます
次のパラメータはlaunchHandler これがAppの起動時に呼ばれます BGTaskのタイプだけでいいです ここではメソッドを呼びます handleAppRefreshで― BGTaskを BGAppRefreshTaskにダウンキャスト リフレッシュに使われるからです ではメソッドを書きます
これで必要なコードはすべて書けました serverから最新情報を得て― データベースとUIを更新します しかしBackgroundTasksと統合するには 必要なことが2つ まず失効をハンドルします タスクに与えられる時間は限られます 期限が迫れば警告し すばやく 作業を切り上げられるようにします もしシステム状態が悪くなれば― 早めにタスクを 停止させることも考えられます そこでexpirationHandlerを設定
そしてその中で cancelAllOperationsを呼びます 作業を止め その後の作業もキャンセルします
終わったら setTaskCompletedを呼ぶようにします expirationHandlerが呼ばれた時もです これに失敗すればAppが停止され― 次の起動パフォーマンスに影響します そこで このようにします キューの最後の操作が完了したら setTaskCompletedを呼びます 完了したか キャンセルされたかにかかわらず― 操作は完了ブロックを呼びます それを利用しタスクの成否を判定します そして最後に BGTaskRequestをスケジュールします これはAppが バックグラウンドに入った時にします では書いてみましょう
applicationDidEnterBackground内で scheduleAppRefreshメソッドを呼びます BGAppRefreshTaskRequestを作成し 先ほどと同じ識別子を渡します そして BGTaskSchedulerにsubmitします BGTaskRequestで 追加で呼びたいプロパティが earliestBeginDateです これで開始の遅れを指定します この場合は― スケジュール時より 15分以上あとに開始しろと言っています setMinimumBackground FetchInterval APIと同じ動きをします
ただ最後に もう1つしておきたいことがあります BGTaskRequestは 1度の起動にしか対応しないので 今 実行されれば次にユーザが開くまで Appは起動しません 1日中 リフレッシュさせたい場合は? handle内で scheduleAppRefreshを呼び出して 次のリクエストをスケジュールします これで必要なコードはすべて書けました
でもAppをスクロールしてみると― かなり前のエントリーがあります おそらくもう不要なデータです データベースを クリーンアップしたい場合は BGProcessingTaskが最適です これも実装しましょう 先ほどと同じく設定を開きます Signing & Capabilitiesタブへ 今回は Background processingをチェックして
info.plistに行きます
+を押して識別子を追加します ここで com.colorfeed.db.cleaningを呼び
保存します そしてまたデリゲートを開き― registerを呼びます
先ほどと同じですが 識別子が違います handleDatabaseCleaningを呼び BGProcessingTaskにダウンキャスト ではハンドルを実装します
BackgroundTasksと統合済みです これで前日より前のものは削除されます expirationHandlerの設定を 忘れないように 終わったら setTaskCompletedを呼ぶようにします 1つ違うのは 最後に成功した時を記録するところです
システムのリソースを意識し タスクをスケジュールしたいからです 必要もないのにデータベースを クリーンアップさせたくありません そこでscheduleDatabaseCleaning IfNeededというメソッドを加えます
前回から 少なくとも1週間たっていなければ― すぐやめさせます そうでなければ実行します BGProcessingTaskRequestを作成し 識別子で渡します
TaskRequestで 他にもプロパティを紹介します 1つはrequiresNetworkConnectivity デフォルトでfalseです 通信が必要なら trueに設定することをお忘れなく そうしないと 通信がない時間にも起動されます ただ今回は 必要ないのでfalseのままにします 次にrequiresExternalPower デバイスや システム状態やポリシーによっては― 充電中に起動される場合もあります ただ作業量が多く かなりのリソースを使う場合は― trueを強く推奨します バッテリーが長持ちします またこれにより CPU Monitorを無効にできます
あとはスケジューラに送るだけです 必要ならAppが バックグラウンドに入った時に送ります AppRefreshと ProcessingTaskのコードは以上です 動くか確認したいですね 自分は決して 完璧なプログラマーではありません 一番いいテスト方法は― 実際にやってみることです そうすれば 必要な時間とポリシーを確認できます でも座って待つわけにもいきません そこでデバッガに いくつかメソッドを追加しました 実演しましょう iPhoneに新しい BackgroundTasksを構築します
起動しました バックグラウンドにして― タスクをスケジュールさせます その後 戻して ここの一時停止ボタンを押します
これでデバッガに移ります コンソールはここです ドキュメントで入手できるコマンドを 貼り付けます TASK IDENTIFIERを― シミュレートしたい識別子に 置き換えます BGAppRefreshを試したいので com.colorfeed.refreshと書きます ProcessingTaskでも同じです エンターを押します システムが シミュレーションを認識しました
再生ボタンを押します
ご覧のように― タスクが実行され ちゃんと機能しているのが分かります また一時停止し 次は失効がうまくいくか確認します これも重要です 先ほどと同じコマンドを入力し― launchをexpirationに置き換えます エンターを押します システムがリクエストを認識し― 再生を押すと失効が認識され 無事 タスクは完了されました これでBGAppRefreshと― BGProcessingTaskが Appに実装されたことを確認できました
(拍手) ありがとうございます 他にもいくつか フレームワークで注意点があります 最早開始日を あまり遠い未来に設定しないことです 遠すぎると ユーザがその間にAppを開いた時― タスクが起動しない場合もあります ユーザの期待と プライバシーを尊重するためです 使わないAppに急にバックグラウンドで 動いてほしくありません そこでearliestBeginDateは 1週間以下に― 設定することを推奨します
次に― デバイスがロックされても 必要な ファイルはアクセス可能にすること そういう時にタスクを行います ユーザが最初に デバイスをアンロックするまでは― タスクを始めることはありません ファイルはcomplete UntilFirstUserAuthenticationに
今回のデモは 既存のUIKit Appでお見せしましたが マルチウィンドウAppやUIScene APIが 発表されました 新しいAPIを導入するなら― UIApplication. requestSceneSessionRefreshを呼びます システムに アップデートが必要だと知らせます 詳しくはドキュメントにあります
そして最後に BGTaskScheduler.submitは同期的です そのほうが― バックグラウンドでのスケジュール時に 導入が楽だからです しかし起動時など パフォーマンスに 影響しやすい時にスケジュールするなら バックグラウンドキューで呼びましょう メインスレッドの 邪魔をしないようにです
では今日のまとめです バックグラウンドの時間の 有効活用について APIの設計で重要なのは― パワー パフォーマンス プライバシーです
正しいモードを使い― 思いどおりの ユーザ体験を提供しましょう
そして最後に BackgroundTasksでタスクを後回しに BGAppRefreshで 1日を通してAppをリフレッシュし BGProcessingTaskで 充電中や アイドル状態にメンテナンス作業を
詳しくはラボにご参加ください サイトからドキュメントを 入手することもできます ありがとうございました (拍手)
-
-
特定のトピックをお探しの場合は、上にトピックを入力すると、関連するトピックにすばやく移動できます。
クエリの送信中にエラーが発生しました。インターネット接続を確認して、もう一度お試しください。