Assets\Plugins\Android\mainTemplate.gradle 内にて、**DIR_UNITYPROJECT** が展開されないという不具合の暫定修正

次のようなエラーメッセージが出る場合

A problem occurred configuring project ':unityLibrary:GoogleMobileAdsPlugin.androidlib'.
Could not create an instance of type com.android.build.api.variant.impl.LibraryVariantBuilderImpl.
Namespace not specified.
Please specify a namespace in the module's build.gradle file like so
  1. プロジェクト設定
  2. プレイヤー
  3. Android
  4. 公開設定
  5. カスタムGradle設定テンプレートをON
"C:\MyProjectFolder\Assets\Plugins\Android\settingsTemplate.gradle"

以下の maven {} の部分を追加
repositories {
	**ARTIFACTORYREPOSITORY**
	maven {
		url "file:///C:/MyProjectFolder/Assets/GooglePlayGames/com.google.play.games/Editor/m2repository"
	}
	google()
	mavenCentral()
}

2023/06/35 16:35 追記

Google Mobile Ads プラグイン v8.3.0 に更新したら、上記修正と同じコードが入った。よって「カスタムGradle設定テンプレートをON」のみ行えば良さそう。

Sprite Atlas スプライトアトラス

小さい画像を一つにまとめる事で描画負荷を減らす。

https://shibuya24.info/entry/unity-spriteatlas

エディタ設定を変更する際に、Always ではなく Enabled for Builds にする。そうしないと編集中に警告が出続ける
https://forum.unity.com/threads/sprite-atlas-is-constantly-changing-serialized-assets-and-logs-warnings.1011934/

まずは最高品質にして、問題がない範囲で変更

フォルダ指定時は、「パックするオブジェクト」の部分にドロップする

テスクチャタイプは「スプライト(2DとUI)」にする必要があるので、パーティクルのテクスチャは行わない

addressablesとの関係性
https://tsubakit1.hateblo.jp/entry/2019/03/31/233002
グループが一つしかないなら気にしなくて良いようだった

AdMobについて

https://support.google.com/admob/answer/10564477?hl=ja

https://twitter.com/empresarioapps/status/1362312517150777344

https://starhoshi.hatenablog.com/entry/2022/03/23/084007
  1. アプリをリリースする
    • この時、Admobステータスは要審査
  2. Admobの管理画面でリリースされたアプリとAdmobをリンクさせる必要がある
    • Admob側で反映させるのに時間がかかる
    • この時、Admobステータスは審査中
  3. リンクが完了するとAdmob側で審査が走り、審査が完了すると本番で広告が表示される
    • 審査開始が22時、審査完了メールが来たのが翌午前4時だった
    • この時、Admobステータスは準備完了
→試しにやってみたが、「アプリにストア情報を追加する」で検索しても見つからないので公開が先

リリースビルドをする際の設定箇所


ビルドエラー

SDK32以降だと UnityEngine.SystemInfo.deviceName がエラーになる。
PlayFab.Partyで使われているので、手動で変更

権限について

API23以降は、Unity上で確認できるらしい
https://docs.unity3d.com/ja/2021.2/Manual/android-RequestingPermissions.html
今更変えられないので、新しいアプリを作る時に利用

QRコード

https://intellectual-curiosity.tokyo/2021/03/06/unity%E3%81%A7qr%E3%82%B3%E3%83%BC%E3%83%89%E3%82%92%E8%AA%AD%E3%81%BF%E5%8F%96%E3%82%8B%E6%96%B9%E6%B3%95/
https://baba-s.hatenablog.com/entry/2019/11/25/100000
作成
コインイメージを作成したのと同じようなコード
バイナリそのままは入らないのでBase64
読み取り
もちろんカメラ権限がいる

ライセンス Apache License 2.0
https://github.com/micjahn/ZXing.Net/blob/master/COPYING
他のライブラリも含むようなので、それらも確認
https://github.com/micjahn/ZXing.Net/tree/master/3rdparty
https://github.com/zxing/zxing

