今月のみてみて(2024年12月)

Firebase連携アプリ、みてみてエストーク伊勢125社巡り

このうち、みてみてにフォーカスを当て、Firebaseのアクセス動向やアプリの改善を考察する開発記事です。

Firebase
Realtime Database+Storage構成の投稿アプリ

まずはアプリのユーザー数の変動とともにFirebaseのアクセス動向を確認します。

2024年12月1日~2024年12月31日のユーザー数の変動

(ユーザー数の変動)

ユーザー数変動

約8ヶ月ぶりのデータ解析。

ここにきて新規ユーザー獲得数に若干の伸び。

累計インストール数は3000突破。

(インストールの上位国)

東南アジアのトレンドが終わって中東エリアで伸び。

2024年12月31日直近のFirebaseの変動

(Firebaseの変動)

直近のfirebaseの動き
1ヶ月のfirebase使用量

大きな動きはなし。

Cloud Strageが増えず、Realtime Databaseに動きがあるので、投稿がユーザーに受けているわけじゃなく、ユーザー間メッセージに需要がある感じ。

安定の無料枠です。

2024年12月1日~2024年12月31日のAdMob

今月はAdMob広告収入:52円、 Firebase使用料:0円となりました。

今月のみてみて

(今月の投稿ピックアップ)

久しぶりにアウトレット行きました。

今後の改善案

(未消化の課題)

・投稿の編集機能追加

・写真を複数投稿可能にする

・手持ち画像も投稿できるようにする

・UIブラッシュアップ

・チャット機能強化

・フレンドグループ化と共有機能の追加

・ビジュアル強化

・アプリ名変更

ASUSノートPCバッテリー交換

2024年10月20日

長年使ってきたASUSのノートPC(X202E)が壊れました。

壊れた、と言っても基盤が破損した、とかではなく、まったく充電できなくなったわけです。

充電ランプがオレンジの点滅を繰り返し、一向に充電できません。

原因としてまず真っ先に疑うのがバッテリー。

使用年数を考えるとこれしか考えられない。

ということでバッテリーを購入します。

amazonでASUSノートPC(X202E)のバッテリーを探してみると純正ではないですが、いくつか候補が見つかります。

その中からバッテリーを専用で扱っている店をチョイスして購入しました。

税込み、6980円。

ノートPCの裏面のネジをはずします。

そして、カバーをはずします。

はめ込まれているので意外と固いですが、マイナスドライバーを差し込んでゆっくりと隙間をひろげていきました。

バッテリーの周辺のネジをはずし、最後にコネクターを抜きます。

コネクターはスライドして差し込まれているのでスライドさせるよう少し力を入れるとすんなりと抜けました。

バッテリー交換が終わったので充電してみたところ・・・

オレンジのランプが点滅したまま。

なんだと!?

バッテリー交換で復旧しない。

となるとアダプターなのか!?

ということでアダプターを購入。

こちらも純正ではないですが、型にあうものをチョイス。

税込み、2328円。

新しいアダプターが届いたのでもう一度充電してみます・・・

ついに充電ができました!

まさか根本原因はアダプターだったのか。

これであと2~3年は使えそうです。

ファイル・ディレクトリのアクセス権限変更

chmod -R 777 (指定ディレクトリ名)

777は、(オーナー)(グループ)(他ユーザー)の権限状態。

オーナー、グループ、他ユーザーそれぞれが下記の権限に基づきアクセスの制御を受ける。

Read(読み取り):4、Write(書き込み):2、eXcute(実行):1

700なら、オーバーのみフルアクセス。

-Rは、オプションで指定したディレクトリ配下に適用される。

HTMLファイルを表示する

2024年7月15日

開発環境
OS:Windows 11
SDK:VS Code + Flutter 3.7.12

概要

アプリ内のローカルストレージに格納したhtmlファイルを画面に表示します。

WebViewウィジェットを準備する

HTMLファイルはWebViewウィジェットを通して表示します。

そのため、WebViewパッケージをインストールする必要があります。

サンプルプロジェクトを生成して動作確認してみます。

webview_flutterをインストールします。

HTMLファイルを準備する

次にHTMLファイルを準備します。

<!DOCTYPE html>
<html lang="ja">

  <head>
    <meta charset="UTF-8">
    <title>Top Page</title>
  </head>

  <script>
    function sendData1() {
      // Flutterへデータ送信
      sample.postMessage("1");
    }
    function sendData2() {
      // Flutterへデータ送信
      sample.postMessage("2");
    }
  </script>

  <body>
    <h1>Please tap a button.</h1>
    <br>
    <br>
    <button onclick="sendData1()">Send Data 1</button>
    <br>
    <br>
    <button onclick="sendData2()">Send Data 2</button>
  </body>
