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


摘要:當Java桌面程序開發完成做產品的時候,面對未知的安裝環境,通常是編寫一些預安裝檢測腳本/程序,讓程序傻瓜化安裝以便減少分發出去的產品帶來

的未知工作量(安裝答疑,操作系統問題引起安裝失敗等),當然你也可以把安裝過程中出現的問題寫入文檔手冊。本文寫作的背景是

1.不想讓客戶知道產品是用Java編寫的 

2. 客戶懶的幫助文檔都不想看

  截至本文編寫的時候,JDK官方最新版本為jdk 8u144,本文測試環境在虛擬機Windows XP,使用的版本為jdk-8u144-windows-i586.exe

       Java 安裝是使用 Microsoft Window Installer (MSI) 2.0 技術構建的。MSI 包含對靜默或無人參與安裝的內置支持。

  從Google搜索"java silent install"總結出了一些安裝參數  

 /lang=<語言代碼> 安裝特定語言包

  支持的語言包如下

 

語言   語言代碼
英語 (en) 1033
法語 (fr) 1036            
德語 (de) 1031
意大利語 (it) 1040
日語 (ja) 1041
韓語 (ko) 1042
西班牙語 (es) 1034
瑞典語 (sv) 1053
簡體中文 (zh) 2052
繁體中文 (zh_TW) 1028

經過筆者實測,設置語言代碼為1041,即日語。安裝命令:

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=D:\develop\Java\jdk1.8.0_144 ADDLOCAL="ToolsFeature,SourceFeature,,PublicjreFeature" WEB_JAVA=0 AUTO_UPDATE=0 NOSTARTMENU=1 /INSTALLDIRPUBJRE=D:\develop\Java\jre1.8.0_144

 

 
         

命令解釋:筆者選擇了簡體中文靜默安裝,記錄了安裝日志到c:\jdk-install.log,JDK安裝目錄c:\\embededJDK1.8,另外還安裝了開發工具和源代碼組件包、jre,禁用瀏覽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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM