🎍

年末に個人アプリを作っていたら年が終わっていた

に公開

😅夢中で気づかなかった

2024年12月31日に個人開発をしていた。開発からリリースまで6時間ぐらい。終わった頃には、0時過ぎてた笑

作ったアプリはメモと画像をローカルのストレージに保存してオフラインでも使用することができるシンプルなアプリです。

アプリ名: マイショッピングカメラ

どんなアプリかというと、いつもはiPhoneのメモ帳やリマインダーにメモしたりカメラやアップロードした写真を保存していたファイルを開くのが手間だなと思い買い物で購入したいものだけ記録するアプリが欲しくて作ったものです。

保存だけだと面白くないなと思いバージョン2には、🔔ローカル通知をつけました。

使い方

  1. ボタンを押す
  2. ボトムシートが開く
  3. メモを入力
  4. カメラで写真を撮影するか画像をuploadする
  5. 保存すると写真を保存したタブで確認できる
  6. 画像をタップすると拡大することができる

これで一旦申請してみた。最近は気軽にAndroidをリリースできなくなったので、iOSのアプリだけ開発した。年末だから🍏Apple様お休みだ。

技術構成

今回はRiverpodは使わずにSignalsというパッケージで状態管理をしてます。Riverpodばかり使っていたのですがたまには違うのを試したいなーと思い使ってみた。他にはSingletonパターンを使いました。データベースを使ったロジックでは昔から使われているそうです。同じインスタンスを1回しか生成しない。もし何度も生成すると?
他のページで呼び出すとエラー出ました😇
これを防止するためか?

カメラ機能はcameraを使いました。image_pickerにもカメラ機能はありますが、限定的な機能しかありません。ズームイン、フラッシュ機能を求めるならcameraを使う必要がありますね。image_pickerは画像のuploadで使用してます。

画面遷移はauto_routeを使いました。副業でしか使ったことないので、go_router以外を試したいと思った。タイプセーフとやらが使えるらしい?
いまだに恩恵を受けたことないな。。。

認証機能のロジックを作るときは、AuthGuardなるものがある。Riverpodのref.listenと組み合わせないとページを切り替えることができなかったので、GoRouterのリダイレクトとは違った対策が必要。

ローカルデータベースは、driftを使いました。最初は、ObjectBoxでやっていたのですが詰まることが多かった💦
sqfliteを使った方がいいかなーと思いつつSQL直接書くと使いにくいので、PrismaみたいなORMが使いたいと思い導入した。PythonのORMのsqlalchemyに書き方が似ていたので「あれ今はコード読めるな」前は見ても使いずれーと思って避けてましたが興味があり導入してみました。

ローディングで使用するインジケーターは丸だとカッコ悪いのでパッケージを使用してカッコよくした。loading_animation_widget