</html>

ボタンが2つあるHTMLファイル(top.html)を作成しました。

プロジェクトフォルダ内に「html」フォルダを作成し、その中に作成したhtmlファイルを格納します。

次にpubspec.yamlのassets項目にhtmlファイルを定義します。

  assets:
    - html/top.html

WebViewウィジェット実装

main.dartにWebViewウィジェットを追加します。

ネットワーク上のurlにアクセスして表示するわけではないため、htmlのロード処理もあわせて追加する必要があります。

import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:webview_flutter/webview_flutter.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  late WebViewController controller;
  late Future<void> controllerInitialization;

  @override
  void initState() {
    super.initState();
    controllerInitialization = initController();
  }

  Future<void> initController() async {
    final html = await rootBundle.loadString('html/top.html');
    controller = WebViewController()
      ..setJavaScriptMode(JavaScriptMode.unrestricted)
      ..addJavaScriptChannel('sample', onMessageReceived: (result) async {
          switch (result.message) {
            case "1":
              print("call 1.");
              break;
            case "2":
              print("call 2.");
              break;
          }
        })
      ..loadRequest(
        Uri.dataFromString(
          html,
          mimeType: "text/html",
          encoding: Encoding.getByName("utf-8"),
        ),
      );
  }

  @override
  Widget build(BuildContext context) {
    return FutureBuilder<void>(
      future: controllerInitialization,
      builder: (context, snapshot) {
        if (snapshot.connectionState == ConnectionState.done) {
          return Scaffold(
            appBar: AppBar(title: const Text("Test Page")),
            body: WebViewWidget(controller: controller),
          );
        } else {
          return const CircularProgressIndicator();
        }
      },
    );
  }
}

※Android向けのビルドが失敗した場合はこちら↓をチェックしてみてください。

動作確認

デバッグモードで起動しました。

HTMLのテキストと2つのボタンは期待通りに表示されています。

次にボタンを押し分けてみると・・・

ターミナルに「call 1.」、「call 2.」が表示されました。

ボタン操作も処理できることが確認できました。

今回は以上です。

ビルドエラー解消(JAVA_HOME)

2024年7月15日

開発環境
OS:Windows 11
SDK:VS Code + Flutter 3.7.12

概要

久しぶりにFlutterの動作確認をしようとサンプルプロジェクトを生成し、Android向けにビルドしたら失敗しました。

Android向けビルド時に発生したビルドエラーの解消方法についての話。

Flutter ビルドエラーの発生

サンプルプロジェクトを生成。

AndroidスマホをPCにUSB接続し、デバイスをチェック。

スマホのデバイスIDを取得し、デバイスIDを指定してデバッグ起動。

たったこれだけの手順でビルドエラーが発生してしまいました。

以前はビルドできたはずなんですが。。。

エラー内容は、以下。

環境変数「JAVA_HOME」に指定したディレクトリが存在しないってことのようです。

ということでディレクトリを見てみると・・・

ディレクトリ「jre」の直下はディレクトリ「bin」のみ。

そのディレクトリ「bin」の直下も.makerファイルのみと見事にもぬけの殻になっていました。

そういえば、最近、Android StudioのバージョンをFlamingoからIguanaにバージョンアップしたんだったっけ。。。

環境変数を編集する

ということでAndroid Studioの実体を探してみると・・・

環境変数を編集します。

Flutterビルドエラーの解消

ターミナルを立ち上げなおして再度、ビルドしてみます。

ビルドが成功し、スマホ上でサンプルアプリが起動しました。

今回は以上です。

com.google.android.play.coreの警告に対処する

2024年7月15日

開発環境
OS:Windows 11
SDK:Android Studio Iguana | 2023.2.1 Patch 1

概要

Google Play Consoleの受信トレイにcom.google.android.playに関する警告がきており、8月31日までに対処が必要とのことで対応しました。

警告を確認する

Google Play Consoleの受信トレイにcom.google.android.playに関する警告が届きました。

警告の内容を確認すると、

com.google.android.play.core(1.8.0)がAndroid 14(sdk 34)に対応できなくてアプリがクラッシュするため、それを回避するために8月31日までにライブラリの参照を変更しなさい。

とのことのようです。

