ホームページ > ウェブフロントエンド > CSSチュートリアル > Google Playでnuxtを使用してワードゲームアプリを構築したことを学んだこと

Google Playでnuxtを使用してワードゲームアプリを構築したことを学んだこと

Christopher Nolan
リリース: 2025-03-24 10:00:17
オリジナル
812 人が閲覧しました

Google Playでnuxtを使用してワードゲームアプリを構築したことを学んだこと

私は最初のCSSを作成した瞬間にコーディングに恋をしました:Hover Effect。数年後、ウェブ上のインタラクティブ性への最初の噛みつきは、私を新しい目標に導きました。ゲームを作ることです。

目次

  • ゲームは何ですか(そしてその名前は何ですか)?
  • nuxtの選択
  • ネイティブアプリの感触をWebで達成します
  • 振動と音
    • 音に余分な
  • ゲームプレイ、歴史、賞
  • このアプローチの長所と短所
    • 長所
    • 短所
  • ロジスティクス:Webアプリをネイティブアプリに変える
  • TWAアプリとは何ですか?
    • TWA要件
    • TWAアプリを構築することの利点と欠点
  • AndroidアプリAPKを生成する方法
  • 署名キー
  • アプリのリストについて知っておくべきこと
  • 収益化、ロック解除、Googleの回避
  • Google Playのアプリエクスペリエンスをカスタマイズします
  • アカウントの会計
  • まとめます

一緒に遊ぶ初期の瞬間:ホバーは特別なものでも、役に立たなかった。青い正方形のレスポンシブなグリッドを作成したことを覚えています(フロートで作られている場合、タイムラインのアイデアが得られる場合)。私は何時間も箱の上に覆い隠しているように感じたものを費やし、窓をサイズに変更してサイズとアライメントを変更し、それからもう一度やり直しました。それは純粋な魔法のように感じました。

私がウェブ上に構築したものは、当然、長年にわたって

要素のグリッドよりも複雑になりましたが、本当にインタラクティブなものを生き返らせるスリルはいつも私に留まっています。そして、JavaScriptについてますます学んだように、私は特にゲームを作るのが大好きでした。

時にはそれは単なるCodepenデモでした。時には、VercelまたはNetlifyに展開された小さなサイドプロジェクトでした。カラーフラッド、ハングマン、またはブラウザで4つを接続するなどのゲームを再現するという課題が大好きでした。

しばらくして、ゴールが大きくなりました。実際のゲームを作ったらどうでしょうか Webアプリだけではありません。本当のライブ、誠実さ、アプリからダウンロードからのダウンロードゲーム。昨年8月、私はこれまでで最も野心的なプロジェクトに取り組み始めました。4か月後、私はそれを世界にリリースしました(読んで:それをいじるのにうんざりしました):Quinaと呼ぶワードゲームアプリ。

ゲームは何ですか(そしてその名前は何ですか)?

Quinaを説明する最も簡単な方法は、それは首謀者ですが、5文字の言葉があります。実際、首謀者は実際には古典的なペンアンドペーパーゲームのバージョンです。 Quinaは、同じオリジナルゲームの単なる別のバリ​​エーションです。

Quinaのオブジェクトは、秘密の5文字の単語を推測することです。推測のたびに、コードワードに推測がどれほど近づいているかを示す手がかりが得られます。その手がかりを使用して次の推測を改善しますが、合計では10個しかありません。尽きるとあなたは負けます。

