首页 > web前端 > css教程 > 我学到了在Google Play上使用NUXT构建Word Game应用程序的内容

我学到了在Google Play上使用NUXT构建Word Game应用程序的内容

Christopher Nolan
发布: 2025-03-24 10:00:17
原创
812 人浏览过

我学到了在Google Play上使用NUXT构建Word Game应用程序的知识

我爱上了我创建第一个CSS的那一刻:悬停效果。多年后,最初的咬人在网络上互动使我达到了一个新目标:制作游戏。

目录

  • 游戏是什么(那个名字)?
  • 选择nuxt
  • 通过网络实现本地应用感觉
  • 振动和声音
    • 旁边的声音
  • 游戏玩法,历史和奖项
  • 这种方法的优缺点
    • 优点
    • 缺点
  • 物流:将Web应用程序变成本机应用
  • 什么是TWA应用程序?
    • TWA要求
    • 构建TWA应用程序的优点和缺点
  • 如何生成Android App APK
  • 签名键
  • 您应该了解列出应用程序的知识
  • 货币化,可解锁和围绕Google获取
  • 自定义Google Play的应用程序体验
  • 帐户会计
  • 总结

那些早期玩的时刻:悬停并不是什么特别的,甚至没有用。我记得制作蓝色正方形的响应式网格(如果这使您对时间轴的想法,则用浮子制成),当光标移到它们上时,每种都变成橙色。我花了一些时间在盒子上放在盒子上,调整了窗户的大小,看着它们改变尺寸和对齐方式,然后再进行一次。感觉就像纯粹的魔法。

我在网络上构建的东西自然变得比多年来的

元素的网格更加复杂,但是将真正互动的东西带给我的刺激总是困扰着我。当我越来越多地了解JavaScript时,我特别喜欢制作游戏。

有时候只是一个代码蛋白演示。有时这是部署在Vercel或Netlify上的小型项目。我喜欢重新创建诸如彩色洪水,handman或在浏览器中连接四个游戏之类的游戏的挑战。

一段时间后,目标变得更大:如果我做了一场实际的游戏怎么办?不仅仅是网络应用程序;真实的现场直播,善良,下载从申请店的游戏。去年八月,我开始从事我迄今为止最雄心勃勃的项目,四个月后,我将其发布给了世界(阅读:厌倦了摆弄它):我称之为Quina的Word Game应用程序。

游戏是什么(那个名字)?

解释Quina的最简单方法是:它是策划者,但带有五个字母的单词。实际上,策划者实际上是经典的笔和纸游戏的版本。 Quina只是同一原始游戏的另一种变体。

Quina的目的是猜测一个秘密的五个字母单词。每次猜测之后,您都会得到一个线索,可以告诉您您的猜测与代码单词有多近。您使用该线索来完善您的下一个猜测,依此类推,但是您只能得到十个猜测。用完了,你输了。

“ Quina”这个名字之所以出现,是因为它在拉丁语中的意思是“一次”(无论如何,Google告诉我)。传统游戏通常使用四个字母的单词或有时四位数(或者是策划者,四种颜色); Quina使用没有重复的字母的五个字母的单词,因此游戏应该具有根据自己的规则扮演的名称,这很合适。 (我不知道原始拉丁语是如何发音的,但是我说“ Quinn-ah”,这可能是错误的,但是,嘿,这是我的游戏,对吗?)

在大约四个月的时间里,我晚上和周末都在建立该应用程序。我想花这篇文章来谈论游戏背后的技术,所涉及的决定以及所学到的经验教训,以防您有兴趣自己走的道路。

选择nuxt

我是Vue的忠实拥护者,并希望将这个项目用作扩大我对其生态系统的了解的一种方式。我考虑过使用另一个框架(我还在Svelte和React中构建了项目),但是我觉得Nuxt遇到了熟悉,易用性和成熟度的最佳位置。 (顺便说一句,如果您不知道或没有猜到过:NUXT可以公平地描述为Next.js的Vue)

以前我对Nuxt并没有太深。只有几个非常小的应用程序。但是我知道NUXT可以编译到静态应用程序中,这正是我想要的 - 不担心(节点)服务器。我知道NUXT可以像将VUE组件放入A /页文件夹一样容易处理路由,这非常吸引人。