アセットストアにあるものは有料のみ

動作時警告

2023/03/04 14:45:09.545 16801 17238 Warn ****.**** Accessing hidden method Lcom/android/org/conscrypt/ConscryptEngineSocket;->setUseSessionTickets(Z)V (max-target-q,core-platform-api, reflection, denied)
2023/03/04 14:45:09.545 16801 17238 Warn ****.**** Accessing hidden method Lcom/android/org/conscrypt/OpenSSLSocketImpl;->setUseSessionTickets(Z)V (max-target-q,core-platform-api,reflection, denied)
2023/03/04 14:45:09.545 16801 17238 Warn ****.**** Accessing hidden method Lcom/android/org/conscrypt/AbstractConscryptSocket;->setUseSessionTickets(Z)V (max-target-q, reflection, denied)
2023/03/04 14:45:09.545 16801 17238 Warn ****.**** Accessing hidden method Lcom/android/org/conscrypt/ConscryptEngineSocket;->setHostname(Ljava/lang/String;)V (max-target-q,core-platform-api, reflection, denied)
2023/03/04 14:45:09.545 16801 17238 Warn ****.**** Accessing hidden method Lcom/android/org/conscrypt/OpenSSLSocketImpl;->setHostname(Ljava/lang/String;)V (max-target-q,core-platform-api, reflection, denied)
2023/03/04 14:45:09.545 16801 17238 Warn ****.**** Accessing hidden method Lcom/android/org/conscrypt/AbstractConscryptSocket;->setHostname(Ljava/lang/String;)V (max-target-q, reflection, denied)
2023/03/04 14:45:09.545 16801 17238 Warn ****.**** Accessing hidden method Lcom/android/org/conscrypt/OpenSSLSocketImpl;->setAlpnProtocols([B)V (max-target-q,core-platform-api, reflection, denied)
2023/03/04 14:45:09.545 16801 17238 Warn ****.**** Accessing hidden method Lcom/android/org/conscrypt/AbstractConscryptSocket;->setAlpnProtocols([B)V (max-target-q, reflection, denied)
https://github.com/amplitude/Amplitude-Android/issues/309
com.squareup.okhttp3:okhttp を更新する?
→ 互換性の問題があるようなので保留

FindObjectOfType より FindAnyObjectByType の方が実行効率が良い


#if UNITY_2021_3_18_OR_NEWER
var nextScene = FindAnyObjectByType<SettingsSceneScript>();
#else
var nextScene = FindObjectOfType<SettingsSceneScript>();
#endif

同じく FindObjectsOfType より FindObjectsByType を使う。
#if で囲っているのは、不具合調査でバージョンを戻すことがあったため。

https://unity.com/releases/editor/whats-new/2021.3.18

Google Play Console の自動テストでタップターゲットサイズが小さいという警告

解決できなかった

UniTaskでのタイムアウトの書き方

https://qiita.com/toRisouP/items/69dc07ba8d1c81b0e7ac

デュエル中の通信でフリーズする。
原因が不明なので、そこだけ Observable.Timeout の実装とした。
スレッドに関係しそうではある。

UI.Text でサイズ自動調整をしても大きくならない場合

日本語に対応した折り返しルールになっておらず、空白を開けるなどしないといけないため。

以下を元に日本語を考慮した折り返しをする事で対処できた。
https://tsubakit1.hateblo.jp/entry/2014/12/28/135446

https://github.com/tsubaki/HyphenationJpn_uGUI/blob/master/Assets/HyphenationJpn.cs
HyphenationJpn.GetText でスクリプト上からテキストを設定できる。SetTextではないが正しい。

スクリプト内で水平オーバーフローに変更した後に戻していないが、スクリプトが改行を入れる前提であるため。
しかし一部メッセージで枠外に出てしまう事があった。
本来不要だが処理後に戻すよう修正した。結果文字サイズが小さくなったがやむを得ず

さらに別の文章では、おかしい位置で改行された。文章には自分で改行を入れていたが、入れないようにして回避した

Google Mobile Ads のバナー、インタースティシャル、リワードの各イベントにある OnAdPaid は呼ばれない。

呼ばれるようにするには、 AdMob内で設定する
https://developers.google.com/admob/unity/impression-level-ad-revenue?hl=ja
https://support.google.com/admob/answer/11322405?hl=ja

得た広告と同じ量のポイントをユーザーに与えるために使えそうだが、
どれぐらい通信が発生するかが不安なので適用していない

レビューボタンが効かない


proguardに追加
-keep public class com.google.android.play.core.**{
   public *;
}

https://developer.android.com/guide/playcore/in-app-review?hl=ja#quotas
一回レビューすると一か月変更できない
→エラーが返ってきたらストアページを開く

警告

Mapping new ns http://schemas.android.com/sdk/android/repo/sys-img2/02 to old ns http://schemas.android.com/sdk/android/repo/sys-img2/01
System.Threading.ThreadHelper:ThreadStart ()
という警告が複数出る。

ビルドツールを更新すると直る、という説明があるが、Unityなので出来ない。
Unityが対応するしかなさそうだが、更新したら直ったという記事もあり、一過性の物かも

Unity から Android のプロジェクト出力してビルドする場合にやった事

ビルド時にエラー、または端末にインストールする際にエラーが出る場合

キーストアのパスワード入力を確認する。
一度パスワードありでインストールした場合、無しで入れるにはアンインストールが必要だろうという予想

圧縮(minify)で動かない場合


https://community.playfab.com/questions/50440/android-exception-on-startup-while-using-party-uni.html
-keep class com.microsoft.** {
	*;
}
-keep class com.bumblelion.** {
	*;
}

Google Play Console

https://qiita.com/minuro/items/f1eba5b3a14fd3110085

内部テストでメーリングリストを設定したいが、メーリングリストの設定が出てこない
→アプリの選択ではなく全てのアプリの状態にするとメニュー構成が変わる
→メーリングリストがアプリごとではなく全体の設定であるため

リリースノート

<ja-JP>
ファーストリリース
</ja-JP>
<en-US>
first release
</en-US>

同じバージョンを再度出そうとすると、既にあるというエラーが出る。名前を変えるか、左パネル内 App Bundle エクスプローラから消す。
→バージョンは表示名ではなく「バンドルバージョンコード」を元にする。整数なのでバージョンが1.0.0なら 1 00 00 のように2桁ずつの値などにする

リリースでの警告
難読化解除ファイルの指定
→プレイヤー設定 → Android 公開設定 → ファイル圧縮 → リリース にチェックを入れるとファイルが増えた
→ aabファイルを指定しただけで警告が消えた。自動的に取り込まれたのかaabファイルに含まれるのか

リリースビルドで強制終了

Exception java.lang.ExceptionInInitializerError: at java.lang.Class.newInstance (Class.java) at android.app.AppComponentFactory.instantiateProvider (AppComponentFactory.java:147) at androidx.core.app.CoreComponentFactory.instantiateProvider (CoreComponentFactory.java) at android.app.ActivityThread.installProvider (ActivityThread.java:7411) at android.app.ActivityThread.installContentProviders (ActivityThread.java:6939) at android.app.ActivityThread.handleBindApplication (ActivityThread.java:6710) at android.app.ActivityThread.access$1500 (ActivityThread.java:247) at android.app.ActivityThread$H.handleMessage (ActivityThread.java:2053) at android.os.Handler.dispatchMessage (Handler.java:106) at android.os.Looper.loopOnce (Looper.java:201) at android.os.Looper.loop (Looper.java:288) at android.app.ActivityThread.main (ActivityThread.java:7839) at java.lang.reflect.Method.invoke (Method.java) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:548) at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1003) Caused by java.lang.IllegalStateException: Could not find Library Package Name in BuildConfig. at com.microsoft.playfab.party.PartyLibInitializationProvider.getPackageName (PartyLibInitializationProvider.java) at com.microsoft.playfab.party.PartyLibInitializationProvider.<clinit>(PartyLibInitializationProvider.java)
原因は最適化
C:\MyProjectFolder\Assets\Plugins\Android\proguard-user.txt
に、以下を追加した。
-keep class com.microsoft.playfab.party.BuildConfig {
	public <fields>;
}

