JavaFX本地应用自动更新功能的实现——FXLauncher

看了官方的demo,还是研究了好久才实现了此功能。描述实在是太简单了。

参考地址:fxldemo    fxlauncher  JavaFX本地应用自动更新功能的实现——FXLauncher

在看了那些参考资料后,感觉还是无从下手。资料上说主要是以下几个步骤:

1.FXLauncher的使用步骤

1)编译项目JAR到app.dir

2)复制依赖包到app.dir

3)生成app.xml manifest

4)创建本地安装器

5)上传artifact到自动更新仓库

没有具体的步骤,只能研究fxldemo和fxlauncher的源码了。经过昨天12个小时的编译调试,终于实现了该功能。把实现该功能的步骤详细记录以下。

实现该功能后,回过头来看官方给的步骤就比较好理解了。其实步骤中最关键的地方就是  生成app.xml manifest 。

只要能搞定app.xml和理解fxlauncher是个什么东东就好办了。

下面是我的具体步骤:

2. 打开我的javafx项目MyBrowser

(就是该javafx要实现自动更新功能。可以参考例子fxldemo)。

此时项目应该是一个可以编译运行的应用了,只是没有自动更新功能。现在就是要在此基础上实现该功能。

MyBrowser项目是按照javafx入门教程创建的,项目项目和运行使用的是ant,和fxldemo使用的maven不一样,所以需要根据fxldemo中的pom.xml修改对应的build.xml。

3. 修改build.xml。这个是重点。

先把修改后的build.xml文件贴出来:

<?xml version="1.0" encoding="UTF-8"?>
	<project name="AddressApp" default="create-app-xml" basedir="."  xmlns:fx="javafx:com.sun.javafx.tools.ant">
		<property name="java.jdk.home" value="H:\Program Files\Java\jdk1.8.0_112" />
		<property name="appName" value="MyBrowser" />
		<property name="vendor" value="MyBrowser.pelin" />
		<property name="mainClass" value="application.Main" />

		<property name="app.url" value="http://10.100.1.240:8089/" />
		<property name="app.cacheDir" value="USERLIB/${appName}" />

		<property name="app.dir" value="${basedir}\dist" />
		<property name="app.installerdir" value="${basedir}\deploy\bundles" />
		<!-- Should the client downgrade if the server version is older than the local version? -->
		<property name="app.acceptDowngrade" value="true" />
		<!-- Optional parameters to the application, will be embedded in the launcher and can be overriden on the command line -->
		<property name="app.parameters" value="--myOption=myValue --myOtherOption=myOtherValue" />

		<echo message="basedir: ${basedir}" />
		<echo message="app.dir: --cache-dir=${app.cacheDir}" />
		<echo message="java.home:${java.home}" />
		<echo message="java.jdk.home:${java.jdk.home}" />
	<target name="init-fx-tasks">
		<path id="fxant">
			<filelist>
				<file name="${java.jdk.home}\lib\ant-javafx.jar"/>
				<file name="${java.jdk.home}\jre\lib\ext\jfxrt.jar"/>
				<file name="${basedir}"/>
			</filelist>
		</path>

		<taskdef resource="com/sun/javafx/tools/ant/antlib.xml"
			uri="javafx:com.sun.javafx.tools.ant"
			classpathref="fxant"/>
	</target>

	<target name=‘do-compile‘>
		<delete dir="build" />
		<mkdir dir="build" />
		<mkdir dir="build/classes" />

		<javac includeantruntime="false" source="1.8" target="1.8" srcdir="${basedir}/../src" destdir="build/classes" encoding="GBK">
			<classpath>
				<fileset dir="${basedir}/../lib">
					<include name="**/*"/>
				</fileset>
			</classpath>
		</javac>

		<!-- Copy over none Java-Files-->
		<copy todir="build/classes">
			<fileset dir="${basedir}/../src">
				<exclude name="**/*.java"/>
			</fileset>
		</copy>

		<!-- Copy xml-Files -->
		<copy todir="build/classes">
			<fileset dir="${basedir}/../config">
				<filename name="**"/>
			</fileset>
		</copy>

	</target>
	<target name="do-deploy" depends=" do-compile, init-fx-tasks">
		<delete dir="dist"/>
		<delete dir="deploy" />

		<mkdir dir="dist" />

		<copy todir="dist">
			<fileset dir="${basedir}\..">
				<filename name="**"/>
				<exclude name=".settings/**" />
				<exclude name="bin/**" />
				<exclude name="build/**" />
				<exclude name="src**" />
				<exclude name=".classpath" />
				<exclude name=".project" />
				<exclude name="build.fxbuild" />
			</fileset>
		</copy>

		<fx:resources id="appRes">
			<fx:fileset dir="dist" includes="${appName}.jar"/>
			<fx:fileset dir="dist" includes="lib/**"/>
		</fx:resources>
		<!---->
		<fx:resources id="appRes2">
			<fx:fileset dir="dist" includes="${appName}.jar"/>
			<fx:fileset dir="dist" includes="**"/>
		</fx:resources>

		<fx:application id="fxApplication"
			name="${appName}"
			mainClass="${mainClass}"
			version="1.0"
		/>

		<!--<mkdir dir="build/classes/META-INF" /> -->

		<fx:jar destfile="dist/${appName}.jar">
			<fx:application refid="fxApplication"/>
			<fileset dir="build/classes">
			</fileset>
			<fx:resources refid="appRes"/>

			<manifest>
				<attribute name="Implementation-Vendor" value="${vendor}"/>
				<attribute name="Implementation-Title" value="${appName}"/>
				<attribute name="Implementation-Version" value="1.0"/>
				<attribute name="JavaFX-Feature-Proxy" value="None"/>
			</manifest>
		</fx:jar>

		<echo message="开始部署" />
		<mkdir dir="deploy" />
		<!-- Need to use ${basedir} because somehow the ant task is calculating the directory differently
		<fx:deploy
			embedJNLP="false"
			extension="false"
			includeDT="false"
			offlineAllowed="true"
			outdir="${basedir}/deploy"
			outfile="${appName}" nativeBundles="exe"
			updatemode="background" >

			<fx:platform basedir="${java.jdk.home}"/>
			<fx:info title="${appName}" vendor="${vendor}"/>

			<fx:application refId="fxApplication"/>
			<fx:resources refid="appRes2"/>
		</fx:deploy>
	-->
	</target>
	<target name="create-app-xml"  depends=" do-deploy">
		<path id="lib_classpath">
			<filelist>
				<file name="${basedir}\..\lib\fxlauncher.jar"/>
			</filelist>
			<fileset dir="${java.home}">
	            <include name="**/*.jar"/>
	        </fileset>
	    </path>

		<java classname="fxlauncher.CreateManifest"   classpathref="lib_classpath">
			<arg value="${app.url}"/>
			<arg value="${mainClass}"/>
		 	<arg value="${app.dir}"/>
			<arg value="--cache-dir=${app.cacheDir}"/>
			<arg value="--accept-downgrade=${app.acceptDowngrade}"/>
			<!--jar文件类型是默认的,其他的类型使用逗号分割.大小写不敏感,大小写不匹配也会加载进去-->
			<arg value="--include-extensions=Java,dll,properties"/>
			<arg value="${app.parameters}"/>
		</java>
	</target>
</project>

主要修改的地方:

① default="do-deploy"  改为了 default="create-app-xml"。

② 添加了一个新的target,即<target name="create-app-xml"  depends=" do-deploy">。

③ 前面定义create-app-xml任务需要的相关参数。

④ 在项目的lib目录下添加fxlauncher.jar包。

其中相关参数说明:

${app.url} : 就是app.xml中的  http://10.100.1.240:8089/,该参数是必须的

${mainClass}:application.Main,这个是我们javafx项目的入口类。即我们项目运行时main方法所在的类。该参数是必须的

