当前位置:   article > 正文

【JD-GUI】MacOS 中使用Java反编译工具JD-GUI_mac java 反编译工具

mac java 反编译工具

希望文章能给到你启发和灵感~
如果觉得文章对你有帮助的话,点赞 + 关注+ 收藏 支持一下博主吧~

开篇说明

现在的反编译软件繁多,Apktool,JD-GUI,dedexer,IDA Pro等等,每种反编译工具都有各自使用的场景,例如Apktool我们在反编译apk类型文件时会用到,JD-GUI则是常用来反编译Java中的class文件,或者Jar等源文件;

在这里插入图片描述

概念理解

【1】什么是反编译?

简单的说,就是将机器语言转换成我们能看懂的语言,这个过程就叫反编译,例如Java中的class文件反编译后,就能变成我们日常开发写的代码xxx.java文件;

【2】反编译是否一定能成功?

不一定,随着现在很多代码编译中都会加入代码混淆,加密,或是加壳等等技术,加大反编译的难度和降低反编译代码的可读性,不过如果想完全避免反编译也是不可能的。只是反编译的还原度的大小问题了;

一、基础环境说明

考虑环境因素,大家适当的对比自己的软硬件环境情况分析~请仔细阅读硬件、软件环境

1.1 硬件环境

MacOS Monterey 版本 12.6.8 Apple M1

1.2 软件环境

JD-GUI版本:jd-gui-osx-1.6.6

二、下载与安装

Github下载JD-GUI软件github java-decompiler/jd-gui Public

2.1 选择对应版本

macOS系统我们选择jd-gui-osx-1.6.6.tar压缩包即可;

在这里插入图片描述

2.2 解压运行排除异常:

解压后,进入文件打开JD-GUI;
在这里插入图片描述
【注】运行时需要注意自己环境已经安装了JDK,否则你可能会遇到这样的错误:

在这里插入图片描述
若是确认JDK安装后,仍然提示该错误,需要修改文件->显示包内容->Contents->MacOs->universalJavaApplicationStub.sh;
在这里插入图片描述
将内容替换成下面的内容:

#!/bin/bash
##################################################################################
#                                                                                #
# universalJavaApplicationStub                                                   #
#                                                                                #
# A BASH based JavaApplicationStub for Java Apps on Mac OS X                     #
# that works with both Apple's and Oracle's plist format.                        #
#                                                                                #
# Inspired by Ian Roberts stackoverflow answer                                   #
# at http://stackoverflow.com/a/17546508/1128689                                 #
#                                                                                #
# @author    Tobias Fischer                                                      #
# @url       https://github.com/tofi86/universalJavaApplicationStub              #
# @date      2020-03-19                                                          #
# @version   3.0.6                                                               #
#                                                                                #
##################################################################################
#                                                                                #
# The MIT License (MIT)                                                          #
#                                                                                #
# Copyright (c) 2014-2020 Tobias Fischer                                         #
#                                                                                #
# Permission is hereby granted, free of charge, to any person obtaining a copy   #
# of this software and associated documentation files (the "Software"), to deal  #
# in the Software without restriction, including without limitation the rights   #
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell      #
# copies of the Software, and to permit persons to whom the Software is          #
# furnished to do so, subject to the following conditions:                       #
#                                                                                #
# The above copyright notice and this permission notice shall be included in all #
# copies or substantial portions of the Software.                                #
#                                                                                #
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR     #
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,       #
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE    #
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER         #
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,  #
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE  #
# SOFTWARE.                                                                      #
#                                                                                #
##################################################################################
 
 
 
# function 'stub_logger()'
#
# A logger which logs to the macOS Console.app using the 'syslog' command
#
# @param1  the log message
# @return  void
################################################################################
function stub_logger() {
	syslog -s -k \
		Facility com.apple.console \
		Level Notice \
		Sender "$(basename "$0")" \
		Message "[$$][${CFBundleName:-$(basename "$0")}] $1"
}
 
 
 
# set the directory abspath of the current
# shell script with symlinks being resolved
############################################
 
PRG=$0
while [ -h "$PRG" ]; do
	ls=$(ls -ld "$PRG")
	link=$(expr "$ls" : '^.*-> \(.*\)$' 2>/dev/null)
	if expr "$link" : '^/' 2> /dev/null >/dev/null; then
		PRG="$link"
	else
		PRG="$(dirname "$PRG")/$link"
	fi
done
PROGDIR=$(dirname "$PRG")
stub_logger "[StubDir] $PROGDIR"
 
 
 
# set files and folders
############################################
 
# the absolute path of the app package
cd "$PROGDIR"/../../ || exit 11
AppPackageFolder=$(pwd)
 
# the base path of the app package
cd .. || exit 12
AppPackageRoot=$(pwd)
 
# set Apple's Java folder
AppleJavaFolder="${AppPackageFolder}"/Contents/Resources/Java
 
# set Apple's Resources folder
AppleResourcesFolder="${AppPackageFolder}"/Contents/Resources
 
# set Oracle's Java folder
OracleJavaFolder="${AppPackageFolder}"/Contents/Java
 
# set Oracle's Resources folder
OracleResourcesFolder="${AppPackageFolder}"/Contents/Resources
 
# set path to Info.plist in bundle
InfoPlistFile="${AppPackageFolder}"/Contents/Info.plist
 
# set the default JVM Version to a null string
JVMVersion=""
JVMMaxVersion=""
 
 
 
# function 'plist_get()'
#
# read a specific Plist key with 'PlistBuddy' utility
#
# @param1  the Plist key with leading colon ':'
# @return  the value as String or Array
################################################################################
plist_get(){
	/usr/libexec/PlistBuddy -c "print $1" "${InfoPlistFile}" 2> /dev/null
}
 
