20210430のAndroidに関する記事は3件です。

Android 12 DP 3で追加されたSplash screenの挙動を見てみる

Android 12 で新たに Splash screen の API が登場したので、どのような挙動で何ができそうか書いていきます。 ※ Android 12 はこの記事を書いている 2021/4/30 時点で DP 3 なので、おそらく API 自体にも変更が入るはずです。今すぐに対応が必要というわけではないのですが、今後の動向は気にしておきましょう。 Android 12 では強制的にスプラッシュが表示される DP 3 時点では targetSDK のバージョン関係なく Android 12 でアプリを起動すると Splash screen が表示されるようになっています そのため既存のアプリを Android 12 DP3 で起動させると Splash screen が表示されます DP 3 時点ではこれを無効にする記載がありません (見落としているかもなので、見つけた方がいればコメントお願いします ) 既存アプリでスプラッシュの画面を独自に実装している場合は 2 回続けてスプラッシュの画面が表示されることになります Splash Screen の API でアプリの初期化処理は可能 スプラッシュが出ている間に初期化処理を行い、初期化処理が終わればスプラッシュを閉じるという処理は以下のようなコードで可能です。 override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.main_activity) // Set up an OnPreDrawListener to the root view. val content: View = findViewById(android.R.id.content) content.viewTreeObserver.addOnPreDrawListener( object : ViewTreeObserver.OnPreDrawListener { override fun onPreDraw(): Boolean { // Check if the initial data is ready. return if (viewModel.isReady) { // The content is ready; start drawing. content.viewTreeObserver.removeOnPreDrawListener(this) true } else { // The content is not ready; suspend. false } } } ) } ただこの処理は Android 12 だけで使うことになるので、Android 12 までのバージョンでは別途スプラッシュ用の画面を用意することになります (Jetpack でなんとかならないだろうか…) アイコンと背景色と Splash screen を閉じるときのアニメーションをカスタマイズ可能 Splash screen のデフォルトの背景色は android:windowBackground が適用される android:windowBackground を変更するとアプリの他画面の背景色にも影響があるので、Splash screen だけ背景色を変えたい時のために android:windowSplashScreenBackground の属性が追加されている android:windowSplashScreenAnimatedIcon でアニメーション付きのアイコンを設定できたり、(デザインガイドラインでは推奨されていないが)android:windowSplashScreenBrandingImage でスプラッシュの下にも画像を表示させることができる Splash screen を閉じる時のアニメーションもコードでカスタマイズできる https://developer.android.com/about/versions/12/features/splash-screen#customize-animation ドキュメント https://android-developers.googleblog.com/2021/04/android-12-developer-preview-3.html https://developer.android.com/about/versions/12/features/splash-screen
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

スマホゲームのプッシュ案

