我应该如何实现自动更新程序?


71

许多程序都包含一个自动更新程序,该程序有时会在网上查找更新,然后下载并应用找到的所有更新。程序错误已修复,支持文件已修改,并且(通常)情况有所改善。

不幸的是,无论我多么努力,在任何地方都找不到有关此过程的信息。似乎已实施的自动更新程序是专有的,或者不重要。

实施在网络上查找更新并下载更新的系统似乎相当容易。自动更新的该部分将在实现之间发生重大变化。问题是应用补丁的不同方法是什么?只是下载文件并用新文件替换旧文件,运行已下载的迁移脚本,对系统的某些部分进行猴子修补等?概念是优选的,但是将理解Java,C,Python,Ruby,Lisp等中的示例。


6
我一直在看谷歌的奥马哈。如果您仍然有兴趣(4年后..)
看看吧

Answers:


53

我认为“不可知的语言”将成为一个限制因素。应用程序的形状和大小是如此之多,以至于无法解决所有问题。我已经用几种语言实现了几个自动更新器,没有两个是相似的。

最一般的哲学是,应用程序会检查一些家庭位置(网址,网络查询,公司网络位置等),以询问其当前版本,或询问最新版本。如果答案需要更新,则每种情况下的处理过程都会有所不同。

一种流行的替代方法是在应用程序启动时邀请家庭位置运行脚本。脚本可以检查版本,必要时下载更新,并询问使用情况反馈。

如果您缩小参数范围,我们可能会更好地提供帮助。

更新:“修补”的方法还取决于应用程序的性质,并且这里有非常广泛的多样性。例如,如果您只有一个可执行文件,那么替换可执行文件可能是最实际的。如果您的应用程序包含许多文件,则应寻找减少替换文件数量的方法。如果您的应用程序是高度定制的或参数化的,则应努力减少重新定制工作。如果您的应用程序使用解释后的代码(例如Excel VBA应用程序或MS Access MDB应用程序),则您可以替换部分代码。在Java应用程序中,您可能只需要替换JAR文件,甚至是JAR内容的子集。您还需要一种识别当前客户端版本并适当更新的方法。我可以继续下去,但我希望你能看到我关于多样性的观点。这是最佳答案通常以“嗯,取决于...!”开头的许多次之一。这就是为什么这么多答案都包括“请缩小参数范围”的原因。


20

确保还考虑吸收有关更新的信息以及更新二进制文件本身的安全性。

您信任下载源吗?您可能打电话回家获取更新,但是如果中间有人重定向到恶意服务器该怎么办。HTTPS或类似的安全连接会有所帮助,但建议您使用数字签名检查仔细检查最终下载的位。


8

首先,您需要在应用程序主页网站上找到最新版本的文件。我认为最好的方法是为此任务准备一个特殊的SQL表,并在发布新版本/每晚构建完成后自动填充它。您的应用程序创建了新线程,该线程请求带有版本的内置http链接并与当前线程进行比较。在.NET中,可以使用如下代码:

