java语言如何生成plist下载ipa文件
作者:永不停歇的火车
这篇文章主要介绍了java语言如何生成plist下载ipa文件问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
java语言生成plist下载ipa文件
在通过html页面下载ipa文件安装,需要通过plist文件下载,并且还要遵循 itms-services协议。
也就说我们需要生产plist文件,然后通过html页面链接指向plist文件。
下面是通过java语言生成plist文件:
public static String createPlist(String url,String version,String title) throws IOException{ log.info("==========开始创建plist文件"); //这个地址应该是创建的服务器地址,在这里用生成到本地磁盘地址 final String path = GetPropertiesValue.getValues("ios_plists_path"); File file = new File(path); if (!file.exists()) { file.setWritable(true);//赋予文件权限 file.mkdirs(); } String plistFile = GetPropertiesValue.getValues("plists_name");//文件名称 final String PLIST_PATH = path + plistFile; file = new File(PLIST_PATH); if (!file.exists()) { try { file.createNewFile(); } catch (IOException e) { e.printStackTrace(); } } String sub_title = GetPropertiesValue.getValues("plists_sub_title"); String plist = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n" + "<plist version=\"1.0\">\n" + "<dict>\n" + "<key>items</key>\n" + "<array>\n" + "<dict>\n" + "<key>assets</key>\n" + "<array>\n" + "<dict>\n" + "<key>kind</key>\n" + "<string>software-package</string>\n" + "<key>url</key>\n" //你之前所上传的ipa文件路径 + "<string>"+url+"</string>\n" + "</dict>\n" + "</array>\n" + "<key>metadata</key>\n" + "<dict>\n" + "<key>bundle-identifier</key>\n" //这个是开发者账号用户名,也可以为空,为空安装时看不到图标,完成之后可以看到 + "<string></string>\n" + "<key>bundle-version</key>\n" + "<string>"+version+"</string>\n" + "<key>kind</key>\n" + "<string>software</string>\n" + "<key>subtitle</key>\n" + "<string>"+sub_title+"</string>\n" + "<key>title</key>\n"
上面重要的地方有两点
- url:这个参数是为了找到你自己上传的ipa文件;
- bundle-identifier:这个参数是开发者账号用户名,可以为空或任意,区别在于安装的过程中有无图标和进度
下面是生成html文件,通过html的方式下载这个ipa文件。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>下载</title> <script type="text/javascript"> var url = 'https://127.0.0.1:8080//upload/plists/20160606143426371_63551_1.plist'; window.location.href = "itms-services://?action=download-manifest&url=" + url; </script> </head> <body></body> </html>
注意:访问这个plist文件的时候必须是基于HTTPS的,所以这就需要有一台https服务器 。
这样只要我们只要访问这个html地址,就可以自动下载ipa文件了。
解析ipa生成plist文件
1.引入工具类jar
<dependency> <groupId>ant</groupId> <artifactId>ant</artifactId> <version>1.6.5</version> </dependency> <dependency> <groupId>com.googlecode.plist</groupId> <artifactId>dd-plist</artifactId> <version>1.8</version> </dependency>
2.解析代码
package com.ouyeel.ssx.admin.utils; import com.dd.plist.NSDictionary; import com.dd.plist.NSString; import com.dd.plist.PropertyListParser; import org.apache.tools.zip.ZipEntry; import org.apache.tools.zip.ZipFile; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.*; import java.util.Enumeration; import java.util.HashMap; import java.util.Map; public class AnalysisIpa { private static Logger logger = LoggerFactory.getLogger(AnalysisIpa.class); /** * 解压IPA文件,只获取IPA文件的Info.plist文件存储指定位置 * @param file * zip文件 * @param unzipDirectory * 解压到的目录 * @throws Exception */ private static File getZipInfo(File file, String unzipDirectory) throws Exception { // 定义输入输出流对象 InputStream input = null; OutputStream output = null; File result = null; File unzipFile = null; ZipFile zipFile = null; try { // 创建zip文件对象 zipFile = new ZipFile(file); // 创建本zip文件解压目录 String name = file.getName().substring(0,file.getName().lastIndexOf(".")); unzipFile = new File(unzipDirectory + "/" + name); if (unzipFile.exists()){ unzipFile.delete(); } unzipFile.mkdir(); // 得到zip文件条目枚举对象 Enumeration<ZipEntry> zipEnum = zipFile.getEntries(); // 定义对象 ZipEntry entry = null; String entryName = null; String names[] = null; int length; // 循环读取条目 while (zipEnum.hasMoreElements()) { // 得到当前条目 entry = zipEnum.nextElement(); entryName = new String(entry.getName()); // 用/分隔条目名称 names = entryName.split("\\/"); length = names.length; for (int v = 0; v < length; v++) { if(entryName.endsWith(".app/Info.plist")){ // 为Info.plist文件,则输出到文件 input = zipFile.getInputStream(entry); result = new File(unzipFile.getAbsolutePath()+ "/Info.plist"); output = new FileOutputStream(result); byte[] buffer = new byte[1024 * 8]; int readLen = 0; while ((readLen = input.read(buffer, 0, 1024 * 8)) != -1){ output.write(buffer, 0, readLen); } break; } } } } catch (Exception ex) { ex.printStackTrace(); } finally { if (input != null) input.close(); if (output != null) { output.flush(); output.close(); } // 必须关流,否则文件无法删除 if(zipFile != null){ zipFile.close(); } } // 如果有必要删除多余的文件 if(file.exists()){ file.delete(); } return result; } /** * IPA文件的拷贝,把一个IPA文件复制为Zip文件,同时返回Info.plist文件 * 参数 oldfile 为 IPA文件 */ private static File getIpaInfo(File oldfile) throws IOException { try{ int byteread = 0; String filename = oldfile.getAbsolutePath().replaceAll(".ipa", ".zip"); File newfile = new File(filename); if (oldfile.exists()){ // 创建一个Zip文件 InputStream inStream = new FileInputStream(oldfile); FileOutputStream fs = new FileOutputStream(newfile); byte[] buffer = new byte[1444]; while ((byteread = inStream.read(buffer)) != -1){ fs.write(buffer,0,byteread); } if(inStream != null){ inStream.close(); } if(fs != null){ fs.close(); } // 解析Zip文件 return getZipInfo(newfile,newfile.getParent()); } }catch(Exception e){ e.printStackTrace(); } return null; } /** * 通过IPA文件获取Info信息 * 这个方法可以重构,原因是指获取了部分重要信息,如果想要获取全部,那么应该返回一个Map<String,Object> * 对于plist文件中的数组信息应该序列化存储在Map中,那么只需要第三发jar提供的NSArray可以做到! */ public static Map<String,String> getIpaInfoMap(File ipa) throws Exception{ Map<String,String> map = new HashMap<String,String>(); File file = getIpaInfo(ipa); // 第三方jar包提供 NSDictionary rootDict = (NSDictionary) PropertyListParser.parse(file); // 应用包名 NSString parameters = (NSString)rootDict.objectForKey("CFBundleIdentifier"); map.put("CFBundleIdentifier", parameters.toString()); // 应用名称 parameters = (NSString) rootDict.objectForKey("CFBundleName"); map.put("CFBundleName", parameters.toString()); // 应用版本 parameters = (NSString) rootDict.objectForKey("CFBundleShortVersionString"); map.put("CFBundleShortVersionString", parameters.toString()); // 应用展示的名称 parameters = (NSString) rootDict.objectForKey("CFBundleDisplayName"); map.put("CFBundleDisplayName", parameters!=null?parameters.toString():null); // 应用所需IOS最低版本 parameters = (NSString) rootDict.objectForKey("MinimumOSVersion"); map.put("MinimumOSVersion", parameters.toString()); //文件大小 map.put("FileSize",String.valueOf(file.length())); // 如果有必要,应该删除解压的结果文件 file.delete(); file.getParentFile().delete(); return map; } /** * 生成plist文件,返回 * @param map:ipa解析信息 * @param downloadIpaPath:下载ipa文件路径(https://xxx/xxx/x.ipa) * @param ipaFilePath:ipa文件存放路径(/home/tomcat/xxx/x.ipa) * @return plist下载地址 */ public static String createPlistXml(Map<String,String> map,String downloadIpaPath,String ipaFilePath){ logger.info("==========开始创建plist文件"); //将.ipa文件变为.plist文件后缀 ipaFilePath = ipaFilePath.replace(".ipa",".plist"); File file = new File(ipaFilePath); if (!file.exists()) { try { file.createNewFile(); } catch (IOException e) { e.printStackTrace(); } } String icon = "http://xxx.oss-cn-beijing.aliyuncs.com/chemcn-ec-web/resources/chemcn-app/testApp/5d0b57f2b1696b03c1ca22ab/icon/com.ouyeel.nbapp_1.0.0_100_i.png"; String plist = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +"<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n" +"<plist version=\"1.0\">\n" +"<dict>\n" +"<key>items</key>\n" +"<array>\n" +"<dict>\n" +"<key>assets</key>\n" +"<array>\n" +"<dict>\n" +"<key>kind</key>\n" +"<string>software-package</string>\n" +"<key>url</key>\n" +"<string>"+downloadIpaPath+"</string>\n" +"<key>md5-size</key>\n" +"<integer>"+map.get("FileSize")+"</integer>\n" +"</dict>\n" +"<dict>\n" +"<key>kind</key>\n" +"<string>display-image</string>\n" +"<key>needs-shine</key>\n" +"<true/>\n" +"<key>url</key>\n" +"<string>"+icon+"</string>\n" +"</dict>\n" +"</array>\n" +"<key>metadata</key>\n" +"<dict>\n" +"<key>bundle-identifier</key>\n" +"<string>"+map.get("CFBundleIdentifier")+"</string>\n" +"<key>bundle-version</key>\n" +"<string>"+map.get("CFBundleShortVersionString")+"</string>\n" +"<key>kind</key>\n" +"<string>software</string>\n" +"<key>title</key>\n" +"<string>"+map.get("CFBundleName")+"</string>\n" +"</dict>\n" +"</dict>\n" +"</array>\n" +"</dict>\n" +"</plist>"; FileOutputStream output = null; OutputStreamWriter writer = null; try { output = new FileOutputStream(file); writer = new OutputStreamWriter(output, "UTF-8"); writer.write(plist); } catch (Exception e) { logger.error("==========创建plist文件异常:" + e.getMessage()); }finally { if(writer != null){ writer.close(); } if(output != null){ output.close(); } } logger.info("==========成功创建plist文件"); return downloadIpaPath.replaceAll(".ipa",".plist"); } public static void main(String[] args) throws Exception { File file = new File("/Users/xuchuanjiang/Documents/temp/xxx-xxx-ios.ipa"); Map<String,String> map = getIpaInfoMap(file); for(String key : map.keySet()){ System.out.println(key+" : "+map.get(key)); } createPlistXml(map,"https://xxx.xxx.com/ssx/static/xxx-xxx-ios.ipa","/Users/xuchuanjiang/Documents/temp/xxx-app-ios.ipa"); } }
3.提供下载的plist链接需要是https
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。