package com.reandroid.lib.apk; import com.reandroid.archive.InputSource; import com.reandroid.lib.arsc.chunk.TableBlock; import com.reandroid.lib.arsc.chunk.xml.AndroidManifestBlock; import com.reandroid.lib.arsc.chunk.xml.ResXmlBlock; import com.reandroid.lib.json.JSONObject; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.util.HashSet; import java.util.Set; public class ApkJsonDecoder { private final ApkModule apkModule; private final Set decodedPaths; private final boolean splitTypes; public ApkJsonDecoder(ApkModule apkModule, boolean splitTypes){ this.apkModule = apkModule; this.splitTypes = splitTypes; this.decodedPaths = new HashSet<>(); } public ApkJsonDecoder(ApkModule apkModule){ this(apkModule, false); } public File writeToDirectory(File dir) throws IOException { this.decodedPaths.clear(); writeUncompressed(dir); writeManifest(dir); writeTable(dir); writeResourceIds(dir); //writePublicXml(dir); writeResources(dir); writeRootFiles(dir); return new File(dir, apkModule.getModuleName()); } private void writeUncompressed(File dir) throws IOException { File file=toUncompressedJsonFile(dir); UncompressedFiles uncompressedFiles=new UncompressedFiles(); uncompressedFiles.addCommonExtensions(); uncompressedFiles.addPath(apkModule.getApkArchive()); uncompressedFiles.toJson().write(file); } private void writeResources(File dir) throws IOException { for(ResFile resFile:apkModule.listResFiles()){ writeResource(dir, resFile); } } private void writeResource(File dir, ResFile resFile) throws IOException { if(resFile.isBinaryXml()){ writeResourceJson(dir, resFile); } } private void writeResourceJson(File dir, ResFile resFile) throws IOException { InputSource inputSource= resFile.getInputSource(); String path=inputSource.getAlias(); File file=toResJson(dir, path); ResXmlBlock resXmlBlock=new ResXmlBlock(); resXmlBlock.readBytes(inputSource.openStream()); JSONObject jsonObject=resXmlBlock.toJson(); jsonObject.write(file); addDecoded(path); } private void writeRootFiles(File dir) throws IOException { for(InputSource inputSource:apkModule.getApkArchive().listInputSources()){ writeRootFile(dir, inputSource); } } private void writeRootFile(File dir, InputSource inputSource) throws IOException { String path=inputSource.getAlias(); if(hasDecoded(path)){ return; } File file=toRootFile(dir, path); File parent=file.getParentFile(); if(parent!=null && !parent.exists()){ parent.mkdirs(); } FileOutputStream outputStream=new FileOutputStream(file); inputSource.write(outputStream); outputStream.close(); addDecoded(path); } private void writeTable(File dir) throws IOException { if(!splitTypes){ writeTableSingle(dir); return; } writeTableSplit(dir); } private void writeTableSplit(File dir) throws IOException { if(!apkModule.hasTableBlock()){ return; } TableBlock tableBlock = apkModule.getTableBlock(); File splitDir= toJsonTableSplitDir(dir); TableBlockJson tableBlockJson=new TableBlockJson(tableBlock); tableBlockJson.writeJsonFiles(splitDir); addDecoded(TableBlock.FILE_NAME); } private void writeTableSingle(File dir) throws IOException { if(!apkModule.hasTableBlock()){ return; } TableBlock tableBlock = apkModule.getTableBlock(); File file= toJsonTableFile(dir); tableBlock.toJson().write(file); addDecoded(TableBlock.FILE_NAME); } private void writeResourceIds(File dir) throws IOException { if(!apkModule.hasTableBlock()){ return; } TableBlock tableBlock = apkModule.getTableBlock(); ResourceIds resourceIds=new ResourceIds(); resourceIds.loadTableBlock(tableBlock); JSONObject jsonObject= resourceIds.toJson(); File file=toResourceIds(dir); jsonObject.write(file); } private void writePublicXml(File dir) throws IOException { if(!apkModule.hasTableBlock()){ return; } TableBlock tableBlock = apkModule.getTableBlock(); ResourceIds resourceIds=new ResourceIds(); resourceIds.loadTableBlock(tableBlock); File file=toResourceIdsXml(dir); resourceIds.writeXml(file); } private void writeManifest(File dir) throws IOException { if(!apkModule.hasAndroidManifestBlock()){ return; } AndroidManifestBlock manifestBlock = apkModule.getAndroidManifestBlock(); File file = toJsonManifestFile(dir); manifestBlock.toJson().write(file); addDecoded(AndroidManifestBlock.FILE_NAME); } private boolean hasDecoded(String path){ return decodedPaths.contains(path); } private void addDecoded(String path){ this.decodedPaths.add(path); } private File toJsonTableFile(File dir){ File file=new File(dir, apkModule.getModuleName()); String name = TableBlock.FILE_NAME + ApkUtil.JSON_FILE_EXTENSION; return new File(file, name); } private File toJsonTableSplitDir(File dir){ File file=new File(dir, apkModule.getModuleName()); return new File(file, ApkUtil.SPLIT_JSON_DIRECTORY); } private File toResourceIds(File dir){ File file=new File(dir, apkModule.getModuleName()); String name = ResourceIds.JSON_FILE_NAME; return new File(file, name); } private File toResourceIdsXml(File dir){ File file=new File(dir, apkModule.getModuleName()); String name = "public.xml"; return new File(file, name); } private File toUncompressedJsonFile(File dir){ File file = new File(dir, apkModule.getModuleName()); return new File(file, UncompressedFiles.JSON_FILE); } private File toJsonManifestFile(File dir){ File file=new File(dir, apkModule.getModuleName()); String name = AndroidManifestBlock.FILE_NAME + ApkUtil.JSON_FILE_EXTENSION; return new File(file, name); } private File toResJson(File dir, String path){ File file=new File(dir, apkModule.getModuleName()); file=new File(file, ApkUtil.RES_JSON_NAME); path=path + ApkUtil.JSON_FILE_EXTENSION; path=path.replace('/', File.separatorChar); return new File(file, path); } private File toRootFile(File dir, String path){ File file=new File(dir, apkModule.getModuleName()); file=new File(file, ApkUtil.ROOT_NAME); path=path.replace('/', File.separatorChar); return new File(file, path); } }