2020年5, 6月のアプリ開発収益
こんにちは。こんばんは🐶
資格試験のため、少し離れていました。泣 勉強とアプリ開発を並行してできればよかったのですが、不器用なもので、、😅
遅ればせながら、5月、6月の収益報告をいたします!
収益報告
5月の収益報告 「133円」(前月から+100円)
6月の収益報告 「526円」(前月から+393円)
振り返り
収益が上がっている要因は、以下の2点が影響しているのかなと思いました🤔
説明文の変更に伴うインストール数の増加 4月にAndroid版MyReviewの説明文を変えてみた。それによりインストール数が増加した! (今までAndroid版MyReviewの説明文がかなり雑だったので、iPhone版に合わせただけだが、、) インストール数の増加に伴い、クリック数も少し上がり、収益も上がっているようだ!
レビュー投稿で高評価コメントを頂けた これもAndroid版MyReviewだが、高評価のコメントを頂くことができた! これのレビューを見て、訪問してくれた方がインストールしてみようかという気持ちになっているのかもしれない🙌
今回でわかった事は、
説明文もかなり重要な要素! スクリーンショットだけではインストールまでいかないみたい。今まで疎かにし過ぎました。。今度からはちゃんと書きます😅
レビューを書いてもらえる仕組み作りがあった方が良い! 今回は優しいユーザー様にレビューを書いて頂きましたが、こちらからレビューを依頼する機能があった方が良いと思った👨💻
今後のアクション
レビュー依頼の機能を実装してみる レビューをより頂けるように仕組み作りを構築したい。👨💻
ユーザー様にご要望頂いている機能を実装 今まで手がつけられていなかった機能を実装していく!👨💻
5月の新規アプリのリリース 月1アプリ開発が遅れているので、そろそろリリースせんとヤバイ、、
雑談
自宅で手料理するようになった🍳 料理系のアプリも作ってみたいなーと思ったりしています。
では〜🐈
2020年4月のアプリ開発収益
こんにちは!こんばんは!🐶 もう5月も終わりそうですが、4月の収益報告をしたいと思います。
収益報告
2020年4月の合計収入は「33円」でした。。 やはりクリックされないと厳しい状況ですね。
前月が「185円」でしたので、-152円減💸
振り返り
やはり無料アプリは、クリックされないと厳しいようだ。。 アプリ開発の現実は厳しい。。。
今後のアクション
・クリックされる≒ユーザー数を増やすことだと思うので、前月同様、アプリのユーザー数を増やす&維持するため、以下の対応をしてみる。
①スクリーンショットを少し変えてみる。
②アプリの説明文を変えてみる。
・有料版アプリを出してみたい。
・ 新規アプリの開発
雑談
個人アプリ開発で万単位で稼いでる人って本当にすごいなーと日々思いますな。。 そういう人も私みたいに下積み時代があるのかしら。。
では〜🐈
【Android】KotlinでRecyclerViewの無限スクロール
マイレビューは初期表示時、一度に全データをロードする処理だったが、 テスト的に大量データを登録したらロード時に時間がかかりこれはいかんと思い修正。。 対応策として、無限スクロールを採用した。
1. RecycleViewにスクロールイベントを追加
無限スクロールを実現するために、リストをスクロールし、末尾付近に差し掛かったら、データをロードする処理を追加。 まずはスクロールリスナーを追加する!今回はこちらを参考にさせて頂きました。
abstract class ScrollPageListener(layoutManager: LinearLayoutManager): RecyclerView.OnScrollListener() { private var mLayoutManager: LinearLayoutManager? = null private var mPage: Int = 0 private var mPreTotalCount: Int = 0 private var mIsLoading: Boolean = false private var visibleThreshold = 0 init { mLayoutManager = layoutManager } override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) { super.onScrollStateChanged(recyclerView, newState) } override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { super.onScrolled(recyclerView, dx, dy) // ロードするときに走るのは無駄なので、先にreturnする if (dx == 0 && dy == 0) { return } val visibleItemCount: Int = recyclerView.childCount val totalItemCount: Int = mLayoutManager!!.itemCount // グリッドの表示個数 val firstVisibleItem: Int = mLayoutManager!!.findFirstVisibleItemPosition() if (mIsLoading) { if (totalItemCount > mPreTotalCount) { mIsLoading = false mPreTotalCount = totalItemCount } } if (!mIsLoading && (totalItemCount - visibleItemCount) <= (firstVisibleItem + visibleThreshold)) { mIsLoading = true load(++mPage) } } abstract fun load(page: Int) }
次にActivity側でRecycleViewのスクロールイベントにスクロールリスナーを設定する!
recycleView.addOnScrollListener(object: ScrollPageListener(reviewRecycleView.layoutManager as LinearLayoutManager) { override fun load(page: Int) { Log.d("scroll", "末尾だよ! $page") // ここでデータをロードする処理を追加! } })
2. 末尾を検知し、データをロードした後の処理
末尾を検知したらデータをロード!ロードしたら、RecycleViewのアダプター側でデータを追加する! ここでつまずいた。。Adapterの「notifyItemRangeInserted」を実行しても行が追加されなかった。 色々調べると、データを追加し、Adapterで「notifyItemRangeInserted」を実行した後、 RecycleViewの「recycleView.scrollToPosition」を実行しないと行が追加されないみたい🐶
Activity側の処理
// ロードしたデータをAdapterに追加する(selectedReviewList→ロードしたデータのリスト) reviewAdapter!!.addItem(selectedReviewList) // ロードしているデータの末尾までスクロール(これをやらないとスクロールしないとデータが表示されない!) recycleView.scrollToPosition(reviewRowList.size)
Adapter側の処理
override fun getItemCount(): Int { // ・・・ } @Override override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder { // ・・・ } @Override override fun onBindViewHolder(holder: MyViewHolder, position: Int) { // ・・・ } /** * 行を追加する */ fun addItem(reviewList: ArrayList<Review>) { val fromIdx = this.itemCount for (review in reviewList) { val idx = this.reviewList.indexOf(review) if (idx == -1) { this.reviewList.add(review) } } // ここでデータを追加されたことを通知!(通知しないと追加したデータが表示されない!) this.notifyItemRangeInserted(fromIdx, reviewList.size) }
リストって色々と考慮しないといけないなー🐈
マイレビューも是非インストールしてみてください!
今回は以上!
2020年3月のアプリ開発収益
こんにちは!こんばんは!🐶 ありがたいことに最近、利用者様が徐々に増えて収益がコンスタントに3桁になってきたので、テキトーなタイミングで個人アプリ開発の収益を振り返り、 次のアクションを考えられたらと思います。
収益報告
2020年3月の合計収入は「185円」でした!(185円で何ができる。。。!)
前月が「121円」でしたので、+64円増!💰
振り返り
今月はクリック数が多く、収益が上がった。以前はクリックしてもらうことなどほとんどなかった。恐らく使って頂く回数が増えていることが要因と考える。 当面は、現在のプロダクトを改善していき、利用して頂く方々を増やしていきたい!🐈 最近は「MyReview」をよく使って頂けているようだ!ありがとうございます!
今後のアクション
・既存プロダクトのデザイン(レイアウトやストアのスクリーンショットなど)を見直し、ブラッシュアップすることで、新規ユーザー様の獲得、既存ユーザー様に長く使って頂く努力をする。 ・月に1回アプリのリリースを行うので、4月は新しいアプリを開発する!
雑談
アプリ収益で知人とご飯を食べに行くのが目標なのですが、まだまだ道のりは長い。。めげずに頑張ろうと思います。。 これからもよろしくお願い致します!
では〜🐈
【アプリ】MyReviewのデータバックアップ・復元手順について(詳細)
いつもMyReviewをご利用頂きありがとうございます。
当記事は、MyReviewのデータバックアップ、復元方法の詳細記事です。
データバックアップ手順
バックアップ手順を以下に記します。なお、データバックアップはアプリに登録されているデータ・写真をバックアップし、ソート設定などは引き継がれませんのでご了承下さい。
1. MyReviewを開き、バックアップ・復元画面を開きます。その後、[バックアップ]ボタンをタップします。
2. 確認画面が表示されるので、「OK」ボタンを選択します。
3. バックアップが完了すると、お使いの端末のストレージに「MyReview」というフォルダが作成されており、その中に「BackupFile」というフォルダが作成されます。このフォルダ内に現在アプリで登録されているデータ・写真が保管されています。
4. BackupFileのフォルダをGoogle Driveやメールに添付などして、適宜保管して下さい。
データ復元手順
データの復元手順を以下に記します。 お使い端末のMyReview>ImportFile>BackupFileを読み込んでデータを復元します。
1. お使いの端末ストレージ内の「MyReview」フォルダの中の「ImportFile」というフォルダが存在するか確認します。存在しない場合は、MyReviewのアプリを開き、バックアップ・復元画面を一度開いてみて下さい。
2. ImportFileの中にデータバックアップで取得したBackupFileフォルダを置きます。(BackupFileというフォルダの名前は編集しないで下さい。)
3. MyReviewのアプリを開き、バックアップ・復元画面を開きます。その後、[復元]ボタンをタップします。
4. 確認画面が表示されるので、「OK」ボタンを選択します。(現時点でアプリ内に登録されているデータは一度削除されますので、ご注意下さい。)
5. データが復元されていることを確認します。
以上です。その他ご不明点等ございましたら、コメント欄にご連絡頂ければ幸いです。
【Android】画像保存の際、カメラからの画像か保存されている画像かを選ばせる方法
仕事の方が忙しく、全く書けていませんでした。。
最近は、色々と落ち着いてきて、またアプリ開発の方に着手ができてきました。
先日、MyReviewの機能追加を行いました。 MyReviewは、自身で好きなもののレビュー記録を付けることができるアプリです。 レビュー記録を作成する際、画像を一緒に付けることができます。
以前はカメラの機能が使えなかったのですが、使えるようにしました!
・カメラを起動させて撮影した画像を保存
・予め保存している画像を保存
どちらかを選ばせる様な挙動にしています。
こんな感じです。(画質が粗いですが、アプリ上は問題ありません。)
流れとしては、以下のイメージです。
- ギャラリーからのIntentを生成
- カメラ起動のIntentを生成
- createChooserメソッドに1と2を渡し、1と2を選ばせる画面を表示
今回はKotlinで書きました。
まずは、Intentの生成
// ギャラリー、カメラのIntentを入れるList val targets: MutableList<Intent> = mutableListOf() // ギャラリーのIntent val intent = Intent(Intent.ACTION_GET_CONTENT) intent.type = "image/*" targets.add(intent) // カメラのIntent val intent2 = Intent(MediaStore.ACTION_IMAGE_CAPTURE).apply { addCategory(Intent.CATEGORY_DEFAULT) putExtra(MediaStore.EXTRA_OUTPUT, createSaveFileUri()) } // ギャラリーとカメラのIntentをListに追加 targets.add(intent2) val chooserIntent = Intent.createChooser(Intent(), "選択して下さい").apply { putExtra(Intent.EXTRA_INITIAL_INTENTS, targets.toTypedArray()) } startActivityForResult(chooserIntent, requestCode)
画像が選ばれた後のコールバック処理
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { if (resultCode == Activity.RESULT_OK) { // ここの中で受け取った画像に対して処理する } }
では〜🐶