[原創]自定義參數靜默方式安裝JDK1.8

摘要:當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

Java 8 SE Documentation

How do I arrange a silent (unattended) Java installation?

Language IDs

Installing the JDK Silently

相關文章
相關標籤/搜索