${app.dir}: F:\eclipseworkJavaFX\MyBrowser\build\dist,这个是fxlauncher要遍历的文件目录,fxlauncher会遍历该目录下所有文件然后在app.xml中添加相应的记录(根据配置的--include-extensions=Java,dll,properties,所以遍历时只把*.java,*.dll,*.propertiers类型文件添加到app.xml中)。该参数是必须的

${app.cacheDir}:   USERLIB/MyBrowser, 这个非必须。

${app.acceptDowngrade}: 例子上写的是false,具体有什么用还没研究。 这个非必须。

${app.parameters}: --myOption=myValue --myOtherOption=myOtherValue ,这个非必须。

fxllauncher.jar工具提供了一个CreateManifest类。该类输入相关参数可以创建app.xml。

fxlauncher.CreateManifest 大概需要了解的暂时这些就够了。

4. ant运行新增的任务后,生成以下格式的app.xml文件。

理解app.xml是做什么的很重要。

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Application ts="1491906975319" uri="http://10.100.1.240:8089/" launch="application.Main">
    <lib file="config/config.properties" checksum="785530472" size="164"/>
    <lib file="lib/jshortcut-0_4.jar" checksum="109661545" size="85955"/>
    <lib file="lib/jshortcut.dll" checksum="1759411124" size="58368"/>
    <lib file="MyBrowser.jar" checksum="3533345451" size="8774"/>
    <lib file="src/application/Main.java" checksum="972920204" size="1940"/>
    <lib file="src/application/util/ConfigUtil.java" checksum="1261655196" size="1071"/>
    <lib file="src/application/util/DialogUtil.java" checksum="3703146705" size="432"/>
    <lib file="src/application/util/PathUtil.java" checksum="15328486" size="1965"/>
    <lib file="src/application/util/ShortcutUtil.java" checksum="3757256008" size="3870"/>
    <lib file="src/application/view/RootLayoutController.java" checksum="3654994656" size="1514"/>
    <updateText>Updating...</updateText>
    <updateLabelStyle>-fx-font-weight: bold;</updateLabelStyle>
    <progressBarStyle>-fx-pref-width: 200;</progressBarStyle>
    <wrapperStyle>-fx-spacing: 10; -fx-padding: 25;</wrapperStyle>
    <parameters>--myOption=myValue --myOtherOption=myOtherValue</parameters>
    <cacheDir>USERLIB/MyBrowser</cacheDir>
    <acceptDowngrade>true</acceptDowngrade>
    <lingeringUpdateScreen>false</lingeringUpdateScreen>
</Application>

Application 标签

ts属性:这个是该app.xml文件生成的时间long值。fxlauncher判断是否需要远程同步本地的app.xml。当远程服务器(即自动更新仓库)上的app.xml中ts如果比本地的要大,则远程下载app.xml到本地。具体本地所在位置即cacheDir配置中的位置,我的是H:\Users\Pelin\AppData\Local\MyBrowser\application.Main.xml

uri属性:远程服务器访问地址。

launch属性:本地应用MyBrowser的入口类mainClass。

lib标签

file属性:和前面的uri组合成文件下载地址,从改地址下载文件后覆盖或者新增到本地,从而实现本地应用的更新。如:

http://10.100.1.240:8089/config/config.properties      http://10.100.1.240:8089/MyBrowser.jar 等

所以要实现本地应用自动更新,以上地址必须能正常下载文件才行(这个自动更新仓库项目部署之后再说)

checksum和size属性:size属性容易理解,就是文件的大小,checksum 我没仔细看,但是fxlauncher会根据这2个属性判断本地对应的文件是否是最新的,如果不是则会从服务器下载最新的。需要注意的是:这个和前面的ts比较后,同步app.xml没有关系,即使app.xml不需要更新,但是这2个参数和本地文件不匹配的话也会去服务器上同步更新的。比如手动改了app.xml文件中的size属性,导致其和本地的文件不一致,fxlauncher会每次启动都去服务器中同步,所以一般不要手动修改lib标签的checksum和size属性。

