SwiftUI Screen Time API iOS

iPhoneのアプリ制限を3種類に分けて実装した
— Screen Time API設計記録

「今だけ止める」「毎日この時間は止める」「使いすぎたら止める」。
似ている3機能を、干渉させずに動かすための構成です。

← Articles 一覧へ戻る

作っているもの

「あなたのスマホを妨げるサマターゲ」は、選んだアプリやWebサイトを一定時間使えない状態にするiPhoneアプリです。制限中の画面には、プロジェクト共通のキャラクター「サマターゲ」が現れます。

単純なタイマーだけでは、就寝時間のような毎日の予定や、SNSを1日に使う合計時間の管理には対応できません。そこで制限を次の3系統へ分けました。

制限開始条件主な用途
今すぐ制限ボタンを押した時点15・25・45・60・120分の集中
毎日の時間帯指定した開始時刻就寝中や勉強時間
1日の利用上限当日の累計利用時間SNSや動画の使いすぎ対策
この記事は開発中アプリの実装記録です。一般公開できるWeb版はなく、iOSのScreen Time APIを使う実機アプリとして検証しています。

Screen Time APIを3つの役割で見る

実装では、AppleのScreen Time関連フレームワークを役割ごとに使い分けています。

  • FamilyControls:利用者が制限対象のアプリ、カテゴリ、Webドメインを選ぶ
  • DeviceActivity:時間帯や累計利用時間を監視し、開始・終了イベントを受け取る
  • ManagedSettings:対象へシールドを適用し、起動できない状態にする

最初に AuthorizationCenter へ個人利用の認可を要求し、FamilyActivityPicker の選択結果を保存します。選択できるのは、個別アプリ、アプリカテゴリ、Webドメイン、または全アプリです。

選択情報は通常のBundleとは別に動くDevice Activity MonitorやShield拡張からも読む必要があります。そのため、App Groupの共有領域に設定を保存し、アプリ本体と拡張機能が同じ状態を参照する構成にしました。

制限ごとにManagedSettingsStoreを分ける

3種類の制限を1つの ManagedSettingsStore で扱うと、どれかを解除したときに、まだ有効な別の制限まで外れる可能性があります。そこで、即時・時間帯・利用上限にそれぞれ名前付きStoreを用意しました。

ManagedSettingsStore(named: .immediate)
ManagedSettingsStore(named: .schedule)
ManagedSettingsStore(named: .dailyLimit)

例えば即時制限が終わったときは、.immediate のStoreだけを解除します。同時に就寝時間の制限が有効なら、.schedule のシールドは残ります。状態を分けることで、「どのルールが現在ブロックしているか」も画面へ説明しやすくなりました。

シールド対象は、全カテゴリ・全Webドメインをまとめて指定する場合と、Family Activity Pickerで選ばれたアプリ・カテゴリ・ドメインだけを指定する場合に分けています。

日付をまたぐ時間帯を正しく扱う

22時から翌朝7時までのような予定は、開始時刻より終了時刻のほうが小さくなります。単純に「現在時刻が開始以上かつ終了未満」と比較すると、この夜間スケジュールを判定できません。

開始 < 終了:
  開始 <= 現在 < 終了

開始 > 終了(日付をまたぐ):
  現在 >= 開始 または 現在 < 終了

保存した設定をアプリ起動時に読み直す際も、この判定で「今すでに制限時間内か」を確認します。監視イベントを待つだけにすると、端末の再起動やアプリ更新の直後に状態表示がずれるためです。

DeviceActivityの時間帯監視は毎日繰り返す設定にし、終了イベントではスケジュール用Storeだけを解除します。

利用時間の上限はイベントで受け取る

1日の利用上限では、0時から23時59分までの監視区間を作り、選択した対象の利用時間が設定分数に達したときのイベントを登録します。設定値は1〜1439分の範囲で扱います。

しきい値へ達するとMonitor拡張が通知を受け、日次上限用Storeへシールドを適用します。翌日の監視区間に切り替わったら、そのStoreを解除します。iOS 17.4以降では、その日の設定前に使った時間も含めるための includesPastActivity を利用します。

この方式はアプリ本体を開き続けるタイマーではありません。監視とシールド適用を拡張機能へ委ねるため、アプリが前面にいないときもOSの仕組みで動作します。

即時制限にも監視を使う理由

即時制限は開始ボタンを押した時点でシールドを適用し、終了予定時刻までのDeviceActivity監視も登録します。画面上のカウントダウンだけに任せると、アプリを終了した後に解除処理を実行できないためです。

DeviceActivityの区間には最小の長さがあるため、短すぎる区間にならないよう15分を確保しつつ、共有設定には利用者が選んだ実際の終了時刻を保持します。アプリ本体とMonitor拡張のどちらが先に状態を確認しても、同じ終了時刻を基準にできます。

実装して分かった境界

  • Screen Timeの認可が拒否された場合は制限を開始できない
  • 利用者が端末設定から認可やアプリを変更した場合、状態の再確認が必要
  • DeviceActivityのイベント時刻は、通常の秒単位タイマーと同じ精度を前提にできない
  • アプリの削除や拡張機能の停止まで防ぐ、管理者向けMDMではない
  • 「集中できる」ことを保証するものではなく、操作のきっかけを減らす補助ツール

一番重要だったのは、画面上の設定、OSによる監視、実際のシールドを同じ処理へ詰め込まないことでした。制限の種類ごとに状態を分離し、共有領域を境界にすることで、バックグラウンドでも理由の分かる状態を保ちやすくなりました。