热代码推送

如何诊断 Meteor Cordova 应用程序中热代码推送的问题

您的 Meteor Cordova 应用程序是否没有获得您正在部署的更新?

阅读本文后,您将了解

  1. 使用热代码推送的先决条件
  2. 一些诊断和解决常见问题的方法
  3. 如果这不能解决您的问题,如何更深入地挖掘

本文基于 Cordova 文章。我们建议先阅读该文章,尽管我们已尝试链接回其相关部分。

先决条件

请确保您拥有

  • 基于 Meteor 的 Cordova 集成 的 Android 和/或 iOS 移动应用程序
  • 列在您的 .meteor/versions 文件中的 hot-code-push
  • 本地:确保您的测试设备和开发设备 在同一网络上
  • 在生产环境中:确保您的 meteor build 命令的 --server 标志指向与您的 ROOT_URL 环境变量(或在 Galaxy 上,meteor deploy site 中的站点)相同的位置。查看详细信息

已知问题

覆盖兼容性版本

更新 Meteor 或更改插件后,应用程序是否突然停止获取新代码?

客户端可能会记录:由于 Cordova 平台版本或插件版本已更改且可能不兼容,因此跳过下载新版本

Meteor、Cordova 和插件无法通过热代码推送进行更新。因此,Meteor 默认情况下会禁用热代码推送到与服务器具有不同版本的应用程序版本。这避免了用户应用程序崩溃,例如,当新的 JS 调用其应用程序版本尚不存在的插件时。

您可以 覆盖此行为。只需确保您在 JS 中处理了可能不兼容的版本。

更新您的 AUTOUPDATE_VERSION

AUTOUPDATE_VERSION 是您可以添加到您的 rundeploy 命令 中的环境变量

$ AUTOUPDATE_VERSION=abc meteor deploy example.com

如果您的应用程序设置了 AUTOUPDATE_VERSION,请确保在您希望部署更新客户端时更改其值。

Cordova 不会单独热重载 CSS

您是否看到您的 Web 应用程序在没有重新加载的情况下合并更改,但您的 Cordova 应用程序每次都重新加载?

对于仅限 CSS 的更改,这是预期行为。浏览器会在不重新加载的情况下更新布局,但在 Cordova 中,任何更改都会重新加载整个应用程序

如果您想为 Cordova 实现软 CSS 更新,请参见下面的 如何编辑源代码

过时的自定义重新加载代码和包

几个重新加载包,并且您的应用程序可能包含一些自定义重新加载代码。当然,这些可能存在错误或已过时。

特别是,当您推送更新时,应用程序是否重新加载但仍然使用旧代码?可能,代码尚未更新以与 Meteor 1.8.1 或更高版本一起使用。如 变更日志 中所述,我们建议您在强制浏览器重新加载之前调用 WebAppLocalServer.switchToPendingVersion

或者,使用内置行为重新加载。例如,不要使用 window.location.reload(),而是调用传递给 Reload._onMigrate() 回调的 retry 函数。例如

Reload._onMigrate((retry) => {
  if (/* not ready */) {
    window.setTimeout(retry, 5 * 1000); // Check again in 5 seconds
    return [false];
  }
  // ready
  return [true];
});

如果您使用不再兼容的包,请考虑对其进行分叉或使用上述更改打开 PR。或者,您可以切换到兼容的包,例如 quave:reloader

避免使用哈希片段