今回の主な話題:スマホゲームのプッシュ案、Unity UI特殊効果についてフロントエンドエンジニアとのコミュニケーション問題、ローエンドマシンでマルチスレッドレンダリングを有効にするかどうか、モバイル端末でRenderTextureメモリが大きくなる、自分で実現するTextストロークがDrawCall増加問題を引き起こす。 Android Q1:「クラッシュ・オブ・クラン」のようなゲームに対して、あなたの主要都市が他の誰かに襲われた場合、誰かがあなたを襲っているというプッシュ通知がスマアホに届きます。問題は、ゲームが強制終了されたということですが、なぜこの通知を受け取ることができるのですか?これはリアルタイムの通知であり、時間指定の通知ではありません。どうやってこれを実現できますか? ① こんな正確なプッシュ時間はクライアントが計算できないため、サーバーに頼ります。以前AndroidでAuroraPushを使用したことがありますが、あまり悪くないです。iOSにはサーバープッシュソリューションが提供されています。大体の原理は、私たちのサーバーからお知らせをAppleのサーバーまたはAuroraPushのサーバーに送信し、次にプレーヤー達に送信します。 ② Tencentの伝書鳩も使えます。プッシュは一般的にサーバープッシュがとローカルプッシュに分かれます。このような要件について、ローカルプッシュを採用する方がよりいいで、iOSシステムにはこのようなプッシュサービスがサポートしていますが、Androidには対応するAPIはありません。サーバーを自分で起動し、システムプロセスにバインドして、プロセスが強制終了されないようにする必要があります。しかし、今の各大手メーカーが独自のシステムを開発しており、このステップを達成することは困難です。一部のメーカーのアプリはシステムのホワイトリストに含まれており、バックグラウンドプロセスが強制終了されることはありません。 アセット管理 Q2: 私たちのゲームには、Animationとパーティクルを使って作成するUI特殊効果がたくさんありますが、これについてまだ1つの問題があります。パフォーマンス問題に注意しにくいで、私が一部の属性を変更すると、再びフレームを処理する必要があり、コミュニケーションコストが高いので、何か良い解決策ありませんか? ① 私のやり方は、アーティストが作成した特殊効果Prefabを直接使用することではなく、1つのツールを提供して新しいPrefabを生成します。 これの利点は、エクスポート時にテクスチャの数、パーティクルの数、アニメーションなどをチェックすることができます。事前にUIパーティクル特殊効果の標準を設定でき、エクスポート時にアセットが標準に合わないまた問題がある場合、エラーと表示してPrefabのエクスポートを却下します。これで、アーティストがSVNプログラムをアップロードできないため、問題のあるまたは効率に問題がある特殊効果に更新されません。 実際、このアイデアは特殊効果だけでなく、UIインターフェイス、キャラクター、シーンなどにも使用できます。Prefabが自動的に生成する時には、いくつかの追加ロジックを同時に生成することもできます。 ② 私のやり方は前のひとの方法と似ています。インポーターを使用して標準化されたアセットを強制することはできません。毎日0時にパッカーが起動するとアセットスキャンアクションを開始し、標準に合わない内容をスキャンして、レポートを生成します。 ③ 自分がTimelineエディター(Unity、Unrealの公式も利用可能)を作成します。エディターでアーティストに関する操作範囲(例えば、単一パーティクル特殊効果を再生する時の数またはモデル、アニメーション、マテリアルなどのアセットの使用範囲。)を設定します。最終的に特殊効果データを生成する時に、アセットとデータの検査及びアセット整理を行い、アセットの冗長性や不規則性を回避します。 利点: 1.アセットとデータが分離されており、アセット間に結合がないため、すばやく変更および調整できます。 2.データは編集モードで共有でき、衝突にすばやく対処できる共同制作にも便利です。 3.テンプレート化された特殊効果により、開発効率が大幅に向上します。 2つの点に注意する必要があります。 1、FBXアセットの冗長性。Unityは、関連付けられたモデルとアニメーションリソースをFBXパスとしてデフォルト設定します。私が採用した方法は、使用されたアセットをFBXから抽出してAssetファイルに作成することです。(Unity自体もこれを行いますが、事前に行って手伝ってあげますだけです。パッケージスピードも向上ですます。)Timelineにあるアセット依頼を新生成するアセットに変換します。 2.エディター自体は、再生機能(特にパーティクル)を出来る限りに実現する必要があります。 RenderTexture Q3: RenderTexture AAを1に、depthを0に設定しました。PC端末のメモリサイズは正しいけど、モバイル端末では約3倍になりました。これはなぜですが? ① 3倍までは間違ったはずです。UWA GOT Onlineサービスを介して各RenderTextureの具体的なパラメーターをチェックし、解像度、形式、およびその他のパラメーターを確認することをお勧めします。 ② メモリの変化は解像度が原因である可能性があります。RenderTextureのサイズは解像度に従うので、PCでRenderTextureの解像度とスマホでRenderTextureの解像度を比較してみることができます。 UI Q4: 画像のように、私たちがプロジェクトのために自分でテキストストロークを実現しました。私がUnityバッチ処理の理解により、DrawCallは2つあるはずですが、実際には4つあります。TextShaderOutlineのModifyMesh関数にあるSetUIVertex方法がバッチ処理の失敗を引き起こしたと推測されます。そうだった場合、原理はなぜですか?何か良い解決策ありませんか? 機能URL:TextureShaderOutline.rar 私のUnityバージュンは少し古いので、このプロジェクトを開くと乱雑になります。表示に問題があるように感じます。赤い字を左右にドラッグすると、色が変わります。これは非常に奇妙です。 ブログにある元方案を使って、このような重ね合わせ状況ではバッチ処理ができます。(条件はShaderが同じであり、カラーが違って、2つのShaderになります。) そして、Unity 2018に対して、方案を調整しました。 Unity 2018は、UV2とUV3を伝えられ、そしてtangent.zw normal.zもなんとか使用できます。ですから、UV1とUV2を使って、最も原始的なUV範囲を保存し、UV3とtangent.zwを使ってoutlinecolorを伝え、normal.zでoutlineborderを伝えます。これでカラーと幅変化はShaderを変更する必要がなく、バッチ処理できます。(z軸方向はズームできず、UIとそれが配置されているキャンバスはフラットである必要があることに注意してください。そうしないと、tangent.zとnormal.zの送信が不正確になります。) 問題主からの補充: ModifyMesh方法にあるpositionを削除してアップロードすると、バッチ処理出来るになりました。 UWA Technologyは、モバイル/VRなど様々なゲーム開発者向け、パフォーマンス分析と最適化ソリューション及びコンサルティングサービスを提供している会社でございます。 UWA公式サイト:https://jp.uwa4d.com UWA公式ブログ:https://blog.jp.uwa4d.com
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Android]DI(依存性注入)ってなんか危ないことなのかなって思ったけど、怖いもの見たさで使ってみる(ゆるく解説)