「Quina」という名前は、ラテン語で「一度に5つずつ」を意味するために生じました(または、とにかくGoogleは私に言った)。従来のゲームは通常、4文字の単語、または時には4桁(または首謀者の場合は4色)で再生されます。 Quinaは繰り返し文字なしで5文字の単語を使用しているため、ゲームには独自のルールで再生される名前があることにふさわしいと感じました。 (元のラテン語がどのように発音されたのかわかりませんが、「Quinn-Ah」と言います。

私は約4か月間、アプリを構築するために夜と週末を過ごしました。この記事に、ゲームの背後にある技術、関係する決定、そしてこれがあなたが自分自身を旅することに興味がある道である場合に学んだ教訓について話したいと思います。

nuxtの選択

私はVueのファンであり、このプロジェクトをそのエコシステムの知識を拡大する方法として使用したかったのです。私は別のフレームワークを使用することを検討しました(私もSvelteとReactでプロジェクトを構築しました)が、Nuxtは親しみやすさ、使いやすさ、成熟のスイートスポットに当たったと感じました。 (ちなみに、あなたが知らなかったか、推測していなかった場合:Nuxtはnext.jsに相当するVUEと公正に説明できます。)

私は以前にNuxtと深く深くなっていませんでした。非常に小さなアプリをいくつか。しかし、私はNuxtが静的アプリにコンパイルできることを知っていました。これはまさに私が望んでいたものです。また、 NuxtがVueコンポーネントをA /Pagesフォルダーにドロップするのと同じくらい簡単にルーティングを処理できることも知っていましたが、これは非常に魅力的でした。

さらに、Vuex(Vueの公式の国家管理者)はそれ自体がそれだけでは複雑ではありませんが、Nuxtがそれをさらに簡単にするためにほんの少しの砂糖を追加する方法に感謝しました。 (Nuxtは、使用する前にコンポーネントを明示的にインポートする必要がないなど、さまざまな方法で物事を簡単にします。マークアップに配置することができ、Nuxtは必要に応じてそれを把握し、自動輸入します。)

最後に、私は事前にプログレッシブWebアプリ(PWA)を構築していることを知っていたので、既に関連するすべての機能(オフライン機能のサービスワーカーなど)を構築するのに役立つNuxt PWAモジュールが既に存在しているという事実は、すでに大きな引き分けでした。実際、目に見えないハードルに利用可能なNUXTモジュールの印象的な配列があります。それにより、ヌックスは最も簡単で、最も明白な選択肢になり、私は決して後悔しなかったものです。

最終的に、私が行ったときに、より多くのモジュールを使用することになりました。これには、Markdownでページコンテンツを書くことができます。 「FAQ」ページと「再生方法」ページにもその機能を使用しました(Markdownでの執筆は、ハードコーディングHTMLページよりはるかに優れているため)。

ネイティブアプリの感触をWebで達成します

Quinaは最終的にGoogle Playストアに家を見つけるでしょうが、それがどのように、どこで再生されたかに関係なく、私はそれがGet-Goの本格的なアプリのように感じたいと思っていました。

開始するために、それはオプションのダークモードと、多くのネイティブアプリが持っているように最適な使いやすさのためにモーションを減らすための設定を意味します(そして、アニメーションのあるものと同じように、モーションが減少する場合)。

ボンネットの下では、両方の設定は最終的にアプリのVuexデータストアのブール値です。 Trueの場合、設定はアプリのデフォルトレイアウトで特定のクラスをレンダリングします。 Nuxtレイアウトは、すべてのコンテンツを「ラップ」し、アプリのすべて(または多くの)ページ(一般的に共有ヘッダーやフッターなどに使用されるが、グローバル設定にも役立つ)でレンダリングするVUEテンプレートです。

 

  <div>
    <nuxt></nuxt>
  </div>
テンプレート>


'vuex'から{mapgetters}をインポート

デフォルトのエクスポート{
  計算:{
    ... MapGetters(['DarkMode'、 'Recucemotion'])、
  }、
  //他のレイアウトコンポーネントコードはこちら
}
ログイン後にコピー

設定といえば、Webアプリはいくつかの異なるページ(メニュー、設定、概要、再生など)に分割されていますが、共有されたグローバルVUEXデータストアは、アプリの領域間で物事を同期させ、シームレスに感じるのに役立ちます(ユーザーは1ページで設定を調整し、別のページでゲームに適用することを確認します)。

アプリ内のすべての設定は、ユーザーがページ間でナビゲートするときに設定を追跡することに加えて、セッション間で値を保存とロードすることを可能にするLocalStorageとVuexストアの両方に同期されます。

ナビゲーションについて言えば、ページ間を移動することは、フルページのトランジションを追加することで、キーナをネイティブアプリのように感じる機会がたくさんあると感じた別の領域です。

Vueの移行は一般的にかなり簡単です。「To」および「From」の遷移状態のCSSクラスと名付けられたCSSクラスを書くだけですが、Nuxtはさらに一歩進んで、ページのVueファイルに1行しかないページ遷移を設定できます。

 

デフォルトのエクスポート{
  トランジション:「ページスライド」
  // ...残りのコンポーネントプロパティ
}
ログイン後にコピー

その移行プロパティは強力です。 Nuxtは、このページに移動するたびにページスライドトランジションをこのページに適用する必要があります。そこから、私たちがする必要があるのは、アニメーションを処理するクラスを定義することだけです。これが私のページスライドSCSです:

 / * assets/css/_animations.scss */

.page-slide {
  &-enter-active {
    遷移:0.35キュービックベジエすべて(0、0.25、0、0.75);
  }

  &-Leave-active {
    遷移:すべての0.35キュービックベジエ(0.75、0、1、0.75);
  }

  &-入力、
  &-Leave-to {
    不透明:0;
    変換:翻訳(1REM);

    .reduce-motion&{
      変換:なし!重要。
    }
  }

  &-Leave-to {
    変換:translatey(-1rem);
  }
}
ログイン後にコピー

.reduce-motionクラスに注意してください。それが私たちがすぐ上のレイアウトファイルで話したことです。ユーザーが、変換プロパティを無効にすることで、モーションの減少(メディアクエリまたは手動設定を介して)を好むことを示したときに視覚的な動きを防ぎます(これは、分裂的!重要なフラグの使用を保証するように思われました)。ただし、これは実際には動きではないため、不透明度はまだ消えていくことが許可されています。

トランジションと処理に関するサイドノート404:もちろん、トランジションとルーティングは、JavaScriptによってフードの下で処理されます(正確にはVueルーター)が、スクリプトがアイドルページで実行されるのを停止するイライラする問題に遭遇しました(たとえば、ユーザーがアプリまたはタブをしばらく開いた場合)。これらのアイドルページに戻ってリンクをクリックすると、Vueルーターが実行を停止していたため、リンクは相対的で404として扱われます。

例: /FAQページはアイドル状態になります。ユーザーが戻ってきて、リンクをクリックして /optionsページにアクセスします。アプリは /FAQ /オプションに移動しようとしますが、もちろん存在しません。

これに対する私の解決策は、カスタムエラーページ(これはすべてのエラーを自動的に処理するNUXTページです)で、着信パスで検証を実行し、パスの最後にリダイレクトします。

 //レイアウト/error.vue
mounted(){
  const lastpage = '/' this。$ route.fullpath.split( '/')。pop()
  //リダイレクトループを作成しないでください
  if(lastpage!== this。$ route.fullpath){
    これ。$ router.push({
      パス:ラストページ、
    })
  }
}
ログイン後にコピー

a)ネストされたルートがないため、これは私のユースケースで機能しました。 b)最後に、パスが有効でない場合、404にヒットします