Version GetLatestVersion() {
HttpWebRequestrequest = (HttpWebRequest)WebRequest.Create(new Uri(new Uri(http://example.net), "version.txt));
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
if (request.HaveResponse)
{
  StreamReader stream = new StreamReader(response.GetResponseStream(), Encoding.Default);
  return new Version(stream.ReadLine());
}
else
{
  return null;
}
}

Version latest = GetLatestVersion();
Version current = new Version(Application.ProductVersion);
if (current < latest)
{
  // you need an update
}
else
{
  // you are up-to-date
}

在此示例中,version.php仅包含一个简单的字符串,如1.0.1.0。

我可以提供的另一个提示-如何下载更新。我非常喜欢下一个想法:在应用程序的资源中,有一串CLR代码,您可以即时(使用CodeDom)将其编译到一个临时文件夹中,主应用程序将其调用并关闭。Updater读取参数,设置或注册表并下载新模块。并调用删除所有临时文件的主应用程序。做完了!

(但是这里的所有内容都是关于.NET的)


6

最简单的解决方案(由许多程序使用)正在运行旧版本的卸载程序,并运行新版本的安装程序(可选地跳过用户已经回答的问题,例如EULA)。唯一的问题是新版本必须能够从旧版本读取配置选项。

另外,在Windows上,您无法删除正在使用的可执行文件,因此您可能需要在Temp文件夹中删除一个小的可执行文件,该文件夹将运行整个过程,然后在新版本的实例末尾将其删除哪个启动了(或者只是注册它以便在下次重新启动时删除)。


14
当您无法删除使用中的EXE时,可以对其进行重命名-因此,让运行中的实例重命名其自身,弹出新版本,并在下次启动时检查是否存在已重命名的先前版本,然后将其删除。
奥利弗·吉森

哇,真不可思议!谢谢你的小费!
灰豹

2

最简单的方法是让程序查询服务器(网站)以查看是否有更新。如果有更新,则可以向用户显示一条消息,提示他们下载更新的版本并提供链接。

另一种更复杂的解决方案是创建一个小型Windows服务(或unix守护程序),该服务会定期检查是否有更新,该服务可以下载更新并启动安装程序。

一般的架构是,您拥有一台控制的中央服务器,该服务器知道最新版本以及在何处获取它。然后,程序查询服务器。我将不包含示例代码,因为它在服务器和您选择的格式上是高度被告。不过这并不可怕。


我要解决的问题(我已经编辑了问题以反映这一点)是如何应用补丁的?
num1

2

这并不是一个完整的答案,而是我最近实现的自动更新机制的一个示例。这种情况与传统的Firefox类型的用户应用程序有所不同,因为它是工作中使用的内部工具。

基本上,这是一个小脚本,用于管理要在安装程序中构建和打包的Subversion分支队列。它读取一个小文件,在其中写入分支的名称,获取第一个,在文件末尾重新编写,然后启动生成过程,其中涉及调用一堆脚本。每个要构建的分支的配置均写入.INI文件,该文件与工具本身一起存储在Subversion存储库中。

由于此工具可以在多台计算机上运行,​​因此我希望有一种方法可以在对工具本身或配置脚本进行更改后立即在所有计算机上自动对其进行更新。

我实现它的方式很简单:启动该工具时,它就变成了“外壳”。这个外壳做2件非常简单的事情:

  • svn update 本身和配置文件上
  • 再次启动自身,这次作为“内壳”,它实际上处理一种配置(然后再次退出)。

这个非常简单的“自我更新”系统已经为我们服务了几个月。它非常优雅,因为它是独立的:自动更新程序是程序本身。因为“外壳程序”(自动更新程序部分)是如此简单,所以它不会因为“内壳程序”(每次从更新的源文件执行)而没有从更新中受益。


仅供参考,Metasploit还使用“ svn更新”进行更新过程。
Gray Panther

2

尚未真正提到的一件事是,您应该认真考虑运行程序的用户可能实际上没有足够的特权来升级它。至少对于企业用户而言,这应该是相当普遍的,对于家庭用户而言,这种情况可能较少。

出于安全原因,我始终使用(自我施加)受限帐户进行操作,这总是让我感到恼火,因为大多数自动更新程序仅假设我以管理员身份运行,然后在下载后只是失败而无法提供其他执行方式除了实际关闭程序并在管理上下文中再次运行以外,进行更新。大多数甚至不缓存下载的更新,而必须重新做一遍。

如果自动更新程序仅在需要时提示提示管理员凭据并继续使用它,那就更好了。


1
这正是我们的更新程序所做的。wyUpdate(请参阅:wyday.com/wyupdate)是一个用C#编写的开源更新程序。
Wyatt O'Day 2010年

1

由于自动更新是一种常见情况,因此大多数语言都至少有一个软件包可用于支持此更新。(下面列出了一些可用的软件包)

真正的好主意之一是.NET的ClickOnce发行版,它是一个安装程序,可以将您的应用程序沙盒化并在用户上下文中安装,因此不需要管理员权限。您可以在发布中配置ClickOnce,以在每次启动应用程序时检查更新。

Java具有Java Web Start,它为Java小程序提供了相同的功能。

Delphi有许多有关自动更新的文章,Torry有WebUpdate组件的列表,例如GoUpdater似乎具有非常广泛的功能。

他们都使用网站/网络共享来检查新版本,然后检索补丁程序或完整的安装文件并运行它。因此,您应该尝试为您的应用程序找到一个不错的程序包,从而避免开发和维护自己的解决方案的麻烦。


1

我将假设Windows的答案。

这种方法似乎很好用。

在安装程序中执行以下操作:
1.创建一个作为LocalSystem运行的手动启动服务,启动该服务时更新将停止。
2.更改服务权限,以便所有用户都可以启动服务(如果所有用户都应能够更新无管理员权限)。
3.更改主程序,以使用简单的机制启动时检查更新。如果它检测到更新,则提示用户是否要应用它。
4.如果用户接受更新,请启动服务。

如果体系结构允许,请创建一种在更新运行时对其进行监视的方法。


1
作为LocalSystem运行的手动启动服务,所有用户都可以启动?这听起来像一场安全灾难正在等待发生。
米兰加迪安

1
仅当更新软件造成安全灾难时。除非他们可以写入服务二进制文件,否则启动服务的能力不是攻击它的能力。
约书亚

0

在Java-Webstart设置中,您将启动JNLP文件,该文件随后触发下载运行该应用程序所需的Jar文件。每次Webstart都会检查是否有较新版本的Jars,并会下载它们以替换本地缓存的Jars。使用名为jardiff的工具,您将仅创建指向较新jar的diff,并通过服务器分发它们(例如,仅获得更新)。

优点:

  • 总是最新的

缺点:

  • 您需要一个应用程序服务器(tomcat,JBoss)才能分发文件
  • 您需要互联网连接才能获取应用程序

只是指出您只需要一个Web服务器即可分发JAR。Tomcat是此类服务器之一,并且还实现了servlet规范。
卡米洛·迪亚斯·雷普卡(CamiloDíazRepka)2009年

0

阅读Carl Seleborgs的答案给了我一些想法,如何使用通用代码存储库。

svn带有一个称为svnsync的工具,该工具的行为类似于svn导出,但会跟踪您的导出所处的实际版本。

有人可以利用此系统以便仅从用户实际修订中获取更改的文件。

实际上,您将拥有一个已编译二进制文件的存储库,而运行svnsync将仅获取已修改的二进制文件。它也可能能够使用新的配置选项将本地更改合并到基于文本的配置文件中。


0

将补丁安装到程序的功能基本上是安装程序的基本功能之一。在许多地方记录了安装程序软件的文档,但通常以每个安装程序为基础:Microsoft安装程序(带有Install Shield Extensions),Ruby gemsJava .jar文件,各种Linux软件包管理器系统(RPMApt-get)和其他。

这些都是复杂的系统,通常可以解决补丁程序的问题,但对于稍有不同的系统。为了确定最适合您的系统,请考虑您的应用程序最类似于哪个系统。自己动手可以,但是查看这些系统是一个起点。


0

您可以编写应用程序的内部模块以进行更新。您可以编写一个外部迷你应用程序进行更新。

还要看一下.NET即时编译技术,它使按需即时创建这样的小型应用程序成为可能。例如,http://fly.sf.net/



0

如果您的软件是开源的,并且针对Linux或开发人员。将软件安装为git repo很有趣。并使其偶尔或每次启动时拉动稳定分支。

当通过npm,sbt,mavan,stack,elm-package或类似方式管理您的应用程序时,这特别容易。


-1

如果要搜索跨平台软件更新解决方案,请访问www.updatenode.com。

一些重点:

  • 对于开源项目免费
  • 跨平台和开源更新客户端工具
  • 已针对最重要的语言进行了本地化
  • 易于集成且易于处理
  • 基于云的管理平台,用于定义和管理更新
  • 提供额外的显示消息支持(有关新事件,产品等的信息)
  • Web界面已打开(您可以使用该服务创建自己的客户端)
  • 许多使用情况统计信息,例如使用的操作系统,地理位置,版本使用情况等。
  • 用于移动应用程序更新的Android API

就试一试吧。

顺便说一句,我是开源客户端开发团队的一员。:)


2
您是否在updatenode.com工作?因为您已经回答了几个建议的老问题。
crashmstr 2014年

我为开放源代码客户端开发做出了贡献:bitbucket.org/updatenode/unclient
萨拉哈

1
您可能应该阅读以下内容:如何在答案中提及自己的产品?
crashmstr 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.