🍎

Cursorを使って7日でiOSアプリをリリースしてみた件

2024/08/22に公開

はじめに

「プログラミングって難しそう...」「アプリ開発なんて、何年もかかるんじゃない?」

正直、私もそう思ってました。でも、最近のAI技術の進歩ってすごくないですか?ChatGPTやClaudeみたいな賢いAIサービスのおかげで、プログラミングの敷居がグッと下がった気がするんです(ご察しの通り本記事もAIサービスの力をお借りして何とか作りあげました...)

そんな中、「よし、これを使って短期間でどこまでアプリを作れるかチャレンジしてみよう!」...と思い切ったきっかけは、実はちょっと恥ずかしい話です。

というのも実は私、バーに行く時でジントニックしか頼まないんですよね。こないだ友人とバーに行った時も他のカクテルも試してみたい気持ちはありつつ、とりあえずジントニックでいいや...になっていました。「あ、簡単にカクテルが調べられるアプリがスマホに入ってたら手元に置いておきたいかも」と思いついたものをまずはアプリにしてみよう思ったのが、このアイディアの始まりです。

この記事では、エンジニア出身ではなかった私が、AIの力も借りながらiOSアプリを作った奮闘記をお届けします。

目標は2つ!

  1. 自分の限界に挑戦すること(どこまでできるかな?)
  2. 「私にもできるかも!」と思ってもらうこと(あなたにもきっとできます!)

ちなみに先に公開されたアプリを気になっていただいている方は、是非下記のリンクからダウンロードしてみて頂けると非常に嬉しいです...!
https://apps.apple.com/jp/app/カクテルマイスターlite/id6642687706

準備段階

開発言語ですが、今回はSwiftUIという言語でアプリを作ろうと決めました(Flutterの方がよかったかも...)。めちゃめちゃ昔に買って積読状態にあったこちらのSwiftUI解説本を改めて読み直しました。

まず、開発環境のセットアップから始めました。環境としては、元々使用しているM1 MacBookにXcodeをインストール。Xcodeはインストール時に、SimulatorというPCでiPhoneを動かすエミュレーターのようなものも同時にインストールが走るらしく、結構時間と容量喰われます...

1日目:プロジェクトの立ち上げと基本設計

アプリのコンセプト決定

前述の通り、バーが好きな私がジントニック以外のカクテルも頼める、頼みたいと思えるアプリがコンセプトです。ターゲットユーザーは、バーに行く前・行った時に自信を持って色んなカクテルを注文してみたい、種類だけでも覚えておきたいライトなカクテル好きな方です。

基本的なUI設計

アプリの基本構造を決めるため、Figmaを開いて簡単なワイヤーフレームを描きました。プロトタイピングツールって便利ですね!Figmaはたまに本業で利用したことがあるので、時間かけすぎた感はありつつも、以下の4つの主要画面のラフなイメージが完成:

  1. ホーム画面:人気のカクテル一覧
  2. カクテル詳細画面:レシピと作り方の詳細
  3. カクテルクイズ画面:カクテルを学ぶためのクイズ一覧
  4. クイズ挑戦画面:実際のクイズが表示される画面


Figmaワイヤーフレーム

特にホーム画面のレイアウトは、カクテルカードを縦にスクロールできるシンプルなデザインにしました。「見やすさ」と「使いやすさ」を重視!UIイメージは個人的に好きだったAirbnbのアプリデザインを参考にしようと決めました。


Airbnbの画面スクリーンショット

ステップのイメージ具体化

Figmaでデザインを描いた後、「さて、どういう順番で作っていこうか」と考えました。「最初から全部完璧に作ろう」とすると絶対につまずくだろうなと。

そこで、色々考えた結果最終的には以下のようなステップでとりあえず行こうと考えました:

  1. 簡単なデータモデルの定義
  2. 主要画面の実装(まずはモックデータで)
  3. データベース構築・連携
  4. ログイン認証周りの実装
  5. App Storeへの審査提出
  6. 細かいUIの更新
  7. App Store再審査

特に注目したのは、最初の段階でデータベース連携やログイン周りを考えないこと。「まずは動くものを作る」を徹底するため、画面とデータの取り扱いを切り分けて考えることにしました。

「モックデータでいいから、とにかく画面を作って動かしてみよう」

この考え方が、後々功を奏することになります。データベースやログイン周りでつまずいても、すでに動く画面があるので、途中で投げ出さずにモチベーションが保てます。

