65.9K
CodeProject 正在变化。 阅读更多。
Home

如何将更新推送到生产环境中的 Raspberry Pi UWP 应用程序

starIconstarIconstarIconstarIconstarIcon

5.00/5 (2投票s)

2018 年 5 月 27 日

CPOL

5分钟阅读

viewsIcon

7871

如何将更新推送到生产环境中的 Raspberry Pi UWP 应用程序

在现场更新 Raspberry Pi 应用可能很棘手。本文档涵盖了普遍存在的问题,并解决了一些你可能会遇到的特定侧载问题。

(重新)部署问题

设想一下,你有一个 IoT 应用,比如一个售货亭、数字标牌或温度读取器,你想将其产品化并部署到像 Raspberry Pi 这样的小型(廉价)设备上。如果你已经在使用 Microsoft 生态系统,或者你想要 BitLocker、自动更新或企业数据保护(远程擦除丢失设备的功能),那么 Windows IoT 操作系统是一个显而易见的选择(而且 Windows IoT Core 版是免费的)。

但是,一旦你开发完应用程序并准备好进行部署,你如何才能快速、一致地将你的应用程序(或者更可能是你的一组前台和后台应用程序)部署到设备上呢?更重要的是,当你有一个 bug 修复或功能增强时,你如何将其推送到现场的设备上?

初始映像

在大多数方面,Microsoft 关于构建 Windows IoT 映像的文档非常出色。安装一些必备软件后,你将使用一组提供的命令行工具来创建许多 XML 文件,这些文件共同描述了一个映像。然后,你将这些 XML 文件编译成一个多 GB 的 .ffu 映像文件,你可以使用 Windows IoT Core Dashboard 软件(或者更好的,flashsd 命令行工具)将其写入 SD 卡。

现在,你可以将新刷写好的 SD 卡插入许多 Raspberry Pi 设备中,并将它们发送到世界各地。然而,除非你是查克·诺里斯(Chuck Norris),否则你需要为这些 Raspberry Pi 设备发送 bug 修复,而逐个访问它们是不可能的。主要有两个选项:商店更新和侧载更新。

商店更新

Microsoft 允许开发者 Windows IoT 应用发布到 Microsoft Store,然后它将自动将应用更新推送到设备并进行安装。这个选项非常安全可靠。但是,它也有一些缺点。

  1. 有一个特殊的注册流程,可能很耗时。我猜想现在已经有所改进,但我花了几个星期才获得批准。
  2. 后台应用程序需要额外的发布工作,因为每个后台应用程序都需要一个特殊的空的前台 UWP 应用,开发者必须将其提交到商店(请参阅无头应用的特殊说明)。
  3. 同时发布多个依赖应用作为一个包很难实现。
  4. 更新需要审批流程,而且在审批之后,可能需要长达 24 小时才能推送到设备。

侧载更新

如果你需要完全控制部署过程,例如要确保多个依赖包按特定顺序升级,那么还有一个额外的选项。你可以使用 PackageManager API 和允许侧载应用更新的特殊 .appxmanifest 权限来管理你自己的应用部署。当然,你需要一个服务器来托管你的应用更新文件,并通知你的客户端有可用的更新。然后,你创建一个后台 UWP 应用,该应用监视你的服务器,并在检测到更改时下载并安装包。

虽然此选项具有更多控制的优点,但请牢记以下缺点:

  1. 手动编写侧载代码会增加你应用的攻击面。
  2. 你将不得不维护一个专用的服务器 SSL 证书。
  3. 它可能更脆弱,因为整个过程可能会中断,如果你的 URL 发生更改、SSL 证书过期,或者你的升级器后台应用出现问题。

Matthijs Hoekstra 在他的博文《侧载 UWP 应用的自动更新程序》中,精美地记录了一种实现此目的的方法。他的方法是通过 UWP 应用间通信机制向更新程序后台应用发送通知,该机制我在去年发表于 Visual Studio Magazine 的一篇文章中进行了描述。

如果你更喜欢由一个应用程序同时监视更改和安装更新,从而将所有部署职责隔离到一个应用程序中,那么你可能想看看 SirenOfShame.Uwp.Maintenance 项目,它是 Siren of Shame UWP App 的一部分。如果你查看该代码,你会发现我将应用程序下载到一个临时目录(可能是新的 UWP 要求),提供了大量的日志记录,并使用证书固定来提高安全性。我设计该项目时使其足够通用,你可以将其复制粘贴到新项目中,只需进行少量更改。

无论如何,如果你将侧载和映像创建结合起来,很可能会遇到问题。以下是我发现的一些问题和解决方案。

问题

包更新失败

ErrorCode = -2147009293
System.Runtime.InteropServices.COMException (0x80073CF3):
Package failed updates, dependency or conflict validation.

当你在映像中包含 appx 而不是 appxbundle 时,会出现此错误。在 Lab 1b 的第 4 步中,他们告诉你“生成应用包:否”时,包含 appx 就是他们告诉你的做法。问题在于,如果你最初安装的是 appxbundle,那么你只能侧载 appxbundle。为了解决这个问题,请忽略这些说明,在生成要包含在映像中的应用时,将“生成应用包”设置为“始终”。运行 newAppxPkg 命令时,你可以直接引用你的 appxbundle 而不是 appx,之后一切都与之前完全相同。

移除失败

ErrorCode = -2147009286
System.Runtime.InteropServices.COMException (0x80073CFA): Removal failed. 
Please contact your software vendor.

如果你尝试通过 PackageManager.RemovePackageAsync() 卸载一个已作为 appx 包含在映像中的包,就会出现此错误。相反,在构建映像时,请始终包含 appxbundle 而不是 appx(参见上文)。

安装失败

ErrorCode = -2147009287
System.Runtime.InteropServices.COMException (0x80073CF9): Install failed. 
Please contact your software vendor.

如果你尝试通过 .UpdatePackageAsync() 来侧载一个最初包含在映像中,但随后又通过 Visual Studio 的 F5 部署覆盖的应用程序,就会出现此错误。解决方案是在调用 .UpdatePackageAsync() 的地方放置一个 try/catch 块,如果出现 COMException,则尝试先卸载再安装。

摘要

我花了无数个小时才弄清楚这个过程,我希望这份文档能为别人节省一些时间。如果能帮助到你,请在评论中分享你的 IoT 部署经验,或者在 @lprichar 上给我发消息。

© . All rights reserved.