完整版java讀取apk、ipa包名、版本名、版本號等信息

無意中發現了一個巨牛的人工智能教程,忍不住分享一下給大家。教程不僅是零基礎,通俗易懂,而且非常風趣幽默,像看小說一樣!覺得太牛了,所以分享給大家。點這裏可以跳轉到教程

有時候,我們上傳apk或者是ipa文件的時候,是需要讀取到裏面的一些信息的,比如軟件的包名,以及其版本信息等。在網上搜索了一下資料 , 找了很多版本,對於apk文件的版本號,一直讀取不到,在這裏,筆者自己總結了,讀取apk、ipa文件的一些代碼,大家可以參考下,去其糟粕,取其精華。以便適用於自己的需求。

如果大家希望解析到圖標的話,可以看我後面寫的博文
博文地址請戳 :

Java解析apk、ipa圖標,包名,應用名稱,版本號

下面會提供源碼給大家,我用的開發工具是eclipse,直接導入就可以,jar包也是我已經下載好的,大家可以免積分拿去。本來裏面是有2個apk、2個ipa文件提供測試的,但是由於文件太大,上傳不了源碼,所以就刪除了一個最大的ipa包

apk jar包地址:java解析apk所需jar包下載
ipa jar包地址:java解析ipa所需jar包下載

首先看一下我的項目目錄
這裏寫圖片描述

下面請看代碼

package com.zsl.cn;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;

import org.apkinfo.api.util.AXmlResourceParser;
import org.apkinfo.api.util.TypedValue;
import org.apkinfo.api.util.XmlPullParser;

import com.dd.plist.NSDictionary;
import com.dd.plist.NSString;
import com.dd.plist.PropertyListParser;
/**
 * 
 * @author ZSL
 *
 */
public final class ReadUtil {
	/**
	 * 讀取apk
	 * @param apkUrl
	 * @return
	 */
	public static Map<String,Object> readAPK(String apkUrl){
		ZipFile zipFile;
		Map<String,Object> map = new HashMap<String, Object>();
		try {
			zipFile = new ZipFile(apkUrl);
			Enumeration<?> enumeration = zipFile.entries();
			ZipEntry zipEntry = null;
			while (enumeration.hasMoreElements()) {
				zipEntry = (ZipEntry) enumeration.nextElement();
				if (zipEntry.isDirectory()) {

				} else {
					if ("androidmanifest.xml".equals(zipEntry.getName().toLowerCase())) {
						AXmlResourceParser parser = new AXmlResourceParser();
						parser.open(zipFile.getInputStream(zipEntry));
						while (true) {
							int type = parser.next();
							if (type == XmlPullParser.END_DOCUMENT) {
								break;
							}
							String name = parser.getName();
							if(null != name && name.toLowerCase().equals("manifest")){
								for (int i = 0; i != parser.getAttributeCount(); i++) {
									if ("versionName".equals(parser.getAttributeName(i))) {
										String versionName = getAttributeValue(parser, i);
										if(null == versionName){
											versionName = "";
										}
										map.put("versionName", versionName);
									} else if ("package".equals(parser.getAttributeName(i))) {
										String packageName = getAttributeValue(parser, i);
										if(null == packageName){
											packageName = "";
										}
										map.put("package", packageName);
									} else if("versionCode".equals(parser.getAttributeName(i))){
										String versionCode = getAttributeValue(parser, i);
										if(null == versionCode){
											versionCode = "";
										}
										map.put("versionCode", versionCode);
									}
								}
								break;
							}
						}
					}
					
				}
			}
			zipFile.close();
		} catch (Exception e) {
			map.put("code", "fail");
			map.put("error","讀取apk失敗");
		}
		return map;
	}
	