cacheDir标签

<cacheDir>USERLIB/MyBrowser</cacheDir>

该标签下的路径表示的是fxlauncher从远程服务器上下载文件后所存放的位置。USERLIB通过fxlauncher的解析,在win 7下真正目录为:

H:\Users\Pelin\AppData\Local

H表示是的操作系统盘。我的操作系统在H盘,所以是H,如果操作系统在C盘,那下载后的文件应该是放到了C盘。

5. 把app.xml文件压缩到fxlauncher.jar中。

前面都搞定了,接下来就比较简单了。

fxldemo中使用了maven的插件功能,配置了app.xml文件压缩到jar中。我运行demo时提示报错,说可能和我的系统不兼容,总是压缩不成功。我的是win7 32位系统。不知道是因为win7和linux系统的原因还是32位和64位系统的原因。研究了2个小时,没搞定,先不管了。

简单粗暴的解决办法:直接手动使用winRAR打开方式打开jar,然后把app.xml文件拖入jar。

反正就是操作一次,以后发布时不用再次压缩,就是一次操作,别整那么复杂了。

6.配置自动更新仓库服务器。

这个简单弄了下,先测试通过就行。

服务器ip:10.100.1.240。然后在该服务器上配置tomcate 8,其端口号改为8089。如果使用默认8080的话,那前面的配置对应改为8080.生成的app.xml中uri也是使用8080.

总之tomcate启动端口和app.xml中uri中的端口一致就好。

7.将编译打包好的应用发布的服务器。

我的项目build.xml中配置编译后程序目录在${basedir}\dist  即 F:\eclipseworkJavaFX\MyBrowser\build\dist。

把该目录下所有文件都拷贝到服务器上的%tomcate_home%webapps/root目录下。(%tomcate_home%表示tomcate安装目录)

8.发布你的应用程序。

现在可以发布你的应用程序了,只要把压缩了app.xml的fxlauncher.jar发布,用户下载fxlauncher.jar后运行会自动下载程序到本地。下载完成后会自动启动应用。

下面是启动后界面:

9. 应用更新后发布到服务器。

编译运行项目。即使用ant运行build.xml。将dist目录下所有文件拷贝到tomcate的root目录下,相同文件也覆盖。

这样用户再次打开之前的fxlauncher.jar就会自动更新本地应用了。大功告成!!

这样本地应用自动更新功能就实现了。这个应该适应所有的jar程序吧,不一定非得javafx。fxlauncher只是根据app.xml下载更新文件,并根据mainClass启动程序。

时间: 2024-11-06 02:16:55

JavaFX本地应用自动更新功能的实现——FXLauncher的相关文章

JavaFX本地应用自动更新功能的实现FXLauncher

JavaFX本地应用自动更新功能的实现--FXLauncher 作者:chszs,未经博主允许不得转载.经许可的转载需注明作者和博客主页:http://blog.csdn.net/chszs 一.Javapackager介绍 JavaFX已经成为构建现代桌面应用最好的UI框架之一,但是它一直存在部署不方便的问题.Javapackager工具就是针对这个问题的解决方案,正如同JavaFX已经打包进JDK 8中,Javapackager工具也随同JDK 8一同提供. Javapackager工具使得

JavaFX本地应用自己主动更新功能的实现FXLauncher

JavaFX本地应用自己主动更新功能的实现--FXLauncher 作者:chszs,未经博主同意不得转载.经许可的转载需注明作者和博客主页:http://blog.csdn.net/chszs 一.Javapackager介绍 JavaFX已经成为构建现代桌面应用最好的UI框架之中的一个.可是它一直存在部署不方便的问题. Javapackager工具就是针对这个问题的解决方式,正如同JavaFX已经打包进JDK 8中,Javapackager工具也随同JDK 8一同提供. Javapackag