另外,尽管Vuex(Vue的官方国家管理层)本身并不是很复杂,但我赞赏Nuxt添加一点糖的方式使其变得更加简单。 (顺便说一句,NUXT以多种方式使事情变得容易,例如不需要您在使用它们之前明确导入组件;您可以将它们放入标记中,而Nuxt将其弄清楚并根据需要弄清楚它并自动象征。)

最后,我提前知道我正在构建一个渐进式网络应用程序(PWA),因此已经有一个NUXT PWA模块可以帮助构建所涉及的所有功能(例如已经包装并准备就绪的离线功能的服务工作者)是一个很大的吸引力。实际上,有一个令人印象深刻的NUXT模块可用于任何看不见的障碍。这使NUXT成为最简单,最明显的选择,而我从未后悔。

我最终在进行的过程中使用了更多模块,包括Stellar Nuxt内容模块,该模块可让您在Markdown中编写页面内容,甚至可以混合Markdown和Vue组件的混合物。我也将该功能用于“常见问题解答”页面和“如何播放”页面(因为在Markdown中写作比硬编码HTML页面好得多)。

通过网络实现本地应用感觉

奎纳(Quina)最终会在Google Play商店中找到房屋,但是无论它如何玩耍,我都希望它感觉像是一开始就像一个成熟的应用程序。

首先,这意味着一个可选的黑模式,以及减少最佳可用性运动的设置,就像许多本机应用程序一样(在减少运动的情况下,就像动画一样的任何东西)。

在引擎盖下,两个设置最终都是应用程序VUEX数据存储中的布尔值。如果为true,则设置将在应用程序的默认布局中呈现特定类。 NUXT布局是“包装”您所有内容的VUE模板,并在您的应用程序的所有页面上呈现(通常用于共享标头和页脚等内容,但对全球设置也有用):

 

  <div>
    <nuxt></nuxt>
  </div>


<script>
导入{mapgetters}从&#39;vuex&#39;

导出默认{
  计算:{
    ... mapgetters([&#39;darkmode&#39;,&#39;reducemotion&#39;]),),
  },,
  //此处的其他布局组件代码
}
</script>
登录后复制

说到设置:尽管Web应用程序分为几个不同的页面 - 菜单,设置,关于,播放等。

应用程序中的每个设置也都同步到LocalStorage和Vuex Store,允许在会话之间保存和加载值,除了在用户在页面之间导航时跟踪设置。

说到导航:在页面之间移动是我觉得有很多机会通过添加整页过渡来使Quina感觉像本地应用的另一个领域。

总体而言,VUE过渡非常简单 - 您只是为“ TO”和“从”过渡状态编写特殊命名为CSS类 - 但是NUXT更进一步,并允许您在页面VUE文件中仅使用一行单行设置完整页面过渡

 
<script>
导出默认{
  过渡:“页面滑动”
  // ...其余的组件属性
}
</script>
登录后复制

该过渡属性是强大的;它使NUXT知道我们希望每次导航到远离它时都将页面滑动过渡应用于此页面。从那里开始,我们需要做的就是定义处理动画的类,就像您在任何VUE过渡时一样。这是我的页面滑动SCSS:

 / * Assets/css/_animations.scss */

.page-slide {
  &-enter-Active {
    过渡:所有0.35s立方晶体(0,0,0.25,0,0.75);
  }

  & -  leave-active {
    过渡:所有0.35s立方晶体(0.75,0,1,0.75);
  }

  &-进入,
  & -  leave-to {
    不透明度:0;
    变换:翻译(1REM);

    。
      变换:无!重要;
    }
  }

  & -  leave-to {
    变换:translatey(-1REM);
  }
}
登录后复制

请注意。降低运动班;这就是我们在上面的布局文件中谈论的内容。当用户指出他们更喜欢减少运动(通过媒体查询或手动设置)时,它可以防止视觉运动,通过禁用任何变换属性(似乎值得使用分裂!重要的标志)。但是,不透明度仍然可以褪色,但是,这并不是真正的运动。

关于过渡和处理404s的旁注:当然,过渡和路由是由引擎盖下的JavaScript处理(确切地说是Vue路由器),但是我遇到了一个令人沮丧的问题,脚本会停止在空闲页面上运行(例如,如果用户将应用程序在后台打开或在背景中打开时,我会停止使用)。回到这些空闲页面并单击链接时,Vue路由器将停止运行,因此该链接将被视为相对和404。

示例: /FAQ页面闲置;用户返回它,然后单击链接以访问 /选项页面。该应用程序将尝试转到 /常见问题 /选项,这当然不存在。

我对此的解决方案是一个自定义错误。VUE页面(这是一个自动处理所有错误的NUXT页面),我将在传入路径上运行验证并将其重定向到路径的尽头

 //布局/error.vue
安装(){
  const lastpage ='/'this。$ route.fullpath.split('/')。pop()
  //不要创建重定向循环
  如果(lastpage!==this。$ route.fullpath){
    这个。$ router.push({{
      路径:最后一个页面,
    }))
  }
}
登录后复制

这适用于我的用例,因为a)我没有任何嵌套路线; b)最后,如果路径不有效,它仍然达到404。

