個人開発で1円を稼ぐ──それがどれほど難しいか知っていますか?
Flutter Kaigiのセッションで月1,000ドル以上稼げるアプリの割合の少なさを知った、いせりゅーさん。この時からアプリを“価値化”する挑戦が始まりました。リリースしたアプリ『FoodGram』のこれまでの開発についてをこの記事に凝縮してお届け。この記事を読み終えたとき、あなたも「個人開発で価値を出す一歩を踏み出したい」と思うはずです。
個人開発をしてリリースした先で“価値”を届けられる人はまだまだ少ない...
FlutterKaigiに参加して衝撃を受けた言葉があります。
「月1,000ドル以上稼げるアプリは、Revenucat利用アプリのうち17%しかない」
Flutterでよく使われる課金管理サービスRevenucatのエンジニアJeffrey Bunnさんの英語のセッションだったので全部を理解できたわけではないんですが、それでもこの数字は強烈でした。アプリをリリースしている人はたくさんいるのに、マネタイズできている人は本当に少ないんだなと。終わったあと、Jeffrey氏に 「このアプリでマネタイズするならどう思う?」と質問ができました。この時、直接話をしたことで、「本気でマネタイズしてみよう」と決めたんです。
実際、開発した『FoodGram』では少しずつですが収益化を達成できています。
Appleから初めて振り込みがあったときは、部屋で一人ガッツポーズしたり、SNSにも思わずシェアしてしまうくらい嬉しかったです。自分のアプリの価値を初めて客観的に見られた、大事な瞬間でした。
はじまりは、技術をアウトプットする手段としての個人開発
『FoodGram』を作る前も、学生時代からたくさんアプリをリリースしていました。とにかく作って出してみるというスタンスで技術を学んできました。その時に工夫していたのは、学んだ技術を使って手順の通りにやってみて、その後自分なりに工夫を加えてさらに技術を定着させるというプロセスを踏むことです。例えば電卓アプリを作ったときのこと。まずはインプットした通りに電卓アプリを作ってみました。そしてさらにフリック入力で演算できるようにアップデートをしたんです。こんなふうに少し上のレベルの開発に挑戦する癖をつけていたおかげで技術の定着はとても早かったと思います。
この「まずはやってみる」という姿勢は、今でも変わりません。一度リリースしてうまくいかない挙動があったら直すということも怖くなくなりました。今までたくさんアウトプットしてきた経験が活きているところかなと思います。実は、『FoodGram』はもともとは違ったレビューアプリをリリースする予定で進めていたんです。でも、諸事情でリリースを諦めることになってしまって、せっかく作り込んでいた機能をこのままにするのはもったいないなと思いました。そんな時、普通のSNSで食べ物だけを共有するアカウントで発信していたこともあって、「これをフードの情報共有に特化したアプリとしてリリースしたら面白そうだな」と思い立ち、スタートしました。前進のアプリも『FoodGram』もまさに「まずはやってみる」から始まっています。
このお話の詳細はnote記事もぜひ併せてご覧ください!
「やりたいことをやりたいだけ」挑戦し続ける開発スタイル
『FoodGram』は、とにかく「やりたいことをやりたいだけやる」のモットーに基づいて、今まで自分が触れてきて面白いと思った技術的アプローチや興味のある最新の技術・機能を扱った新規実装にチャレンジしていることが技術的にこだわっているポイントです。基本的にはFlutterで全て開発しているので、Flutterでできることをできるだけやっているつもりです。アプリの内容としては一般的なフードシェアアプリではあるものの、技術の中身は新しいものも入れつつ、「ここにこんな技術を取り入れるんだ」って思ってもらえるような技術選定や開発を進めています。そして、それは全てpublicで運用をしています。
▼『FoodGram』のリポジトリ
もちろん、publicで運用にするにあたり必要な部分は難読化したりしていますが、基本的には開発者の方が新しい技術を使うにあたり参考になるようなコードや設計を意識しているのでぜひソースコードなどもみてもらえたらと思います。
ここから少し、実装の際にこだわった点について紹介していきます。
まず、ひとつめは、ソーシャルログイン機能です。この機能はアプリの根幹を支える重要な機能です。もちろん『FoodGram』にも実装することにしました。今回のログイン機能の実装には、Supabaseを採用しています。
まず初めに、ドキュメントを参考にGoogleログインとAppleログインから実装をしたのですが、その2つのログイン方法だけの場合に問題点があることに気がつきました。それは、Androidユーザーが何らかの理由でGoogleログインできなかった場合、アプリそのものが利用できなくなるというリスクです。そこで、第三のログイン方法としてTwitter(X)ログインを追加することにしました。
ところが、この実装は簡単ではありませんでした。Supabase側・Twitter Developer側・Flutter側のすべてが正しく連携していないと動作せず、何度試しても失敗の連続。それでも諦めず、一つひとつ確認しながら修正を重ねた結果、ようやく動作させることができました。今後も、さらに多様なソーシャルログインを導入し、より多くのユーザーにとって使いやすいアプリを目指していこうと思っています。

