最近在写和移动端相关的项目,所以无聊写了个配置文件解析工具类
1、引入apk解析jar包依赖
<dependency>
<groupId>net.dongliu</groupId>
<artifactId>apk-parser</artifactId>
<version>2.5.0</version>
</dependency>
2、解析工具类书写
package com.example.demo.utils;
import net.dongliu.apk.parser.AbstractApkFile;
import net.dongliu.apk.parser.bean.ApkSignStatus;
import net.dongliu.apk.parser.utils.Inputs;
import java.io.*;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
/**
* 分析APK文件,取得APK文件中的 包名、版本号及图标
* @author wzy
* @return
* @date 2018/9/17
**/
public class ApkUtil extends AbstractApkFile implements Closeable {
private final ZipFile zf;
private File apkFile;
public ApkUtil(File apkFile) throws IOException {
this.apkFile = apkFile;
this.zf = new ZipFile(apkFile);
}
public ApkUtil(String filePath) throws IOException {
this(new File(filePath));
}
@Override
protected List<CertificateFile> getAllCertificateData() throws IOException {
Enumeration<? extends ZipEntry> enu = zf.entries();
List<CertificateFile> list = new ArrayList<>();
while (enu.hasMoreElements()) {
ZipEntry ne = enu.nextElement();
if (ne.isDirectory()) {
continue;
}
String name = ne.getName().toUpperCase();
if (name.endsWith(".RSA") || name.endsWith(".DSA")) {
list.add(new CertificateFile(name, Inputs.readAll(zf.getInputStream(ne))));
}
}
return list;
}
@Override
public byte[] getFileData(String path) throws IOException {
ZipEntry entry = zf.getEntry(path);
if (entry == null) {
return null;
}
InputStream inputStream = zf.getInputStream(entry);
return Inputs.readAll(inputStream);
}
@Override
protected ByteBuffer fileData() throws IOException {
FileChannel channel = new FileInputStream(apkFile).getChannel();
return channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size());
}
@Override
@Deprecated
public ApkSignStatus verifyApk() throws IOException {
ZipEntry entry = zf.getEntry("META-INF/MANIFEST.MF");
if (entry == null) {
// apk is not signed;
return ApkSignStatus.notSigned;
}
try (JarFile jarFile = new JarFile(this.apkFile)) {
Enumeration<JarEntry> entries = jarFile.entries();
byte[] buffer = new byte[8192];
while (entries.hasMoreElements()) {
JarEntry e = entries.nextElement();
if (e.isDirectory()) {
continue;
}
try (InputStream in = jarFile.getInputStream(e)) {
// Read in each jar entry. A security exception will be thrown if a signature/digest check fails.
int count;
while ((count = in.read(buffer, 0, buffer.length)) != -1) {
// Don't care
}
} catch (SecurityException se) {
return ApkSignStatus.incorrect;
}
}
}
return ApkSignStatus.signed;
}
@Override
public void close() throws IOException {
super.close();
zf.close();
}
}
3、解析demo
例如 我们要获取D:XXX.apk 配置文件内的自定义属性
/**
* 文章——上传
*
* @param file
* @return
*/
@GetMapping("/upload")
public void upLoadArticle(@RequestParam(value = "file") MultipartFile file) throws Exception {
if (Objects.requireNonNull(file.getOriginalFilename()).endsWith(".apk")) {
String filePath = "D:\\";
File file1 = new File(filePath+file.getOriginalFilename());
ApkUtil apkUtil = new ApkUtil(file1);
String manifestXml = apkUtil.getManifestXml();
//解析xml文档 获取对应的环境URL字段
org.json.JSONObject xmlJSONObj = XML.toJSONObject(manifestXml);
Object manifest = xmlJSONObj.get("manifest");
Map map = JSONObject.parseObject(manifest.toString(), Map.class);
List list = (List) map.get("meta-data");
AppInfoBO appInfoBO = new AppInfoBO();
Object result = null;
if(CollectionUtils.isEmpty(list)){
appInfoBO.setDeployUrl("");
}else {
Map<String, Object> metadata = (Map<String, Object>) list.get(0);
if (CollectionUtils.isEmpty(metadata)) {
appInfoBO.setDeployUrl("");
}
result = metadata.get("android:value");
if (result == null) {
appInfoBO.setDeployUrl("");
} else {
appInfoBO.setDeployUrl(result.toString());
}
}
IpaUtils reader = new IpaUtils(file1);
reader.parse();
}
}
结果:
当然 还有pull,dom,sax,jdom,dom4j这几种方式解析