また、早めにApp Store審査を通すことで、「公開できる最小限の機能」を意識しながら開発を進められると考えました。(これは、App Storeの審査が厳しいという噂はよく聞くので、最後になって出せない...となることを避けたかったからというのもあります)

もちろん、この計画を立てた時点では、「よし、これなら7日間でなんとかなりそうだ!」という自信は...なかったです笑

2-3日目:主要機能の実装開始

さて、2日目。ここからが本番です。chatGPTにコードを出力させて、コピペは面倒くさそうだな...でも、でもそうするしかないか...と考えていたところ、どうやら「Cursor」というAI搭載コードエディタがあることを発見しました。以下、参考にさせて頂いた記事です。

https://zenn.dev/gamuprog/articles/53e7adee04b337

https://zenn.dev/nenenemo/articles/a4a565cdeb2771#ターミナルのエラー修正

早速、Cursorをサイトからインストールして、起動。XCodeで作成したプロジェクトをCursorで開いて開発スタートです。
https://www.cursor.com/

データモデルの作成

まずは、カクテルのデータモデルを定義することから始めました。Cursorの「Command +K」コマンドでチャットを呼び出して、「カクテルのデータモデルを作成して」とAIに指示してみました。すると、AIが一瞬で↓のようなコードを提案してくれます。まじですごいし、早い。

cocktailmaster/Models/Cocktail.swift
struct Cocktail: Identifiable, Codable {
    let id: String
    let name: String
    let description: String
    let base: String
    let ingredients: [String]
    let instructions: [String]
    let imageURL: String
    let tags: [String]
    let abv: Double // アルコール度数
    
    // お気に入り状態を追跡するための計算プロパティ
    // これは永続化されないので、別途管理が必要です
    var isFavorite: Bool = false
}

Identifiable...? Coable...?

コード生成以外にも出力された内容についてもAIに聞くことができます。何でその記載をしたのかも説明してくれるので概念のキャッチアップもAIで余裕です(ただし、違和感を感じたらちゃんとググりましょう)。

ちなみに、Cursor上で.swiftファイルを作ってもXCodeで認識されなかったため、ファイルはXCode上で生成した方がいいです。

主要画面の実装

次に、ホーム画面とカクテル詳細画面の基本的なレイアウトを実装することにしました。ここでもCursorの力を借りて、SwiftUIでの画面実装に挑戦しました。

ちなみにCursorの強い所として画像も読み込んでくれます。なので、最初に作ったFigmaのワイヤーフレームと要件を纏めてとAIに指示すると、イメージに近いコードを生成してくれました:

cocktailmaster/Views/ContentView.swift
import SwiftUI

struct ContentView: View {
    @State private var searchText = ""
    @State private var selectedTab = 0
    
    let tabs = ["お気に入り", "カクテル", "ワイン", "ビール"]
    
    var body: some View {
        VStack(spacing: 0) {
            // 検索バー
            SearchBar(text: $searchText)
            
            // タブバー
            TabView(selection: $selectedTab) {
                ForEach(0..<tabs.count) { index in
                    CocktailListView()
                        .tabItem {
                            Text(tabs[index])
                        }
                        .tag(index)
                }
            }
            .tabViewStyle(PageTabViewStyle(indexDisplayMode: .never))
            
            // カスタムタブインジケーター
            TabIndicator(selectedTab: $selectedTab, tabs: tabs)
            
            // ナビゲーションバー
            CustomTabBar()
        }
    }
}

このコードを見て、SwiftUIの書き方直感的だなぁと思いつつ、AIの助けを借りて実際に動くコードを書くことができて感動しました。

ただし、画面を出力してという命令だとひたすらにコードを作るので、色々作らせると気づいたらディレクトリが散らかってしまいます。なので、私は後から整理することになりましたが、最適なディレクトリ構成などについてもAIに尋ねてファイル群を整理しておいた方が良さそうです。

ただ、Cursorを使うことで、コードの書き方に悩む時間が大幅に減り、アイデアの実装に集中できました。AIが提案してくれたコードを基に、少しずつカスタマイズを加えていくことで、自分のイメージに近づけていくことができます。

細かい画面設計の話は3日目が終わる頃には、基本的なデータモデルとワイヤーフレームで作成していた画面+αはほとんど完成していました。「これ、本当に作れてるの?」と、自分でも信じられないくらいの進捗に驚きました。Cursorのようなツールの存在が、開発初心者の私にとって、大きな助けになったことは間違いないです。