振動と音

トランジションは素晴らしいですが、Quinaは、振動と音の両方なしで、特にスマートフォンでネイティブアプリのように感じないことも知っていました。

ナビゲーターAPIのおかげで、最近のブラウザでは振動が比較的簡単に達成できます。ほとんどの最新のブラウザを使用すると、window.navigator.vibrate()を呼び出してユーザーに少し話題になります。または、非常に短い期間を使用して、スマートフォンキーボードでキーをタップするときのように、ほんの少しの触覚フィードバックを使用できます。

明らかに、いくつかの理由で、振動を控えめに使用したいと考えています。第一に、多すぎると簡単に悪いユーザーエクスペリエンスになる可能性があるためです。第二に、すべてのデバイス/ブラウザがそれをサポートしているわけではないため、Vibrate()関数を呼び出そうとする方法と場所に非常に注意する必要があるため、現在実行中のスクリプトをシャットダウンするエラーを引き起こさないようにします。

個人的には、私の解決策は、ユーザーが振動を許可していることを確認するためにVuex Getterを設定することでした(設定ページから無効になる可能性があります)。現在のコンテキストがサーバーではなくクライアントであること。そして最後に、機能が現在のブラウザに存在すること。 (ES2020オプションチェーンは、その最後の部分でもここでも機能していたでしょう。)

 // store/getters.js
振動(状態){
  もし (
    process.client &&
    state.options.vibration &&
    typeof window.navigator.vibrate!== '未定義'
  ){
    trueを返します
  }
  falseを返します
}、
ログイン後にコピー

サイドノート: Process.Clientのチェックは、NUXTで重要です - およびノー​​ドで実行される可能性のあるコードを使用して他の多くのフレームワーク - ウィンドウは常に存在するとは限りません。コンポーネントはビルド時にノードで検証されるため、これは静的モードでNUXTを使用していても真です。 Process.Client(およびその反対のProcess.Server)は、実行時にコードの現在の環境を検証するだけで、ブラウザのみのコードを分離するのに最適なNuxt nuxt nuxt nuxt nuxt nuxt nuxtです。

サウンドは、アプリのユーザーエクスペリエンスのもう1つの重要な部分です。私自身の効果を作るのではなく(間違いなくプロジェクトにさらに数十時間を追加したでしょう)、私はその領域で彼らが何をしているのかをよりよく知っていて、オンラインで無料のゲームのサウンドを提供した数人のアーティストのサンプルを混合しました。 (詳細については、アプリのFAQを参照してください。)

ユーザーは、好みのボリュームを設定したり、完全にサウンドをシャットダウンしたりできます。これと振動は、ユーザーのブラウザのLocalStorageにも設定されており、Vuexストアに同期されます。このアプローチにより、ブラウザに保存された「永続的な」設定を設定できますが、参照するたびにブラウザから取得する必要はありません。 (たとえば、音が再生されるたびに現在のボリュームレベルを確認し、経験を殺すのに十分な場合に毎回ローカルストレージコールを待つことの待ち時間を確認してください。)

音に余分な

何らかの理由で、サファリは音に関しては非常に遅れていることがわかります。すべてのクリック、ブープ、へこみは、イベントの後、特にiOSで実際にプレーするように彼らを引き起こしたイベントの後、顕著な時間がかかります。それは契約を破るものであり、ウサギの穴は私がかなりの時間を絶望的にトンネリングして過ごしました。

幸いなことに、クロスプラットフォームのサウンドの問題を非常に簡単に解決するhowler.jsというライブラリを見つけました(そして、それも楽しい小さなロゴを持っています)。 Howlerを依存関係としてインストールし、すべてのアプリのサウンドを実行するだけで、基本的に1行または2行のコードを実行するだけで、問題を解決するのに十分でした。

Sypariの問題が何であるか Howlerがそれを解決する方法がわからないので、Howlerを使用することを強くお勧めします。私が試したことは何もなかったので、オーバーヘッドやコードの変更が非常に少ないため、問題を簡単に解決しただけでうれしいです。

ゲームプレイ、歴史、賞