简单实现安卓app自动更新功能

一般的安卓app都有自动更新功能,实现app的更新,以让用户体验新版本的功能,这里也是项目中用到的,今天就来总结一下,代码应该有点多,还请耐心点哈. 安卓应用实现自动更新比较简单,这里跟大家介绍下: 第一步 服务器端: 服务端提供一个借口,或者网址,我这里就用的服务器是tomcat,这里提供一个网址如下: //也就是一个json数据接口 public static final String UPDATE_URL = "http://192.168.1.103:8080/update.json&q

WinForm应用程序中实现自动更新功能

WinForm应用程序中实现自动更新功能 编写人:左丘文 2015-4-20 近来在给一客户实施ECM系统,但他们使用功能并不是我们ECM制造版提供的标准功能,他们要求对系统作一些定制功能,为了避免因程序的bug而带来频繁让用户更新程序的不良影响,就想给ECM增加一个winform自动更新功能,今天在这里,我想与大家一起分享代码,在此做个小结,以供参考.有兴趣的同学,可以一同探讨与学习一下,否则就略过吧.   1. 首先我们在这里先分析一下其它程序猿的一些基本情况: 相信有许多程序猿都喜欢用Wi

Android应用自动更新功能的实现!!!

自动更新功能的实现原理,就是我们事先和后台协商好一个接口,我们在应用的主Activity里,去访问这个接口,如果需要更新,后台会返回一些数据(比如,提示语:最新版本的url等).然后我们给出提示框,用户点击开始下载,下载完成开始覆盖安装程序,这样用户的应用就保持最新的拉. 为了让大家容易理解,我像往常一样准备一个小例子,这里为了方便我就省去了和后台交互部分了.步骤分别如下: 第一步:新建一个Android工程命名为:UpdateDemo.代码结构如下图所示: 第二步:新建一个UpdateMana

Android应用自动更新功能的代码实现

由于Android项目开源所致,市面上出现了N多安卓软件市场.为了让我们开发的软件有更多的用户使用,我们需要向N多市场发布,软件升级后,我们也必须到安卓市场上进行更新,给我们增加了工作量.因此我们有必要给我们的Android应用增加自动更新的功能. 既然实现自动更新,我们首先必须让我们的应用知道是否存在新版本的软件,因此我们可以在自己的网站上放置配置文件,存放软件的版本信息: <update> <version>2</version> <name>baidu

Android 应用自动更新功能的代码

由于Android项目开源所致,市面上出现了N多安卓软件市场.为了让我们开发的软件有更多的用户使用,我们需要向N多市场发布,软件升级后,我们也必须到安卓市场上进行更新,给我们增加了工作量.因此我们有必要给我们的Android应用增加自动更新的功能. 既然实现自动更新,我们首先必须让我们的应用知道是否存在新版本的软件,因此我们可以在自己的网站上放置配置文件,存放软件的版本信息: <update> <version>2</version> <name>baidu

[转]Android应用自动更新功能的代码实现

本文转自:http://www.cnblogs.com/coolszy/archive/2012/04/27/2474279.html 由于Android项目开源所致,市面上出现了N多安卓软件市场.为了让我们开发的软件有更多的用户使用,我们需要向N多市场发布,软件升级后,我们也必须到安卓市场上进行更新,给我们增加了工作量.因此我们有必要给我们的Android应用增加自动更新的功能. 既然实现自动更新,我们首先必须让我们的应用知道是否存在新版本的软件,因此我们可以在自己的网站上放置配置文件,存放软

Android 云服务器的搭建和友盟APP自动更新功能的实现

setContentView(R.layout.activity_splash); //Bmob SDK初始化--只需要这一段代码即可完成初始化 //请到Bmob官网(http://www.bmob.cn/)申请ApplicationId,具体地址:http://docs.bmob.cn/android/faststart/index.html?menukey=fast_start&key=start_android Bmob.initialize(this, Constant.BMOB_APP