左上の矢印ボタンでシミュレーターを起動。動かせた時はテンション上がります

4日目:データベース連携開始

4日目に入り、いよいよデータベース連携に挑戦です。データベースと後述のログイン認証はGoogleのFirebaseを使うことにしました。理由は、無料枠が十分そうだったことと、下記のような関連記事も豊富でSwiftUIとの連携が簡単そうだったことです。

https://zenn.dev/joo_hashi/articles/a4f8865bbef202

Firebaseのプロジェクト作成

まず、Firebase側の設定は既に存在する関連記事を読みながら、Firebaseのサイトから今回のプロジェクトを作成。連携用のGoogleService-Info.plistをダウンロードして、xcodeのプロジェクト内に配置。

FireStoreでデータ作成と連携

次にコード側のFirebaseのセットアップ。「FirebaseをSwiftUIプロジェクトに追加する方法を教えて」とCursorに聞いてみました。すると、Firebaseのiosパッケージ(sdk)のインストールなどの詳細な手順と必要なコードを提示してくれました。

import Firebase

@main
struct YourApp: App {
    init() {
        FirebaseApp.configure()
    }
    
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

このコードを追加し、Firebaseの初期設定完了!

次に、カクテルデータをFirebaseのデータベース機能であるFirestoreに保存し、アプリから読み込む機能を実装。ここでもCursorの助けを借りて、データの取得と表示のコードを書きました。

import Firebase

class CocktailViewModel: ObservableObject {
    @Published var cocktails: [Cocktail] = []
    
    func fetchCocktails() {
        let db = Firestore.firestore()
        db.collection("cocktails").getDocuments { (querySnapshot, err) in
            if let err = err {
                print("Error getting documents: \(err)")
            } else {
                self.cocktails = querySnapshot!.documents.compactMap { document in
                    try? document.data(as: Cocktail.self)
                }
            }
        }
    }
}

AIの助言を得ながら、少しずつ進めることができましたが、データベース連携のコードを書くのに苦戦しました。特に、画面横断でデータモデルが連携できていない処理があったりしたので原因把握に一番時間を割きました...。

5日目:ログイン実装・審査準備

5日目は、ユーザー認証の実装と、そろそろ一通りの動作ができていたので、App Store審査の準備にも取り組みました。

Firebase Authでログイン機能の実装

Firebase Authenticationを使ってログイン機能を実装。SignInもスモールにまずはAppleSignInだけに限定。ここでも、Cursorに「FirebaseでSwiftUIアプリにログイン機能を追加する方法」を聞いて、基本的なコードを生成してもらいました。

import Firebase

class AuthViewModel: ObservableObject {
    @Published var user: User?
    
    func signIn(email: String, password: String) {
        Auth.auth().signIn(withEmail: email, password: password) { result, error in
            if let error = error {
                print("Error signing in: \(error.localizedDescription)")
            } else {
                self.user = result?.user
            }
        }
    }
}

ログイン画面のUIも、SwiftUIを使って簡単に作成。ちなみに、このタイミングでユーザーのデータモデルを作成しました。

App Storeの審査準備

審査準備では、何が必要なのかを確認していきつつ、まずは作成したコードをビルドしました。

  1. コードをApp Store Connectに上げるためには、XcodeメニューバーProductArchiveを実施
  2. 処理完了後に表示されるポップアップを進めて、アップロードを完了させる。

※アップロード時に何かのエラーが出ていた気がしましたが、何のエラーか忘れました笑
※ここでは詳細は割愛しますが、アップロードする前にApple Developerのアカウント作成が必要です。大体1万円くらい払う必要があります。

ビルドするだけでは、審査提出できないので、

  1. アプリ情報の記載(アプリ名・サブタイトル・キーワード・概要欄など)
  2. プライバシーポリシー・利用規約リンクの設定
  3. プライバシー情報の設定
  4. アプリプレビュー・スクリーンショット画像のアップロード
  5. その他(審査提出ボタンを押した時に何が足りないかは表示してくれたのでそこから確認)

も行いました...(ここが一番大変)。

4で必要な画像について、最初は下記サイトで紹介している作り方で作成しようと思いました、1枚あればOKだったので、まずは最低限の横長画像1枚をiPhone6.7, 5.5インチ用の2種類を作成してアップロードしました。
https://zenn.dev/kazuki23/articles/4c814b1f722669

審査申請ボタンを押す前に、全ての必要項目が埋まっているか再確認しました。この時点では特に問題なさそうに見えたので、心躍らせながら申請ボタンを押しました。

6日目:審査待ち・データ投入

審査を提出したので、待っている間でこれまで一部しか作成していなかったカクテルデータを増やすために、Firestoreにデータを投入することにしました。ここで問題発生。大量のデータを手動で入力するのはめっちゃ大変そうなことに気付きました...。

データ投入

そこで、ChatGPTを使ってカクテルデータのJSONを生成し、それをFirestoreに一括投入し、その後に投入内容を確認して不備があれば更新する方法を考えました。Cursorに「FirestoreにJSONデータを一括投入する方法」を聞いて、以下のようなスクリプトを作成:

import Firebase

func importCocktails() {
    let db = Firestore.firestore()
    
    // JSONファイルからデータを読み込む
    if let path = Bundle.main.path(forResource: "cocktails", ofType: "json") {
        do {
            let data = try Data(contentsOf: URL(fileURLWithPath: path), options: .mappedIfSafe)
            let cocktails = try JSONDecoder().decode([Cocktail].self, from: data)
            
            // Firestoreにデータを追加
            for cocktail in cocktails {
                db.collection("cocktails").addDocument(data: [
                    "name": cocktail.name,
                    "description": cocktail.description,
                    // その他のフィールド
                ]) { err in
                    if let err = err {
                        print("Error adding document: \(err)")
                    } else {
                        print("Document added successfully")
                    }
                }
            }
        } catch {
            print("Error: \(error)")
        }
    }
}

このスクリプトだけだと労力はそこまで変わらないので後ほど一部改良して使い、大量のカクテルデータを一気にFirestoreに投入できました。AIの力を借りて、データ生成の手間を大幅に削減できて本当に助かりました。

7日目:リジェクト・再審査・アプリ公開

審査結果

ついに7日目。朝起きるとApp Storeからメールが来てました!

...リジェクトされていました。理由は「Missing Push Notification Entitlement」。Push通知の権限が設定されていないというエラーでした。

正直、Push通知機能はまだ実装していなかったのですが、後々使用することになると思いApp Store ConnectのCertificateで設定していたようです。

  1. Xcodeでプロジェクトを開く
  2. プロジェクトの設定で「Signing & Capabilities」タブを選択
  3. 「+ Capability」ボタンをクリックし、「Push Notifications」を追加

これらの手順に従って設定を変更し、再度ビルドとアップロードを行いました。
(ついでに審査結果が返ってくるまでの間でに少し検索欄のUIを少し改善していてこのタイミングで更新してみました)

その後、新しくコードをアップロードし、App Store Connectで再審査を申請(一応リジェクトメッセージにも返信した方が反応が早いかと思って返信)。今度こそ大丈夫だろうと、少し不安を抱えながら待ちました。

再審査後...

そして、数時間後...ついに承認のメールが届きました!

「カクテルマイスターlite」が無事App Storeに公開されたのです。7日間の挑戦を経て、素人の私でもアプリを作り上げ、公開までこぎつけられたことに感動しました。


App Storeに載っている...

もちろん、7日間でこの通りにストレートに開発を進めたわけではなく読みやすいように加工している部分はありますが、友達と思いついたアイディアを投げかけたのが8/14だったので大体6-7日間でした。


最初はカクテルの達人という名前で出そうとしていましたがダサいと言われやめました...笑

最後に今回学べたことです:

  1. 「完璧を求めすぎないこと」:まずは動くものを作り、徐々に改善していく姿勢が大切。
  2. 「AIツールを上手く活用すること」:CursorやChatGPTの力を借りることで、開発速度が格段に上がりました。
  3. 「小さな成功を積み重ねること」:毎日少しずつでも進捗があると、モチベーションが維持できます。

プログラミング初心者の皆さん、AIの力を借りれば、あなたもきっとアプリを作れます。エラーに遭遇しても諦めずに、一つずつ解決していけば、必ず解決します。ぜひチャレンジしてみてください!

ここまで読んでいただきありがとうございました!公開されたアプリを気になっていただけた方は、是非下記のリンクからダウンロード & コメント頂けると非常に嬉しいです!

https://apps.apple.com/jp/app/カクテルマイスターlite/id6642687706

Discussion