Cordovaを使用して簡単にAndroidアプリを作る方法

コロナで在宅ワークになり残業も減って家にいる時間が増えたため、スマホアプリでも作ってみようかなと思い立ったのがきっかけです。副業とまではいかないですが将来的にはアプリの広告収入で小遣い稼ぎもできたらなぁという淡い夢もあります。
ただJavaで一から実装を開始すると仕事が忙しくなったときに心が折れてしまいそうだと思い、なるべく簡単にスマホアプリが作れないか考えました。そこで以前プログラムの勉強として作った簡単なJavaScriptのミニゲームをAndroidに移植できないかと思い立ちました。

##開発環境構築
ごく普通のWindows10のPCで開発します。
JavaScriptのWebアプリをそのまま流用できそうなCordova(10.0)で開発することにしました。
環境構築方法(概要)は以下。それぞれ他に詳しいサイトがあるはずなので詳細は割愛します。

1. Java8とAndroid SDKをインストールしてPATHとJAVA_HOMEの設定
1. Node.jsとGradleもインストール
1. npmでCordovaをインストール `npm install -g cordova`

##移植するプログラムについて
昔作ったブロック崩しゲームを移植します。
[リンクはこちら](https://hrg123.xxxxxxxx.jp/page/tmp/block.html)

※本当にソースも見られたくないような完成度の低いブロック崩しです。
　Androidのブラウザで動いたので採用しました。

##Cordovaのプロジェクト作成
ただのAndroidアプリなら以下だけで作れるのですが、

```
cordova create myApp xxx.xxx.hrg_soft.block TestApp
cd myApp
cordova platform add android
```
広告収入の淡い夢があったのでAdmobのプラグインを入れておきました。
※ADMOB_APP_IDの部分は[Google AdMob](https://admob.google.com/home/)で登録して取得する必要があります。
必要なければプラグインの追加(cordova plugin add ...)は飛ばしてもアプリは作れます。

```
cordova create myApp xxx.xxx.hrg_soft.block TestApp
cd myApp
cordova plugin add cordova-promise-polyfill
cordova plugin add cordova-admob-sdk
cordova plugin add cordova-plugin-admob-free
cordova plugin add cordova-plugin-admob-free --save --variable ADMOB_APP_ID="ca-app-pub-XXXXX"
cordova platform add android
```

##アプリの移植方法
www/index.htmlがアプリの本体なので、このファイルに移植するWebアプリのコードを貼り付けます。
注意点としてはheadタグはそのままにしてscriptブロックを追加して編集したほうがいいです。
また、bodyの下部にある「cordova.js」「js/index.js」のscriptタグも上書きせず残す必要があります。

基本的にはそれだけです。
もちろんフォントサイズやデザイン等、スマホのサイズに合わせて色々調整は必要です。

##ビルド＆デバッグ
まずはビルドしてみます。

```
cordova build android
```
ビルドに成功したらスマホ(Android端末)をUSBで接続します。
※事前にAndroid側の開発者モードはONにしておいてください。
　設定のデバイス情報のビルド番号かなんかを連打するとONになるはずです。
　機種によって違うみたいです。できなければGoogleで調べましょう。

さらに以下コマンドで実機でデバッグ開始します。
※ビルドも同時に行われるので以降このコマンドだけでOK

```
cordova run android --device
```

##不具合の調査について
PCのブラウザのようにF12開発者ツールは使えないのでJavaScriptの先頭で以下を定義しておくのがおすすめです。
スクリプトエラーになったら画面にエラーメッセージが出るようになります。

```Javascript
window.onerror = function(msg, uri, line) {
    alert(msg + uri + line);
};
```

エラーを特定する最終手段としてconsole.logでログを仕込む方法があります。
以下コマンドで実機上のconsole.logの出力を見ることができます。（Ctrl＋Cで終了）

```
adb logcat chromium:V *:S
```

##AdMobの広告をアプリで表示する
広告収入の淡い夢のためにAdMobの広告をアプリ内で表示します。
BANNER(バナー)とREWARD(リワード)の広告を使用することにしました。
Cordovaのプロジェクト作成時にプラグインはインストール済なので
広告表示用のコードを追加します。

AdMob管理用のJavaScriptライブラリを作成したので
以下のコードをコピペして「hrg.admob.js」という別ファイルに保存してください。

```Javascript:hrg.admob.js
/*
  Google AdMob管理用
*/
var HrgAdmob = {};

(function() {
	// REWARD広告の頻度(N回に1回)
	var REWARD_ONCE_PER_TIME = 5;

	// --------------------------------------------------------------------------------------------
	// 初期化
	// --------------------------------------------------------------------------------------------
	HrgAdmob.init = function(releaseBannerId, releaseRewardId) {
		// BANNER広告の設定
		var isTesting = true;
		var bannerId = 'ca-app-pub-3940256099942544/6300978111';
		if (window.isRelease) {
			isTesting = false;
			bannerId = releaseBannerId;
		}
		admob.banner.config({
			id: bannerId,
			isTesting: isTesting,
			autoShow: true
		});
		admob.banner.prepare();
		document.addEventListener("admob.banner.events.LOAD_FAIL", function() {
			// 読込失敗なら30秒後にリトライ
			setTimeout(function() {
				console.log("BANNER retry");
				admob.banner.prepare();
			}, 30000);
		}, false);
		// admob.banner.show(); // ※autoshowのため不要
		
		// REWARD広告の設定
		var admobRewardCntDown = REWARD_ONCE_PER_TIME;
		isTesting = true;
		bannerId = 'ca-app-pub-3940256099942544/5224354917';
		if (window.isRelease) {
			isTesting = false;
			bannerId = releaseRewardId;
		}
		admob.rewardvideo.config({
			id: bannerId,
			isTesting: isTesting,
			autoShow: false
		});
		admob.rewardvideo.prepare();
		window.admobRewardReady = false;
		document.addEventListener('admob.rewardvideo.events.LOAD', function() {
			console.log("LOAD ok");
			window.admobRewardReady = true;
		});
		document.addEventListener('admob.rewardvideo.events.LOAD_FAIL', function() {
			console.log("LOAD error");
			window.admobRewardReady = false;
		});
		document.addEventListener('admob.rewardvideo.events.REWARD', function() {
			console.log("REWARD ok");
			admobRewardCntDown = REWARD_ONCE_PER_TIME;
			if (window.admobRewardCallback) window.admobRewardCallback();
		});
		document.addEventListener('admob.rewardvideo.events.CLOSE', function() {
			admob.rewardvideo.prepare();
		});
		
		// REWARD広告表示処理
		window.admobReward = function(callback) {
			window.admobRewardCallback = callback;
			admobRewardCntDown--;
			console.log("SHOW start");
			
			if (!window.admobRewardReady) {
				console.log("SHOW cancel");
				if (window.admobRewardCallback) window.admobRewardCallback();
			}
			
			if (admobRewardCntDown <= 0) {
				admob.rewardvideo.show().then(function(){
					// success
				}, function(){
					// error
					console.log("SHOW error");
					if (window.admobRewardCallback) window.admobRewardCallback();
				});
			} else {
				console.log("SHOW break");
				if (window.admobRewardCallback) window.admobRewardCallback();
			}
		};
		
		// AdMob設定完了後の処理があれば実行
		if (window.admobReady) window.admobReady();
	};
	
})();

```

このJavaScriptを呼び出すscriptタグを以下のようにindex.htmlに追加します。
※index.jsから呼び出すのでindex.jsより前に読み込むようにしてください。
※デバッグ時はisReleaseをfalseにしておくとテスト広告で動作します。
　（テストで本当の広告を表示したらダメ）
　Google Play登録時のリリースビルドをするときのみtrueに変更してビルドしましょう。

```
<script>
var isRelease = false;
</script>
<script type="text/javascript" src="js/hrg.admob.js"></script>
```

さらにindex.jsのonDeviceReadyに以下のコードを追記します。
※BANNER(バナー)とREWARD(リワード)の広告は事前に[Google AdMob](https://admob.google.com/home/)で作成してIDを取得しておきましょう。

```Javascript
function onDeviceReady() {
    // Cordova is now initialized. Have fun!

    //console.log('Running cordova-' + cordova.platformId + '@' + cordova.version);
    //document.getElementById('deviceready').classList.add('ready');

    // 追記するコードここから
    HrgAdmob.init(
        // BANNER
        "ca-app-pub-XXXXXXXXXXXXXXXX/XXXXXXXXXX",
        // REWARD
        "ca-app-pub-XXXXXXXXXXXXXXXX/XXXXXXXXXX");
    // 追記するコードここまで
}
```

これでバナー広告は起動時に表示されるので、あとはリワード広告を追加します。

ゲーム開始処理を以下のように修正するとゲーム開始前にリワード広告が出るようになります。
※広告が出すぎても使ってもらえないと思い、ライブラリ内部で5回に1回表示するようにしています。

```Javascript
	// startGame();
	// ↓↓↓
	admobReward(function(){
		startGame();
	});
```

さらに広告が表示される「ゲーム開始」ボタンについてはAdMobの初期化前に押されると困るので、最初は非表示(visibility:hidden)にしておきます。
以下のようなfunctionを定義してAdMobの初期化後に表示するようにします。

```Javascript
// AddMob関連の初期化
function admobReady() {
	el("startBtn").style.visibility = "visible";
}
```

##Google Playでのアプリ公開について
Google Playでのアプリ公開方法については本家でもその他のサイトでも
説明しているサイトはたくさんあるので割愛します。
アプリ登録時の注意点としてはリリースビルドした後、jarsignerとzipalignというコマンドで署名と最適化の必要があります。
※2021年3月時点の方法です。2021年の夏くらいから新規アプリは最適化の代わりにAABというビルドが必須になるようです。
アプリを登録した後は気長に審査が通るのを待つしかないです。

##完成したアプリ
「[HRGシンプルブロック崩し](https://play.google.com/store/apps/details?id=jp.co.hrg_soft.block)」としてGoogle Playでアプリを公開することができました。
アプリとしての完成度はまだあまり高くないですがCordovaでもこんなことができるんだよっていう参考にはなるかと思います。
今回そのままだとあまりにシンプル過ぎるので効果音/BGMやランキング機能を追加してみました。
そこら辺のCordovaでの実装方法についても機会があれば投稿したいと思っています。