DIとは? どうもReoです。 DI(依存性注入)とは、危ないお薬を注射で、、、 DI(依存性注入)とは、あるオブジェクトから他のオブジェクトを使う関係を注入することを意味します。 そして、そちらを自動でやってくれるのがHiltというライブラリです。 リファレンスを一旦読んでみましょう。 https://developer.android.com/training/dependency-injection/hilt-android?hl=ja 元々DaggerというDIライブラリがあるみたいですね。 筆者は初めてDIを学んでいるので、Daggerのことは良く分かりません。 取り敢えず、DaggerはHiltの前身みたいなので、Hilt使えばいいかなと思いました。 リファレンスには、このように書いてあります。 Hilt は Android 用の依存関係インジェクション ライブラリです。これを使うことで、プロジェクトで依存関係の注入(DI)を手動で行うためのボイラープレートが減ります。 まずは、依存関係とは?についてコードで見てみましょう。 class Sonic { var km: Double = 0.0 val action = Action() km = action.run(km) } class Action { fun run(distance: Double): Double = distance + 10.0 } 自分自身、DIというと凄く難しい概念を想像していました。 しかし、以下のように考えると割と簡単でし、ある程度Androidの学習をされている方でしたら一度は見たことある書き方だと思います。 最初に DIとはあるオブジェクトから他のオブジェクトを使う関係を注入することを意味します と表現しましたが、上記の例で例えるとSonicというオブジェクトからActionというオブジェクトを使う依存関係を注入している、つまりDIと換言することが出来ます。 ちなみに、こちらの記事を中心に読みながらこの記事を書いています。 https://qiita.com/MoriokaReimen/items/750644062b3f5bec18ed#gradle%E3%81%AE%E8%A8%AD%E5%AE%9A ちなみに、この記事内にあるように、HiltにはField InjectionとConstructor Injectionの二つのDI手法をサポートしています。 先程、書いたソニックのコードがField Injection そして、以下がConstructor Injection class Sonic(private var action: Action) { var km: Double = 0.0 km = action.run(km) } class Action() { fun run(distance: Double): Double = distance + 10.0 } より感覚的に掴みたい方は、こちらの記事も見てみると良きかなと思います。 https://qiita.com/keidroid/items/7f0112502a08e2107c67 そんで? この時点で、DIができているので、「なるほど。これが、DIか・・・。」と記事が終了してしまいそうになります。 しかし、これを自動化できるライブラリがあるので、そちらを解説して終了したいと思います。 使い方 導入 では、いつものようにプラグインをしていきましょう! https://developer.android.com/training/dependency-injection/hilt-android?hl=ja#setup ところで、リファレンスでは依存関係を追加すると表現しています。 あ、なるほど。 依存関係を追加するということは、それを使える関係を注入するということで、これもある意味ではDI(依存性注入)なのかぁー!と自分の中でひらめきがありつつ、Gradleの設定をしていきやす。 まずは、build.gradle(project)を開き buildscript { ... dependencies { ... classpath 'com.google.dagger:hilt-android-gradle-plugin:2.32-alpha' } } 続いて、build.gradle(:app) ... apply plugin: 'kotlin-kapt' apply plugin: 'dagger.hilt.android.plugin' android { ... } dependencies { implementation "com.google.dagger:hilt-android:2.32-alpha" kapt "com.google.dagger:hilt-android-compiler:2.32-alpha" } あとあと、HiltはJava8の機能を使うみたいです。 筆者は、デフォルトで設定されていたので追加する必要なかったのですが、そうでない人のために。 build.gradle(project)にて、以下を追加。 android { ... compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } } Applicationクラスを作成 まずは、Applicationクラスを自作します。 そして、Hiltアノーテーションを付けます。 @HiltAndroidApp class Myapplication : Application() { ... } これにより、このアプリはHiltで動きます!というのを教えました。 Manifestを変更 アプリケーションクラスが変更されたので、Manifestを開きapplicationタグ内の名前を変更 <application android:name=".MyApplication" // ここを追加 android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/Theme.DIPractice"> <activity android:name=".MainActivity"> // こっちじゃないよ!(筆者間違えた…) <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> この設定によりアプリが起動するときに、一番最初にMyApplicationファイルが開かれます。 ここで、Hiltを提供しており、アプリケーションレベルでHiltにアクセスすることが可能になります。 リファレンスでは、 Hilt のコード生成をトリガーします と表現していますね。(かっこいいけど、分かりにくっ…笑) これにて、Hiltが使う準備完了です。 注入先を定義 方法はかなりシンプルです。 @AndroidEntryPoint class MainActivity : AppCompatActivity() { ... } 上記のアノーテーションを追加します。 これによって、MainActivityはHiltを使います!というのをHiltに対して教えることになります。 Hiltモジュールを作成 MainActivityにActionクラスを依存性注入しやす。 その為、以下のようにHiltモジュールを作る必要があります。 @InstallIn(SingletonComponent::class) @Module object ActionModule { @Provides fun provideAction(): Action = Action() } アノテーションの意味については、こちらの記事で解説しておりますので参照ください。 https://qiita.com/MoriokaReimen/items/750644062b3f5bec18ed#%E3%82%A2%E3%82%AF%E3%83%86%E3%82%A3%E3%83%93%E3%83%86%E3%82%A3%E3%81%AB%E5%85%B7%E8%B1%A1%E3%82%AF%E3%83%A9%E3%82%B9%E3%82%92di%E3%81%99%E3%82%8B @Moduleは、このクラスがHiltであることの証明 @Providesは、インスタンス生成時のメソッド @InstallInは、インスタンスの寿命指定 SingleComponentは、アプリと寿命が一致(applicationContext的な!) ってな感じですね!! では、本題の依存性注入!!! 先程@AndroidEntryPointというアノーテーションを付けたMainActivityにて、 @AndroidEntryPoint class MainActivity : AppCompatActivity() { @Injection lateinit var action: Action ... } @Injectionが注入という意味なので、actionをDIしていることがお分かりかと思います。 ちなみに、裏では先ほど@Providesにて定義した関数、provideAction()が呼び出されて、Actionインスタンス生成処理が行われています。 もう、@MoriokaReimenさんの輪唱みたいになっちゃいますが(笑)、この場合だとDIするたびにインスタンスを生成されてしまうので、それは冗長的だ!という場合には、以下のアノテーションを追加すると最初のインスタンス生成後は、同じインスタンスを使い回すことができます! @InstallIn(SingletonComponent::class) @Module object ActionModule { @Provides @Singleton fun provideAction(): Action = Action() } 確認 @AndroidEntryPoint class MainActivity : AppCompatActivity() { @Injection lateinit var action: Action var km: Double = 0.0 ... km = action.run(km) Log.d("degug-app","$Km") } これで、MainActivityクラスにActionクラスをDIできましたね。 終わりに インターン先でHiltを用いるかもしれないとのことから、急遽Hiltを使ってみました。 まだ、Hiltの一部の機能しか使えてはいないものの、何とか記事に出来たのは良かったです。 参考記事 ・https://developer.android.com/training/dependency-injection/hilt-android?hl=ja ・https://qiita.com/MoriokaReimen/items/750644062b3f5bec18ed#gradle%E3%81%AE%E8%A8%AD%E5%AE%9A ・https://qiita.com/takahirom/items/46053e031041405e2a9e#dagger-hilt%E3%82%92videoplayer%E3%81%AE%E4%BE%8B%E3%81%A7%E4%BD%BF%E3%81%A3%E3%81%A6%E3%81%BF%E3%82%88%E3%81%86
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む