Google Play Console でアプリの詳細を App Bundle Explorer で見た時に、対応言語がほとんど含まれる。

https://stackoverflow.com/questions/22655257/how-to-easily-remove-unnecessary-localization-resources-from-added-libraries-in

以下の両方に書く。表示上は launcher だけでいいかもしれないが、mainの方はリソースデータも減るかも
C:\MyProjectFolder\Assets\Plugins\Android\mainTemplate.gradle
C:\MyProjectFolder\Assets\Plugins\Android\launcherTemplate.gradle

以下調査
https://developer.android.com/studio/build/shrink-code?hl=ja#unused-alt-resources
https://developer.android.com/guide/topics/androidgo/optimize-size?hl=ja#string-size
https://qiita.com/tatsuhama/items/668097d909ae1c792759

外部ライブラリにより自動的に追加されたpermissionは、プロジェクトの AndroidManifest.xml で以下のように書くと消せる。

<uses-permission android:name="android.permission.RECORD_AUDIO" tools:node="remove"/>
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" tools:node="remove"/>
<uses-permission android:name="android.permission.BLUETOOTH" tools:node="remove"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" tools:node="remove"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" tools:node="remove"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" tools:node="remove"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" tools:node="remove"/>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" tools:node="remove"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" tools:node="remove"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" tools:node="remove"/>
本質的にはライブラリ側を修正すべきだが調べるのも面倒なので。
BLUETOOTH 等は uses-permission-sdk-23 でも宣言しているが、上記で uses-permission の宣言だけ消せた

