Screen Time API を使ったセルフコントロールアプリを作ろうとすると、最初に3つのフレームワークが登場する。FamilyControls、ManagedSettings、そして ManagedSettingsUI だ。iOS 開発が初めてだとフレームワークの役割分担がわかりにくく、どれを import すればいいか迷う。それぞれの責務を先に把握しておくと、後で設計が崩れにくい。
まず許可を取る: AuthorizationCenter
アプリが Screen Time API を使って制限を適用するには、ユーザーからの認可が必要だ。エントリポイントは AuthorizationCenter.shared.requestAuthorization(for:) で、AuthorizationCenter は FamilyControls フレームワークに属している。
認可の種類は2つある。子どもの端末を保護者がコントロールする individual と、自分自身の端末を自分でコントロールする selfRestriction だ。セルフコントロール系アプリでは後者を使う。iOS 開発に慣れていないと「認可」と「パーミッション(位置情報などの許可)」が混同しやすいが、ここでいう認可は Screen Time 機能全体を使う権限の取得で、一度取れば以降は維持される。
アプリ起動ごとにリクエストするのではなく、初回起動フローの中で一度だけ呼ぶ設計にする。
ブロック対象を選ぶ: FamilyActivityPicker
ブロックしたいウェブサイトやカテゴリを選ぶ UI は、Apple が FamilyActivityPicker として提供している。これは SwiftUI のシートとして表示する。
ここで iOS 未経験者がよく詰まるのは、選択結果をフリーテキストの URL やドメイン名として取り出せないことだ。FamilyActivitySelection というモデルに包まれたトークンとして返ってくる。このトークンは Codable に準拠しているので JSON やファイルに保存できるが、中身の URL 文字列を直接読むことはできない。
「自分でドメインのリストを管理したい」という発想で設計すると、ここで詰まる。FamilyActivityPicker が返す FamilyActivitySelection をそのまま使う設計が前提だ。Web 開発の経験があるとドメインを文字列で扱いたくなるが、iOS の Screen Time API はその設計を取らない。
ルールを適用する: ManagedSettings
ユーザーが行った選択を実際の制限として効かせるのが ManagedSettings の役割だ。ManagedSettingsStore に対してルールを書き込む。
let store = ManagedSettingsStore()store.shield.webDomains = selection.webDomainsstore.shield.applicationCategories = .specific(selection.categories)shield.webDomains に FamilyActivitySelection から取り出したトークンを渡すと、該当するウェブサイトへのアクセス時にシールド画面が表示されるようになる。「シールド」は Apple の Screen Time が用意したブロック画面のことで、Safari 上に重なって表示される。
ルールは store.clearAllSettings() で全解除できる。アンロック処理の実装ではこの呼び出しが中心になる。
設計の骨格
3つを組み合わせると、基本的なフローはこうなる。
起動時に AuthorizationCenter で認可を確認し、未認可であればリクエストを出す。設定画面で FamilyActivityPicker を表示し、ユーザーの選択を FamilyActivitySelection として App Group の共有コンテナに保存する。フォーカスモード開始時に ManagedSettingsStore にルールを書き込み、終了時に clearAllSettings() で解除する。
フリーテキストのドメイン管理と比べてユーザーの選択肢が限定されるように見えるが、これがこのプラットフォームの仕様だ。メンテナンスや誤登録の心配がなく、Apple のカテゴリ分類をそのまま活用できる。iOS に慣れてくると「Apple の用意した枠に乗る」という判断が自然になってくる。
実装の複雑さはシールド画面のカスタマイズと、シールドからアプリへのアンロック連携に集中することになる。
hsb.horse