Quinaは特に最初は難しいゲームになる可能性があるため、個人的な好みに合わせてゲームの難しさを調整する方法はいくつかあります。

  1. コードワード(基本的な英語の単語)、トリッキー(より曖昧または綴りが難しい)、またはランダム(2つの加重ミックス)のように取得したい単語の種類を選択できます。
  2. 各ゲームの開始時にヒントを受け取るかどうか、もしそうなら、そのヒントがどれだけ明らかになるかを選択できます。

これらの設定により、さまざまなスキル、年齢、および/または英語の習熟度を持つプレイヤーが自分のレベルでゲームをプレイできます。 (強力なヒントを備えた基本的な単語セットは最も簡単です。ヒントがないことが最も難しいか、トリッキーまたはランダムになります。)

調整可能な難易度で一連の一連のゲームをプレイするだけで十分に楽しいかもしれませんが、実際の本格的なゲームというよりも標準的なWebアプリやデモのように感じるでしょう。したがって、そのネイティブアプリの感触の追求に合わせて、Quinaはゲームの歴史を追跡し、プレイ統計をさまざまな方法で示し、さまざまな成果にいくつかの「賞」を提供します。

ボンネットの下では、各ゲームは次のようなオブジェクトとして保存されます。

 {
  推測:3、
  難易度:「トリッキー」、
  勝利:本当、
  ヒント:「なし」、
}
ログイン後にコピー

このアプリは、ゲームの歴史的な配列の形式でプレイしたゲームをカタログにします(再び、Vuex StateがLocalStorageに同期されます)。その後、アプリはあなたの統計を表示するために使用します。

これはすべて、さまざまなVuexゲッターで十分に簡単に行われます。それぞれがGameHistoryアレイに.filter()や.reduce()などのJavaScriptアレイメソッドを使用します。たとえば、これはユーザーが「トリッキーな」設定でプレイしている間に勝ったゲームの数を示すゲッターです。

 // store/getters.js
TrickyGamesWon(STATE){
  return state.gamehistory.filter(
    (game)=> game.win && game.difficulty === 'Tricky'
  )。長さ
}、
ログイン後にコピー

さまざまな複雑さの他にも多くのゲッターがあります。 (ユーザーの最長の勝利連勝を決定したのは、特にgnarlyでした。)

賞を追加することは、それぞれが特定のVuex Getterに結び付けられ、それぞれが要件を持つ一連の賞のオブジェクトを作成することです。その賞がロック解除された時期を示す責任(つまり、ゲッターによって返された値が十分に高い)。これがサンプルです:

 // assets/js/awards.js
デフォルトのエクスポート[
  {
    タイトル: '開始'、
    要件: {
      ゲッター:「TotalGamesPlayed」、
      しきい値:1、
      テキスト:「Quinaの最初のゲームをする」、
    }
  }、
  {
    タイトル:「シャープ」、
    要件: {
      ゲッター:「TrickyGamesWon」、
      しきい値:10、
      テキスト:「トリッキーで合計10ゲームに勝つ」、
    }、
  }、
]
ログイン後にコピー

そこから、VUEテンプレートファイルの成果をループするという非常に簡単な問題であり、その要件を使用して最終出力を取得するために最終的な出力を取得します(ただし、賞の達成に向けたユーザーの進捗状況を示すためにゲージを埋めるために数学とアニメーションがかなりあります):

特定の数のゲームに勝つ、すべてのゲームモードを試し、最初の3つの推測内でゲームに勝つなど、さまざまな成果について、すべての賞(テーマに合わせて5×5)があります。 (それは「ラッキー」と呼ばれます。追加の小さなイースターエッグとして、各賞の名前は潜在的なコードワード、つまり、繰り返しのない5文字です。)