https://stackoverflow.com/questions/31616334/how-to-remove-specific-permission-when-build-android-app-with-gradle

Androidビルド後の最終的なAndroidManifest.xmlファイル

https://developer.android.com/studio/debug/apk-analyzer?hl=ja
aab でも開ける
Android Studio
メニュー ビルド → Analize APK
base → manifest → AndroidManifest.xml

BuildConfig.class も同じように探せる。
クラスがアルファベット順ではない事に注意

NearByで通信時に警告が出る

01/02 13:53:52.550 11621 11621 Warn Unity AndroidJNIHelper.GetSignature: using Byte parameters is obsolete, use SByte parameters instead
01/02 13:53:52.550 11621 11621 Warn Unity UnityEngine.Logger:Log(LogType, Object)
01/02 13:53:52.550 11621 11621 Warn Unity UnityEngine._AndroidJNIHelper:GetSignature(Object)
01/02 13:53:52.550 11621 11621 Warn Unity UnityEngine._AndroidJNIHelper:GetSignature(Object)
01/02 13:53:52.550 11621 11621 Warn Unity UnityEngine._AndroidJNIHelper:GetSignature(Object[])
01/02 13:53:52.550 11621 11621 Warn Unity UnityEngine._AndroidJNIHelper:GetMethodID(IntPtr, String, Object[], Boolean)
01/02 13:53:52.550 11621 11621 Warn Unity UnityEngine.AndroidJNIHelper:GetMethodID(IntPtr, String, Object[], Boolean)
01/02 13:53:52.550 11621 11621 Warn Unity UnityEngine.AndroidJavaObject:_Call(String, Object[])
01/02 13:53:52.550 11621 11621 Warn Unity GooglePlayGames.Android.PayloadCallback:onPayloadReceived(String, AndroidJavaObject)
これは既存の不具合で、byte と SByte の変換によるもの。
NearByはライブラリ内なので修正出来ない。
この警告は無視するか、byte を使わずBase64で文字にして渡す事で回避

マネージドストリッピングレベルは 低 または Minimal にする。