# function 'plist_get_java()'
#
# read a specific Plist key with 'PlistBuddy' utility
# in the 'Java' or 'JavaX' dictionary (<dict>)
#
# @param1  the Plist :Java(X):Key with leading colon ':'
# @return  the value as String or Array
################################################################################
plist_get_java(){
	plist_get ${JavaKey:-":Java"}$1
}
 
 
 
# read Info.plist and extract JVM options
############################################
 
# read the program name from CFBundleName
CFBundleName=$(plist_get ':CFBundleName')
 
# read the icon file name
CFBundleIconFile=$(plist_get ':CFBundleIconFile')
 
 
# check Info.plist for Apple style Java keys -> if key :Java is present, parse in apple mode
/usr/libexec/PlistBuddy -c "print :Java" "${InfoPlistFile}" > /dev/null 2>&1
exitcode=$?
JavaKey=":Java"
 
# if no :Java key is present, check Info.plist for universalJavaApplication style JavaX keys -> if key :JavaX is present, parse in apple mode
if [ $exitcode -ne 0 ]; then
	/usr/libexec/PlistBuddy -c "print :JavaX" "${InfoPlistFile}" > /dev/null 2>&1
	exitcode=$?
	JavaKey=":JavaX"
fi
 
 
# read 'Info.plist' file in Apple style if exit code returns 0 (true, ':Java' key is present)
if [ $exitcode -eq 0 ]; then
	stub_logger "[PlistStyle] Apple"
 
	# set Java and Resources folder
	JavaFolder="${AppleJavaFolder}"
	ResourcesFolder="${AppleResourcesFolder}"
 
	APP_PACKAGE="${AppPackageFolder}"
	JAVAROOT="${AppleJavaFolder}"
	USER_HOME="$HOME"
 
 
	# read the Java WorkingDirectory
	JVMWorkDir=$(plist_get_java ':WorkingDirectory' | xargs)
	# set Working Directory based upon PList value
	if [[ ! -z ${JVMWorkDir} ]]; then
		WorkingDirectory="${JVMWorkDir}"
	else
		# AppPackageRoot is the standard WorkingDirectory when the script is started
		WorkingDirectory="${AppPackageRoot}"
	fi
	# expand variables $APP_PACKAGE, $JAVAROOT, $USER_HOME
	WorkingDirectory=$(eval echo "${WorkingDirectory}")
 
 
	# read the MainClass name
	JVMMainClass="$(plist_get_java ':MainClass')"
 
	# read the SplashFile name
	JVMSplashFile=$(plist_get_java ':SplashFile')
 
	# read the JVM Properties as an array and retain spaces
	IFS=$'\t\n'
	JVMOptions=($(xargs -n1 <<<$(plist_get_java ':Properties' | grep " =" | sed 's/^ */-D/g' | sed -E 's/ = (.*)$/="\1"/g')))
	unset IFS
	# post processing of the array follows further below...
 
	# read the ClassPath in either Array or String style
	JVMClassPath_RAW=$(plist_get_java ':ClassPath' | xargs)
	if [[ $JVMClassPath_RAW == *Array* ]] ; then
		JVMClassPath=.$(plist_get_java ':ClassPath' | grep "    " | sed 's/^ */:/g' | tr -d '\n' | xargs)
	else
		JVMClassPath=${JVMClassPath_RAW}
	fi
	# expand variables $APP_PACKAGE, $JAVAROOT, $USER_HOME
	JVMClassPath=$(eval echo "${JVMClassPath}")
 
	# read the JVM Options in either Array or String style
	JVMDefaultOptions_RAW=$(plist_get_java ':VMOptions' | xargs)
	if [[ $JVMDefaultOptions_RAW == *Array* ]] ; then
		JVMDefaultOptions=$(plist_get_java ':VMOptions' | grep "    " | sed 's/^ */ /g' | tr -d '\n' | xargs)
	else
		JVMDefaultOptions=${JVMDefaultOptions_RAW}
	fi
 
	# read StartOnMainThread and add as -XstartOnFirstThread
	JVMStartOnMainThread=$(plist_get_java ':StartOnMainThread')
	if [ "${JVMStartOnMainThread}" == "true" ]; then
		JVMDefaultOptions+=" -XstartOnFirstThread"
	fi
 
	# read the JVM Arguments in either Array or String style (#76) and retain spaces
	IFS=$'\t\n'
	MainArgs_RAW=$(plist_get_java ':Arguments' | xargs)
	if [[ $MainArgs_RAW == *Array* ]] ; then
		MainArgs=($(xargs -n1 <<<$(plist_get_java ':Arguments' | tr -d '\n' | sed -E 's/Array \{ *(.*) *\}/\1/g' | sed 's/  */ /g')))
	else
		MainArgs=($(xargs -n1 <<<$(plist_get_java ':Arguments')))
	fi
	unset IFS
	# post processing of the array follows further below...
 
	# read the Java version we want to find
	JVMVersion=$(plist_get_java ':JVMVersion' | xargs)
	# post processing of the version string follows below...
 
 