振动和声音

过渡很不错,但我也知道Quina不会感觉像是一个本地应用,尤其是在智能手机上 - 没有振动和声音。

借助导航器API,如今,浏览器相对容易实现振动。大多数现代浏览器都可以允许您调用window.navigator.fibrate()给用户一点嗡嗡声或一系列嗡嗡声 - 或者,使用非常短的持续时间,一点点触觉反馈,例如当您在智能手机键盘上点击键时。

显然,出于某些原因,您想谨慎使用振动。首先,因为太多很容易成为糟糕的用户体验;其次,因为并非所有设备/浏览器都支持它,因此您需要非常谨慎地谨慎使用振动()函数,以免您导致关闭当前运行脚本的错误。

就个人而言,我的解决方案是设置Vuex Getter,以验证用户允许振动(可以从“设置”页面禁用);当前的上下文是客户端,而不是服务器;最后,该功能存在于当前浏览器中。 (ES2020可选链接在最后一部分也将在这里工作。)

 // store/getters.js
振动(状态){
  如果 (
    process.client &&
    state.options.振动&&
    typeof window.navigator.dibrate!=='undefined'
  ){
    返回true
  }
  返回false
},,
登录后复制

旁注:检查process.client在NUXT中很重要,并且许多其他可能在节点上运行的代码的框架 - 由于窗口并不总是存在。即使您在静态模式下使用NUXT,这也是正确的,因为组件在构建时间期间在节点中验证。 process.client(及其相反的process.server)是仅在运行时验证代码当前环境的nuxt nieties,因此它们非常适合隔离浏览器的代码。

声音是应用程序用户体验的另一个关键部分。我没有做出自己的效果(毫无疑问会在项目中增加数十个小时),而是将一些艺术家的样本混合在一起,他们更了解他们在该领域的工作,并在网上提供一些免费的游戏听起来。 (有关完整信息,请参见应用程序的常见问题。)

用户可以设置他们喜欢的音量,也可以完全关闭声音。这和振动也设置在用户浏览器的LocalStorage中,并同步到Vuex商店。这种方法使我们能够设置保存在浏览器中的“永久”设置,但无需在每次引用时从浏览器中检索它。 (例如,听起来每次播放时都要检查当前音量级别,并且每次发生的局部记录呼叫等待的延迟可能足以杀死体验。)

旁边的声音

事实证明,无论出于何种原因,野生动物园在听起来时都非常卑鄙。事件发生后,所有点击,boops和ding都将需要大量的时间,这些时间触发了它们实际在Safari中玩耍,尤其是在iOS上。那是一个破坏交易的人,一个兔子的洞我花了很多时间绝望地隧道了。

幸运的是,我找到了一个名为howler.js的库,可以很容易地解决跨平台声音问题(而且还有一个有趣的小徽标)。只需将Howler作为依赖项安装并通过它运行所有应用程序的声音(基本上是一两个代码)就足以解决问题。

