# 讓開發自動化: 使用基于向導的安裝程序
_使用 IzPack 生成 GUI 安裝程序_
對于大多數用戶來說,安裝軟件常常是一件痛苦的事情。生成安裝包是軟件開發的 “最后一步”,但它可能導致不同的結果:要么用戶采用軟件,要么它就成為無人問津的垃圾品。在本期的 [_讓開發自動化_](http://www.ibm.com/developerworks/cn/java/j-ap/)中,自動化專家 Paul Duvall 演示了如何使用免費、開源的工具 IzPack 來編寫為您的用戶安裝軟件的基于向導的安裝程序。
在我職業生涯的大部分時間里,我參與了軟件開發的整個生命周期 —不僅設計軟件的需求、設計、開發和測試,還涉及部署、構建管理、文檔編制和安裝等活動。最近,隨著敏捷開發越來越流行,這些活動可能會更加規范。然而,我在敏捷項目方面的經驗表明,有效的部署和安裝并沒有受到同等的重視。這很滑稽,因為如果潛在用戶不能輕松地安裝您的軟件,那么您很可能會失去他們。提供一種簡單的方式來安裝您的軟件,這對于吸引和留住用戶至關重要。
## 關于本系列
作為開發人員,我們致力于為用戶自動化流程;但許多開發人員疏忽了自動化我們自己的開發流程的機會。為此,我們編寫了 [_讓開發自動化_](http://www.ibm.com/developerworks/cn/java/j-ap/)系列文章,專門探討軟件開發流程自動化的實踐應用,為您介紹 _何時_以及 _如何_成功應用自動化。
這些年來,我使用過很多安裝程序工具。我們團隊在今年年初開始的一個大型項目中,為了創建企業級安裝程序,必須滿足一些非常特別的需求。我們看過 Antigen、AntInstaller、Denova、install4j、InstallAnywhere、IzPack、NSIS 等工具。但是根據項目的特定需求,我們最后決定使用 IzPack,因為:
* 它可以在多種平臺上運行。我們需要支持 Windows?、Linux?和 Macintosh。
* IzPack 使用 Java?語言,而我們團隊對于這種語言有豐富的經驗。
* 它可以執行 Apache Ant 腳本。我們已經花了大量的時間為軟件部署而編寫 Ant 腳本。
* IzPack 可免費下載。
IzPack 在 2001 年已經出現。它為創建基于向導的安裝程序提供了一套豐富的特性。在本文中,我演示如何使用該工具創建安裝程序,并給出定義面板、用腳本編寫驗證器、設置資源等方面的例子。
## 下載和安裝 IzPack
## IzPack 文檔
要仔細查看的第一個子文件夾是 doc 文件夾。它包含 HTML、PDF 和 Javadoc 版本的文檔,當您查閱如何在 IzPack 中編寫腳本時,它們是您忠實的伙伴。
下載和安裝 IzPack 非常簡單。IzPack 使用 IzPack 來安裝 IzPack,這也許并不奇怪。請訪問 IzPack 網站,下載 IzPack JAR 文件(請參閱 [參考資料](#resources))。
要安裝 IzPack,必須有一個正在運行的 Java Runtime Environment(JRE)。打開命令行提示符,輸入 `java -jar IzPack-install-4.1.0.jar`,可以根據需要修改版本。
基于向導的安裝程序要求提供基本的安裝信息,比如想將 IzPack 安裝在哪里。IzPack 安裝完畢后,將得到一個可以運行的示例安裝程序。
* * *
## 修改示例腳本
IzPack 提供了一套完整的示例安裝腳本。以它們為基礎編寫自己的安裝程序,這是獲得一個可運行的安裝程序的最快方法。安裝 IzPack 的根目錄下有一些子目錄,包括 bin、doc 和 lib 等。示例安裝程序在子文件夾 sample 中,實際上它包含了開發您自己的安裝程序所需的所有東西。我選擇復制這個 sample 目錄,這樣就可以隨意修改它,而不會破壞原始的內容。圖 1 顯示了 sample 目錄的內容:
##### 圖 1\. IzPack 文件的文件列表

下面是對圖 1 中列出的每個文件的描述:
* **antActionSpec.xml**:執行與構建相關的 Ant 腳本的文件。
* **install.jar**:IzPack 編譯期間生成的 JAR 安裝文件。這是用戶運行的安裝程序文件。
* **install.xml**:IzPack 的主安裝腳本。IzPack 安裝程序中使用的所有資源都以這個腳本開始。
* **Licence.txt**:安裝程序的許可文件。
* **Readme.txt**:軟件用戶使用的 readme 文件。
* **userInputSpec.xml**:IzPack 特有的 XML 腳本,用于定義用戶在一個安裝程序面板中輸入信息時的行為(驗證、默認值、字段大小等)。
接下來,通過查看 install.xml 腳本仔細研究 IzPack。
### 資源
通過資源定義不同的腳本、圖像、許可和其他文件,它們共同構成我將要創建的安裝程序。我在 install.xml 腳本中定義了一個 `<resources>`XML 元素。在 `<resources>`元素下,我可以定義安裝程序將使用的多個文件,如清單 1 所示:
##### 清單 1\. 在 IzPack install.xml 中定義資源文件
```
<resources>
<res id="LicencePanel.licence" src="Licence.txt"/>
<res id="InfoPanel.info" src="Readme.txt"/>
<res id="AntActionsSpec.xml" src="antActionSpec.xml" />
<res id="userInputSpec.xml" src="userInputSpec.xml" />
</resources>
```
可以將 IzPack 的資源看作安裝程序的 “原料單”,其中定義了用于安裝程序的所有文件。
### 面板
面板是用戶在安裝向導的每一步中看到的東西。IzPack 提供了很多類型的開箱即用的面板,您可以根據自己的需求定制它們。在圖 2 中,我定制了 IzPack 的 `HelloPanel`,以便向用戶提供介紹信息:
##### 圖 2\. IzPack 提供的定制的基于向導的 GUI 安裝

標準面板包括 `LicensePanel`、`UserInputPanel`和 `PacksPanel`等。在 install.xml 文件中,可以使用 `<panels>`元素定義要顯示的面板,然后再定義編寫安裝程序時將使用的面板模板。清單 2 中的例子演示了如何定義面板模板:
##### 清單 2\. 確定安裝程序中顯示的面板
```
<panels>
<panel classname="HelloPanel"/>
<panel classname="InfoPanel"/>
<panel classname="LicensePanel"/>
<panel classname="UserInputPanel" id="UserInputPanel.0" />
<panel classname="TargetPanel"/>
<panel classname="PacksPanel"/>
<panel classname="InstallPanel"/>
<panel classname="FinishPanel"/>
</panels>
```
您最常用的是模板類型可能是 `UserInputPanel`。這是讓用戶可以輸入可變信息而定制的面板模板。這包括用戶的聯系方式信息、認證憑證、目錄位置等。用戶可能需要根據他們特定的環境在面板上輸入信息。由于我們的團隊需要用戶連接到一個數據庫并設置多個 JBoss 容器,所以我們使用面板提示用戶提供特定的信息。
清單 3 是從 userInputSpec.xml 摘錄的一個例子,在 [清單 1](#listing1)中我將它定義為一個資源。在這個例子中,我將收集特定于用戶的信息,用于連接到一個特定的數據庫。
##### 清單 3\. 定義安裝程序中的面板的屬性
```
<panel order="0">
<field type="title" txt="Configuring your database connection" bold="true" size="1" />
<field type="staticText" align="left" txt="Connect to an existing database..."/>
<field type="divider" align="top"/>
<field type="text" variable="database.hostname">
<spec txt="Database Host Name:" id="databasehostname.label" size="40" set=""/>
<validator class="com.izforge.izpack.util.NotEmptyValidator"
txt=" Database Hostname is a required field" />
</field>
...
</panel>
```
該面板的 `order`屬性被設置為 `0`,這對應于 [清單 2](#listing2)中的面板集合中定義的 `UserInputPanel`的數量。
在用戶輸入面板中,可以為用戶定義信息文本。而且,我加入了一個 `NotEmptyValidator`,它要求用戶在文本域中輸入一個值。這樣可以防止因用戶忘記輸入必需的信息而導致安裝錯誤。圖 3 中顯示了基于 [清單 3](#listing3)的 `UserInputPanel`:
##### 圖 3\. 供用戶輸入信息的面板

用戶常常根據輸入信息和顯示消息的難易程度來判斷安裝程序的好壞。因此一定要讓用戶看到的東西容易使用。
### pack
IzPack 使用術語 _pack_表示負責實際安裝開發團隊已實現的軟件的組件。所有其他的 IzPack 組件(面板、用戶輸入、驗證器等)都是為運行這些 pack 做準備。我的項目使用 pack 做兩件事:下載我們已經用 Ant 編寫好的一個 ZIP 安裝發布包,然后運行這個安裝。這種方法使我們可以重用之前編寫的在命令行運行的命令。清單 4 定義了一個 `<pack>`:
##### 清單 4\. 在 install.xml 中定義一個 `<pack>`
```
<packs>
<pack name="download_install" id="download_install"
installGroups="ap" required="no">
<description>The base files</description>
<file src="autopeople.zip.file"
targetdir="$SYSTEM_user_home/_cnnew1_cnnew1@{installer.dir}"/>
<file src="build.xml"
targetdir="$SYSTEM_user_home/@{installer.dir}"/>
<file src="property-template"
targetdir="$SYSTEM_user_home/@{installer.dir}">
<excludes>**/.svn/**</excludes>
</file>
</pack>
```
圖 4 顯示一個進行中的 pack 安裝:
##### 圖 4\. 執行一個 pack

IzPack 中的 packs 可以包含多個 _pack_!如果您已經完成了用戶驗證、診斷和獲取特定于環境的信息等前期工作,那么用戶應該很容易運行安裝包。
* * *
## 運行 Ant 腳本
在我的團隊中,我們花了很多時間用 Ant 創建基于發布包的安裝程序。我們不想在 IzPack 中再次重新實現該功能。幸運的是,IzPack 支持調用已有 Ant 文件。還記得嗎,我在 [清單 1](#listing1)中定義資源時,曾列出了 antActionSpec.xml 作為一個資源。清單 5 顯示了摘自 antActionSpec.xml 腳本的一個片段:
##### 清單 5\. 在 antActionSpec.xml 中執行 pack 行為
```
<antactions>
<pack name="download_install">
<antcall buildfile="$SYSTEM_user_home/${installer.dir}/build.xml"
order="afterpack"
verbose="yes"
logfile="$SYSTEM_user_home/${installer.dir}/antlog_installer.txt"
inheritall="false"
messageid="AntAction.download-install">
<target name="install"/>
<property name="install.path" value="$SYSTEM_user_home/${installer.dir}"/>
</antcall>
</pack>
...
</antactions>
```
這個腳本中最重要的執行 `build.xml`的部分。這是現有的 Ant 構建腳本,它執行下載和提取一個 ZIP 安裝文件,安裝并配置 Web 容器,然后完成安裝中剩下的其他任務。antActionSpec.xml 使我們可以重用現有的 Ant 腳本。
* * *
## 編譯安裝程序
最后一步就是 IzPack 的 _編譯_。編寫好 install.xml 和相關腳本之后,就可以生成安裝程序。清單 6 是一個可用于生成 install.jar(可以修改這個文件的文件名)的單行命令的例子:
##### 清單 6\. 創建一個安裝程序
```
compile ../sample/install.xml -b ../sample
```
清單 6 中的命令假設您是從 IzPack 的 bin 子目錄運行它。`sample`是對 IzPack 提供的 sample 子目錄的引用。生成安裝程序后,可以通過從 sample 子目錄中生成 install.jar 的位置運行 `java -jar install.jar`來測試它。
* * *
## 結束語
在本文中,我展示了如何使用 IzPack 的不同組件為用戶創建易于使用的安裝包。他們可能是安裝基于客戶機的軟件的用戶,也可能是安裝和配置多個服務器的遠程站點的用戶,還可能是安裝和配置企業工具套件的團隊。如果軟件容易安裝,則更易被采納,這一點在安裝比較復雜的環境中尤為突出。如果安裝需要很多手動步驟或者干脆無法進行,那么用戶很快就會對軟件失去信心。通過 IzPack 等工具使安裝變得更加容易,這可以幫助您贏得并留住熱情的用戶。
- 讓開發自動化
- 讓開發自動化: 部署自動化模式,第 2 部分
- 讓開發自動化: 部署自動化模式,第 1 部分
- 讓開發自動化: 使用基于向導的安裝程序
- 讓開發自動化: 針對廣大開發人員的并行開發
- 讓開發自動化: 實現自動化數據庫遷移
- 讓開發自動化: 持續重構
- 讓開發自動化: 文檔化一鍵通
- 讓開發自動化: 利用 Ivy 管理依賴項
- 讓開發自動化: 自動負載測試
- 讓開發自動化: 使用自動化加速部署
- 讓開發自動化: 持續集成反模式
- 讓開發自動化: 斷言架構可靠性
- 讓開發自動化: 持續測試
- 讓開發自動化: 用 Eclipse 插件提高代碼質量
- 讓開發自動化: 除掉構建腳本中的氣味
- 讓開發自動化: 選擇持續集成服務器
- 讓開發自動化: 持續檢查