	private static String getAttributeValue(AXmlResourceParser parser, int index) {
		int type = parser.getAttributeValueType(index);
		int data = parser.getAttributeValueData(index);
		if (type == TypedValue.TYPE_STRING) {
			return parser.getAttributeValue(index);
		}
		if (type == TypedValue.TYPE_ATTRIBUTE) {
			return String.format("?%s%08X", getPackage(data), data);
		}
		if (type == TypedValue.TYPE_REFERENCE) {
			return String.format("@%s%08X", getPackage(data), data);
		}
		if (type == TypedValue.TYPE_FLOAT) {
			return String.valueOf(Float.intBitsToFloat(data));
		}
		if (type == TypedValue.TYPE_INT_HEX) {
			return String.format("0x%08X", data);
		}
		if (type == TypedValue.TYPE_INT_BOOLEAN) {
			return data != 0 ? "true" : "false";
		}
		if (type == TypedValue.TYPE_DIMENSION) {
			return Float.toString(complexToFloat(data)) + DIMENSION_UNITS[data & TypedValue.COMPLEX_UNIT_MASK];
		}
		if (type == TypedValue.TYPE_FRACTION) {
			return Float.toString(complexToFloat(data)) + FRACTION_UNITS[data & TypedValue.COMPLEX_UNIT_MASK];
		}
		if (type >= TypedValue.TYPE_FIRST_COLOR_INT && type <= TypedValue.TYPE_LAST_COLOR_INT) {
			return String.format("#%08X", data);
		}
		if (type >= TypedValue.TYPE_FIRST_INT && type <= TypedValue.TYPE_LAST_INT) {
			return String.valueOf(data);
		}
		return String.format("<0x%X, type 0x%02X>", data, type);
	}

	private static String getPackage(int id) {
		if (id >>> 24 == 1) {
			return "android:";
		}
		return "";
	}

	// ///////////////////////////////// ILLEGAL STUFF, DONT LOOK :)
	public static float complexToFloat(int complex) {
		return (float) (complex & 0xFFFFFF00) * RADIX_MULTS[(complex >> 4) & 3];
	}

	private static final float RADIX_MULTS[] = 
	{
		 0.00390625F, 3.051758E-005F, 
		 1.192093E-007F, 4.656613E-010F 
	 };
	private static final String DIMENSION_UNITS[] = { "px", "dip", "sp", "pt", "in", "mm", "", "" };
	private static final String FRACTION_UNITS[] = { "%", "%p", "", "", "", "", "", "" };
	