如果您要构建具有同步声音的JavaScript应用程序,我强烈建议您使用Howler,因为我不知道Safari的问题是什么Howler如何解决它。我没有尝试过任何工作,所以我很高兴只有很少的开销或代码修改即可轻松解决问题。

游戏玩法,历史和奖项

Quina可能是一个困难的游戏,尤其是起初,因此有几种方法可以调整游戏难以适应您的个人喜好:

  1. 您可以选择要获得哪种单词作为代码单词:基本(常见的英语单词),棘手(更晦涩或更难拼写)或随机(两者的加权混合)。
  2. 您可以选择是否收到每个游戏开始的提示,如果是,则暗示了这一点。

这些设置允许具有各种技能,年龄和/或英语能力的玩家在自己的水平上玩游戏。 (一个带有强烈提示的基本单词将是最简单的;没有提示的棘手或随机性是最难的。)

虽然简单地玩一系列具有可调节难度的一次性游戏可能很有趣,但与真实的,成熟的游戏相比,这种感觉更像是标准的Web应用程序或演示。因此,为了符合对该本地应用程序的追求,Quina跟踪您的游戏历史记录,以多种不同的方式显示您的游戏统计信息,并为各种成就提供了多种“奖项”。

在引擎盖下,每个游戏都被保存为看起来像这样的对象:

 {
  猜测:3,
  困难:“棘手”,
  赢:是的,
  提示:“无”,
}
登录后复制

该应用程序以您的游戏播放(再次,通过Vuex State同步到LocalStorage)的形式以游戏史的形式出现游戏对象的形式,然后该应用程序用来显示您的统计数据,例如您的胜利/损失率,您玩了多少游戏以及您的平均猜测,以及您对游戏“ Achards”的进度。

对于各种Vuex Getter,它们都使用JavaScript数组方法,例如.filter()和.Reduce(),这一切都足够轻松地完成。例如,这是显示用户在“棘手”设置时赢得多少游戏的Getter:

 // store/getters.js
TrickyGameswon(state){
  返回state.gamehistory.filter(
    (game)=> game.win && game.difficulty ==='Tricky'
  )。长度
},,
登录后复制

还有许多其他复杂性不同的人。 (确定用户最长的连胜纪录的人特别粗糙。)

添加奖励是创建一系列奖励对象的问题,每个对象都与特定的vuex getter绑定,每个奖项都有要求。阈值财产指示何时解锁该奖项(即,何时返回Getter的值足够高的值)。这是一个示例:

 //资产/JS/Awards.js
导出默认[
  {
    标题:“发作”,
    要求: {
      getter:“ totalgamesplayed',
      阈值:1,
      文字:“玩第一个Quina游戏”,
    }
  },,
  {
    标题:“尖锐”,
    要求: {
      getter:'trickygameswon',
      阈值:10,
      文字:“赢得十张棘手的比赛”,
    },,
  },,
这是给出的
登录后复制

从那里开始,使用其要求属性(尽管添加了大量的数学和动画)来填充仪表以显示用户在获得奖励方面的进步),从而使对VUE模板文件中的成就进行循环是一个非常简单的问题以获取最终输出。

总共有25个奖项(与主题保持一致),包括赢得一定数量的游戏,尝试所有游戏模式,甚至在前三个猜测中赢得游戏。 (那个被称为“幸运” - 作为额外的小复活节彩蛋,每个奖项的名称也是一个潜在的代码单词,即,五个没有重复的字母。)

解锁奖项除了赋予您吹牛的权利外,没有任何作用,但是其中一些很难实现。 (发布后几周我花了几周!)

这种方法的优缺点

关于“构建一次,在各处部署”策略有很多值得爱的人,但它也带来了一些缺点:

优点

  • 您只需要一次部署商店应用程序即可。之后,所有更新都可以是网站部署。 (这比等待App Store发布要快得多。)
  • 构建一次。这是正确的,但事实证明,由于Google的付款政策(稍后会详细介绍),事实证明并不像我想象的那样简单。
  • 一切都是浏览器。无论用户是否意识到,您的应用程序始终在您使用的环境中运行。

缺点

  • 活动处理程序可能会变得非常棘手。由于您的代码同时在所有平台上运行,因此您必须一次预测所有类型的用户输入。应用程序中的某些元素可以挖掘,单击,长期压力,并且对各种键盘键的响应有所不同。立即处理所有这些操作者而没有任何处理人员踩在彼此的脚趾上,这可能很棘手。
  • 您可能必须分裂经验。这取决于您的应用程序在做什么,但是我需要在Android应用程序上的用户和其他仅用于Web的用户显示一些事情。 (我在下面的另一部分中详细介绍了我如何解决此问题。)
  • 一切都是浏览器。您并不担心用户使用哪种版本的Android,但是您担心他们的默认浏览器是什么(因为该应用程序会在幕后使用默认的浏览器)。通常,在Android上,这将意味着Chrome,但是您必须考虑到所有可能性。

物流:将Web应用程序变成本机应用

那里有很多技术使“网络构建,到处释放”承诺 - 反应本地,科尔多瓦,离子,流星和本地录,仅举几例。

通常,这些归结为两类:

  1. 您按照框架希望您的方式编写代码(不是正常的方式),并且该框架将其转换为合法的本机应用程序;
  2. 您以通常的方式编写代码,而技术只是将本机“外壳”包裹在您的Web技术周围,并从本质上掩盖了本机应用程序。

第一种方法似乎是两者中更理想的方法(因为在理论上,您最终都以“真实”的本机应用程序最终出现),但我也发现它带来了最大的障碍。每个平台或产品都要求您学习其做事的方式,因此,本身必须成为整个生态系统和框架。在我的经验中,“只写你所知道的”的承诺是一个非常强烈的夸大。我猜想将在一两年的时间里解决这些问题,但是现在,您仍然会在编写Web代码和运送本机应用程序之间感到很大的差距。

另一方面,第二种方法是可行的,因为一种称为“ TWA”的东西,这就是使将网站首先纳入应用程序的原因。

什么是TWA应用程序?

TWA代表可信赖的网络活动 - 由于该答案根本不太可能有帮助,所以让我们再分解一点,对吗?

TWA应用程序基本上将网站(或Web应用程序,如果您想将头发拆开)变成本机应用程序,并在一个小UI骗局的帮助下。

您可以将TWA应用程序视为变相的浏览器。除Web浏览器外,这是一个没有任何内部设备的Android应用程序。 TWA应用程序指向特定的Web URL,每当启动该应用程序时,而不是执行普通的本机应用程序,它只是加载了该网站 - 全屏 - 没有浏览器控件,有效地使网站看起来和表现得像是成熟的应用程序。

TWA要求

很容易看到将网站包裹在本机应用程序中的吸引力。但是,不仅有任何旧站点或URL都有资格;为了将您的网站/应用程序作为TWA本机应用程序启动,您需要选中以下框:

  • 您的网站/应用必须是PWA。 Google作为灯塔的一部分提供验证检查,或者您可以使用BubbleWrap检查(稍后详细介绍)。
  • 您必须自己生成应用程序捆绑包/apk;这并不像提交进步网络应用程序的URL并为您完成所有工作那样容易。 (不用担心;即使您对本地应用程序开发一无所知,我们也会介绍一种方法。)
  • 您必须在Android应用中具有匹配的安全密钥,在特定URL上上传到Web应用程序。

最后一点是“值得信赖的”部分出现的地方; TWA应用程序将检查自己的密钥,然后验证Web应用程序上的密钥是否与之匹配,以确保其加载正确的站点(大概是为了防止对应用程序URL的恶意劫持)。如果密钥不匹配或找不到,则该应用程序仍然可以正常工作,但是TWA功能将消失;它只会将网站加载到普通的浏览器,铬和所有方面。因此,关键对于应用程序的体验极为重要。 (您可以说这是一个关键部分。对不起,对不起。)

构建TWA应用程序的优点和缺点

TWA应用程序的主要优点是,它根本不需要您更改代码 - 没有学习框架或平台;您只是构建像正常现象一样的网站/网络应用程序,一旦完成,您也基本上也完成了应用程序代码。