com.google.android.play.coreって何に使ってたんだろうか?

com.google.android.play.coreの使用状況を確かめる

まずは警告が届いたアプリのソースコードを確認します。

Android Studioで立ち上げ、「com.google.android.play」で検索してみると・・・

検索の結果、In-App Reviewのモジュールがヒットしました。

import com.google.android.play.core.review.ReviewManagerFactory
import com.google.android.play.core.review.ReviewManager

build.gradleのライブラリを確認すると

今回の警告対象である「com.google.android.play:core-kt」が見つかりました。

 dependencies {

    implementation("com.google.android.play:core-ktx:1.8.1")

}

「com.google.android.play:core-kt」を削除してビルドしなおしてみるとReviewManagerのインポートで参照エラーがでました。

「com.google.android.play:core-kt」の代替ライブラリが必要のようです。

ライブラリを差し替える

改めてIn-App Reviewの実装方法を公式サイトで確認するとライブラリが変わっていました。

 dependencies {

    implementation 'com.google.android.play:review-ktx:2.0.1'

}

ということで「com.google.android.play:core-ktx」を「com.google.android.play:review-ktx」に変更し、ビルドしてみると・・・

これで警告の対応が完了です。

お疲れさまでした。

アプリにIn-App Reviewを組み込む

2024年7月15日

開発環境
OS:Windows 11
SDK:Android Studio Iguana | 2023.2.1 Patch 1

概要

AndroidアプリにIn-App Reviewを組み込みます。

In-App Review

In-App Reviewとはアプリの評価やレビューの入力を促すポップアップ機能です。

アプリの操作中に意図したタイミングでポップアップさせることができます。

アプリの評価やレビューはアプリの改善に役に立つため、In-App Reviewの実装はおススメです。

In-App Review実装の流れ

実装していきます。

まずはbuild.gradleにライブラリを組み込みます。

 dependencies {

    implementation 'com.google.android.play:review-ktx:2.0.1'

}

次に必要なモジュールをインポートします。

import com.google.android.play.core.review.ReviewManagerFactory
import com.google.android.play.core.review.ReviewManager

Activityの起動時にレビューマネージャーを生成します。

    private lateinit var reviewmanager : ReviewManager

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        reviewmanager = ReviewManagerFactory.create(this)

    }

あとは適当な場所(画面起動時やイベント終了後など)でポップアップ処理をコールします。

    val request = reviewmanager.requestReviewFlow()
    request.addOnCompleteListener { task ->
        if (task.isSuccessful) {
            val reviewInfo = task.result
            val flow = reviewmanager.launchReviewFlow(this@MapsActivity, reviewInfo)
            flow.addOnCompleteListener { _ ->

            }
        }
    }

In-App Reivewの実装は以上です。

デバッグ方法

デバッグをしたい場合、FakeReviewManagerを使用します。

FakeReviewManagerをインポートします。

import com.google.android.play.core.review.ReviewManagerFactory
import com.google.android.play.core.review.ReviewManager
import com.google.android.play.core.review.testing.FakeReviewManager

FakeReviewManagerを生成します。

    private lateinit var reviewmanager : ReviewManager

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

//        reviewmanager = ReviewManagerFactory.create(this)
        reviewmanager = FakeReviewManager(this)

    }

ポップアップ処理は変更不要です。

FakeReviewManagerのデバッグではポップアップは表示されず、正常系のシーケンスのみ確認できます。

ステップ実行してみるとrequestReviewFlowに成功し、launchReviewFlowがコンプリートします。

これでIn-App Reviewの組み込みは終了です。

お疲れさまでした。

ポリシー違反「サイトの仕様:ナビゲーション」を解決した話

2024年4月10日

開発環境
OS:Windows 11
SDK:Android Studio Flamingo | 2022.2.1

概要

ポリシー違反「サイトの仕様:ナビゲーション」がなかなか解決せず、解決まで1ヶ月半かかった話。

最初の警告メールの指摘はアプリのクラッシュ

2月29日、ポリシー違反「サイトの仕様:ナビゲーション」の警告メールが届きました。

指摘を受けたアプリは「WatchOverMe」。

早速、AdMobコンソールのポリシーセンターを確認します。

指摘されたポリシー違反は、「サイトの仕様:ナビゲーション」。

添付されていた画像を確認するとアプリがクラッシュした画面のスクリーンショットでした。

「サイトの仕様:ナビゲーション」とはどんな違反なのか?

どうやら「ユーザーにとって有益ではないページを表示している」違反のようです。

