ios plist解析工具类

1、引入pom

<dependency>
    <groupId>com.googlecode.plist</groupId>
    <artifactId>dd-plist</artifactId>
    <version>1.23</version>
</dependency>

2、IosParseUtil工具类

/**

* ios安装包解析工具类

*/

@Log4j2

public class IosParseUtil {

        private static final String INFO_PLIST = "info.plist";

        private static final String CONFIG_PLIST = "config.plist";

        private static final String EMBEDDED_MOBILEPROVISION = "embedded.mobileprovision";


        public static JSONObject parseIPA(MultipartFile multipartFile, String appName) throws Exception {

                log.info("开始进行解析ios安装包操作");

                String version = null; // 内部版本

                String displayVer = null; //  显示版本号


                Map<String, String> iplist = getInfoPlistFromIPA(multipartFile);

                String cplist = getConfigPlistFromIPA(multipartFile);

                String teamId = getAppIdFromIPA(multipartFile);

                String appId = iplist.get("appId"); // ios的appid

                String appTitle = iplist.get("appTitle"); // ios的应用名称

                appTitle = StringUtil.isEmpty(appTitle) ? appName : appTitle;

                

                log.info("开始获取版本号");

                if(StringUtil.isNotEmpty(cplist)) {

                        InputStream cplistIn =  new ByteArrayInputStream(cplist.getBytes("utf-8"));

                        HashMap<String, Object> cplistMap = PlistHandler.getMapFromPlist(cplistIn);

                        version = String.valueOf(cplistMap.get("IPAVersionNum"));

                        displayVer = String.valueOf(cplistMap.get("IPAVersionDisplay"));

                }

                JsonObject json = new JSONObject();

                json.put("teamId", teamId);

                json.put("appId", appId);

                json.put("appTitle", appTitle);

                json.put("deviceType", "Iphone");

                json.put("displayVer", displayVer);

                json.put("platform", "IOS");

                json.put("version", version);

                log.info("解析完成");


                return json;

        }


        /**
        * 解析info.plist文件返回AppId和AppName

        */

        private static Map<String, String> getInfoPlistFormIPA(MultipartFile multipartFile) throws Exception {

                String plistPath = getPlistFromIPA(multipartFile, INFO_PLIST);

                String plist1 = null;

                String appId = null;

                String appTitle = null;

                Map<String, String> map = new HashMap<>();

                if(StringUtil.isNotEmpty(plistPath)) {

                        File file = new File(plistPath);

                        if(file != null && file.exists()) {

                                FileInputStream fis = new FileInputStream(file);

                                plist1= convertToString(fis); // 转为string

                                String plist2 = plist1.replace("<!DOCTYPE", "<!-- !DOCTYPE"); // 注释掉需要联外网才可以查询到www.apple.com,保证断网也可以正常使用

                                String plist = plist2.replace("dtd\">", "dtd\"> -->"); // 注释掉需要联外网才可以查询到www.apple.com,保证断网也可以正常使用

                                log.info("string转为xml doc,开始...");

                                StringReader reader = new StringReader(plist);

                                InputSource is = new InputSource(reader);

                                DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); // 获取dom解析工厂

                                DocumentBuilderImpl builder = (DocumentBuilderImpl)factory.newDocumentBuilder(); // 获取具体的dom解析器

                                DeferredDoumentImpl doc = (DeferredDoumentImpl)builder.parse(is);

                                log.info("获取doc节点中的信息,开始...");

                                NodeList list = doc.getElementByTagName("key");

                                for(int i = 0; i  < list.getLength(); i++) {

                                        String keyValue = list.item(i).getFirstChild().getNodeValue();

                                        if("CFBundleIdentifier").equals(keyValue) {

                                                Node idNode = list.item(i).getNextSibling(); // 获取id

                                                while(idNode.getNodeType() != 1){

                                                        // 若节点类型非元素

                                                        idNode = idNode.getNextSibling();

                                                }

                                                appId = idNode.getFirstChild().getNodeValue();

                                                log.info("成功获取到CFBundleIdentifier,值为:" + appId);

                                        }

                                        if("CFBundleDisplayName").equals(keyValue) {

                                                Node nameNode = list.item(i).getNextSibling(); // 获取名字

                                                while(nameNode.getNodeType() != 1){

                                                        // 若节点类型非元素

                                                        nameNode = nameNode.getNextSibling();

                                                }

                                                appTitle = nameNode.getFirstChild().getNodeValue();

                                                log.info("成功获取到CFBundleDisplayName,值为:" + appTitle);

                                        }

                                }

                                fis.close();

                                file.delete();

                        }

                }

