📱

【SwiftUI】ScreenTimeAPIを使って他アプリの使用を制限する方法

2023/08/29に公開

来たる203年9月にはiOS17が使えるようになると思いますが、iOS15から使えるScreenTimeAPIをご存知でしょうか?

OB-1にアプリ制限機能をつけるために、ScreenTimeAPIのデモアプリを作ったので、その知見を紹介したいと思います。

ScreenTimeAPIとは

iOSの機能として、ScreenTimeというアプリの使用時間を制限する機能がありますが、その機能をサードパーティアプリからも使えるようにしてくれているのが、ScreenTimeAPIです。

今回、OB-1にて、「自分の作ったTODOを全部クリアするまでSNSの使用を制限する」といった機能を実装したいと思い、ScreenTimeAPIを使うに至りました。

デモアプリ作成手順

上図のような手順でデモアプリを作成する方法を紹介していきます。

①Appleに許可をもらう

まずは、ScreenTimeAPIを使いたいアプリのidなどの情報を以下のフォームに入力して申請します。審査に2週間以上かかることもあるみたいです。僕は忘れちゃいましたが、結構すぐ来ました。

https://developer.apple.com/contact/request/family-controls-distribution

その後、プロビジョニングプロファイルの設定で、Additional Capabilitiesのタブに行き、Family Controlにチェックをします。

②Xcodeでちょっと環境設定

次に、該当のアプリのSigning & Capabilitiesのところで「+Cabability」ボタンを押して、新しいCababilityを追加します。

↓検索するのはFamily Controlです。これを使うのに①の段階で許可取っておかないとダメなんですね。

↓追加すると、「entitlement追加しますか?」と聞かれるので、素直に「はい」を押すと、以下のように追加されます。(これがないと後でAPI叩いた時にエラーが出るので注意しましょう。)

③認証する

他のアプリに対して影響を及ぼせる機能にアクセスするので、ユーザーに許可を取る必要があります。

以下のコードを呼ぶと、認証できます。

import FamilyControls

func authorize() async {
    do {
        try await AuthorizationCenter.shared.requestAuthorization(for: .individual)
    } catch {
            
    }
}

↓動作の様子

④制限するアプリを選択するUI作成

SwiftUIにて familyActivityPicker というのが用意されているので、ボタンを押したら呼ばれるようなコードを書いていきます。

@State var isPresented = false

Button("Select Apps to Discourage") {
    isPresented = true
}
.familyActivityPicker(
    isPresented: $isPresented,
    selection: $model.selectionToDiscourage
)

↓動作の様子

SwiftUIの使い方等の説明は割愛しますが、今回は、以下のようにContentView内に2つのボタンを作ったデモアプリを作りました。

struct ContentView: View {
    @State var isPresented = false
    
    var body: some View {
        Button("Authorize")  {
            Task {
                await authorize()
            }
        }
        .padding()
        
        Button("Select Apps to Discourage") {
            isPresented = true
        }
        .familyActivityPicker(
            isPresented: $isPresented,
            selection: $model.selectionToDiscourage
        )
        .padding()
    }
}

ここまでで、アプリの制限自体はかけることができます。

次はさらに、シールド画面のカスタマイズをしていきます。

⑤シールドのUIをカスタマイズ

そのままだと、 上図のようなiOSのScreenTimeと同じシールドのUIが出てしまって面白くないので、このUIをカスタマイズしていきます。

このUIをカスタマイズするためには、AppExtensionを追加する必要があります。

App Extensionのtargetを追加

XcodeでFile>New>Targetを選択し、新しいtargetを追加していきます。

Shield Configurationを選択

数あるApp Extentsionの中でもShield ConfigurationがシールドをかけるためのUIです。

文言や色を変更する

文言や色、画像を変更することができます。あくまでもShieldConfigurationに準拠する必要があるので、自由にUIが組めるわけではありません。

↓動作の様子

まとめ

  • ScreenTimeAPIのドキュメントが少なくて苦戦した
  • 時間のモニタリングまでやると、めんどくさそう
  • 今制限中のアプリについてはUserDefault等で
独自で持っておかないといけないのが面倒くさい

サンプルコード

https://github.com/kboy-silvergym/ScreenTimeAPIDemo

この機能を実装予定のOB-1の紹介

自分が禁酒してることと、禁欲系YouTuberの友人がいることもあり、彼とコラボしてOB-1という禁酒禁欲アプリを作りました。

禁酒禁欲に限らず、目標達成のために自分を律するのに使うアプリです。欲のコントロールをしたい全ての人類が対象です。え?自分は大丈夫だって?あなたがダメなのはそういうところです。

https://apps.apple.com/jp/app/id1666271955?platform=iphone

参考資料

https://developer.apple.com/videos/play/wwdc2021/10123/

https://developer.apple.com/videos/play/wwdc2022/110336/

https://qiita.com/segawanko/items/22ee9e7766eb1450bad1

https://bannzai.hatenadiary.jp/entry/2023/03/27/100223

https://github.com/ioridev/flutter_screentime/blob/main/ios/Runner/AppDelegate.swift

https://github.com/YazanHalawa/Explore-iOS-15-Screentime-API/tree/main/TestScreentimeAPI

https://developer.apple.com/documentation/FamilyControls

https://developer.apple.com/documentation/familycontrols/authorizationcenter/requestauthorization(completionhandler:)

https://stackoverflow.com/questions/74599044/swiftui-does-anyone-know-how-family-control-works

追記: ScreenTimeAPIの呼び出しをpackage化しました!

https://pub.dev/packages/screen_time_api_ios

Flutter大学

Discussion