📹

「勉強のやる気が出ない」を技術で殴るために、iOS 17のInteractive Widgetとカメラ機能をフル活用した話

に公開

はじめに

「勉強、始めるまでが一番つらくないですか?」

机に向かってもついスマホを触ってしまう。
いざ始めても「自分はいったい何時間頑張ったのか」が目に見えないから、達成感がなくて続かない。

そんな自分の悩みを解決するために、「スマホを触る暇があったら、ホーム画面から0秒で勉強を開始できるアプリ」 を作りました。
名前は 『StudyReel (スタディリール)』 です。

技術的な縛りは 「徹底的にiOSネイティブであること」
FlutterやReact Nativeも便利ですが、最新の Interactive Widget (iOS 17+)SwiftData のパフォーマンスを極限まで引き出すために、あえて SwiftUI 100% で挑みました。

作ったもの:StudyReel

「学習の瞬間を記録し、モチベーションを可視化する」

主な機能

  1. Interactive Widget: アプリを開かずに、ホーム画面からワンタップでポモドーロタイマーを開始。
  2. Visual Stats: 勉強時間を Swift Charts で美しくグラフ化。
  3. App Group Sync: ウィジェットとアプリ本体でデータをリアルタイム同期(iOSのサンドボックス制限を越えてデータを共有する仕組み)。

技術スタック:Appleの最新技術をしゃぶり尽くす

今回は「学習コスト」を度外視して、Appleが提供する最新フレームワークを積極的に採用しました。

コンポーネント 技術 役割
Language Swift 5.9 安全でモダンな記述。
UI SwiftUI 宣言的UI。アニメーションの実装が楽。
Database SwiftData Core Dataの後継。@Model マクロで定義が爆速。
Widget WidgetKit 今回の主役。 インタラクティブなホーム画面体験。

こだわり①:アプリを開かせない「Interactive Widget」

かつてのiOSウィジェットは「情報の表示」しかできませんでした。
しかしiOS 17からは、ウィジェット上のボタンを押して直接コードを実行できる App Intents が導入されました。

これを使わない手はありません。StudyReelでは、「勉強しよう」と思った0.5秒後にはタイマーが回っている 体験を実現しました。

StudyReelWidget/StudyReelWidget.swift
// 実際のコード:App Intentによるタイマー開始
@available(iOS 17.0, *)
struct StartTimerIntent: AppIntent {
    static var title: LocalizedStringResource = "Start Pomodoro"
    
    @Parameter(title: "Duration")
    var duration: Int
    
    // このメソッドがウィジェットのボタンから直接呼ばれる
    func perform() async throws -> some IntentResult {
        // AppGroup経由でデータを保存
        PomodoroData.startTimer(minutes: duration)
        return .result() // UIを即座にリロード
    }
}

この perform() メソッドの中で UserDefaults (App Group) を更新することで、アプリ本体を起動することなく、裏側でタイマー状態を同期しています。
「アプリを起動する」という些細なハードルすら取り除くことが、継続の鍵だと考えたからです。

実験中の機能:タイムラプス自撮り

(※現在実装中のα機能です)
ただ時間を計るだけでなく、「勉強している自分の姿」 をタイムラプスで記録する機能も実験しています。
「誰かに見られている(または後で見返す)」という感覚は、最強の集中スイッチになるからです。

Views/CameraPreview.swift
// AVFoundationを使ったプレビュー実装
struct CameraPreview: UIViewRepresentable {
    func makeUIView(context: Context) -> UIView {
        let view = PreviewView()
        // 録画セッションをレイヤーに接続
        recorder.startSession(previewLayer: view.previewLayer)
        return view
    }
}

こちらは AVFoundation をゴリゴリに使って実装しています。
SwiftUIとのブリッジ (UIViewRepresentable) が必要になりますが、ネイティブならではの滑らかなプレビュー動作は必見です。

こだわり③:ユーザーの声で進化するUX

「タイマー中に画面が消えてしまうと困る」「今日は顔を撮りたくない」
そんな実際のユーザー(身近な人)からのフィードバックを即座に反映しました。

  • 画面自動ロックの無効化: タイマー稼働中は UIApplication.shared.isIdleTimerDisabled を制御し、画面常時点灯を実現。
  • 録画トグル機能: 「集中はしたいけど撮影はしたくない」という気分のために、タイムラプス機能のON/OFFを実装。

個人開発だからこそ、こうした「かゆいところに手が届く」改善を爆速で回せるのが強みです。

おわりに

Web技術(React/Next.js) も便利ですが、OSの機能を限界まで引き出すなら、やはり ネイティブアプリ開発 に軍配が上がります。
特にWidgetKitのような「OSの特権」を使える機能は、ユーザー体験を劇的に変えるポテンシャルを持っています。

もし「最近勉強続いてないな…」という方がいたら、ぜひStudyReelで 「まずはホーム画面をタップ」 してみてください。
そこから、あなたの新しい習慣が始まるかもしれません。

GitHubリポジトリ
https://github.com/naki0227/StudyReel

Discussion