Angular7:服务工作者未按预期运行

Angular7: Service worker does not function as expected

我有一个 angular service worker 并且我缓存了声音(mp3 文件)以便可以离线播放。这是 ngsw-config-json:

{
  "index": "/index.html",
  "assetGroups": [{
    "name": "app",
    "installMode": "prefetch",
    "resources": {
      "files": [
        "/favicon.ico",
        "/index.html",
        "/*.css",
        "/*.js",
        "/*.svg",
        "/*.eot",
        "/*.woff",
        "/*.woff2",
        "/*.tff"
      ]
    }
  }, {
    "name": "assets",
    "installMode": "prefetch",
    "updateMode": "prefetch",
    "resources": {
      "files": [
        "/assets/sounds/character1/**",
        "/assets/sounds/character2/**"
      ]
    }
  }]
}

在我的网络应用程序中,声音是这样播放的:

let audioLink = `/assets/sounds/${character}/${soundURL}`;
let player = new Audio(audioLink);
player.play()

该网站离线工作。 HTML、CSS、JS、JSON 文件都在缓存中。但是声音不播放(当我尝试播放时,出现上面显示的错误)。

在 Chrome 开发人员工具 > Application > Cache 中,我可以看到有一些声音(路径),但不是全部。但是 none 正在离线工作。

有时会出现这些错误:

有时也说 manifest.json 有问题,但在线时在开发者工具的清单部分显示没有问题。

这个问题有什么解决办法吗?这不是 Chrome 错误,因为我在 Safari 和 Firefox 中也看到了相同的行为。我知道新 chrome 版本中有一个错误,由于这个错误,favicon.ico 没有显示为离线

不确定这是否有帮助,但 here 是托管 Web 应用程序的 link。如果您在 Chrome 开发人员工具中看到网络选项卡,您可以看到 mp3 文件是 'downloading',但它们不能离线播放。

生成用于生产的网站 (ng build --prod --base-href="/") 后,我查看了 ngsw.json,这是我看到的(删除了一些行):

{
  "name": "assets",
  "installMode": "prefetch",
  "updateMode": "prefetch",
  "urls": [
    "/assets/sounds/character1/sound one.mp3",
    "/assets/sounds/character1/sound two.mp3",
    "/assets/sounds/character2/sound three.mp3"
    "/assets/sounds/character2/sound four.mp3"
  ],
  "patterns": []
}

Here 是完全生成的 ngsw.json。一切都已设置为预缓存而不是延迟缓存。

并且所有这些资产 URL 也在 "hashTable" 对象中。我还看到它们在 chrome 开发人员工具(开发人员工具 > 网络)中下载,但我只在应用程序缓存部分看到其中一些(可能是总共 150 个中的前 20-30 个)。

我在这里做错了什么?这可能是 Angular 7 错误吗?我已经看到关于类似问题的各种其他 Whosebug 和 Reddit 问题。

我试过的东西正在改变

let audioLink = `/assets/sounds/${character}/${soundURL}`;

let audioLink = `assets/sounds/${character}/${soundURL}`;

(删除了开头的斜杠),但这并没有什么不同。

我完全确定所有声音文件路径都是正确的,因为当网站 运行 在线时绝对没有错误。

除上述之外,我尝试手动更改所有网址并在应该是 space 的地方插入 %20。例如,将 "/assets/sounds/character1/sound one.mp3" 更改为 "/assets/sounds/character1/sound%20one.mp3",但这也不起作用。

我注意到的一件事是,如果您是第一次访问该网站,并等待所有声音下载,然后无关紧要,关闭您的互联网连接并试用该网站,所有声音都有效.但只有一段时间,通常在 10-15 分钟左右,然后它们就会停止工作。我已经在 Chrome、Chrome Android、Firefox、Safari 和 IOS Safari 上进行了测试。

编辑: 根据某人的建议,我尝试更改

{
  "name": "assets",
  "installMode": "prefetch",
  "updateMode": "prefetch",
  "urls": [
    "/assets/sounds/character1/sound one.mp3",
    "/assets/sounds/character1/sound two.mp3",
    "/assets/sounds/character2/sound three.mp3"
    "/assets/sounds/character2/sound four.mp3"
  ],
  "patterns": []
}

{
  "name": "assets",
  "installMode": "prefetch",
  "updateMode": "prefetch",
  "urls": [
    "/assets/sounds/**"
  ],
  "patterns": []
}

但同样的问题仍然存在:声音可能离线缓存 10-15 分钟,之后就无法离线播放。我只能在 Chrome 和 Chrome Android.

中进行测试

我已经尝试制作一个演示来隔离错误并且似乎有效。在应用程序缓存中注意到一些奇怪的 url:

不确定这是导致问题的原因。您已经提到在您使设备离线后声音有效,我猜这是浏览器缓存而不是离线缓存。 当我尝试刷新页面时,声音根本不起作用。我的猜测是 ngsw 的配置或 ngsw 缓存文件的方式与音频不兼容 class.

您可以通过先使用 @angular/common/http 获取 blob 将其传递到 Audio 来测试它是否有效。我认为这是因为音频文件似乎位于不同的缓存目录中(请参见屏幕截图)。由于某种原因,css/js 文件的存储方式似乎有所不同,音频文件只能由 angular.

访问(离线)

作为回复发布,因为评论太长了

我在@codeninja 的帮助下找到了问题的答案。

首先,audioLink 必须直接 link 声音。我在 Github 上托管网站,所以 link 看起来像这样:

let url = `sounds/path_to_sound.mp3`
let audioLink = `https://raw.githubusercontent.com/username/repo_name/master/assets/sounds/${url}`;

其次,我们不能只使用 sound.play()Audio() 方法,我们必须使用 HttpClient 检索音频。我不确定具体原因,但 codeninja 建议 ngsw 缓存文件的方式与 Audio class 不兼容。我不确定这是否属实,但我发现在离线时,我不得不使用 HttpClient 来检索音频 blob(如下所示)。否则,您会收到 response not Ok 错误。即使我直接给出 link https://raw.githubusercontent.com/username/repo_name/master/assets/sounds/direct.mp3,它也会抛出同样的错误。

总而言之,代码如下所示:

首先有一个getSound()函数:

getSound(url) {
  return this.http.get(url, {responseType: 'blob'});
}

然后在另一个函数(playSound(url))中,我们有这个:

playSound(url) {
  let audioLink = `https://raw.githubusercontent.com/username/repo_name/master/assets/sounds/${url}`;

  this.getSound(audioLink)
    .subscribe(data => {
      console.log(data);
      // data is an audio blob
      let url = URL.createObjectURL(data);

      let sound = document.createElement('audio');
      sound.src = url;
      sound.play();
    })
}

此外,我还必须更改 ngsw-config.json。我只更改了 "assets" 部分,所以我将展示:

{
  "name": "assets",
  "installMode": "lazy",
  "updateMode": "prefetch",
  "resources": {
    "files": [
    ],
    "urls": [
       "https://raw.githubusercontent.com/username/repo_name/master/assets/sounds/**"
    ]
  }
}

我也无法让它与 "prefetch" 一起工作。虽然缓存的声音现在可以离线播放,但它们只会在之前播放过的情况下播放,因为它被设置为 "lazy".

我在 Chrome、Chrome Android 和 Firefox 上测试了这个解决方案,它工作正常。