添付画像から察するとアプリがクラッシュして使えないからポリシー違反ということか?

と、いうことで「正常に動作します。」という旨を記載し、再審査の申請をしました。

次の警告メールの指摘はマップ画面?

再審査の申請から2日後、またしても警告メールが届きました。

やはり違反内容は、「サイトの仕様:ナビゲーション」。

そして、添付されていた画像はマップ画面。

アプリはやっぱりクラッシュしなかったのか。。。

次の指摘は、アプリ起動後に表示されるマップ画面が真っ青だという指摘のようです。

これは現在地座標が取得できなくて(0,0)地点を表示しているためだと思われるため、

「アプリは位置情報の取得を許可して使います」という旨を記載し、再度、再審査を申請。

次の警告メールはアプリ起動時広告

再審査を申請した翌日、警告メールが届きました。

違反内容は変わらず、「サイトの仕様:ナビゲーション」。

そして、添付されていた画像はアプリ起動時広告。

えっ、アプリ起動時広告が指摘されるのか!?

AdMobの標準機能であるアプリ起動時広告が指摘されてしまいました。

そして、なんとGoogle Playからも広告表示に関するポリシー違反の指摘が届きました。

AdMobだけではなく、アプリ自体にポリシー違反が!?

まずはGooglePlayに対し、「広告表示にはAdMobの標準機能を使っている」という旨で異議申し立てを行います。

違反してました

異議申し立てから10日後、異議申し立て却下の通知がきました。

どういうことか?

改めてアプリ起動時広告のガイドラインを確認してみると下記の記載を発見。

思いっきり違反していました。

そこでアプリ起動時広告を削除してアプリを再リリースします。

まだ続くポリシー違反

GooglePlayのポリシー違反は解除されました。

が、AdMobのポリシー違反は相変わらず解除されません。

次はスプラッシュ画面を指摘されました。

スプラッシュ画面の表示を7秒→3秒に変更してアプリを再リリースします。

まだまだ続くポリシー違反

次はホーム画面を指摘されました。。。

位置情報の許可をしないと表示されないんだが。。。

対応する

ニッチもサッチも展開になってしまったので思い切って起動周りの処理を変えます。

プッシュ通知の表示でコールするstartForegroundの引数追加に対応できていませんでした。

最初の指摘はこれだったのか・・・

最終的に以下の改修を実施。

・対象年齢を8歳から13歳以上に引き上げ、ファミリー向けプログラムを回避

・それに伴い、アプリ起動時広告を再度、表示させるよう改修

・イニシャル画面を追加し、位置情報を許可させるよう改修(許可しない場合はアプリ強制終了)

・Android14対応(アプリクラッシュ回避)

そして、修正版アプリをリリース。

リリースが反映されたのを確認し、審査をリクエストします。

ポリシー違反解除

ついにようやくポリシー違反が解除されました。

上記について押させておく必要がありました。

今月のみてみて(2024年4月)

Firebase連携アプリ、みてみてエストーク伊勢125社巡り

このうち、みてみてにフォーカスを当て、Firebaseのアクセス動向やアプリの改善を考察する開発記事です。

Firebase
Realtime Database+Storage構成の投稿アプリ

まずはアプリのユーザー数の変動とともにFirebaseのアクセス動向を確認します。

2024年3月28日~2024年4月27日のユーザー数の変動

(ユーザー数の変動)

1ヶ月の新規獲得ユーザー数

約4ヶ月ぶりのデータ解析。

若干、獲得数、減少数ともに上がっているもののイン、アウトが拮抗しているため、あいかわらずインストール数が伸び悩んでいます。

(インストールの上位国)

フィリピン、インドネシアに頼っている状態も変わっていません。

エジプト、モロッコの動きは新しい。

2024年4月27日直近のFirebaseの変動

(Firebaseの変動)

直近のfirebaseの動き
1ヶ月のfirebase使用量

大きな動きはなし。

安定の無料枠です。

2024年3月28日~2024年4月27日のAdMob

今月はAdMob広告収入:16円、 Firebase使用料:0円となりました。

今月のみてみて

(今月の投稿ピックアップ)

激安中古家具店。
ほんとやすいから。

今後の改善案

(未消化の課題)

・投稿の編集機能追加

・写真を複数投稿可能にする

・手持ち画像も投稿できるようにする

・チャット機能強化

・アプリUIブラッシュアップの継続

・フレンドグループ化と共有機能の追加

・ビジュアルの強調