1. 程式人生 > >JavaFX本地應用自動更新功能的實現——FXLauncher

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啟動程式。














           

再分享一下我老師大神的人工智慧教程吧。零基礎!通俗易懂!風趣幽默!還帶黃段子!希望你也加入到我們人工智慧的隊伍中來!https://blog.csdn.net/jiangjunshow