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





5.00/5 (2投票s)
如何将更新推送到生产环境中的 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,然后它将自动将应用更新推送到设备并进行安装。这个选项非常安全可靠。但是,它也有一些缺点。
- 有一个特殊的注册流程,可能很耗时。我猜想现在已经有所改进,但我花了几个星期才获得批准。
- 后台应用程序需要额外的发布工作,因为每个后台应用程序都需要一个特殊的空的前台 UWP 应用,开发者必须将其提交到商店(请参阅无头应用的特殊说明)。
- 同时发布多个依赖应用作为一个包很难实现。
- 更新需要审批流程,而且在审批之后,可能需要长达 24 小时才能推送到设备。
侧载更新
如果你需要完全控制部署过程,例如要确保多个依赖包按特定顺序升级,那么还有一个额外的选项。你可以使用 PackageManager
API 和允许侧载应用更新的特殊 .appxmanifest 权限来管理你自己的应用部署。当然,你需要一个服务器来托管你的应用更新文件,并通知你的客户端有可用的更新。然后,你创建一个后台 UWP 应用,该应用监视你的服务器,并在检测到更改时下载并安装包。
虽然此选项具有更多控制的优点,但请牢记以下缺点:
- 手动编写侧载代码会增加你应用的攻击面。
- 你将不得不维护一个专用的服务器和 SSL 证书。
- 它可能更脆弱,因为整个过程可能会中断,如果你的 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 上给我发消息。