# read 'Info.plist' file in Oracle style
else
	stub_logger "[PlistStyle] Oracle"
 
	# set Working Directory and Java and Resources folder
	JavaFolder="${OracleJavaFolder}"
	ResourcesFolder="${OracleResourcesFolder}"
	WorkingDirectory="${OracleJavaFolder}"
 
	APP_ROOT="${AppPackageFolder}"
 
	# read the MainClass name
	JVMMainClass="$(plist_get ':JVMMainClassName')"
 
	# read the SplashFile name
	JVMSplashFile=$(plist_get ':JVMSplashFile')
 
	# read the JVM Options as an array and retain spaces
	IFS=$'\t\n'
	JVMOptions=($(plist_get ':JVMOptions' | grep "    " | sed 's/^ *//g'))
	unset IFS
	# post processing of the array follows further below...
 
	# read the ClassPath in either Array or String style
	JVMClassPath_RAW=$(plist_get ':JVMClassPath')
	if [[ $JVMClassPath_RAW == *Array* ]] ; then
		JVMClassPath=.$(plist_get ':JVMClassPath' | grep "    " | sed 's/^ */:/g' | tr -d '\n' | xargs)
		# expand variables $APP_PACKAGE, $JAVAROOT, $USER_HOME
		JVMClassPath=$(eval echo "${JVMClassPath}")
 
	elif [[ ! -z ${JVMClassPath_RAW} ]] ; then
		JVMClassPath=${JVMClassPath_RAW}
		# expand variables $APP_PACKAGE, $JAVAROOT, $USER_HOME
		JVMClassPath=$(eval echo "${JVMClassPath}")
 
	else
		#default: fallback to OracleJavaFolder
		JVMClassPath="${JavaFolder}/*"
		# Do NOT expand the default 'AppName.app/Contents/Java/*' classpath (#42)
	fi
 
	# read the JVM Default Options
	JVMDefaultOptions=$(plist_get ':JVMDefaultOptions' | grep -o " \-.*" | tr -d '\n' | xargs)
 
	# read the Main Arguments from JVMArguments key as an array and retain spaces (see #46 for naming details)
	IFS=$'\t\n'
	MainArgs=($(xargs -n1 <<<$(plist_get ':JVMArguments' | tr -d '\n' | sed -E 's/Array \{ *(.*) *\}/\1/g' | sed 's/  */ /g')))
	unset IFS
	# post processing of the array follows further below...
 
	# read the Java version we want to find
	JVMVersion=$(plist_get ':JVMVersion' | xargs)
	# post processing of the version string follows below...
fi
 
 
# (#75) check for undefined icons or icon names without .icns extension and prepare
# an osascript statement for those cases when the icon can be shown in the dialog
DialogWithIcon=""
if [ ! -z ${CFBundleIconFile} ]; then
	if [[ ${CFBundleIconFile} == *.icns ]] && [[ -f "${ResourcesFolder}/${CFBundleIconFile}" ]] ; then
		DialogWithIcon=" with icon path to resource \"${CFBundleIconFile}\" in bundle (path to me)"
	elif [[ ${CFBundleIconFile} != *.icns ]] && [[ -f "${ResourcesFolder}/${CFBundleIconFile}.icns" ]] ; then
		CFBundleIconFile+=".icns"
		DialogWithIcon=" with icon path to resource \"${CFBundleIconFile}\" in bundle (path to me)"
	fi
