├── GUITools.png ├── ipaTest ├── target │ ├── maven-status │ │ └── maven-compiler-plugin │ │ │ ├── compile │ │ │ └── default-compile │ │ │ │ ├── createdFiles.lst │ │ │ │ └── inputFiles.lst │ │ │ └── testCompile │ │ │ └── default-testCompile │ │ │ └── inputFiles.lst │ ├── ipaTest-1.0-SNAPSHOT.jar │ ├── maven-archiver │ │ └── pom.properties │ └── ipaTest-1.0-SNAPSHOT-jar-with-dependencies.jar ├── ipaTest.iml ├── src │ └── main │ │ └── java │ │ ├── utils │ │ ├── ReUtils.java │ │ ├── FileUtils.java │ │ └── IpaUtil.java │ │ ├── test.java │ │ ├── vo │ │ └── ipaInfo.java │ │ └── MainUI.java └── pom.xml ├── iOS-checkIPA.jar ├── README.md ├── .gitignore └── AnalysisRecord └── ipa文件分析.txt /GUITools.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Github-Benjamin/iOS-checkIPA/HEAD/GUITools.png -------------------------------------------------------------------------------- /ipaTest/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /iOS-checkIPA.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Github-Benjamin/iOS-checkIPA/HEAD/iOS-checkIPA.jar -------------------------------------------------------------------------------- /ipaTest/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/inputFiles.lst: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ipaTest/ipaTest.iml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /ipaTest/target/ipaTest-1.0-SNAPSHOT.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Github-Benjamin/iOS-checkIPA/HEAD/ipaTest/target/ipaTest-1.0-SNAPSHOT.jar -------------------------------------------------------------------------------- /ipaTest/target/maven-archiver/pom.properties: -------------------------------------------------------------------------------- 1 | #Generated by Maven 2 | #Wed Jan 09 21:18:03 CST 2019 3 | version=1.0-SNAPSHOT 4 | groupId=ipaTest 5 | artifactId=ipaTest 6 | -------------------------------------------------------------------------------- /ipaTest/target/ipaTest-1.0-SNAPSHOT-jar-with-dependencies.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Github-Benjamin/iOS-checkIPA/HEAD/ipaTest/target/ipaTest-1.0-SNAPSHOT-jar-with-dependencies.jar -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # iOS-checkIPA 2 | Java Scans an IPA file and parses its Info.plist and embedded.mobileprovision files. Performs checks of expected key/value relationships and displays the results. 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | *.war 15 | *.nar 16 | *.ear 17 | *.zip 18 | *.tar.gz 19 | *.rar 20 | 21 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 22 | hs_err_pid* 23 | -------------------------------------------------------------------------------- /ipaTest/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst: -------------------------------------------------------------------------------- 1 | C:\Users\xielianshi\Desktop\javas\ipaTest\src\main\java\utils\IpaUtil.java 2 | C:\Users\xielianshi\Desktop\javas\ipaTest\src\main\java\MainUI.java 3 | C:\Users\xielianshi\Desktop\javas\ipaTest\src\main\java\utils\FileUtils.java 4 | C:\Users\xielianshi\Desktop\javas\ipaTest\src\main\java\vo\ipaInfo.java 5 | C:\Users\xielianshi\Desktop\javas\ipaTest\src\main\java\utils\ReUtils.java 6 | C:\Users\xielianshi\Desktop\javas\ipaTest\src\main\java\test.java 7 | -------------------------------------------------------------------------------- /ipaTest/src/main/java/utils/ReUtils.java: -------------------------------------------------------------------------------- 1 | package utils; 2 | 3 | import java.util.regex.Matcher; 4 | import java.util.regex.Pattern; 5 | 6 | /** 7 | * Created by Benjamin on 2019/1/9. 8 | */ 9 | public class ReUtils { 10 | 11 | // 传入正则表达式和字符串匹配指定字符串 12 | public static String findString(String filedata,String re){ 13 | // 正则匹配dict字段 14 | Pattern fildDict = Pattern.compile(re); 15 | Matcher fildDictData = fildDict.matcher(filedata); 16 | if ( fildDictData.find( )) { 17 | return fildDictData.group(1); 18 | } 19 | return null; 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /AnalysisRecord/ipa文件分析.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | iOS Info.plist 5 | Android AndroidManifest.xml 6 | 7 | 在线解析: 8 | http://www.atool.org/plist_reader.php 9 | 10 | 扫毒报告: 11 | https://www.virustotal.com/zh-cn/file/fd23a30f2f6d2f1b0b2aae18e4f5be3adbe3a05752937cbcdfd5a362dbe26ae5/analysis/1546943243/ 12 | 13 | 14 | 15 | ---------------- 16 | 文件基本信息 17 | ---------------- 18 | 19 | CFBundleIconFiles icon 20 | 21 | CFBundleName | name 22 | CFBundleIdentifier | packge 23 | CFBundleShortVersionString | versionName 24 | CFBundleVersion | versionCode 25 | MinimumOSVersion | Min.SDK 26 | 证书MD5 | 目前缺失 27 | 28 | 29 | 文件信息: 30 | 文件名路径 31 | MD5 32 | 大小 33 | 34 | 35 | 36 | 签名信息:embedded.mobileprovision 37 | 38 | Name | string | iOS Team Inhouse Provisioning Profile: xxx 39 | AppIDName | string | XC com xxx 40 | UUID | string | xxx 41 | TeamName | string | xxx 42 | CreationDate | date 无需要该信息 | 2018-04-28T06:52:43Z 43 | ExpirationDate | date | 2018-12-15T04:23:56Z 44 | -------------------------------------------------------------------------------- /ipaTest/src/main/java/test.java: -------------------------------------------------------------------------------- 1 | 2 | import org.apache.commons.codec.digest.DigestUtils; 3 | import utils.IpaUtil; 4 | import vo.ipaInfo; 5 | import java.io.*; 6 | import java.text.DecimalFormat; 7 | 8 | 9 | /** 10 | * Created by Benjamin on 2019/1/8. 11 | */ 12 | public class test { 13 | 14 | private static String filename = "C:\\Users\\xielianshi\\Desktop\\iOS测试整理\\test\\aibench.ipa"; 15 | 16 | public static void main(String[] args) throws Exception { 17 | 18 | 19 | // System.out.println(DigestUtils.md5Hex(new FileInputStream(filename))); // 获取文件MD5 20 | // 21 | // File file = new File(filename); 22 | // if (file.exists() && file.isFile()) { 23 | // String fileName = file.getName(); 24 | // System.out.println(file.length()); // 打印字节 25 | // 26 | // float num= (float)file.length()/1024/1024; 27 | // DecimalFormat df = new DecimalFormat("0.00");//格式化小数 28 | // String s = df.format(num); 29 | // System.out.println(s); 30 | // } 31 | 32 | 33 | // File files = new File(filename); 34 | // IpaUtil.getIpaMobileProvisio(files); 35 | // 36 | // // 获取一条信息 37 | // System.out.println(ipaInfo.getAppName()); 38 | // System.out.println(ipaInfo.getPackgeName()); 39 | // System.out.println(ipaInfo.getVersionCode()); 40 | // System.out.println(ipaInfo.getVersionName()); 41 | // System.out.println(ipaInfo.getMinSdk()); 42 | // 43 | // System.out.println(ipaInfo.getProvisionName()); 44 | // System.out.println(ipaInfo.getAppIDName()); 45 | // System.out.println(ipaInfo.getUUID()); 46 | // System.out.println(ipaInfo.getTeamName()); 47 | // System.out.println(ipaInfo.getExpirationDate()); 48 | 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /ipaTest/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | ipaTest 8 | ipaTest 9 | 1.0-SNAPSHOT 10 | 11 | 12 | 13 | 14 | 15 | 16 | commons-codec 17 | commons-codec 18 | 1.11 19 | 20 | 21 | com.googlecode.plist 22 | dd-plist 23 | 1.16 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | org.apache.maven.plugins 36 | maven-assembly-plugin 37 | 2.5.5 38 | 39 | 40 | 41 | 42 | MainUI 43 | 44 | 45 | 46 | jar-with-dependencies 47 | 48 | 49 | 50 | 51 | org.apache.maven.plugins 52 | maven-compiler-plugin 53 | 54 | 6 55 | 6 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /ipaTest/src/main/java/utils/FileUtils.java: -------------------------------------------------------------------------------- 1 | package utils; 2 | 3 | import org.apache.commons.codec.digest.DigestUtils; 4 | import vo.ipaInfo; 5 | 6 | import java.io.*; 7 | import java.text.DecimalFormat; 8 | 9 | /** 10 | * Created by Benjamin on 2019/1/9. 11 | */ 12 | public class FileUtils { 13 | 14 | // 回收资源,删除文件 15 | public static void fileDelet(File filename){ 16 | // 如果有必要,应该删除解压的结果文件 17 | boolean result = filename.delete(); 18 | 19 | int tryCount = 0; 20 | while(!result && tryCount++ < 6 ) 21 | { 22 | System.gc(); 23 | result = filename.delete(); 24 | } 25 | 26 | // if ( !result ) { 27 | // System.gc(); // 强制解除对文件的占用,回收资源 28 | // filename.delete(); 29 | // } 30 | 31 | filename.getParentFile().delete(); 32 | 33 | } 34 | 35 | // 读文件并以字符串形式返回 36 | public static String fileRead(File filename) throws IOException { 37 | /* 读入文件 */ 38 | InputStreamReader reader = new InputStreamReader(new FileInputStream(filename)); // 建立一个输入流对象reader 39 | BufferedReader br = new BufferedReader(reader); // 建立一个对象,它把文件内容转成计算机能读懂的语言 40 | 41 | String filedata = ""; 42 | String line = ""; 43 | line = br.readLine(); 44 | while (line != null) { 45 | line = br.readLine(); // 一次读入一行数据 46 | filedata += line; 47 | } 48 | br.close(); // 关闭文件流 49 | 50 | return filedata; 51 | } 52 | 53 | // 判断文件后缀名并存储到实体类中 54 | public static void fileName(String dirpath,String filename){ 55 | 56 | if ( filename.substring(filename.length() - 3).equals("ipa") ){ //文件后缀名是否包含 ipa 57 | ipaInfo.setFilePath( dirpath + filename ); 58 | }else if (dirpath == null || filename == null){ //判断路径和文件是否为空 59 | ipaInfo.setFilePath( null ); 60 | } 61 | else{ 62 | ipaInfo.setFilePath( null ); 63 | } 64 | 65 | } 66 | 67 | // 获取文件MD5 68 | public static void getFileMD5(String filename) throws IOException { 69 | // 设置文件MD5值 70 | String fileMD5 = DigestUtils.md5Hex(new FileInputStream(filename)); 71 | ipaInfo.setFileMD5(fileMD5); 72 | 73 | } 74 | 75 | // 获取文件大小 76 | public static void getFileSize(String filename) throws IOException { 77 | 78 | getFileMD5(filename); // 获取文件MD5 79 | 80 | File file = new File(filename); 81 | if (file.exists() && file.isFile()) { 82 | 83 | long filelen = file.length(); 84 | float num= (float)filelen/1024/1024; 85 | DecimalFormat df = new DecimalFormat("0.00"); //格式化小数 86 | 87 | ipaInfo.setFileSizeByte(String.valueOf(filelen)); 88 | ipaInfo.setFileSizeMB(df.format(num)); 89 | } 90 | 91 | } 92 | 93 | 94 | 95 | } 96 | -------------------------------------------------------------------------------- /ipaTest/src/main/java/vo/ipaInfo.java: -------------------------------------------------------------------------------- 1 | package vo; 2 | 3 | import java.io.File; 4 | 5 | /** 6 | * Created by Benjamin on 2019/1/9. 7 | */ 8 | public class ipaInfo { 9 | public static String appName; 10 | public static String packgeName; 11 | public static String versionCode; 12 | public static String versionName; 13 | public static String minSdk; 14 | 15 | public static String provisionName; 16 | public static String AppIDName; 17 | public static String UUID; 18 | public static String TeamName; 19 | public static String ExpirationDate; 20 | 21 | public static String filePath; 22 | public static File mobileprovision; 23 | 24 | public static String fileMD5; 25 | public static String fileSizeByte; 26 | public static String fileSizeMB; 27 | 28 | 29 | public static String getAppName() { 30 | return appName; 31 | } 32 | 33 | public static void setAppName(String appName) { 34 | ipaInfo.appName = appName; 35 | } 36 | 37 | public static String getPackgeName() { 38 | return packgeName; 39 | } 40 | 41 | public static void setPackgeName(String packgeName) { 42 | ipaInfo.packgeName = packgeName; 43 | } 44 | 45 | public static String getVersionCode() { 46 | return versionCode; 47 | } 48 | 49 | public static void setVersionCode(String versionCode) { 50 | ipaInfo.versionCode = versionCode; 51 | } 52 | 53 | public static String getVersionName() { 54 | return versionName; 55 | } 56 | 57 | public static void setVersionName(String versionName) { 58 | ipaInfo.versionName = versionName; 59 | } 60 | 61 | public static String getMinSdk() { 62 | return minSdk; 63 | } 64 | 65 | public static void setMinSdk(String minSdk) { 66 | ipaInfo.minSdk = minSdk; 67 | } 68 | 69 | public static String getProvisionName() { 70 | return provisionName; 71 | } 72 | 73 | public static void setProvisionName(String provisionName) { 74 | ipaInfo.provisionName = provisionName; 75 | } 76 | 77 | public static String getAppIDName() { 78 | return AppIDName; 79 | } 80 | 81 | public static void setAppIDName(String appIDName) { 82 | AppIDName = appIDName; 83 | } 84 | 85 | public static String getUUID() { 86 | return UUID; 87 | } 88 | 89 | public static void setUUID(String UUID) { 90 | ipaInfo.UUID = UUID; 91 | } 92 | 93 | public static String getTeamName() { 94 | return TeamName; 95 | } 96 | 97 | public static void setTeamName(String teamName) { 98 | TeamName = teamName; 99 | } 100 | 101 | public static String getExpirationDate() { 102 | return ExpirationDate; 103 | } 104 | 105 | public static void setExpirationDate(String expirationDate) { 106 | ExpirationDate = expirationDate; 107 | } 108 | 109 | public static String getFilePath() { 110 | return filePath; 111 | } 112 | 113 | public static void setFilePath(String filePath) { 114 | ipaInfo.filePath = filePath; 115 | } 116 | 117 | public static File getMobileprovision() { 118 | return mobileprovision; 119 | } 120 | 121 | public static void setMobileprovision(File mobileprovision) { 122 | ipaInfo.mobileprovision = mobileprovision; 123 | } 124 | 125 | public static String getFileMD5() { 126 | return fileMD5; 127 | } 128 | 129 | public static void setFileMD5(String fileMD5) { 130 | ipaInfo.fileMD5 = fileMD5; 131 | } 132 | 133 | public static String getFileSizeByte() { 134 | return fileSizeByte; 135 | } 136 | 137 | public static void setFileSizeByte(String fileSizeByte) { 138 | ipaInfo.fileSizeByte = fileSizeByte; 139 | } 140 | 141 | public static String getFileSizeMB() { 142 | return fileSizeMB; 143 | } 144 | 145 | public static void setFileSizeMB(String fileSizeMB) { 146 | ipaInfo.fileSizeMB = fileSizeMB; 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /ipaTest/src/main/java/MainUI.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Benjamin on 2018/12/2. 3 | */ 4 | 5 | import utils.FileUtils; 6 | import utils.IpaUtil; 7 | import vo.ipaInfo; 8 | 9 | import javax.swing.*; 10 | import java.awt.*; 11 | import java.awt.event.ActionEvent; 12 | import java.awt.event.ActionListener; 13 | import java.io.File; 14 | 15 | public class MainUI extends JFrame implements ActionListener { 16 | 17 | // 定义组件 18 | private static FileDialog openDia; // 文件打开窗口 19 | JButton EnterBtn,EmptyBtn; // 定义确认按钮 20 | JMenuItem MenuAbout; 21 | JLabel ipainfo,noneline,fileinfo,appName,packgeName,versionCode,versionName,minSdk,provisionName,AppIDName,UUID,TeamName,ExpirationDate,filePaths,fileMD5,fileSize; 22 | 23 | public static void main(String[] args) { 24 | MainUI mUI=new MainUI(); 25 | } 26 | 27 | public MainUI() 28 | { 29 | 30 | // 创建组件并设置监听 31 | EnterBtn = new JButton("获取IPA信息"); 32 | EmptyBtn = new JButton("清空"); 33 | EnterBtn.addActionListener(this); 34 | EmptyBtn.addActionListener(this); 35 | 36 | //初始化一个菜单栏 37 | JMenuBar menuBar = new JMenuBar(); 38 | MenuAbout = new JMenuItem("About"); 39 | menuBar.add(MenuAbout); 40 | myEvent(); // 加载菜单栏监听事件处理 41 | 42 | getContentPane().add(new JLabel("IPA 信息", SwingConstants.CENTER )); 43 | ipainfo = new JLabel(""); 44 | getContentPane().add(ipainfo); 45 | 46 | getContentPane().add(new JLabel("appName:", SwingConstants.CENTER )); 47 | appName = new JLabel("CFBundleName"); 48 | getContentPane().add(appName); 49 | 50 | getContentPane().add(new JLabel("packgeName:", SwingConstants.CENTER )); 51 | packgeName = new JLabel("CFBundleIdentifier"); 52 | getContentPane().add(packgeName); 53 | 54 | getContentPane().add(new JLabel("versionName:", SwingConstants.CENTER )); 55 | versionName = new JLabel("CFBundleShortVersionString"); 56 | getContentPane().add(versionName); 57 | 58 | getContentPane().add(new JLabel("versionCode:", SwingConstants.CENTER )); 59 | versionCode = new JLabel("CFBundleVersion"); 60 | getContentPane().add(versionCode); 61 | 62 | getContentPane().add(new JLabel("minSdk:", SwingConstants.CENTER )); 63 | minSdk = new JLabel("MinimumOSVersion"); 64 | getContentPane().add(minSdk); 65 | 66 | getContentPane().add(new JLabel("provisionName:", SwingConstants.CENTER )); 67 | provisionName = new JLabel("provisionName"); 68 | getContentPane().add(provisionName); 69 | 70 | getContentPane().add(new JLabel("AppIDName:", SwingConstants.CENTER )); 71 | AppIDName = new JLabel("provisionAppIDName", SwingConstants.LEFT ); 72 | getContentPane().add(AppIDName); 73 | 74 | getContentPane().add(new JLabel("UUID:", SwingConstants.CENTER )); 75 | UUID = new JLabel("provisionUUID", SwingConstants.LEFT ); 76 | getContentPane().add(UUID); 77 | 78 | getContentPane().add(new JLabel("TeamName:", SwingConstants.CENTER )); 79 | TeamName = new JLabel("TeamName", SwingConstants.LEFT ); 80 | getContentPane().add(TeamName); 81 | 82 | getContentPane().add(new JLabel("ExpirationDate:", SwingConstants.CENTER )); 83 | ExpirationDate = new JLabel("ExpirationDate", SwingConstants.LEFT ); 84 | getContentPane().add(ExpirationDate); 85 | 86 | getContentPane().add(new JLabel(" ", SwingConstants.CENTER )); 87 | noneline = new JLabel(" "); 88 | getContentPane().add(noneline); 89 | 90 | getContentPane().add(new JLabel("文件信息", SwingConstants.CENTER )); 91 | fileinfo = new JLabel(""); 92 | getContentPane().add(fileinfo); 93 | 94 | getContentPane().add(new JLabel("filePath:", SwingConstants.CENTER )); 95 | filePaths = new JLabel("filePath"); 96 | getContentPane().add(filePaths); 97 | 98 | getContentPane().add(new JLabel("fileMD5:", SwingConstants.CENTER )); 99 | fileMD5 = new JLabel("fileMD5"); 100 | getContentPane().add(fileMD5); 101 | 102 | getContentPane().add(new JLabel("fileSize:", SwingConstants.CENTER )); 103 | fileSize = new JLabel("fileSize"); 104 | getContentPane().add(fileSize); 105 | 106 | getContentPane().add(new JLabel(" ", SwingConstants.CENTER )); 107 | noneline = new JLabel(" "); 108 | getContentPane().add(noneline); 109 | 110 | getContentPane().add(EnterBtn); 111 | getContentPane().add(EmptyBtn); 112 | 113 | openDia = new FileDialog(this, "打开", FileDialog.LOAD); 114 | 115 | this.setJMenuBar(menuBar); //设置菜单栏 116 | this.setLayout(new GridLayout(0,2)); //选择GridLayout布局管理器 117 | this.setTitle("iOS-checkIPA"); 118 | this.setSize(700,500); 119 | this.setLocation(0, 0); 120 | this.setLocationRelativeTo(null);//窗体居中显示 121 | this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //设置当关闭窗口时,保证JVM也退出 122 | this.setVisible(true); 123 | this.setResizable(true); 124 | 125 | } 126 | 127 | 128 | // 菜单栏监听 129 | private void myEvent() 130 | { 131 | // About 菜单栏监听 132 | MenuAbout.addActionListener(new ActionListener() 133 | { 134 | public void actionPerformed(ActionEvent e) 135 | { 136 | JOptionPane.showMessageDialog(null, "Author: Benjamin\nWeChat: WeChat_Benjamin\nEmail: Benjamin_v@qq.com", "AboutInfo",JOptionPane.INFORMATION_MESSAGE); 137 | return; 138 | } 139 | }); 140 | } 141 | 142 | 143 | // 事件判断 144 | @Override 145 | public void actionPerformed(ActionEvent e) { 146 | 147 | if(e.getActionCommand()=="获取IPA信息") { 148 | 149 | getFilePath(); // 获取文件路径 150 | String filePath = ipaInfo.getFilePath(); 151 | 152 | 153 | if ( filePath == null ){ //判断路径和文件是否为空,或非ipa后缀文件 154 | JOptionPane.showMessageDialog(null,"读取ipa文件异常,请切换文件或替换文件目录后重试。","提示消息",JOptionPane.WARNING_MESSAGE); 155 | return; 156 | } else { 157 | try { 158 | FileUtils.getFileSize(filePath); // 获取文件信息 159 | File files = new File(filePath); // 获取ipa文件路径 160 | IpaUtil.getIpaMobileProvisio(files); // 获取并分析文件信息 161 | } catch (Exception e1) { 162 | JOptionPane.showMessageDialog(null,"读取ipa文件异常,请切换文件或替换文件目录后重试。","提示消息",JOptionPane.WARNING_MESSAGE); 163 | e1.printStackTrace(); 164 | return; 165 | } 166 | 167 | appName.setText(ipaInfo.getAppName()); 168 | packgeName.setText(ipaInfo.getPackgeName()); 169 | versionCode.setText(ipaInfo.getVersionCode()); 170 | versionName.setText(ipaInfo.getVersionName()); 171 | minSdk.setText(ipaInfo.getMinSdk()); 172 | provisionName.setText(ipaInfo.getProvisionName()); 173 | AppIDName.setText(ipaInfo.getAppIDName()); 174 | UUID.setText(ipaInfo.getUUID()); 175 | TeamName.setText(ipaInfo.getTeamName()); 176 | ExpirationDate.setText(ipaInfo.getExpirationDate()); 177 | 178 | filePaths.setText(ipaInfo.getFilePath()); 179 | fileMD5.setText(ipaInfo.getFileMD5()); 180 | fileSize.setText( ipaInfo.getFileSizeByte() + " 字节(" + ipaInfo.getFileSizeMB() + " MB)" ); 181 | 182 | return; 183 | } 184 | 185 | } 186 | 187 | else if(e.getActionCommand() == "清空" ){ 188 | 189 | Object ipaInfo=new ipaInfo(); 190 | ipaInfo = null; // 清空对象,对象被赋值为null将被视为垃圾 191 | 192 | appName.setText("NaN"); 193 | packgeName.setText("NaN"); 194 | versionCode.setText("NaN"); 195 | versionName.setText("NaN"); 196 | minSdk.setText("NaN"); 197 | provisionName.setText("NaN"); 198 | AppIDName.setText("NaN"); 199 | UUID.setText("NaN"); 200 | TeamName.setText("NaN"); 201 | ExpirationDate.setText("NaN"); 202 | 203 | filePaths.setText("NaN"); 204 | fileMD5.setText("NaN"); 205 | fileSize.setText("NaN"); 206 | 207 | return; 208 | 209 | } 210 | 211 | } 212 | 213 | // 弹出窗口选择获取文件路径 214 | public static void getFilePath(){ 215 | openDia.setVisible(true); // 显示打开文件对话框 216 | String dirpath = openDia.getDirectory(); //获取打开文件路径并保存到字符串中。 217 | String fileName = openDia.getFile(); //获取打开文件名称并保存到字符串中 218 | // System.out.println(dirpath+fileName); // 打印获取到的文件路径 219 | FileUtils.fileName(dirpath,fileName); // 判断文件后缀 220 | } 221 | 222 | 223 | } 224 | -------------------------------------------------------------------------------- /ipaTest/src/main/java/utils/IpaUtil.java: -------------------------------------------------------------------------------- 1 | 2 | package utils; 3 | 4 | import com.dd.plist.NSDictionary; 5 | import com.dd.plist.NSString; 6 | import com.dd.plist.PropertyListParser; 7 | import vo.ipaInfo; 8 | import java.io.*; 9 | import java.util.Enumeration; 10 | import java.util.zip.ZipEntry; 11 | import java.util.zip.ZipFile; 12 | 13 | /** 14 | * Created by Benjamin on 2019/1/8. 15 | */ 16 | 17 | 18 | 19 | public class IpaUtil { 20 | 21 | private static String reBody = "(.*?)"; 22 | private static String reprovisionName = "Name.*?(.*?)"; 23 | private static String reAppIDName = "AppIDName.*?(.*?)"; 24 | private static String reUUID = "UUID.*?(.*?)"; 25 | private static String reTeamName = "TeamName.*?(.*?)"; 26 | private static String reExpirationDate = "ExpirationDate.*?(.*?)"; 27 | private static String notFoundFile = "ipa no embedded.mobileprovision file"; 28 | 29 | /** 30 | * 解压IPA文件,只获取IPA文件中的Info.plist、embedded.mobileprovision文件存储指定位置 31 | * @param file zip文件 32 | * @param unzipDirectory 解压到的目录 33 | * @throws Exception 34 | */ 35 | private static File getZipInfo(File file, String unzipDirectory) throws Exception{ 36 | // 定义输入输出流对象 37 | InputStream input = null; 38 | OutputStream output = null; 39 | File result = null; 40 | File unzipFile = null; 41 | ZipFile zipFile = null; 42 | 43 | try{ 44 | // 创建zip文件对象 45 | zipFile = new ZipFile(file); 46 | // 创建本zip文件解压目录 47 | String name = file.getName().substring(0, file.getName().lastIndexOf(".")); 48 | unzipFile = new File(unzipDirectory + "/" + name); 49 | if(unzipFile.exists()){ 50 | unzipFile.delete(); 51 | } 52 | unzipFile.mkdir(); 53 | // 得到zip文件条目枚举对象 54 | Enumeration zipEnum = zipFile.entries(); 55 | // 定义对象 56 | ZipEntry entry = null; 57 | String entryName = null; 58 | String names[] = null; 59 | int length; 60 | 61 | // 循环读取条目 62 | while(zipEnum.hasMoreElements()){ 63 | // 得到当前条目 64 | entry = zipEnum.nextElement(); 65 | entryName = new String(entry.getName()); 66 | // 用/分隔条目名称 67 | names = entryName.split("\\/"); 68 | length = names.length; 69 | for(int v = 0; v < length; v++){ 70 | 71 | 72 | if(entryName.endsWith(".app/embedded.mobileprovision")){ // 为embedded.mobileprovision文件,则输出到文件 73 | input = zipFile.getInputStream(entry); 74 | result = new File(unzipFile.getAbsolutePath() + "/embedded.mobileprovision"); 75 | ipaInfo.setMobileprovision(result); // 将embedded.mobileprovision存到模块实体类中 76 | output = new FileOutputStream(result); 77 | byte[] buffer = new byte[1024 * 8]; 78 | int readLen = 0; 79 | while((readLen = input.read(buffer, 0, 1024 * 8)) != -1){ 80 | output.write(buffer, 0, readLen); 81 | } 82 | break; 83 | } 84 | 85 | if(entryName.endsWith(".app/Info.plist")){ // 为Info.plist文件,则输出到文件 86 | input = zipFile.getInputStream(entry); 87 | result = new File(unzipFile.getAbsolutePath() + "/Info.plist"); 88 | output = new FileOutputStream(result); 89 | byte[] buffer = new byte[1024 * 8]; 90 | int readLen = 0; 91 | while((readLen = input.read(buffer, 0, 1024 * 8)) != -1){ 92 | output.write(buffer, 0, readLen); 93 | } 94 | break; 95 | } 96 | 97 | } 98 | } 99 | } 100 | catch(Exception ex){ 101 | ex.printStackTrace(); 102 | } 103 | finally{ 104 | if(input != null){ 105 | input.close(); 106 | } 107 | if(output != null){ 108 | output.flush(); 109 | output.close(); 110 | } 111 | // 必须关流,否则文件无法删除 112 | if(zipFile != null){ 113 | zipFile.close(); 114 | } 115 | } 116 | 117 | // 如果有必要删除多余的文件 118 | if(file.exists()){ 119 | file.delete(); 120 | } 121 | 122 | return result; 123 | } 124 | 125 | 126 | 127 | /** 128 | * IPA文件的拷贝,把一个IPA文件复制为Zip文件,同时返回Info.plist文件 参数 oldfile 为 IPA文件 129 | */ 130 | private static File getIpaInfo(File oldfile) throws IOException { 131 | try{ 132 | int byteread = 0; 133 | String filename = oldfile.getAbsolutePath().replaceAll(".ipa", ".zip"); 134 | File newfile = new File(filename); 135 | if(oldfile.exists()){ 136 | // 创建一个Zip文件 137 | InputStream inStream = new FileInputStream(oldfile); 138 | FileOutputStream fs = new FileOutputStream(newfile); 139 | byte[] buffer = new byte[1444]; 140 | while((byteread = inStream.read(buffer)) != -1){ 141 | fs.write(buffer, 0, byteread); 142 | } 143 | if(inStream != null){ 144 | inStream.close(); 145 | } 146 | if(fs != null){ 147 | fs.close(); 148 | } 149 | // 解析Zip文件 150 | return getZipInfo(newfile, newfile.getParent()); 151 | } 152 | } 153 | catch(Exception e){ 154 | e.printStackTrace(); 155 | } 156 | return null; 157 | } 158 | 159 | 160 | 161 | /** 162 | * 通过IPA文件获取Info.plist信息 163 | */ 164 | public static void getIpaInfoMap(File ipa) throws Exception{ 165 | 166 | File file = getIpaInfo(ipa); 167 | 168 | // Map map = new HashMap(); 169 | 170 | // 需要第三方jar包dd-plist 171 | NSDictionary rootDict = (NSDictionary)PropertyListParser.parse(file); 172 | 173 | // 应用包名 174 | NSString parameters = (NSString)rootDict.objectForKey("CFBundleIdentifier"); 175 | // map.put("CFBundleIdentifier", parameters.toString()); 176 | ipaInfo.setPackgeName(parameters.toString()); 177 | 178 | // 应用名称 179 | parameters = (NSString) rootDict.objectForKey("CFBundleName"); 180 | // map.put("CFBundleName", parameters.toString()); 181 | ipaInfo.setAppName(parameters.toString()); 182 | 183 | // 应用外部版本 184 | parameters = (NSString)rootDict.objectForKey("CFBundleShortVersionString"); 185 | // map.put("CFBundleShortVersionString", parameters.toString()); 186 | ipaInfo.setVersionName(parameters.toString()); 187 | 188 | // 应用内部版本 189 | parameters = (NSString)rootDict.objectForKey("CFBundleVersion"); 190 | // map.put("CFBundleVersion", parameters.toString()); 191 | ipaInfo.setVersionCode(parameters.toString()); 192 | 193 | // 应用所需IOS最低版本 194 | parameters = (NSString)rootDict.objectForKey("MinimumOSVersion"); 195 | // map.put("MinimumOSVersion", parameters.toString()); 196 | ipaInfo.setMinSdk(parameters.toString()); 197 | 198 | // 如果有必要,应该删除解压的结果文件 199 | FileUtils.fileDelet(file); 200 | 201 | } 202 | 203 | /** 204 | * 通过IPA文件获取embedded.mobileprovision信息 205 | */ 206 | public static void getIpaMobileProvisio(File ipa) throws Exception { 207 | 208 | // 解压文件 Info.plist、embedded.mobileprovision,解析Info.plist文件并获取embedded.mobileprovision文件中的信息 209 | getIpaInfoMap(ipa); 210 | 211 | try { 212 | 213 | // 获取文件并以字符串的形式返回 214 | File filename = ipaInfo.getMobileprovision(); 215 | String filedata = FileUtils.fileRead(filename); 216 | 217 | // 正则匹配Body字段 218 | String dictData = ReUtils.findString(filedata,reBody); 219 | 220 | // 匹配 provisionName 221 | ipaInfo.setProvisionName(ReUtils.findString(dictData,reprovisionName)); 222 | 223 | // 匹配 reAppIDName 224 | ipaInfo.setAppIDName(ReUtils.findString(dictData,reAppIDName)); 225 | 226 | // 匹配 UUID 227 | ipaInfo.setUUID(ReUtils.findString(dictData,reUUID).replaceAll("-","")); 228 | 229 | // 匹配 reTeamName 230 | ipaInfo.setTeamName(ReUtils.findString(dictData,reTeamName)); 231 | 232 | // 匹配 reExpirationDate 233 | ipaInfo.setExpirationDate(ReUtils.findString(dictData,reExpirationDate)); 234 | 235 | // 如果有必要,应该删除解压的结果文件 236 | FileUtils.fileDelet(filename); 237 | }catch(Exception e){ 238 | 239 | ipaInfo.setProvisionName(notFoundFile); 240 | ipaInfo.setAppIDName(notFoundFile); 241 | ipaInfo.setUUID(notFoundFile); 242 | ipaInfo.setTeamName(notFoundFile); 243 | ipaInfo.setExpirationDate(notFoundFile); 244 | 245 | e.printStackTrace(); 246 | } 247 | 248 | } 249 | 250 | 251 | 252 | } 253 | 254 | --------------------------------------------------------------------------------