ふたつめは、シェア機能です。単にフードの画像を共有するのではなく、より目を惹くようなビジュアルを届けたいと考えました。
具体的には、画像やレストラン名などを組み合わせた独自のWidgetを作成し、screenshot というパッケージを用いてそのWidget全体を画像としてキャプチャ。さらに、シェア可能な画像形式に変換し、文言とともにシェアできるように実装しました。

単なる画像のシェアではなく、アプリ独自の世界観を反映したデザインでシェアされる体験を目指し、Widgetの構成やレイアウト、画像変換処理の流れなどに試行錯誤しながら開発を行いました。
▼具体的な実装code部分の抜粋
import 'dart:io';
import 'package:path_provider/path_provider.dart';
import 'package:screenshot/screenshot.dart';
import 'package:share_plus/share_plus.dart';
class WidgetShareService {
Future<void> captureAndShare({
required Widget widget,
}) async {
try {
// 実装を簡潔にするため、毎回新しいインスタンスを作成
// 本格的な実装では、Widgetのライフサイクルに合わせて管理することを推奨
final controller = ScreenshotController();
// ウィジェットをキャプチャ
final bytes = await controller.captureFromWidget(widget);
// 一時ディレクトリを取得
final tempDir = await getTemporaryDirectory();
// 画像ファイルとして保存
final path = '${tempDir.path}/shared_image.png';
final file = File(path);
await file.writeAsBytes(bytes);
// 画像をシェア
await Share.shareXFiles([XFile(file.path)], text: 'シェアする文言');
} catch (e) {
print('シェア処理でエラーが発生: $e');
}
}
}
これからも色々な実装に挑戦し、ユーザーへ届けるための手段やユーザーに使ってもらえる仕組みを考えていきたいと思っています。
月額2ドルだからこそアプリの「価値」を意識する毎日
今は自分がやりたいことはもちろんですが、月2ドルのサブスクで利用をしてもらっているので、いただいているお金に見合った価値を返さないとという意識で開発にあたっています。その中で最初にぶつかった壁は、やっぱり広告について。そこで、自分の体験も含めてユーザーがなるべく不快感を感じないようにということを意識し、より快適に使ってもらうために、磨きをかけています。
まず、サブスク登録をしているユーザーに対しては、広告表示をなくし、より快適に使ってもらえるように。
そして、無料で利用するユーザーには、できるだけ不便だと感じさせないよう、広告の表示頻度やタイミング、広告の場所などを工夫しています。

表示頻度については広告の多さでアプリ利用離脱のリスクと広告収益安定のバランスを踏まえて、乱数を生成し、10回ぐらいに1回の表示など、ちょうどいい具合の調整を頑張りました。
そしてここで、まだあまり知られていない、現段階のサブスク特典についてお話しさせてください!
- 全ての広告が非表示になる
- アカウントの画像を自分で自由に設定できるようになる
- 投稿すればするほどトロフィーとして称号がもらえる
- 自分の好きなジャンルを選択して、表示することができる
正直なところまだまだ特典は弱いと思っているので、これからももっと使ってもらえるような特典や仕組みを考えている最中です。(もちろん、将来的に、サブスク利用をしてくれたユーザーさんが損をしないようなことも着実に考えていますよ!)
リリースを機に、自分が考えた実装を進めるフェーズは落ち着きました。ありがたいことに知り合いから広がりユーザーが増えてきていることもあり、現在は、開発の4割ほどを口コミやフィードバックからの修正改善、アップデートに充てています。
要望を受けて実装中💻
— いせりゅー 🥳 (@isekiryu) July 19, 2025
あと少しでできますが、続きは明日👀#foodgram pic.twitter.com/Px1hnOOFlZ
ここまでで、実際に開発にあたった口コミをひとつ紹介します。
「自宅近くのレストランを投稿すると、住所が特定されそうで不安」というフィードバックです。この意見にはとても納得感があり、すぐに改善に取り掛かることにしました。『FoodGram』の開発にあたっては、できるだけシンプルかつ、自分の手の届く範囲で確実に作り切ることを大切にしています。そこで、複雑になりすぎない実装方法を模索しました。
最終的に思いついたのは、投稿に「匿名かどうか」のフラグをデータベースに追加し、それに応じてアプリ側の表示や共有処理を切り替える、というシンプルな方法です。複雑なロジックを避けつつ、ユーザーの安心感にしっかり応える対応ができたと思います。