fi
 
 
# JVMVersion: post processing and optional splitting
if [[ ${JVMVersion} == *";"* ]]; then
	minMaxArray=(${JVMVersion//;/ })
	JVMVersion=${minMaxArray[0]//+}
	JVMMaxVersion=${minMaxArray[1]//+}
fi
stub_logger "[JavaRequirement] JVM minimum version: ${JVMVersion}"
stub_logger "[JavaRequirement] JVM maximum version: ${JVMMaxVersion}"
 
# MainArgs: replace occurences of $APP_ROOT with its content
MainArgsArr=()
for i in "${MainArgs[@]}"
do
	MainArgsArr+=("$(eval echo "$i")")
done
 
# JVMOptions: replace occurences of $APP_ROOT with its content
JVMOptionsArr=()
for i in "${JVMOptions[@]}"
do
	JVMOptionsArr+=("$(eval echo "$i")")
done
 
 
# internationalized messages
############################################
 
LANG=$(defaults read -g AppleLocale)
stub_logger "[Language] $LANG"
 
# French localization
if [[ $LANG == fr* ]] ; then
	MSG_ERROR_LAUNCHING="ERREUR au lancement de '${CFBundleName}'."
	MSG_MISSING_MAINCLASS="'MainClass' n'est pas spécifié.\nL'application Java ne peut pas être lancée."
	MSG_JVMVERSION_REQ_INVALID="La syntaxe de la version de Java demandée est invalide: %s\nVeuillez contacter le développeur de l'application."
	MSG_NO_SUITABLE_JAVA="La version de Java installée sur votre système ne convient pas.\nCe programme nécessite Java %s"
	MSG_JAVA_VERSION_OR_LATER="ou ultérieur"
	MSG_JAVA_VERSION_LATEST="(dernière mise à jour)"
	MSG_JAVA_VERSION_MAX="à %s"
	MSG_NO_SUITABLE_JAVA_CHECK="Merci de bien vouloir installer la version de Java requise."
	MSG_INSTALL_JAVA="Java doit être installé sur votre système.\nRendez-vous sur java.com et suivez les instructions d'installation..."
	MSG_LATER="Plus tard"
	MSG_VISIT_JAVA_DOT_COM="Java by Oracle"
	MSG_VISIT_ADOPTOPENJDK="Java by AdoptOpenJDK"
 
# German localization
elif [[ $LANG == de* ]] ; then
	MSG_ERROR_LAUNCHING="FEHLER beim Starten von '${CFBundleName}'."
	MSG_MISSING_MAINCLASS="Die 'MainClass' ist nicht spezifiziert!\nDie Java-Anwendung kann nicht gestartet werden!"
	MSG_JVMVERSION_REQ_INVALID="Die Syntax der angeforderten Java-Version ist ungültig: %s\nBitte kontaktieren Sie den Entwickler der App."
	MSG_NO_SUITABLE_JAVA="Es wurde keine passende Java-Version auf Ihrem System gefunden!\nDieses Programm benötigt Java %s"
	MSG_JAVA_VERSION_OR_LATER="oder neuer"
	MSG_JAVA_VERSION_LATEST="(neuste Unterversion)"
	MSG_JAVA_VERSION_MAX="bis %s"
	MSG_NO_SUITABLE_JAVA_CHECK="Stellen Sie sicher, dass die angeforderte Java-Version installiert ist."
	MSG_INSTALL_JAVA="Auf Ihrem System muss die 'Java'-Software installiert sein.\nBesuchen Sie java.com für weitere Installationshinweise."
	MSG_LATER="Später"
	MSG_VISIT_JAVA_DOT_COM="Java von Oracle"
	MSG_VISIT_ADOPTOPENJDK="Java von AdoptOpenJDK"
 
# Simplifyed Chinese localization
elif [[ $LANG == zh* ]] ; then
	MSG_ERROR_LAUNCHING="无法启动 '${CFBundleName}'."
	MSG_MISSING_MAINCLASS="没有指定 'MainClass'!\nJava程序无法启动!"
	MSG_JVMVERSION_REQ_INVALID="Java版本参数语法错误: %s\n请联系该应用的开发者。"
	MSG_NO_SUITABLE_JAVA="没有在系统中找到合适的Java版本!\n必须安装Java %s才能够使用该程序!"
	MSG_JAVA_VERSION_OR_LATER="及以上版本"
	MSG_JAVA_VERSION_LATEST="(最新版本)"
	MSG_JAVA_VERSION_MAX="最高为 %s"
	MSG_NO_SUITABLE_JAVA_CHECK="请确保系统中安装了所需的Java版本"
	MSG_INSTALL_JAVA="你需要在Mac中安装Java运行环境!\n访问 java.com 了解如何安装。"
	MSG_LATER="稍后"
	MSG_VISIT_JAVA_DOT_COM="Java by Oracle"
	MSG_VISIT_ADOPTOPENJDK="Java by AdoptOpenJDK"
 
# English default localization
else
	MSG_ERROR_LAUNCHING="ERROR launching '${CFBundleName}'."
	MSG_MISSING_MAINCLASS="'MainClass' isn't specified!\nJava application cannot be started!"
	MSG_JVMVERSION_REQ_INVALID="The syntax of the required Java version is invalid: %s\nPlease contact the App developer."
	MSG_NO_SUITABLE_JAVA="No suitable Java version found on your system!\nThis program requires Java %s"
	MSG_JAVA_VERSION_OR_LATER="or later"
	MSG_JAVA_VERSION_LATEST="(latest update)"
	MSG_JAVA_VERSION_MAX="up to %s"
	MSG_NO_SUITABLE_JAVA_CHECK="Make sure you install the required Java version."
	MSG_INSTALL_JAVA="You need to have JAVA installed on your Mac!\nVisit java.com for installation instructions..."
	MSG_LATER="Later"
	MSG_VISIT_JAVA_DOT_COM="Java by Oracle"
	MSG_VISIT_ADOPTOPENJDK="Java by AdoptOpenJDK"
fi
 
 
 
# function 'get_java_version_from_cmd()'
#
# returns Java version string from 'java -version' command
# works for both old (1.8) and new (9) version schema
#
# @param1  path to a java JVM executable
# @return  the Java version number as displayed in 'java -version' command
################################################################################
function get_java_version_from_cmd() {
	# second sed command strips " and -ea from the version string
	echo $("$1" -version 2>&1 | awk '/version/{print $3}' | sed -E 's/"//g;s/-ea//g')
}
 
 
# function 'extract_java_major_version()'
#
# extract Java major version from a version string
#
# @param1  a Java version number ('1.8.0_45') or requirement string ('1.8+')
# @return  the major version (e.g. '7', '8' or '9', etc.)
################################################################################
function extract_java_major_version() {
	echo $(echo "$1" | sed -E 's/^1\.//;s/^([0-9]+)(-ea|(\.[0-9_.]{1,7})?)(-b[0-9]+-[0-9]+)?[+*]?$/\1/')
}
 
 
# function 'get_comparable_java_version()'
#
# return comparable version for a Java version number or requirement string
#
# @param1  a Java version number ('1.8.0_45') or requirement string ('1.8+')
# @return  an 8 digit numeral ('1.8.0_45'->'08000045'; '9.1.13'->'09001013')
################################################################################
function get_comparable_java_version() {
	# cleaning: 1) remove leading '1.'; 2) remove build string (e.g. '-b14-468'); 3) remove 'a-Z' and '-*+' (e.g. '-ea'); 4) replace '_' with '.'
	local cleaned=$(echo "$1" | sed -E 's/^1\.//g;s/-b[0-9]+-[0-9]+$//g;s/[a-zA-Z+*\-]//g;s/_/./g')
	# splitting at '.' into an array
	local arr=( ${cleaned//./ } )
	# echo a string with left padded version numbers
	echo "$(printf '%02s' ${arr[0]})$(printf '%03s' ${arr[1]})$(printf '%03s' ${arr[2]})"
}
 
 
# function 'is_valid_requirement_pattern()'
#
# check whether the Java requirement is a valid requirement pattern
#
# supported requirements are for example:
# - 1.6       requires Java 6 (any update)      [1.6, 1.6.0_45, 1.6.0_88]
# - 1.6*      requires Java 6 (any update)      [1.6, 1.6.0_45, 1.6.0_88]
# - 1.6+      requires Java 6 or higher         [1.6, 1.6.0_45, 1.8, 9, etc.]
# - 1.6.0     requires Java 6 (any update)      [1.6, 1.6.0_45, 1.6.0_88]
# - 1.6.0_45  requires Java 6u45                [1.6.0_45]
# - 1.6.0_45+ requires Java 6u45 or higher      [1.6.0_45, 1.6.0_88, 1.8, etc.]
# - 9         requires Java 9 (any update)      [9.0.*, 9.1, 9.3, etc.]
# - 9*        requires Java 9 (any update)      [9.0.*, 9.1, 9.3, etc.]
# - 9+        requires Java 9 or higher         [9.0, 9.1, 10, etc.]
# - 9.1       requires Java 9.1 (any update)    [9.1.*, 9.1.2, 9.1.13, etc.]
# - 9.1*      requires Java 9.1 (any update)    [9.1.*, 9.1.2, 9.1.13, etc.]
# - 9.1+      requires Java 9.1 or higher       [9.1, 9.2, 10, etc.]
# - 9.1.3     requires Java 9.1.3               [9.1.3]
# - 9.1.3*    requires Java 9.1.3 (any update)  [9.1.3]
# - 9.1.3+    requires Java 9.1.3 or higher     [9.1.3, 9.1.4, 9.2.*, 10, etc.]
# - 10-ea     requires Java 10 (early access release)
#
# unsupported requirement patterns are for example:
# - 1.2, 1.3, 1.9       Java 2, 3 are not supported
# - 1.9                 Java 9 introduced a new versioning scheme
# - 6u45                known versioning syntax, but unsupported
# - 9-ea*, 9-ea+        early access releases paired with */+
# - 9., 9.*, 9.+        version ending with a .
# - 9.1., 9.1.*, 9.1.+  version ending with a .
# - 9.3.5.6             4 part version number is unsupported
#
# @param1  a Java requirement string ('1.8+')
# @return  boolean exit code: 0 (is valid), 1 (is not valid)
################################################################################
function is_valid_requirement_pattern() {
	local java_req=$1
	java8pattern='1\.[4-8](\.[0-9]+)?(\.0_[0-9]+)?[*+]?'
	java9pattern='(9|1[0-9])(-ea|[*+]|(\.[0-9]+){1,2}[*+]?)?'
	# test matches either old Java versioning scheme (up to 1.8) or new scheme (starting with 9)
	if [[ ${java_req} =~ ^(${java8pattern}|${java9pattern})$ ]]; then
		return 0
	else
		return 1
	fi
}
 
 
 
# determine which JVM to use
############################################
 
# default Apple JRE plugin path (< 1.6)
apple_jre_plugin="/Library/Java/Home/bin/java"
apple_jre_version=$(get_java_version_from_cmd "${apple_jre_plugin}")
# default Oracle JRE plugin path (>= 1.7)
oracle_jre_plugin="/Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/bin/java"
oracle_jre_version=$(get_java_version_from_cmd "${oracle_jre_plugin}")
 
 
# first check system variable "$JAVA_HOME" -> has precedence over any other System JVM
stub_logger '[JavaSearch] Checking for $JAVA_HOME ...'
if [ -n "$JAVA_HOME" ] ; then
	stub_logger "[JavaSearch] ... found JAVA_HOME with value $JAVA_HOME"
 
	# PR 26: Allow specifying "$JAVA_HOME" relative to "$AppPackageFolder"
	# which allows for bundling a custom version of Java inside your app!
	if [[ $JAVA_HOME == /* ]] ; then
		# if "$JAVA_HOME" starts with a Slash it's an absolute path
		JAVACMD="$JAVA_HOME/bin/java"
	else
		# otherwise it's a relative path to "$AppPackageFolder"
		JAVACMD="$AppPackageFolder/$JAVA_HOME/bin/java"
	fi
	JAVACMD_version=$(get_comparable_java_version $(get_java_version_from_cmd "${JAVACMD}"))
else
	stub_logger "[JavaSearch] ... didn't found JAVA_HOME"
fi
 
 
# check for any other or a specific Java version
# also if $JAVA_HOME exists but isn't executable
if [ -z "${JAVACMD}" ] || [ ! -x "${JAVACMD}" ] ; then
	stub_logger "[JavaSearch] Checking for JavaVirtualMachines on the system ..."
	# reset variables
	JAVACMD=""
	JAVACMD_version=""
 
	# first check whether JVMVersion string is a valid requirement string
	if [ ! -z "${JVMVersion}" ] && ! is_valid_requirement_pattern ${JVMVersion} ; then
		MSG_JVMVERSION_REQ_INVALID_EXPANDED=$(printf "${MSG_JVMVERSION_REQ_INVALID}" "${JVMVersion}")
		# log exit cause
		stub_logger "[EXIT 4] ${MSG_JVMVERSION_REQ_INVALID_EXPANDED}"
		# display error message with AppleScript
		osascript -e "tell application \"System Events\" to display dialog \"${MSG_ERROR_LAUNCHING}\n\n${MSG_JVMVERSION_REQ_INVALID_EXPANDED}\" with title \"${CFBundleName}\" buttons {\" OK \"} default button 1${DialogWithIcon}"
		# exit with error
		exit 4
	fi
	# then check whether JVMMaxVersion string is a valid requirement string
	if [ ! -z "${JVMMaxVersion}" ] && ! is_valid_requirement_pattern ${JVMMaxVersion} ; then
		MSG_JVMVERSION_REQ_INVALID_EXPANDED=$(printf "${MSG_JVMVERSION_REQ_INVALID}" "${JVMMaxVersion}")
		# log exit cause
		stub_logger "[EXIT 5] ${MSG_JVMVERSION_REQ_INVALID_EXPANDED}"
		# display error message with AppleScript
		osascript -e "tell application \"System Events\" to display dialog \"${MSG_ERROR_LAUNCHING}\n\n${MSG_JVMVERSION_REQ_INVALID_EXPANDED}\" with title \"${CFBundleName}\" buttons {\" OK \"} default button 1${DialogWithIcon}"
		# exit with error
		exit 5
	fi
 
 
	# find installed JavaVirtualMachines (JDK + JRE)
	allJVMs=()
	# read JDK's from '/usr/libexec/java_home -V' command
	while read -r line; do
		version=$(echo $line | awk -F $',' '{print $1;}')
		path=$(echo $line | awk -F $'" ' '{print $2;}')
		path+="/bin/java"
		allJVMs+=("$version:$path")
	done < <(/usr/libexec/java_home -V 2>&1 | grep '^[[:space:]]')
	# unset while loop variables
	unset version path
 
	# add Apple JRE if available
	if [ -x "${apple_jre_plugin}" ] ; then
		allJVMs+=("$apple_jre_version:$apple_jre_plugin")
	fi
 
	# add Oracle JRE if available
	if [ -x "${oracle_jre_plugin}" ] ; then
		allJVMs+=("$oracle_jre_version:$oracle_jre_plugin")
	fi
 
	# debug output
	for i in "${allJVMs[@]}"
	do
		stub_logger "[JavaSearch] ... found JVM: $i"
	done
 
 
	# determine JVMs matching the min/max version requirement
	minC=$(get_comparable_java_version ${JVMVersion})
	maxC=$(get_comparable_java_version ${JVMMaxVersion})
	matchingJVMs=()
 
	for i in "${allJVMs[@]}"
	do
		# split JVM string at ':' delimiter to retain spaces in $path substring
		IFS=: arr=($i) ; unset IFS
		# [0] JVM version number
		ver=${arr[0]}
		# comparable JVM version number
		comp=$(get_comparable_java_version $ver)
		# [1] JVM path
		path="${arr[1]}"
		# construct string item for adding to the "matchingJVMs" array
		item="$comp:$ver:$path"
 
		# pre-requisite: current version number needs to be greater than min version number
		if [ "$comp" -ge "$minC" ] ; then
 
			# perform max version checks if max version requirement is present
			if [ ! -z ${JVMMaxVersion} ] ; then
 
				# max version requirement ends with '*' modifier
				if [[ ${JVMMaxVersion} == *\* ]] ; then
 
					# use the '*' modifier from the max version string as wildcard for a 'starts with' comparison
					# and check whether the current version number starts with the max version wildcard string
					if [[ ${ver} == ${JVMMaxVersion} ]]; then
						matchingJVMs+=("$item")
 
					# or whether the current comparable version is lower than the comparable max version
					elif [ "$comp" -le "$maxC" ] ; then
						matchingJVMs+=("$item")
					fi
 
				# max version requirement ends with '+' modifier -> always add this version if it's greater than $min
				# because a max requirement with + modifier doesn't make sense
				elif [[ ${JVMMaxVersion} == *+ ]] ; then
					matchingJVMs+=("$item")
 
				# matches 6 zeros at the end of the max version string (e.g. for 1.8, 9)
				# -> then the max version string should be treated like with a '*' modifier at the end
				#elif [[ ${maxC} =~ ^[0-9]{2}0{6}$ ]] && [ "$comp" -le $(( ${maxC#0} + 999 )) ] ; then
				#	matchingJVMs+=("$item")
 
				# matches 3 zeros at the end of the max version string (e.g. for 9.1, 10.3)
				# -> then the max version string should be treated like with a '*' modifier at the end
				#elif [[ ${maxC} =~ ^[0-9]{5}0{3}$ ]] && [ "$comp" -le "${maxC}" ] ; then
				#	matchingJVMs+=("$item")
 
				# matches standard requirements without modifier
				elif [ "$comp" -le "$maxC" ]; then
					matchingJVMs+=("$item")
				fi
 
			# no max version requirement:
 
			# min version requirement ends with '+' modifier
			# -> always add the current version because it's greater than $min
			elif [[ ${JVMVersion} == *+ ]] ; then
				matchingJVMs+=("$item")
 
			# min version requirement ends with '*' modifier
			# -> use the '*' modifier from the min version string as wildcard for a 'starts with' comparison
			#    and check whether the current version number starts with the min version wildcard string
			elif [[ ${JVMVersion} == *\* ]] ; then
				if [[ ${ver} == ${JVMVersion} ]] ; then
					matchingJVMs+=("$item")
				fi
 
			# compare the min version against the current version with an additional * wildcard for a 'starts with' comparison
			# -> e.g. add 1.8.0_44 when the requirement is 1.8
			elif [[ ${ver} == ${JVMVersion}* ]] ; then
					matchingJVMs+=("$item")
			fi
		fi
	done
	# unset for loop variables
	unset arr ver comp path item
 
	# debug output
	for i in "${matchingJVMs[@]}"
	do
		stub_logger "[JavaSearch] ... ... matches all requirements: $i"
	done
 
 
	# sort the matching JavaVirtualMachines by version number
	# https://stackoverflow.com/a/11789688/1128689
	IFS=$'\n' matchingJVMs=($(sort -nr <<<"${matchingJVMs[*]}"))
	unset IFS
 
 
	# get the highest matching JVM
	for ((i = 0; i < ${#matchingJVMs[@]}; i++));
	do
		# split JVM string at ':' delimiter to retain spaces in $path substring
		IFS=: arr=(${matchingJVMs[$i]}) ; unset IFS
		# [0] comparable JVM version number
		comp=${arr[0]}
		# [1] JVM version number
		ver=${arr[1]}
		# [2] JVM path
		path="${arr[2]}"
 
		# use current value as JAVACMD if it's executable
		if [ -x "$path" ] ; then
			JAVACMD="$path"
			JAVACMD_version=$comp
			break
		fi
	done
	# unset for loop variables
	unset arr comp ver path
fi
 
# log the Java Command and the extracted version number
stub_logger "[JavaCommand] '$JAVACMD'"
stub_logger "[JavaVersion] $(get_java_version_from_cmd "${JAVACMD}")${JAVACMD_version:+ / $JAVACMD_version}"
 
 
 
if [ -z "${JAVACMD}" ] || [ ! -x "${JAVACMD}" ] ; then
 
	# different error messages when a specific JVM was required
	if [ ! -z "${JVMVersion}" ] ; then
		# display human readable java version (#28)
		java_version_hr=$(echo ${JVMVersion} | sed -E 's/^1\.([0-9+*]+)$/ \1/g' | sed "s/+/ ${MSG_JAVA_VERSION_OR_LATER}/;s/*/ ${MSG_JAVA_VERSION_LATEST}/")
		MSG_NO_SUITABLE_JAVA_EXPANDED=$(printf "${MSG_NO_SUITABLE_JAVA}" "${java_version_hr}").
 
		if [ ! -z "${JVMMaxVersion}" ] ; then
			java_version_hr=$(extract_java_major_version ${JVMVersion})
			java_version_max_hr=$(echo ${JVMMaxVersion} | sed -E 's/^1\.([0-9+*]+)$/ \1/g' | sed "s/+//;s/*/ ${MSG_JAVA_VERSION_LATEST}/")
			MSG_NO_SUITABLE_JAVA_EXPANDED="$(printf "${MSG_NO_SUITABLE_JAVA}" "${java_version_hr}") $(printf "${MSG_JAVA_VERSION_MAX}" "${java_version_max_hr}")"
		fi
 
		# log exit cause
		stub_logger "[EXIT 3] ${MSG_NO_SUITABLE_JAVA_EXPANDED}"
 
		# display error message with AppleScript
		osascript -e "tell application \"System Events\" to display dialog \"${MSG_ERROR_LAUNCHING}\n\n${MSG_NO_SUITABLE_JAVA_EXPANDED}\n${MSG_NO_SUITABLE_JAVA_CHECK}\" with title \"${CFBundleName}\"  buttons {\" OK \", \"${MSG_VISIT_JAVA_DOT_COM}\", \"${MSG_VISIT_ADOPTOPENJDK}\"} default button 1${DialogWithIcon}" \
				-e "set response to button returned of the result" \
				-e "if response is \"${MSG_VISIT_JAVA_DOT_COM}\" then open location \"https://www.java.com/download/\"" \
				-e "if response is \"${MSG_VISIT_ADOPTOPENJDK}\" then open location \"https://adoptopenjdk.net/releases.html\""
		# exit with error
		exit 3
 
	else
		# log exit cause
		stub_logger "[EXIT 1] ${MSG_ERROR_LAUNCHING}"
		# display error message with AppleScript
		osascript -e "tell application \"System Events\" to display dialog \"${MSG_ERROR_LAUNCHING}\n\n${MSG_INSTALL_JAVA}\" with title \"${CFBundleName}\" buttons {\"${MSG_LATER}\", \"${MSG_VISIT_JAVA_DOT_COM}\", \"${MSG_VISIT_ADOPTOPENJDK}\"} default button 1${DialogWithIcon}" \
					-e "set response to button returned of the result" \
					-e "if response is \"${MSG_VISIT_JAVA_DOT_COM}\" then open location \"https://www.java.com/download/\"" \
					-e "if response is \"${MSG_VISIT_ADOPTOPENJDK}\" then open location \"https://adoptopenjdk.net/releases.html\""
		# exit with error
		exit 1
	fi
fi
 
 
 
# MainClass check
############################################
 
if [ -z "${JVMMainClass}" ]; then
	# log exit cause
	stub_logger "[EXIT 2] ${MSG_MISSING_MAINCLASS}"
	# display error message with AppleScript
	osascript -e "tell application \"System Events\" to display dialog \"${MSG_ERROR_LAUNCHING}\n\n${MSG_MISSING_MAINCLASS}\" with title \"${CFBundleName}\" buttons {\" OK \"} default button 1${DialogWithIcon}"
	# exit with error
	exit 2
fi
 
 
 
# execute $JAVACMD and do some preparation
############################################
 
# enable drag&drop to the dock icon
export CFProcessPath="$0"
 
# remove Apples ProcessSerialNumber from passthru arguments (#39)
if [[ "$*" == -psn* ]] ; then
	ArgsPassthru=()
else
	ArgsPassthru=("$@")
fi
 
# change to Working Directory based upon Apple/Oracle Plist info
cd "${WorkingDirectory}" || exit 13
stub_logger "[WorkingDirectory] ${WorkingDirectory}"
 
# execute Java and set
# - classpath
# - splash image
# - dock icon
# - app name
# - JVM options / properties (-D)
# - JVM default options (-X)
# - main class
# - main class arguments
# - passthrough arguments from Terminal or Drag'n'Drop to Finder icon
stub_logger "[Exec] \"$JAVACMD\" -cp \"${JVMClassPath}\" -splash:\"${ResourcesFolder}/${JVMSplashFile}\" -Xdock:icon=\"${ResourcesFolder}/${CFBundleIconFile}\" -Xdock:name=\"${CFBundleName}\" ${JVMOptionsArr:+$(printf "'%s' " "${JVMOptionsArr[@]}") }${JVMDefaultOptions:+$JVMDefaultOptions }${JVMMainClass}${MainArgsArr:+ $(printf "'%s' " "${MainArgsArr[@]}")}${ArgsPassthru:+ $(printf "'%s' " "${ArgsPassthru[@]}")}"
exec "${JAVACMD}" \
		-cp "${JVMClassPath}" \
		-splash:"${ResourcesFolder}/${JVMSplashFile}" \
		-Xdock:icon="${ResourcesFolder}/${CFBundleIconFile}" \
		-Xdock:name="${CFBundleName}" \
		${JVMOptionsArr:+"${JVMOptionsArr[@]}" }\
		${JVMDefaultOptions:+$JVMDefaultOptions }\
		"${JVMMainClass}"\
		${MainArgsArr:+ "${MainArgsArr[@]}"}\
		${ArgsPassthru:+ "${ArgsPassthru[@]}"}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329
  • 330
  • 331
  • 332
  • 333
  • 334
  • 335
  • 336
  • 337
  • 338
  • 339
  • 340
  • 341
  • 342
  • 343
  • 344
  • 345
  • 346
  • 347
  • 348
  • 349
  • 350
  • 351
  • 352
  • 353
  • 354
  • 355
  • 356
  • 357
  • 358
  • 359
  • 360
  • 361
  • 362
  • 363
  • 364
  • 365
  • 366
  • 367
  • 368
  • 369
  • 370
  • 371
  • 372
  • 373
  • 374
  • 375
  • 376
  • 377
  • 378
  • 379
  • 380
  • 381
  • 382
  • 383
  • 384
  • 385
  • 386
  • 387
  • 388
  • 389
  • 390
  • 391
  • 392
  • 393
  • 394
  • 395
  • 396
  • 397
  • 398
  • 399
  • 400
  • 401
  • 402
  • 403
  • 404
  • 405
  • 406
  • 407
  • 408
  • 409
  • 410
  • 411
  • 412
  • 413
  • 414
  • 415
  • 416
  • 417
  • 418
  • 419
  • 420
  • 421
  • 422
  • 423
  • 424
  • 425
  • 426
  • 427
  • 428
  • 429
  • 430
  • 431
  • 432
  • 433
  • 434
  • 435
  • 436
  • 437
  • 438
  • 439
  • 440
  • 441
  • 442
  • 443
  • 444
  • 445
  • 446
  • 447
  • 448
  • 449
  • 450
  • 451
  • 452
  • 453
  • 454
  • 455
  • 456
  • 457
  • 458
  • 459
  • 460
  • 461
  • 462
  • 463
  • 464
  • 465
  • 466
  • 467
  • 468
  • 469
  • 470
  • 471
  • 472
  • 473
  • 474
  • 475
  • 476
  • 477
  • 478
  • 479
  • 480
  • 481
  • 482
  • 483
  • 484
  • 485
  • 486
  • 487
  • 488
  • 489
  • 490
  • 491
  • 492
  • 493
  • 494
  • 495
  • 496
  • 497
  • 498
  • 499
  • 500
  • 501
  • 502
  • 503
  • 504
  • 505
  • 506
  • 507
  • 508
  • 509
  • 510
  • 511
  • 512
  • 513
  • 514
  • 515
  • 516
  • 517
  • 518
  • 519
  • 520
  • 521
  • 522
  • 523
  • 524
  • 525
  • 526
  • 527
  • 528
  • 529
  • 530
  • 531
  • 532
  • 533
  • 534
  • 535
  • 536
  • 537
  • 538
  • 539
  • 540
  • 541
  • 542
  • 543
  • 544
  • 545
  • 546
  • 547
  • 548
  • 549
  • 550
  • 551
  • 552
  • 553
  • 554
  • 555
  • 556
  • 557
  • 558
  • 559
  • 560
  • 561
  • 562
  • 563
  • 564
  • 565
  • 566
  • 567
  • 568
  • 569
  • 570
  • 571
  • 572
  • 573
  • 574
  • 575
  • 576
  • 577
  • 578
  • 579
  • 580
  • 581
  • 582
  • 583
  • 584
  • 585
  • 586
  • 587
  • 588
  • 589
  • 590
  • 591
  • 592
  • 593
  • 594
  • 595
  • 596
  • 597
  • 598
  • 599
  • 600
  • 601
  • 602
  • 603
  • 604
  • 605
  • 606
  • 607
  • 608
  • 609
  • 610
  • 611
  • 612
  • 613
  • 614
  • 615
  • 616
  • 617
  • 618
  • 619
  • 620
  • 621
  • 622
  • 623
  • 624
  • 625
  • 626
  • 627
  • 628
  • 629
  • 630
  • 631
  • 632
  • 633
  • 634
  • 635
  • 636
  • 637
  • 638
  • 639
  • 640
  • 641
  • 642
  • 643
  • 644
  • 645
  • 646
  • 647
  • 648
  • 649
  • 650
  • 651
  • 652
  • 653
  • 654
  • 655
  • 656
  • 657
  • 658
  • 659
  • 660
  • 661
  • 662
  • 663
  • 664
  • 665
  • 666
  • 667
  • 668
  • 669
  • 670
  • 671
  • 672
  • 673
  • 674
  • 675
  • 676
  • 677
  • 678
  • 679
  • 680
  • 681
  • 682
  • 683
  • 684
  • 685
  • 686
  • 687
  • 688
  • 689
  • 690
  • 691
  • 692
  • 693
  • 694
  • 695
  • 696
  • 697
  • 698
  • 699
  • 700
  • 701
  • 702
  • 703
  • 704
  • 705
  • 706
  • 707
  • 708
  • 709
  • 710
  • 711
  • 712
  • 713
  • 714
  • 715
  • 716
  • 717
  • 718
  • 719
  • 720
  • 721
  • 722
  • 723
  • 724
  • 725
  • 726
  • 727
  • 728
  • 729
  • 730
  • 731
  • 732
  • 733
  • 734
  • 735
  • 736
  • 737
  • 738
  • 739
  • 740
  • 741
  • 742
  • 743
  • 744
  • 745
  • 746
  • 747
  • 748
  • 749
  • 750
  • 751
  • 752
  • 753
  • 754
  • 755
  • 756
  • 757
  • 758
  • 759
  • 760
  • 761
  • 762
  • 763
  • 764
  • 765
  • 766
  • 767
  • 768
  • 769
  • 770
  • 771
  • 772
  • 773
  • 774
  • 775
  • 776
  • 777
  • 778
  • 779
  • 780
  • 781
  • 782
  • 783
  • 784
  • 785
  • 786
  • 787
  • 788
  • 789
  • 790
  • 791
  • 792
  • 793
  • 794
  • 795
  • 796
  • 797

2.3 关于使用

打开软件,选择自己要反编译的文件即可;
在这里插入图片描述
确认文件打开之后,我们就能看到反编译的源代码了;
在这里插入图片描述

三、最后

Windows的宝子们,方法上大同小异的,除了下载包区分一下,其他基本一致的问题;

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/818621
推荐阅读
相关标签
  

闽ICP备14008679号