                map.put("appId", appId);

                map.put("appTitle", appTitle);


                return map;

        }


        /**
        * 获取ipa安装包中的plist文件并保存到本地

        */

        private static String getPlistFromIPA(MultipartFile multipartFile, String plistName) throws IOException {

                String base = System.getProperty("java.io.tmpdir") + System.getProperty("file.separator");

                ZipInputStream zis = new ZipInputStream(multipartFile.getInputStram());

                ZipEntry zipEntry;

                String xmlPath = null;

                BufferedOutputStream dest;

                while((entry = zis.getNextEntry()) != null) {

                        String fileName = entry.getName();

                        String[] dirName = fileName.split("/");

                        fileName =  fileName.substring(fileName.lastIndexOf("/") + 1);

                        // 目标固定在第二级目录下的文件

                        if(dirName.length == 3 && plistName.equals(dirName[2])) {

                                int buffer = 2048;

                                int count;

                                byte data[] = new byte[buffer];

                                xmlPath = base + System.currentTimeMillis() + fileName;

                                FileOutputStream fos = new FileOutputStream(xmlPath);

                                dest = new BufferedOutputStream(fos, buffer);

                                while((count = zis.read(data, 0, buffer)) != -1) {

                                        dest.write(data, 0, count);

                                }

                                dest.flush();

                                dest.close();

                                break;

                        }

                }

                zis.close();


                return xmlPath;

        }


        /**

        * 从ipa文件中读取config.plist文件

        */

        private static String getConfigPlistFromIPA(MultipartFile multipartFile) throws Exception {

                String plistPath = getPlistFromIPA(multipartFile, CONFIG_PLIST);

                String plist = null;

                if(StringUtil.isNotEmpty(plistPath)) {

                        File file = new File(plistPath);

                        if(file != null && file.exists()) {

                                FileInputStream fis = new FileInputStream(file);

                                plist =  convertToString(fis);

                                fis.close();

                                file.delete();

                        }

                }

                return plist;

        }

        

        public static String getAppIdFromIPA(MultipartFile multipartFile) throws Exception {

                String plistPath = getPlistFromIPA(multipartFile, EMBEDDED_MOBILEPROVISION);

                String plist = null;

                if(StringUtil.isNotEmpty(plistPath)) {

                        File file = new File(plistPath);

                        if(file != null && file.exists()) {

                                InputStreamReader fis = new InputStreamReader(new FileInputStream(file));

                                BufferedReader br = new BufferedReader(fis);

                                String data = null;

                                while((data = br.readLine()) != null) {

                                        if(data.contains("<key>application-identifier</key>")) {

                                                plist = br.readLine();

                                                plist = plist.substring(0, plist.indexOf("</string>"));

                                                plist = plist.substring(plist.indexOf("<string>") + "<string>".length());

                                                break;

                                        }

                                }

                                fis.close();

                                file.delete();

                        }

                }

                return plist;

        }


        private static String convertToString(InputStream in) throws Exception {

                NSObject root = parse(in);

                return root.toXMLPropertyList();

        }


        private static NSObject parse(InputStream is) throws Exception {

                if(is.markSupported()) {

                        is.mark(10);

                        String magicString =  new String(readAll(is, 8), 0, 8);

                        is.reset();

                        if(magicString.startsWith("bplist00")) return BinaryPropertyListParser.parse(is);

                        if(magicString.startsWith("<?xml")) return XMLpropertyListParse.parse(is);

                        if((magicString.startsWith("(")) || (magicString.startsWith("{"))) return ASCIIPropertyListParser.parse(is);


                        thorw new BizException("the given data is neither a binary not a XML property list, ASCII property lists are not supported");

                }


                return parse(readAll(is, 2147483647));

        }


        private static NSObject parse(byte[] bytes) throws Exception {

                String magicString =  new String(bytes, 0, 8);

                if(magicString.startsWith("bplist00")) return BinaryPropertyListParser.parse(is);

                if(magicString.startsWith("<?xml")) return XMLpropertyListParse.parse(is);

                if((magicString.startsWith("(")) || (magicString.startsWith("{"))) return ASCIIPropertyListParser.parse(is);


                thorw new BizException("the given data is neither a binary not a XML property list, ASCII property lists are not supported");

        }


        private static byte[] readAll(InputStream in, int max) throws IOException {

                ByteArrayOutputStream buf  = new ByteArrayOutputStream();

                while (max > 0) {

                        int n = in.read();

                        if(n == -1) break;

                        buf.write(n);

                        max--;

                }

                return buf.toByteArray();

        }

}