▼この機能のコードをチェックする
「やりたいことをやりたいだけやる」とアプリの「価値」のバランスは難しいところですが、たくさんの人にアプリを広めるためにも大事な観点なので、毎日向き合う日々です。
▼X(旧Twitter)での実際にアプリを利用しているユーザーの声
使ってまーす!楽しいし、ランチの記録ができて凄く便利です🍛
— Natsuki (@NatsukiNo8) July 23, 2025
ただ、その共存を目指してまずはなるべく高くなりすぎない金額設定を意識しました。また、現在低コストで運用しているからこそ実現できている背景もあります。特にリリースしてからコストについて意識した選定をしたのはMap表示。ランニングコストが高い地図サービスではなく、オープンソースのMapLibreを採用して運用コストを抑えることで、ユーザーに負担をかけない形を選んでいます。この採用に関しては、同じ業界で活躍する家族やTechTrainのメンターなどからのアドバイスも活用しました。(このお話は、またどこかでできたらと思います。)
▼実際にこだわりがユーザーにも届いていることがわかるポスト
いせりゅーさんのアプリは随所にこだわりを感じられてとても好き #flutter_tokyo
— aq (@aqhayami) June 7, 2025
「まずはやってみる」から「価値」を提供する経験を
アプリをリリースしてお金をいただくとアプリに対しての「価値」を考える必要があります。ただ、「まずはやってみる」とリリースするだけではその経験はなかなか味わえません。ハッカソンで作ったアプリ、個人で作ったアプリ、たくさんの人がその経験をしている中で、まずは1円でも「価値」を提供する経験を本気でしてみませんか?
「やりたいことをやりたいように作る」って、個人開発の特権だと思う。
— いせりゅー 🥳 (@isekiryu) August 8, 2025
でも、ふと「ちゃんと誰かに届けたいな」って思う瞬間がある。そのたびに「価値ってなんだろう」って立ち止まってしまう。
今日もその間を行ったり来たりしながら、ちょっとずつ手を動かしてる🔥
「やりたいことをやりたいだけやる」から始まった開発も、ユーザーがお金を払う価値を感じてくれるのは大きな喜びです。少しずつでも「ちゃんと誰かに届けたいな」と思える瞬間があるからこそ、自分の作ったアプリで提供できる価値を考えながら、これからも挑戦を続けたいと思います。
『FoodGram』とは?
.png)
“FoodGramは、世界中のユーザーと食の楽しさを共有できる「フードシェアリングアプリ」です。美味しかった料理や、お気に入りのレストランを投稿して、みんなでグローバルな「フードマップ」を作ることができます。”
iOSのアプリストア
Androidのアプリストア
ダウンロード用QRコード

公式アカウントやLPサイトなどがまとまったものは以下よりチェック可能です。
TechTrainは、これからも「プロダクトをリリースして価値を提供するまで」の過程を発信し、日々プロダクトと向き合う開発者の方を応援していきます!
リリースまでの背景や実装の楽しさや大変だったこと、そしてリリースした先に見えた景色やその先の未来についてを語ってくださる開発者の方がいらっしゃいましたら、ぜひTechTrain DevRel Rai(X:https://x.com/hiraisoko_rai)宛にお気軽に声がけください。






.png&w=3840&q=75)
.png&w=3840&q=75)