然而,主要的缺点是(尽管有助于迎来了网络和JavaScript的现代时代),但Apple支持TWA应用程序。您无法在Apple App Store中列出它们。只有Google Play。

这听起来像是打破交易的人,但要牢记一些事情:

  • 请记住,要首先列出您的应用程序,它必须是PWA,这意味着默认情况下它是可安装的。任何平台上的用户仍然可以通过浏览器将其添加到其设备的主屏幕中。它不需要在Apple App Store中安装在Apple设备上(尽管它肯定会错过可发现性)。因此,您仍然可以在应用程序中构建营销登陆页面,并提示用户从那里安装它。
  • 也没有什么可以阻止您使用完全不同的策略来开发本机iOS应用程序。即使您同时想要iOSAndroid应用程序,只要Web应用程序也是该计划的一部分,即使TWA有效地削减了一半的工作。
  • 最后,尽管iOS在以英语为主的国家和日本中占有50%的市场份额,但Android拥有超过90%的世界其他地区。因此,根据您的听众,在App Store上错过您可能想象的那么有影响力。

如何生成Android App APK

在这一点上,您可能会说,这个TWA业务听起来不错,但是我如何实际使用我的网站/应用程序并将其推入Android应用程序?

答案的形式为可爱的小CLI工具,称为BubbleWrap。

您可以将BubbleWrap视为从您那里获取一些输入和选项的工具,并生成一个Android应用程序(特别是APK,Google Play商店允许的文件格式之一)。

安装BubbleWrap有点棘手,尽管使用它并不完全是插件,但对于普通的前端开发人员来说,它比我发现的任何其他可比较的选项都要多得多。 BubbleWrap的NPM页面上的README文件介绍了详细信息,但作为简短概述:

通过运行NPM I -G @BubbleWrap/CLI安装BubbleWrap(我假设您在这里熟悉NPM并通过命令行安装软件包)。这将使您可以在任何地方使用BubbleWrap。

安装后,您将运行:

 bubblewrap init-manifest https:// your-webapp-domain/manifest.json
登录后复制

注意:所有PWA都需要清单。JSON文件,BubbleWrap需要该文件的URL,而不仅仅是您的应用程序。还要警告:根据您的清单文件的生成方式,其名称可能是每个构建的唯一名称。 (例如,NUXT的PWA模块将唯一的UUID附加到文件名。)

另请注意,默认情况下,BubbleWrap将验证您的Web应用程序是该过程的有效PWA。由于某种原因,当我经历此过程时,尽管灯塔证实这实际上是一个功能齐全的渐进式Web应用程序,但检查的情况一直落后。幸运的是,BubbleWrap允许您使用-skippwavalidation标志跳过此检查。

如果这是您第一次使用BubbleWrap,它将询问您是否要它安装Java开发套件(JDK)和Android软件开发套件(SDK)。这两个是生成Android应用所需的幕后公用事业。如果不确定,请命中“ Y”。

注意: BubbleWrap期望这两个开发套件在非常具体的位置存在,如果它们不存在,则无法正常工作。您可以运行BubbleWrap医生来验证,或者查看完整的BubbleWrap CLI读数。

安装了所有内容后 - 假设它在提供的URL上找到了您的清单。

许多问题是偏好(例如您的应用程序的主要颜色),或者只是确认基本细节(例如应用程序的域和入口点),并且大多数将从您网站的清单文件中预先填写。

您的清单可能已经预先解决的其他问题包括在哪里找到您的应用程序的各种图标(用作主屏幕图标,状态栏图标等),如果您想强制肖像画或景观,则在应用程序打开时,溅起屏幕应为什么颜色,以及应用程序的屏幕方向。 BubbleWrap还将询问您是否要请求用户的地理位置许可,以及您是否要选择播放计费。

