摘要:當Java桌面程序開發完成作產品的時候,面對未知的安裝環境,一般是編寫一些預安裝檢測腳本/程序,讓程序傻瓜化安裝以便減小分發出去的產品帶來html
的未知工做量(安裝答疑,操做系統問題引發安裝失敗等),固然你也能夠把安裝過程當中出現的問題寫入文檔手冊。本文寫做的背景是java
1.不想讓客戶知道產品是用Java編寫的 windows
2. 客戶懶的幫助文檔都不想看瀏覽器
截至本文編寫的時候,JDK官方最新版本爲jdk 8u144,本文測試環境在虛擬機Windows XP,使用的版本爲jdk-8u144-windows-i586.exe安全
Java 安裝是使用 Microsoft Window Installer (MSI) 2.0 技術構建的。MSI 包含對靜默或無人蔘與安裝的內置支持。架構
從Google搜索"java silent install"總結出了一些安裝參數 oracle
/lang=<語言代碼> 安裝特定語言包
支持的語言包以下app
語言 | 語言代碼 |
英語 (en) | 1033 |
法語 (fr) | 1036 |
德語 (de) | 1031 |
意大利語 (it) | 1040 |
日語 (ja) | 1041 |
韓語 (ko) | 1042 |
西班牙語 (es) | 1034 |
瑞典語 (sv) | 1053 |
簡體中文 (zh) | 2052 |
繁體中文 (zh_TW) | 1028 |
通過筆者實測,設置語言代碼爲1041,即日語。安裝命令:ide
jdk-8u144-windows-i586.exe /lang=1041
安裝包界面以下工具
作對日外包的同窗應該習慣於看到這個界面。這樣就以日語語言環境安裝JDK了。
WEB_JAVA = 1|0 Java瀏覽器支持 1啓用 0禁用
IEXPLORER = 1|0 IE瀏覽器支持 1啓用 0 禁用(jdk1.8命令行實測無效)
SPONSORS= 1|0 繞過贊助商,如瀏覽器插件,實測發現完整安裝了JDK
WEB_JAVA_SECURITY_LEVEL = VH|H|M|L 瀏覽器中運行的未簽名 Java 應用程序的安全級別 很是高|高|中|低
AUTO_UPDATE= 1|0 JDK自動檢測更新 1啓用 0禁用
NOSTARTMENU= 1|0 建立開始菜單 1禁用 0 啓動
固然你也能夠安裝後在控制面板找到Java設置安全級別
以上爲JDK 7u10 release版本起的安裝特性,Java早期的時候有一些應用就是經過Web Applet方式發佈的,筆者工做早些年的時候一
家作ERP的單位他就是經過瀏覽器方式發佈項目的,現今已經不多看到這樣的企業應用,鮮見一些社區裏的Demo程序會有Web Applet的示例程序。
/L install.log 記錄安裝日誌
常規狀況下Oracle公司已經幫我考慮到安裝過程當中遇到的問題,而且他也有本身的解決方法,這些都封裝在安裝包裏,固然有時候若是須要查看java安裝過程的操做,
或者在特殊狀況下(靜默安裝)他都作了什麼,或者是爲了排錯,咱們須要記錄日誌。/L參數便應運而生。
/s 靜默安裝
此參數不須要賦值,直接帶入安裝命令行便可,啓動後將在後臺默默的安裝直至安裝完成結束。
ADDLOCAL = [[ToolsFeature],[SourceFeature],[PublicjreFeature]] 選擇附加組件包各個參數可獨立使用也能夠組合使用
ADDLOCAL = ["ToolsFeature,SourceFeature,PublicjreFeature"] 安裝開發工具/源代碼/JRE
ADDLOCAL = ["ToolsFeature,SourceFeature"] 安裝開發工具和源代碼
除了以上命令還有不少配置方式或者參數,筆者沒有一一測試,筆者最終的安裝命令以下:
jdk-8u144-windows-i586.exe /lang=2052 /s /L c:\jdk-install.log INSTALLDIR=c:\embededJDK1.8 ADDLOCAL="ToolsFeature,SourceFeature" WEB_JAVA=0 AUTO_UPDATE=0 NOSTARTMENU=1
命令解釋:筆者選擇了簡體中文靜默安裝,記錄了安裝日誌到c:\jdk-install.log,JDK安裝目錄c:\\embededJDK1.8,另外還安裝了開發工具和源代碼組件包,禁用瀏覽Java插件,關閉JAVA自動更新,屏蔽了java開始菜單的建立。
安裝後效果圖以下:
從IE瀏覽器「工具」--"管理加載項"找不到java瀏覽器插件
開始菜單也沒了Java的蹤影
windows註冊表啓動項也沒有java的影子
固然文字不是到這裏就結束了。
本文最終目的是要發送福利,在下面,筆者用C#寫了簡單的程序來靜默安裝JDK。
首先從java官方得到JDK的x86和x64版本分別更名爲sdk-x86.bin和sdk-x64.bin
下面奉上代碼(考慮客戶端實際安裝環境,爲兼容Windows XP SP及更高版本,代碼採用C#2.0 .NET Framework 2.0)
using System; using System.IO; using System.ComponentModel; using System.Reflection; using System.Text.RegularExpressions; using System.Diagnostics; using System.Threading; namespace Starter { class Enterance { static string JVM_Pattern = string.Empty; static bool hasFoundJVM = false; static string Target_JDK_FIlE = string.Empty; public static void Main(string[] args) { Console.WriteLine("按任意鍵開始安裝xxx綜合平臺..."); Console.ReadKey(true); Console.Clear(); if(isFileMissed()) { Console.WriteLine("安裝文件丟失請聯繫技術人員"); }else{ doPreInstallCheck(); if(hasFoundJVM){ installJVM(Target_JDK_FIlE); } } Console.ReadKey(true); } /// <summary> /// 判斷主安裝程序是否丟失 /// </summary> /// <returns></returns> static bool isFileMissed() { return !File.Exists("setup.exe"); } static String getArch() { return System.Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE", EnvironmentVariableTarget.Machine); } /// <summary> /// 安裝預檢測 /// </summary> static void doPreInstallCheck(){ String arch =getArch(); Architecture type= (Architecture)Enum.Parse(typeof(Architecture),arch); switch(type){ case Architecture.AMD64: case Architecture.IA64: case Architecture.x64: Console.WriteLine("發現{0}",EnumUtil.GetEnumDescription(type)); JVM_Pattern = "sdk.*x64.*"; break; case Architecture.x86: Console.WriteLine("發現{0}",EnumUtil.GetEnumDescription(type)); JVM_Pattern = "sdk.*x86.*"; break; } string []files = Directory.GetFiles(Environment.CurrentDirectory,"sdk-*.bin"); Action<string> action = new Action<string>(matchJVM); Array.ForEach(files, action); } private static void matchJVM(string jdkfile) { FileInfo fileInfo = new FileInfo(jdkfile); bool isMatched = Regex.IsMatch(fileInfo.Name,JVM_Pattern); if(isMatched) { hasFoundJVM = true; Target_JDK_FIlE = jdkfile; } if(Debugger.IsAttached) Console.WriteLine("{0}與當前操做系統匹配的JVM:{1}",fileInfo.Name,isMatched); } /// <summary> /// 安裝JVM /// </summary> /// <param name="fileName">JDK文件名</param> static void installJVM(String fileName) { Console.WriteLine("即將安裝程序,等待時間取決你電腦的性能"); //https://stackoverflow.com/questions/3360555/how-to-pass-parameters-to-threadstart-method-in-thread Thread thread =new Thread(new ParameterizedThreadStart(DoSlientInstall)); thread.Start(fileName); Thread.Sleep(5000);//等待安裝進程啓動 FileInfo fileInfo = new FileInfo(fileName); InstallState state =new InstallState(); state.processName =fileInfo.Name; Timer timer =new Timer(waitForProcessExitCallBack,state,0,1000); state.tmr = timer; } public static void waitForProcessExitCallBack(object target){ InstallState state = target as InstallState; Timer timer = state.tmr; Process []allProcceses = Process.GetProcesses(); bool isJDKProcExit = true; foreach(Process proc in allProcceses) { string procName = String.Format("{0}",proc.ProcessName); if(Debugger.IsAttached) Console.WriteLine("{0},{1}, {2}",procName,state.processName,procName.Equals(state.processName)); if(procName.Equals(state.processName)){ isJDKProcExit = false; } } if(isJDKProcExit){ Console.WriteLine("\r\n安裝所需軟件使用時間:{0}秒",state.counter); timer.Dispose(); }else{ Console.Write(state.delims); state.counter++; //Thread.Sleep(1000); // //timer.Change(1000,1000); //timer.Dispose(); } } //https://stackoverflow.com/questions/24918768/progress-bar-in-console-application //https://stackoverflow.com/questions/12354883/how-do-i-gracefully-stop-a-system-threading-timer static void DoSlientInstall(object fileName) { Console.WriteLine("安裝進行中,請勿退出..."); ProcessStartInfo pStartInfo = new ProcessStartInfo(); pStartInfo.FileName = (String)fileName; pStartInfo.Verb = "runas"; pStartInfo.Arguments = "/lang=2052 /s /L c:\\jdk-install.log INSTALLDIR=c:\\embededJDK1.8 ADDLOCAL=\"ToolsFeature,SourceFeature\" WEB_JAVA=0 AUTO_UPDATE=0 NOSTARTMENU=1"; pStartInfo.UseShellExecute = false; System.Diagnostics.Process.Start(pStartInfo); //https://stackoverflow.com/questions/6050478/how-do-i-create-edit-a-manifest-file //System.Diagnostics.Process.Start((String)fileName,"/s"); } } //http://www.gnu.org/software/dotgnu/pnetlib-doc/System/Threading/Timer.html class InstallState{ /// <summary> /// 時間計數器 /// </summary> public int counter = 0; /// <summary> /// 進程名 /// </summary> public String processName; /// <summary> /// 分隔符 /// </summary> public string delims="*"; public Timer tmr; } }
using System; using System.ComponentModel; using System.Reflection; using System.Collections.Generic; using System.Data.SqlClient; using System.Data; namespace Starter { /// <summary> /// 操做系統架構枚舉類 /// </summary> //https://msdn.microsoft.com/en-us/library/aa384274.aspx //https://ss64.com/nt/syntax-64bit.html public enum Architecture{ [Description("64位操做系統")] x64 =0, [Description("AMD 64位操做系統")] AMD64=1, [Description("Intel64位操做系統")] IA64=2, [Description("x86架構操做系統")] x86=3 } class EnumUtil{ public static string GetEnumDescription(Enum enumValue) { string enumValueAsString = enumValue.ToString(); Type type = enumValue.GetType(); FieldInfo fieldInfo = type.GetField(enumValueAsString); object[] attributes = fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false); if (attributes.Length > 0) { DescriptionAttribute attribute = (DescriptionAttribute)attributes[0]; return attribute.Description; } return enumValueAsString; } } }
安裝效果圖
參考資料
Installing With a Configuration File