Cordova 不显示 URL 栏,但用户仍然位于某个 URL 上,该 URL 可能具有哈希 (#)。HCP 在没有哈希片段时工作效果更好

如果可以,请在重新加载之前删除哈希片段。

避免下载大型文件

客户端日志 中,您可能会看到 HCP 出现以下错误

Error: Error downloading asset: /
  at https://127.0.0.1:12472/plugins/cordova-plugin-meteor-webapp/www/webapp-local-server.js:51:21
  at Object.callbackFromNative (https://127.0.0.1:12472/cordova.js:287:58)
  at <anonymous>:1:9

来自 cordova-plugin-meteor-webapp 的此错误可能是由大型文件(通常位于 public 文件夹中)引起的。根据连接速度和设备上的可用空间,下载这些文件可能会失败。

您可以运行 $ du -a public | sort -n -r | head -n 20 以查找 20 个最大的文件及其大小。考虑改为从外部存储服务或 CDN 提供它们。然后,只有在真正需要时才会下载它们,并且可以失败下载而不会阻止 HCP。

如果仅在本地中断

如果您注意到 HCP 在生产环境中有效,但在本地测试时无效,则您可能需要启用明文或设置正确的 --mobile-server。两者都在 文档中进行了说明

仍然有问题?

如果上述方法均无法解决您的问题,并且您想更深入地研究,以下是一些入门提示。

如果您最终在 Meteor 的某个包或插件中发现错误,请随时打开 问题 和/或 请求请求

热代码推送位于哪里?

热代码推送通过一系列 官方 Meteor 包 包含在 meteor-base 中,最重要的是 reloadautoupdate

在 Cordova 的情况下,大部分繁重的工作是由 cordova-plugin-meteor-webapp 完成的。

简单来说,autoupdate 决定何时刷新客户端,然后插件下载新的客户端代码和资产,然后 reload 刷新页面以开始使用它们。

它采取的步骤是什么?

我们可以更详细地分解一下

  • 每当服务器认为客户端可能已更改时,它都会计算整个客户端捆绑包的哈希值
  • 它会 发布 此哈希值到所有客户端
  • 客户端订阅此发布
  • 当新的哈希值到达时,每个客户端都会将其与自己的哈希值进行比较
  • 如果不同,它将开始下载新的客户端捆绑包
  • 完成后,客户端会保存任何数据并宣布它将重新加载
  • 应用程序和包有机会 保存其数据或拒绝重新加载
  • 如果/何时允许,它将重新加载

如何监视它?

要找出问题出在哪里,我们可以记录 HCP 采取的各种步骤。

首先,请确保您可以 查看客户端日志(或将它们打印在应用程序的某个屏幕上)。

一些更有用的值要打印,以及要监听的事件,可能是

  • 版本哈希:__meteor_runtime_config__.autoupdate.versions['web.cordova']

  • 反应式 Autoupdate.newClientAvailable():如果这变成 true 然后没有刷新,则表示客户端确实收到了新版本,但尝试下载或应用它时出现问题。

Tracker.autorun(() => {
  console.log(‘new client available:’, Autoupdate.newClientAvailable());
});
  • 要检查客户端对新版本的订阅,请检查 Meteor.default_connection._subscriptions。例如,要记录订阅是否 readyinactive(使用 lodash)
const { ready, inactive } = _.chain(Meteor)
  .get('default_connection._subscriptions', {})
  .toPairs()
  .map(1)
  .find({ name: 'meteor_autoupdate_clientVersions' })
  .pick(['inactive', 'ready']) // comment this to see all options
  .value();
console.log(‘ready:’, ready);
console.log(‘inactive:’, inactive);

或者,每次订阅更改时记录 ready 的值

const hcpSub = _.chain(Meteor)
  .get('default_connection._subscriptions', {})
  .toPairs()
  .map(1)
  .find({ name: 'meteor_autoupdate_clientVersions' })
  .value(); // no .pick() this time; return whole subscription object

Tracker.autorun(() => {
  hcpSub.readyDeps.depend(); // Rerun when something changes in the subscription
  console.log('hcpSub.ready', hcpSub.ready);
});

应打印 false,然后在一秒钟内打印 true

  • 要查看我们是否完成了下载和准备新版本,请监听 WebAppLocalServer.onNewVersionReady
WebAppLocalServer.onNewVersionReady(() => {
  console.log('new version is ready!');
  // Copied from original in autoupdate/autoupdate_cordova.js because we overwrite it
  if (Package.reload) {
    Package.reload.Reload._reload();
  }
});
  • 要查看是否正在请求重新加载权限,请监听 Reload._onMigrate()。请务必返回 [true],否则重新加载可能不会发生。(我相信如果这在您的应用程序代码中运行,则表示所有包都允许重新加载。但我没有找到我的来源。)
Reload._onMigrate(() => {
  console.log('going to reload now');
  return [true];
});
  • 要知道 Meteor.startup 的运行是否是 HCP 重新加载的结果,我们可以利用 Session(如 ReactiveDict)会保留的事实。
Meteor.startup(() => {
  console.log('Was HCP:', Session.get('wasHCP'));
  Session.set('wasHCP', false);

  Reload._onMigrate(() => {
    Session.set('wasHCP', true);
    return [true];
  });
});

如何编辑源代码

最后,如果您想在本地更改一些包和插件代码,可以这样做。

编辑包

假设我们要编辑 autoupdate 包。

在项目的根目录中,创建一个名为 packages 的文件夹,然后添加一个名为 autoupdate 的文件夹。在这里,我们放置来自原始包的代码(位于 ~/.meteor/packages 中),然后对其进行编辑。

Meteor 现在将使用本地版本而不是官方版本。

编辑插件

要安装插件的修改版本,

Meteor 将开始使用本地版本而不是官方版本。但请注意,每次更改插件时,您都需要重新运行 meteor buildmeteor run

发现错误了吗?

如果您在某个软件包或插件中发现了错误,请随时打开一个问题和/或拉取请求

在 GitHub 上编辑
// 搜索框