3、辅助类

public class PlistHandler extends DefaultHandler {

        private boolean isRootElement = false;

        private boolean keyElementBegin = false;

        private String key;

        Stack<Object> stack = new Stack<>();

        private boolean valueElementBegin = false;

        private Object root;

        private HashMap<String, Object> getMapResult() { return (HashMap<String, Object>)root;}

       

        @Override

        public void startDocument() throws SAXException {}


        @Override

        public void endDocument() throws SAXException {}


        @Override

        public void startElement(String uri, String localName, String qName, Attributes attributes) {

                if("plist".equals(qName)) {

                        isRootElement = true;

                }

                if("dict".equals(qName)) {

                        if(isRootElement) {

                                stack.push(new HashMap<String, Object>()); // 压栈

                                isRootElement = !isRootElement ;

                        } else {

                                Object object = stack.peek();

                                HashMap<String, Object> dict =  new HashMap<>();

                                if(object instanceof ArrayList) ((ArrayList<Object>)object).add(dict);

                                else if(Object instanceof HashMap) ((HashMap<String, Object>)object).put(key, dict);

                                stack.push(dict);

                        }

                }


                if("key".equals(qName)) {

                        keyElementBegin = true;

                }

                if("true".equals(qName)) {

                        HashMap<String, Object> parent = (HashMap<String, Object>)stack.peek();

                        parent.put(key, true);

                }

                

                if("false".equals(qName)) {

                        HashMap<String, Object> parent = (HashMap<String, Object>)stack.peek();

                        parent.put(key, false);

                }

                if("array".equals(qName)) {

                        if(isRootElement) {

                                ArrayList<Object> obj = new ArrayList<>();

                                stack.push(obj);

                                isRootElement = !isRootElement;

                        } else {

                                HashMap<String, Object> parent = (HashMap<String, Object>) stack.peek();

                                ArrayList<Object> obj = new ArrayList<>();

                                stack.push(obj);

                                parent.put(key, obj);                               

                        }

                }

                if("string".equals(qName)) {

                        valueElementBegin = true;

                }

        }


        /**

        * 字符串解析(non-javadoc)

        */

        @Override

        public void characters(char[] ch, int start, int length) {

                if(length > 0) {

                        if(keyElementBegin) key = new String(ch, start, length);

                        if(valueElementBegin) {

                                if(HashMap.class.equals(stack.peek().getClass())) {

                                        HashMap<String, Object> parent = (HashMap<String, Object>)stack.peek();

                                        String value = new String(ch, start, length);

                                        parent.put(key, value);

                                } else if(ArrayList.class.equals(stack.peek().getClass())) {

                                        HashMap<String, Object> parent = (HashMap<String, Object>)stack.peek();

                                        String value  = new String(ch, start, length);

                                        parent.add(value);

                                }

                        }

                }

        }


        @Override

        public void endElement(String uri, String localName, String qName) {

                if("plist".equals(qName)) {}

                if("key".equals(qName)) keyElementBegin  = false;

                if("string".equals(qName)) valueElementBegin = false;

                if("array".equals(qName)) root = stack.pop();

                if("dict".equals(qName)) root = stack.pop();

        }


        public static HashMap<String, Object> getMapFromPlist(InputStream in) {

                HashMap<String, Object> hash = new HashMap<>();

                try {

                        SAXParserFactory factorys = SAXParserFactory.newInstance();

                        factorys.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);

                        factorys.setFeature("http://apache.org/sax/features/validation", false);

                        SAXParser saxParser = factorys.newSAXParse();

                        PlistHndler plistHandler = new PlistHndler();

                        saxParser.parse(in, plistHandler);

                        hash = plistHandler.getMapFromPlist();

                } catch(Exception ex) {

                        e.printStackTrace();

                }


                return hash;

        }

}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yujiubo2008

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值