	/**
	 * 讀取ipa
	 */
	public static Map<String,Object> readIPA(String ipaURL){
		Map<String,Object> map = new HashMap<String,Object>();
		try {
			File file = new File(ipaURL);
            InputStream is = new FileInputStream(file);
            InputStream is2 = new FileInputStream(file);
            ZipInputStream zipIns = new ZipInputStream(is);
            ZipInputStream zipIns2 = new ZipInputStream(is2);
            ZipEntry ze;
            ZipEntry ze2;
            InputStream infoIs = null;
            NSDictionary rootDict = null;
            String icon = null;
            while ((ze = zipIns.getNextEntry()) != null) {
                if (!ze.isDirectory()) {
                    String name = ze.getName();
                    if (null != name &&
                     name.toLowerCase().contains(".app/info.plist")) {
                        ByteArrayOutputStream _copy = new 
			                        ByteArrayOutputStream();
                        int chunk = 0;
                        byte[] data = new byte[1024];
                        while(-1!=(chunk=zipIns.read(data))){
                            _copy.write(data, 0, chunk);
                        }
                        infoIs = new ByteArrayInputStream(_copy.toByteArray());
                        rootDict = (NSDictionary) PropertyListParser.parse(infoIs);
                        
                        //我們可以根據info.plist結構獲取任意我們需要的東西
                        //比如下面我獲取圖標名稱,圖標的目錄結構請下面圖片
                        //獲取圖標名稱
                        NSDictionary iconDict = (NSDictionary) rootDict.get("CFBundleIcons");
                         
                        while (null != iconDict) {
            				if(iconDict.containsKey("CFBundlePrimaryIcon")){
			            	NSDictionary CFBundlePrimaryIcon = (NSDictionary)iconDict.get("CFBundlePrimaryIcon"); 
            					if(CFBundlePrimaryIcon.containsKey("CFBundleIconFiles")){
	            				NSArray CFBundleIconFiles =(NSArray)CFBundlePrimaryIcon.get("CFBundleIconFiles"); 
            					icon = CFBundleIconFiles.getArray()[0].toString();
            						if(icon.contains(".png")){
            							icon = icon.replace(".png", "");
            						}
            						System.out.println("獲取icon名稱:" + icon);
            						break;
            					}
            				}
            			}
                        break;
                    }
                }
            }
           
           //根據圖標名稱下載圖標文件到指定位置
            while ((ze2 = zipIns2.getNextEntry()) != null) {
                if (!ze2.isDirectory()) {
                    String name = ze2.getName();
                    System.out.println(name);
                    if(name.contains(icon.trim())){
                    	System.out.println(11111);
                    	FileOutputStream fos = new FileOutputStream(new File("E:\\python\\img\\icon.png"));
	                       int chunk = 0;
	                       byte[] data = new byte[1024];
	                       while(-1!=(chunk=zipIns2.read(data))){
	                    	   fos.write(data, 0, chunk);
	                       }
	                       fos.close();
                    	break;
                    }
                }
            }
	         
            ////////////////////////////////////////////////////////////////
            //如果想要查看有哪些key ,可以把下面註釋放開
//            for (String keyName : rootDict.allKeys()) {
//				System.out.println(keyName + ":" + rootDict.get(keyName).toString());
//			  }
           
           
            // 應用包名
    		NSString parameters = (NSString) rootDict.get("CFBundleIdentifier");
    		map.put("package", parameters.toString());
    		// 應用版本名
    		parameters = (NSString) rootDict.objectForKey("CFBundleShortVersionString");
    		map.put("versionName", parameters.toString());
    		//應用版本號
    		parameters = (NSString) rootDict.get("CFBundleVersion");
    		map.put("versionCode", parameters.toString());
    		
            /////////////////////////////////////////////////
			infoIs.close();
	        is.close();
            zipIns.close();
            
        } catch (Exception e) {
        	map.put("code", "fail");
            map.put("error","讀取ipa文件失敗");
        }
        return map;
	}
	
	
	public static void main(String[] args) {
		System.out.println("======apk=========");
		String apkUrl = "src/shenmiaotaowang_966.apk";
		Map<String,Object> mapApk = ReadUtil.readAPK(apkUrl);
		for (String key : mapApk.keySet()) {
			System.out.println(key + ":" + mapApk.get(key));
		}
		System.out.println("======ipa==========");
		String ipaUrl = "src/IM.ipa";
		Map<String,Object> mapIpa = ReadUtil.readIPA(ipaUrl);
		for (String key : mapIpa.keySet()) {
			System.out.println(key + ":" + mapIpa.get(key));
		}
	}
}

這裏寫圖片描述

下面附上源碼一份:java讀取apk、ipa源碼完整版

總結:對於ipa文件的解析,我們可以根據info.plist文件結構進行解析,獲取我們需要的值,如果我們key對應的是dict ,那麼我們就用NSDictionary來獲取,如果是key下面是array,那麼我們就用NSArray來獲取,這時獲取到的是一個數組。
這裏寫圖片描述
這裏寫圖片描述
這裏寫圖片描述




我們可以看到上面解析到的圖片是黑色的,這個確實是這樣子的,在window或者linux下都是黑色的,只有在mac下才是正常的,應該是ios開發者壓縮的結果。不過不要擔心,可以看後面的文章,怎麼把圖片反編譯成正常圖片。




補充:

1. 2016-9-14補充獲取ipa圖標,並下載到指定位置

如果大家希望解析到圖標的話,可以看我後面寫的博文
博文地址請戳 :

Java解析apk、ipa圖標,包名,應用名稱,版本號







發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章