但是,有一些重要的问题可能有些混乱,所以让我们在这里介绍这些问题:

  • 应用程序ID:这似乎是Java约定,但是每个应用程序都需要一个唯一的ID字符串,通常为2-3个点分隔的部分(例如,Collinsworth.quina.app)。这实际上并不重要。它不起作用,只是惯例。唯一重要的是您记住它,并且它是独一无二的。但是注意,这将成为您应用程序独特的Google Play商店URL的一部分。 (因此,您无法使用先前使用的应用程序ID上传新捆绑包,因此请确保您对ID感到满意。)
  • 启动版:目前这并不重要,但是Play商店将需要您在上传新捆绑时增加版本,并且您无法两次上传同一版本。因此,我建议从0或1开始。
  • 显示模式:实际上,TWA应用程序可以通过几种方式显示您的网站。在这里,您很可能想选择独立的(全屏,但顶部的本机状态栏)或全屏(无状态栏)。我个人选择了默认的独立选项,因为我没有看到隐藏用户状态栏内应用程序的任何理由,但是您可能会根据应用程序的操作选择不同。

签名键

难题的最后一块是签名钥匙。这是最重要的部分。该键是将您的渐进式Web应用程序连接到此Android应用程序的原因。如果该应用程序期望的键与PWA中发现的内容不匹配,则再次:您的应用程序仍然可以正常工作,但是当用户打开它时,它看起来不会像本机应用程序;它将只是一个普通的浏览器窗口。

这里有两种方法有点复杂,无法详细介绍,但是我会尝试给一些指控:

  1. 生成自己的密钥库。您可以让BubbleWrap执行此操作,也可以使用称为Keytool的CLI工具(足够适当),但是无论哪种方式:要非常小心。您需要明确跟踪密钥库的确切名称和密码,并且由于您在命令行上都创建了这两个名称和密码,因此您需要非常小心可能会弄乱整个过程的特殊字符。 (即使输入作为密码提示的一部分,特殊字符也可以在命令行上进行不同的解释。)
  2. 允许Google处理您的密钥。老实说,这在我的经验中并不是很简单,但是通过允许您进入Google Play开发人员控制台,并为应用程序下载预先生成的键来节省一些自己的签名键的麻烦。

无论您选择哪个选项,都有有关应用程序签名的深入文档(为Android应用程序编写,但其中大多数仍然相关)。

本指南涵盖了您将钥匙进入个人网站的部分,以验证Android应用链接。粗略总结:Google将在您网站上的那个确切路径上查找A /.well-newone/assetlinks.json文件。该文件需要包含您的唯一密钥哈希以及其他一些细节:

 [{{
  “关系”:[“ delegate_permission/common.handle_all_urls”],
  “目标”:{“命名空间”:“ android_app”,“ package_name”:“ your.app.id”,
               “ SHA256_CERT_FINGERPRINTS”:[“您:唯一:哈希:在这里”]}
]]
登录后复制

您应该了解列出应用程序的知识

在开始之前,在App Store方面也有一些障碍:

  • 首先,您需要注册,然后才能发布到Google Play商店。此资格的费用为$ 25美元。
  • 一旦获得批准,就知道列出应用程序既不快,也不容易。这比困难或技术性更繁琐,但是Google会在商店中查看每个应用程序并进行更新,并要求您在您甚至可以启动审核过程之前填写有关您自己和应用程序的大量表格和信息 - 即使您的应用程序尚未公开,这本身也可能需要很多天。 (友好的头脑:“我们的经历比通常的评论时间更长”的警告横幅至少六个月。)
    • 在更加乏味的部分中:您必须在审核开始之前上传应用程序中的几张图像。这些最终将成为商店列表中显示的图像 - 请记住,更改它们将开始新的评论,因此,如果您想最大程度地减少周转时间,请准备好桌子。
    • 您还需要提供有关应用程序服务条款和隐私政策条款的链接(这是我的应用程序甚至拥有它们的唯一原因,因为它们几乎毫无意义)。
    • 有很多你不能撤消的事情。例如,即使尚未公开启动和/或下载零,您也永远无法将免费应用程序更改为付款。您还必须严格对上传的版本控制和命名,因为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
头() {
  返回 {
    脚本: [
      {
        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">
    <slot></slot>
  </div>


<script>
导出默认{
  计算:{
    isAndroid() {
      return this.$store.state.isAndroid
    },,
  },,
}
</script>
登录后复制

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.

总结

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构建Word Game应用程序的内容的详细内容。更多信息请关注PHP中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板