中以上だと PlayFabPartySDKの SDK.PartyStartProcessingStateChanges 辺りで NullReferenceException が起きる。

IPointerClickHandler で、Z軸0以上しかクリックを受け付けない事があった。

カメラを真上近くに移動する事で解消したが、原因は不明なまま。

描画最適化

https://developer.android.com/games/sdk/frame-pacing
Unityに統合されている
プレイヤー設定 Android → 画面と解像度 → 最適化されたフレームページング(Optimized Frame Pacing)

関連。有効にすると重くなる
https://qiita.com/ono-honeycomb/items/67d0703e18b743d191cd

→既に有効だった。
60/30/20fpsであることを確認する。

改ざん防止

https://developer.android.com/google/play/integrity/overview
サーバーへの送信データ保護も出来るが、コストもあるのでリアルタイム通信は出来ない。
実装も複雑なので、課金アイテム実装時に検討

ビルドエラー

android のプラグインが変化した後のビルドで、NotSupport とか、ARMv7で使用できないとかメッセージが出た時は、
Library フォルダを消してから再ビルドする。

ビルドエラー

File C:\Users\UserName\.android\repositories.cfg could not be loaded.
というエラーが出た時
https://ushitora.net/archives/2830
同パスを空テキストファイルで作る

最適化

https://docs.unity3d.com/ScriptReference/Unity.Profiling.ProfilerMarker.html
コード上で詳細を調べたい箇所に実装する

最適化

Project Auditor
https://github.com/Unity-Technologies/ProjectAuditor
指摘されたが有効化しなかったもの

https://blog.unity.com/ja/technology/optimize-your-mobile-game-performance-expert-tips-on-graphics-and-assets
Project Auditor 以外の指摘

パフォーマンスチューニング

https://github.com/CyberAgentGameEntertainment/UnityPerformanceTuningBible

    - 176ページ
      - material は複製を返すので、明示的にDestroyが必要
    - 255ページ
      - transform へのアクセス。SetPositionAndRotate を使う
      - Texture2D、Sprite、Material、PlayableGraph などは、明示的にDestroyが必要
    - 266ページ
      - ラムダ式はGC.Allocが発生する
        - 参照するのがstatic変数なら発生しない
        - 参照するのがstatic関数の場合、()=>{func();}の書き方だと、一回だけは作成されるが以降は問題ない。
        - 代替がないので、重いところだけにする
    - 292ページ
      - DOTWeen関連の最適化
        - SetLinkを付ける、Killする、await
        - 実行中に[DGWEEN]の項目を選択しておくと実行されているアニメーションが表示される。
    - 295
      - UniRxの購読はOnDestroyで解除するか、AddTo(this)を付ける

フェードインがちらつく

Project Auditor

https://light11.hatenadiary.com/entry/2022/07/11/194208
- 修正しない
      - Material.material を .sharedMaterial に変える
        - 得たマテリアルを変更しないなら変えていい。変更するなら.materialにする。そうしないとアセット内のマテリアルファイルが編集される

使わない方がいい物

public class ButtonScript : MonoBehaviour
{
	public Button Button;
	public Image Image;
}

ビルドサイズについての公式マニュアル。上記に含まれている。
https://docs.unity3d.com/Manual/ReducingFilesize.html

Android ビルドエラー

java.lang.UnsupportedOperationException: This feature requires ASM7

ビルドボタンのドロップダウンのクリーンビルドを行う
Library フォルダを消してからやり直しても可能

Editor と Android でバナーの大きさが違う


理由はdpiが違うため
Editor  dpi=168
Android1 dpi= 440
Android2 dpi= 480

実際の高さは以下で求まる
static float GetBannerHeight()
{
	float f = Screen.dpi / 160f;
	float dp = Screen.height / f;
	if (720f < dp) return 90f * f;
	if (400f < dp) return 50f * f;
	return 32f * f;
}
環境全てを考慮して場所を開けるのは難しいので、動的に行うようにした。
  1. Canvasの子にGameObjectを作り、アンカーをStretchAllにする
  2. 元々の子全てを、追加したGameObjectの子にする。
  3. シーンのAwakeで、追加したGameObjectのサイズを変える
public void SetBannerSpace(RectTransform canvasInner)
{
	Vector2 offsetMin = Vector2.zero;
	Vector2 offsetMax = Vector2.zero;
	if (UserSettings.Instance.UseAdBannerTop)
	{
		offsetMax = new Vector2(0, -GetBannerHeight());
	}
	else if (UserSettings.Instance.UseAdBannerBottom)
	{
		offsetMin = new Vector2(0, GetBannerHeight());
	}
	canvasInner.offsetMin = offsetMin;
	canvasInner.offsetMax = offsetMax;
}

SingletonMonoBehaviour

派生先で  Awake を実装してはいけない。(ビルドエラーにならない)
SingletonMonoBehaviour.Awake が呼ばれなくなり、シングルトンにならなくなる

エラー

前後に広告関連のログがあったので、広告表示によって起きた可能性
https://forum.unity.com/threads/solved-bizarre-error-unityexception-get_gameobject-can-only-be-called-from-the-main-thread.539830/
→ 問題は、リワードビデオを再生した後、ユニティがメインスレッドに再び切り替わる前にユニティメソッドを呼び出すことができないことだと思います。onApplicationPause が呼び出されるまで待つ必要があります。
Editorでは起きない。設定を変更しないと OnApplicationPause が呼ばれない為

https://stackoverflow.com/questions/42382143/does-unitys-onapplicationpause-work-on-ios-android
Android では OnApplicationFocus に変える必要もありそうだ

https://kan-kikuchi.hatenablog.com/entry/ApplicationBackgroundObserver
bool isBackground = false;
private void OnApplicationFocus(bool pause)
{
	OnChangePause(!pause);
}

private void OnApplicationPause(bool pause)
{
	OnChangePause(pause);
}

void OnChangePause(bool pause)
{
	if (isBackground == pause) return;
	isBackground = pause;

	// 停止から復帰した時
	if (!pause)
	{
		// 処理
	}
}
広告の各イベントで、広告が出たことを記録。pauseが解除されたときに処理する。

Google Mobile Ads を更新する場合


C:\MyProjectFolder\Assets\ExternalDependencyManager
を丸ごと削除

C:\MyProjectFolder\Assets\GoogleMobileAds\Resources
とそのmetaファイルを退避

C:\MyProjectFolder\Assets\GoogleMobileAds
を丸ごと削除

新しいパッケージを取り込む。上記以外のフォルダのファイル上書きは確認する

C:\MyProjectFolder\Assets\GoogleMobileAds\Resources
を戻す

Editor の再起動を何度か繰り返す

Google Play Games Plugin で、ビルドごとに「Warning!! Google Play Games was not configured, Game Services will not work correctly.」が出る件

理由は、以下から構成をしていないため。
Window > Google Play Games > Setup > Android Setup...

構成情報をGoogle開発者コンソールから得て貼ればいいだけだが、それをすると、ゲーム起動ごとに「ようこそ●●さん」が出る事と、
実績機能が必ず有効化されるため。
https://github.com/playgameservices/play-games-plugin-for-unity

どちらも不要であり NearBy で必要なだけなので、コード上から削除した
C:\MyProjectFolder\Assets\GooglePlayGames\com.google.play.games\Editor\GPGSPostBuild.cs

ちなみに上記ページには
NearBy Connection を使用するために、プレーヤーを認証する必要はなく、Google Play デベロッパー コンソールの構成も必要ありません。
という分もあるので問題なさそうだ

ストアページ開くを付ける


Application.OpenURL
https://docs.unity3d.com/ScriptReference/Application.OpenURL.html
https://answers.unity.com/questions/55236/what-do-i-pass-into-applicationopenurl-to-open-up.html

Application.OpenURL($"market://details?id=com.{Application.companyName}.{Application.productName}");