簡単にアニメーションを導入できるlottieというパッケージを今回は試してみました。公式サイトを見ると、Flutterはないな?調べるとあった。使えそうなので導入した。試作してたアプリは、SwiftUIとExpoでしたが(^^;;
他の技術に浮気する。あっちがカメラアプリを開発しやすかったから逃げただけですが。Expoは慣れたら簡単だった。

iPhoneのリマインダーと同じように通知機能が欲しかった。flutter_local_notificationsを導入して、FCMを使わなくもアプリに通知ができるようにした。

導入したパッケージ
name: my_shoping_camera
description: "A new Flutter project."

publish_to: 'none' # Remove this line if you wish to publish to pub.dev

version: 1.0.0+1

environment:
  sdk: ^3.6.0

dependencies:
  flutter:
    sdk: flutter

  cupertino_icons: ^1.0.8
  auto_route: ^9.2.2
  talker: ^4.5.5
  camera: ^0.11.0+2
  image_picker: ^1.1.2
  drift: ^2.23.0
  sqlite3_flutter_libs: ^0.5.28
  path_provider: ^2.1.5
  path: ^1.9.0
  signals: ^6.0.2
  loading_animation_widget: ^1.3.0
  lottie: ^3.3.0
  url_launcher: ^6.3.1
  flutter_local_notifications: ^18.0.1
  shared_preferences: ^2.2.2

dev_dependencies:
  flutter_launcher_icons: ^0.14.2
# launcher_iconを使用するための設定
flutter_launcher_icons:
  android: "launcher_icon"
  ios: true
  image_path: "assets/icon/icon.png"
  min_sdk_android: 21 # android min sdk min:16, default 21
  remove_alpha_ios: true  # iOSのアルファチャンネルを削除
  adaptive_icon_background: "#ffffff"  # Androidのアダプティブアイコン背景色
  adaptive_icon_foreground: "assets/icon/icon.png"  # Androidのアダプティブアイコン前景
  
  flutter_test:
    sdk: flutter
  auto_route_generator: ^9.0.0
  flutter_lints: ^5.0.0
  build_runner: ^2.4.14
  drift_dev: ^2.23.0

flutter:

  uses-material-design: true

  # To add assets to your application, add an assets section, like this:
  assets:
    - assets/
  #   - images/a_dot_burr.jpeg
  #   - images/a_dot_ham.jpeg

  # An image asset can refer to one or more resolution-specific "variants", see
  # https://flutter.dev/to/resolution-aware-images

  # For details regarding adding assets from package dependencies, see
  # https://flutter.dev/to/asset-from-package

  # To add custom fonts to your application, add a fonts section here,
  # in this "flutter" section. Each entry in this list should have a
  # "family" key with the font family name, and a "fonts" key with a
  # list giving the asset and other descriptors for the font. For
  # example:
  # fonts:
  #   - family: Schyler
  #     fonts:
  #       - asset: fonts/Schyler-Regular.ttf
  #       - asset: fonts/Schyler-Italic.ttf
  #         style: italic
  #   - family: Trajan Pro
  #     fonts:
  #       - asset: fonts/TrajanPro.ttf
  #       - asset: fonts/TrajanPro_Bold.ttf
  #         weight: 700
  #
  # For details regarding fonts from package dependencies,
  # see https://flutter.dev/to/font-from-package

スクリーンショットとアプリアイコンの画像は、Canvaで作成しました。アプリアイコンの画像サイズは1024×1024ですね。画像の加工はパッケージでやるので昔から使っているflutter_launcher_iconsを使用しました。

https://www.canva.com/

iPhoneのモック画像はMockviewなるものを昔から使っています。ただこれ困ったことに最近は白い背景が作られてしまうようで邪魔です😇
昔は背景が透明でしたね。背景画像を削除するときは、removebgというサービスを昔から使っております。

https://mockview.app/
https://www.remove.bg/ja

最後に

最近は、Flutterで個人開発やってませんでした。仕事で使うことが多いクラウドやコンテナの学習に時間をかけていました。個人開発するときは、SwiftUI/Jetpack Composeしか使っていませんでした。

作りたいなと思った理由はFlutterでカメラアプリを作ったことがなかったので試しにやってみたかったんですよね。意外と需要がある機能なので勉強目的で作ったアプリですね。

個人開発のいいところは仕事と違って普段使わない技術構成で開発できるところですね。僕は技術が好きなので新しいものを作るときは、今まで使わない技術構成で試しますね。

最近だとこれを試していた

  • Next15/shadcn/ui
  • SvelteKit/Supbase
  • SwiftUI/SwiftData
  • Jetpack Compose/Room
  • FastAPI/GeminiAPI
  • Go/GeminiAPI

同じ技術構成で本業がつまらない。パッケージを使ってみたい。仕事で疲れた。上流工程ばかり。そんな人は個人開発を楽しんでほしい。

HTML/CSS/JavaScriptだけでもいい。デザインの勉強をして美しいWebサイトを作ってみてください。きっと感動すると思います。

プリンシプル オブ プログラミング 3年目までに身につけたい 一生役立つ101の原理原則 (単行本)という本を読んでみるのも良いかもしれません。

テンプレート作って開発を早くするためにコピー&ペーストを多用しますがしてはダメだと書いてある。コードを知ってる人はかけるといこと?

ではなくてコードを自動生成する方法を作れだそうだ。今だと生成AIを使いますね。使い方次第ですが頼り過ぎは危険ですね。とはいえベンチャーでは導入する傾向があるようです。お堅い会社は禁止してますが、新しいものが好き効率をあげたい人は試してみるといいと思います。

開発速度が上がりますよ。私は🐦‍⬛ブラック企業をクビになって暇になった時に、Flutterで始めて個人アプリを作ったのですが、3日かかりました。それが今は6時間ぐらいに短縮できた。

普段から勉強したりテンプレートを作っているからできたことですが、生成AIも活用すれば、上流工程とデザインだけで作れます。

  1. 要件定義 -> 技術選定 -> Figma/Canvaでデザイン
  2. Cursor Editor/Windserf EditorでAIのアシスト機能を使い開発する
  3. ブランチは分けて作業。壊れた時に直せる。定期的にリモートにpushした方がいい
  4. 確認してOKなら申請する

これだけでリリースの申請まで行けました。リリースまだしてませんが💦
皆さんも個人開発楽しんでくださいね。良きFlutterライフを 💙💚

Discussion