ロック解除賞は、自慢する権利を与える以外は何もしませんが、それらのいくつかは達成するのがかなり困難です。 (リリースしてから数週間かかりました。

このアプローチの長所と短所

「一度ビルド、どこにでも展開する」戦略については好きなことがたくさんありますが、いくつかの欠点もあります。

長所

  • ストアアプリを一度展開する必要があります。その後、すべての更新はWebサイトの展開にすぎません。 (これは、アプリストアのリリースを待つよりもはるかに速いです。)
  • 一度構築します。これは真実ですが、Googleの支払いポリシーのために思っていたほど簡単ではないことが判明しました(詳細については後で詳しく説明します)。
  • すべてがブラウザです。アプリは、ユーザーがそれを実現するかどうかにかかわらず、慣れている環境で常に実行されています。

短所

  • イベントハンドラーは本当に注意が必要です。コードはすべてのプラットフォームで同時に実行されているため、あらゆる種類のユーザー入力を一度に予測する必要があります。アプリ内の一部の要素は、タップ、クリック、ロングプレス、およびさまざまなキーボードキーに対して異なって応答することができます。お互いのつま先を踏むハンドラーのいずれかが一度にそれらを一度に処理するのは難しい場合があります。
  • あなたは経験を分割する必要があるかもしれません。これはあなたのアプリが何をしているのかによって異なりますが、AndroidアプリのユーザーやWebのみのみのユーザーにのみ表示する必要があるものがいくつかありました。 (以下の別のセクションでこれをどのように解決したかについてもう少し詳しく説明します。)
  • すべてがブラウザです。ユーザーがオンになっているAndroidのバージョンについては心配していませんが、デフォルトのブラウザが何であるかを心配しています(アプリが舞台裏でデフォルトのブラウザを使用するため)。通常、AndroidではこれはChromeを意味しますが、あらゆる可能性を説明する必要があります。

ロジスティクス:Webアプリをネイティブアプリに変える

「Web用のビルド、Everywhere Where Where Where」を作る多くのテクノロジーがあります。

一般的に、これらは2つのカテゴリに要約されます。

  1. フレームワークがあなたに望んでいる方法でコードを書きます(通常の方法ではなく)、フレームワークはそれを正当なネイティブアプリに変換します。
  2. あなたはあなたのコードを通常の方法で書きます、そして、技術はあなたのウェブ技術の周りにネイティブの「シェル」をラップするだけで、本質的にそれをネイティブアプリとして偽装します

最初のアプローチは、2つの中でより望ましいように思えるかもしれません(その最後に、理論的には「実際の」ネイティブアプリで終わるため)が、最大のハードルが付属していることがわかりました。すべてのプラットフォームまたは製品では、物事を行う方法を学ぶ必要があり、その方法はそれ自体がエコシステム全体とフレームワークになることになります。 「ただあなたが知っていることを書く」という約束は、私の経験において非常に強い誇張です。 1年か2年で、これらの問題の多くが解決されると思いますが、今のところ、Webコードの作成とネイティブアプリの出荷との間にかなりのギャップがあると感じています。

一方、2番目のアプローチは「TWA」と呼ばれるもののために実行可能です。これが、そもそもウェブサイトをアプリにすることを可能にします。

TWAアプリとは何ですか?

TWAは信頼できるWebアクティビティの略です。その答えはまったく役に立たない可能性が高いので、もう少し分解しましょう。

TWAアプリは、基本的に、Webサイト(またはWebアプリ、髪を分割する場合はWebアプリ)をネイティブアプリに変換します。

TWAアプリは変装したブラウザと考えることができます。これは、Webブラウザーを除き、内部のないAndroidアプリです。 TWAアプリは特定のWeb URLを指しており、アプリが通常のネイティブアプリのものを実行するのではなく、アプリが起動するたびに、代わりにそのWebサイトをロードするだけです。フルスクリーン、ブラウザーコントロールなしで、Webサイトを効果的に見た目と振る舞いを本物のネイティブアプリであるかのようにします。

TWA要件

ネイティブアプリでWebサイトをまとめるという魅力を見るのは簡単です。ただし、古いサイトやURLだけではありません。 TWAネイティブアプリとしてWebサイト/アプリを起動するには、次のボックスを確認する必要があります。

  • サイト/アプリはPWAでなければなりません。 GoogleはLighthouseの一部として検証チェックを提供するか、BubbleWrapで確認することもできます(詳細については少し)。
  • アプリバンドル/APKを自分で生成する必要があります。プログレッシブWebアプリのURLを送信し、すべての作業を実行するほど簡単ではありません。 (心配しないでください。ネイティブのアプリ開発について何も知らない場合でも、これを行う方法をカバーします。)
  • Androidアプリ特定のURLでWebアプリにアップロードされる一致するセキュアキーが必要です。

その最後のポイントは、「信頼できる」部分が登場する場所です。 TWAアプリは独自のキーをチェックし、Webアプリのキーが一致していることを確認して、適切なサイトをロードしていることを確認します(おそらく、アプリURLの悪意のあるハイジャックを防ぐため)。キーが一致しない、または見つけられない場合でも、アプリは機能しますが、TWA機能はなくなります。プレーンブラウザ、Chrome、およびすべてにWebサイトをロードするだけです。したがって、このキーは、アプリの経験にとって非常に重要です。 (それは重要な部分だと言えます。ごめんなさい。申し訳ありません。)

TWAアプリを構築することの利点と欠点

TWAアプリの主な利点は、コードをまったく変更する必要がないということです。通常のようなWebサイト/Webアプリを構築するだけで、それが完了したら、基本的にアプリコードも完了しました。

ただし、主な欠点は、(WebとJavaScriptの現代の到来を告げるのに役立つにもかかわらず)、AppleはTWAアプリを支持していないことです。 Apple App Storeにリストすることはできません。 Google Playのみ。

これは契約を破るように聞こえるかもしれませんが、いくつかのことを念頭に置いてください:

  • そもそもアプリをリストするには、PWAである必要があります。つまり、デフォルトでインストール可能です。任意のプラットフォーム上のユーザーは、ブラウザからデバイスのホーム画面に追加できます。 Apple App StoreにAppleデバイスにインストールする必要はありません(ただし、発見可能性については確かに見逃しています)。そのため、アプリにマーケティングランディングページを作成し、ユーザーにそこからインストールするように促すことができます。
  • また、まったく異なる戦略を使用して、ネイティブのiOSアプリを開発することを妨げるものもありません。 iOSアプリAndroidアプリの両方が必要な場合でも、Webアプリも計画の一部である限り、TWAがその作業の半分を効果的に削減します。
  • 最後に、iOSは主に英語を話す国と日本で約50%の市場シェアを持っていますが、Androidは他の世界の90%をはるかに超えています。したがって、視聴者に応じて、アプリストアを逃すことは、あなたが思うほどインパクトがないかもしれません。

AndroidアプリAPKを生成する方法

この時点で、このTWAビジネスはすべてうまく聞こえますが、実際にサイト/アプリを実際に採用してAndroidアプリに押し込むにはどうすればよいですか?

答えは、BubbleWrapと呼ばれる素敵な小さなCLIツールの形で来ます。

BubbleWrapは、入力とオプションを取得し、Androidアプリ(具体的には、Google Playストアで許可されているファイル形式の1つ)を入力から生成するツールと考えることができます。

BubbleWrapをインストールするのは少し難しいです。それを使用することはまったくプラグアンドプレイではありませんが、私が見つけた他の比較可能なオプションよりも平均的なフロントエンド開発の手の届くところに間違いなくあります。 BubbleWrapのNPMページのREADMEファイルは詳細に説明しますが、簡単な概要として:

NPM I -G @BubbleWrap/CLIを実行してBubbleWrapをインストールします(ここでは、NPMに精通し、コマンドラインを介してパッケージをインストールしています)。これにより、どこでもバブルラップを使用できます。

インストールされたら、実行します。

 bubblewrap init-manifest https://your-webapp-domain/manifest.json
ログイン後にコピー

注: Manifest.jsonファイルはすべてのPWAに必要であり、BubbleWrapはアプリだけでなく、そのファイルにURLが必要です。また、注意してください:マニフェストファイルの生成方法によっては、その名前は各ビルドに固有の場合があります。 (たとえば、NUXTのPWAモジュールは、ファイル名に一意のUUIDを追加します。)

また、デフォルトでは、BubbleWrapは、このプロセスの一部としてWebアプリが有効なPWAであることを検証することに注意してください。何らかの理由で、私がこのプロセスを経験していたとき、Lighthouseは実際には完全に機能的なプログレッシブWebアプリであることを確認しているにもかかわらず、チェックはネガティブに戻り続けました。幸いなことに、BubbleWrapを使用すると、-skippwavalidationフラグでこのチェックをスキップできます。

BubbleWrapを使用するのが初めての場合、Java Development Kit(JDK)とAndroid Software Development Kit(SDK)をインストールしたいかどうかを尋ねます。これら2つは、Androidアプリを生成するために必要な舞台裏のユーティリティです。わからない場合は、「Y」を「はい」を押してください。

注: BubbleWrapは、これら2つの開発キットが非常に特定の場所に存在することを期待しており、そこにいない場合は適切に機能しません。 BubbleWrap Doctorを実行して確認するか、完全なBubbleWrap Cli Readmeを確認できます。

すべてがインストールされた後、提供されたURLでmanifest.jsonファイルを見つけたと仮定すると、バブルワラップはアプリについていくつかの質問をします。

質問の多くは、好み(アプリのメイン色など)か、基本的な詳細(アプリのドメインやエントリポイントなど)を確認するだけで、ほとんどはサイトのマニフェストファイルから事前に入力されます。

マニフェストが既に事前に入力している可能性のあるその他の質問には、アプリのさまざまなアイコンを見つける場所(ホーム画面アイコン、ステータスバーアイコンなどとして使用する)、アプリの開いたときにスプラッシュ画面の色、およびポートレートまたはランドスケープを強制したい場合に備えて、アプリの画面の向きが含まれます。また、BubbleWrapは、ユーザーのジオロケーションの許可を要求するかどうか、およびプレイ請求を選択するかどうかを尋ねます。

ただし、少し混乱するかもしれないいくつかの重要な質問があるので、ここでそれらをカバーしましょう。

  • アプリケーションID:これはJavaコンベンションのように見えますが、各アプリには一般に2〜3個のドット分離セクション(collinsworth.quina.app)である一意のID文字列が必要です。実際にこれが何であるかは関係ありません。それは機能的ではなく、単なる慣習です。唯一の重要なことは、あなたがそれを覚えていること、そしてそれがユニークであることです。ただし、これはアプリのユニークなGoogle PlayストアURLの一部になることに注意してください。 (このため、以前に使用されていたアプリIDで新しいバンドルをアップロードすることはできないため、IDに満足していることを確認してください。)
  • 開始バージョン:これは現時点では問題ではありませんが、プレイストアでは、新しいバンドルをアップロードするときにバージョンをインクリメントする必要があり、同じバージョンを2回アップロードすることはできません。したがって、0または1から始めることをお勧めします。
  • 表示モード:実際、TWAアプリがサイトを表示できる方法はいくつかあります。ここでは、スタンドアロン(フルスクリーン)のいずれかを選択したいと思うでしょう(上部にネイティブステータスバーがあります)またはフルスクリーン(ステータスバーなし)。個人的には、アプリ内でユーザーのステータスバーを非表示にする理由がわからなかったため、デフォルトのスタンドアロンオプションを選択しましたが、アプリが何をするかによって異なる方法で選択する場合があります。

署名キー

パズルの最後のピースは署名キーです。これが最も重要な部分です。このキーは、プログレッシブWebアプリをこのAndroidアプリに接続するものです。アプリが期待しているキーがPWAで見つかったものと一致しない場合、再び:アプリはまだ機能しますが、ユーザーが開いたときにネイティブアプリのようには見えません。通常のブラウザウィンドウになります。

ここには、詳細には少し複雑すぎるアプローチが2つありますが、いくつかのポインターを与えようとします。

  1. 独自のキーストアを生成します。 BubbleWrapにこれを行うか、KeyTool(適切に)というCLIツールを使用することもできますが、いずれにしても非常に注意してください。キーストアの正確な名前とパスワードを明示的に追跡する必要があります。コマンドラインで両方を作成するため、プロセス全体を台無しにする可能性のある特殊文字に非常に注意する必要があります。 (特殊文字は、パスワードプロンプトの一部として入力された場合でも、コマンドラインで異なる解釈を行う場合があります。)
  2. Googleがキーを処理できるようにします。この正直なところ、私の経験は劇的に簡単ではありませんが、Google Play Developer Consoleにアクセスしてアプリの事前に生成されたキーをダウンロードできるようにすることで、自分の署名キーを争うというトラブルのいくつかを節約します。

どちらのオプションを選択しても、ここで署名するアプリに関する詳細なドキュメントがあります(Androidアプリ向けに書かれていますが、そのほとんどはまだ関連しています)。

個人サイトにキーを取得する部分については、Androidアプリリンクを検証するためのこのガイドで説明されています。大まかに要約すると、Googleはサイトの正確なパスで /.well-known/assetlinks.jsonファイルを探します。ファイルには、一意のキーハッシュと他のいくつかの詳細が含まれる必要があります。

 [{
  「関係」:["Delegate_permission/common.handle_all_urls"]、
  「ターゲット」:{"namespace": "android_app"、 "package_name": "your.app.id"
               「sha256_cert_fingerprints ":[" your:unique:hash:here "]}
}]
ログイン後にコピー

アプリのリストについて知っておくべきこと

始める前に、物事のアプリストア側には注意すべきハードルもいくつかあります。

  • 何よりもまず、Google Playストアに公開する前にサインアップする必要があります。この資格には、1回限りの25米ドルの料金がかかります。
  • 承認されたら、アプリのリストが迅速でも簡単でもないことを知ってください。難しいや技術よりも退屈ですが、Googleはすべてのアプリをレビューしてストアで更新し、レビュープロセスを開始する前に、自分自身とアプリの両方に関する多くのフォームと情報を入力する必要があります。 (フレンドリーなヘッズアップ:「通常のレビュー時間よりも長く経験している」とプレイコンソールダッシュボードで少なくとも6か月間警告バナーがありました。)
    • より退屈な部分の中で、レビューを開始する前に、アプリのいくつかの画像を動作している画像をアップロードする必要があります。これらは最終的にストアリストに示されている画像になります。また、それらを変更すると新しいレビューキックオフされるため、ターンアラウンド時間を最小限に抑えたい場合は準備されたテーブルに来てください。
    • また、アプリの利用規約およびプライバシーポリシーへのリンクを提供する必要があります(これは、私のアプリがそれらを持っている唯一の理由です。
    • 元に戻すことができないことがたくさんあります。たとえば、無料で公開されていない場合や、ダウンロードがゼロであっても、無料のアプリを有料に変更することはできませ。また、Googleがアプリを上書きまたは削除したり、バンドルをアップロードしたりすることもできず、ダッシュボード内の他の設定を常に元に戻すことができるとは限らないため、バージョンのバージョンとアップロードとの名前を厳格にする必要があります。 If you have a “just jump in and work out the kinks later” approach (like me), you may find yourself starting over from scratch at least once or twice.
  • With a few exceptions, Google has extremely restrictive policies about collecting payments in an app. When I was building, it was charging a 30% fee on all transactions (they've since conditionally lowered that to 15% — better, but still five times more than most other payment providers would charge). Google also forces developers (with a few exceptions) to use its own native payment platform; no opting for Square, Stripe, PayPal, etc. in-app.
    • Fun fact: this policy had been announced but wasn't in effect yet while I was trying to release Quina, and it still got flagged by the reviewer for being in violation. So they definitely take this policy very seriously.

Monetization, unlockables, and getting around Google

While my goal with Quina was mostly personal — challenge myself, prove I could, and learn more about the Vue ecosystem in a complex real-world app — I had also hoped as a secondary goal that my work might be able to make a little money on the side for me and my family.

あまりありません。 I never had illusions of building the next Candy Crush (nor the ethical void required to engineer an addiction-fueled micro-transaction machine). But since I had poured hundreds of hours of my time and energy into the game, I had hoped that maybe I could make something in return, even if it was just a little beer money.

Initially, I didn't love the idea of trying to sell the app or lock its content, so I decided to add a simple “would you care to support Quina if you like it?” prompt after every so many games, and make some of the content unlockable specifically for supporters. (Word sets are limited in size by default, and some game settings are initially locked as well.) The prompt to support Quina can be permanently dismissed (I'm not a monster), and any donation unlocks everything; no tiered access or benefits.

This was all fairly straightforward to implement thanks to Stripe, even without a server; it's all completely client-side. I just import a bit of JavaScript on the /support page, using Nuxt's handy head function (which adds items to the

element specifically on the given page):
 // pages/support.vue
頭() {
  戻る {
    script: [
      {
        hid: 'stripe',
        src: 'https://js.stripe.com/v3',
        defer: true,
        callback: () => {
          // Adds all Stripe methods like redirectToCheckout to page component
          this.stripe = Stripe('your_stripe_id')
        }、
      }、
    ]、、
  }
}、
ログイン後にコピー

With that bit in place (along with a sprinkle of templating and logic), users can choose their donation amount — set up as products on the Stripe side — and be redirected to Stripe to complete payment, then returned when finished. For each tier, the return redirect URL is slightly different via query parameters. Vue Router parses the URL to adjust the user's stored donation history, and unlock features accordingly.

You might wonder why I'm revealing all of this, since it exposes the system as fairly easy to reverse-engineer. The answer is: I don't care . In fact, I added a free tier myself, so you don't even have to go to the trouble. I decided that if somebody really wanted the unlockables but couldn't or wouldn't pay for whatever reason, that's fine. Maybe they live in a situation where $3 is a lot of money. Maybe they gave on one device already. Maybe they'll do something else nice instead. But honestly, even if their intentions aren't good: so what?

I appreciate support, but this isn't my living, and I'm not trying to build a dopamine tollbooth. Besides, I'm not personally comfortable with the ethical implications of using a stack of totally open-source and/or free software (not to mention the accompanying mountain of documentation, blog posts, and Stack Overflow answers written about all of it) to build a closed garden for personal profit.

So, if you like Quina and can support it: sincerely, thank you . That means a ton to me. I love to see my work being enjoyed. But if not: that's cool. If you want the “free” option, it's there for you.

Anyway, this whole plan hit a snag when I learned about Google Play's new monetization policy, effective this year. You can read it yourself, but to summarize: if you make money through a Google Play app and you're not a nonprofit, you gotta go through Google Pay and pay a hefty fee — you are not allowed to use any other payment provider.

This meant I couldn't even list the app; it would be blocked just for having a “support” page with payments that don't go through Google. (I suppose I probably could have gotten around this by registering a nonprofit, but that seemed like the wrong way to go about it, on a number of levels.)

My eventual solution was to charge for the app itself on Google Play, by listing it for $2.99 (rather than my previously planned price of “free”), and simply altering the app experience for Android users accordingly.

Customizing the app experience for Google Play

Fortunately enough, Android apps send a custom header with the app's unique ID when requesting a website. Using this header, it was easy enough to differentiate the app's experience on the web and in the actual Android app.

For each request, the app checks for the Android ID; if present, the app sets a Vuex state boolean called isAndroid to true. This state cascades throughout the app, working to trigger various conditionals to do things like hide and show various FAQ questions, and (most importantly) to hide the support page in the nav menu. It also unlocks all content by default (since the user's already “donated” on Android, by purchasing). I even went so far as to make simple and Vue wrapper components to wrap content only meant for one of the two. (Obviously, users on Android who can't visit the support page shouldn't see FAQs on the topic, as an example.)

 <!-- /src/components/AndroidOnly.vue -->

  <div v-if="isAndroid">
    
  </div>
テンプレート>


デフォルトのエクスポート{
  computed: {
    isAndroid() {
      return this.$store.state.isAndroid
    }、
  }、
}
ログイン後にコピー

Accounting for accounts

For a time while building Quina, I had Firebase set up for logins and storing user data. I really liked the idea of allowing users to play on all their devices and track their stats everywhere, rather than have a separate history on each device/browser.

In the end, however, I scrapped that idea, for a few reasons. One was complexity; it's not easy maintaining a secure accounts system and database, even with a nice system like Firebase, and that kind of overhead isn't something I took lightly. But mainly: the decision boiled down to security and simplicity.

At the end of the day, I didn't want to be responsible for users' data. Their privacy and security is guaranteed by using localStorage, at the small cost of portability. I hope players don't mind the possibility of losing their stats from time to time if it means they have no login or data to worry about. (And hey, it also gives them a chance to earn those awards all over again.)

Plus, it just feels nice. I get to honestly say there's no way my app can possibly compromise your security or data because it knows literally nothing about you. And also, I don't need to worry about compliance or cookie warnings or anything like that, either.

Wrapping up

Building Quina was my most ambitious project to date, and I had as much fun designing and engineering it as I have seeing players enjoy it.

I hope this journey has been helpful for you! While getting a web app listed in the Google Play Store has a lot of steps and potential pitfalls, it's definitely within reach for a front-end developer. I hope you take this story as inspiration, and if you do, I'm excited to see what you build with your newfound knowledge.

以上がGoogle Playでnuxtを使用してワードゲームアプリを構築したことを学んだことの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
関連するチュートリアル
人気のおすすめ
最新のコース
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート