From 0b2f3815db5975182e599e4c6645b0a0935e5871 Mon Sep 17 00:00:00 2001 From: REAndroid Date: Fri, 9 Dec 2022 14:37:16 -0500 Subject: [PATCH] V1.0.3 --- .../com/reandroid/lib/apk/ApkJsonDecoder.java | 3 +- .../java/com/reandroid/lib/apk/ApkModule.java | 26 +++- .../java/com/reandroid/lib/apk/ApkUtil.java | 3 + .../reandroid/lib/apk/StringPoolBuilder.java | 9 +- .../reandroid/lib/apk/UncompressedFiles.java | 117 +++++++++++++++--- .../arsc/chunk/xml/AndroidManifestBlock.java | 80 +++++++++--- .../lib/arsc/chunk/xml/ResXmlAttribute.java | 48 +++---- .../lib/arsc/chunk/xml/ResXmlElement.java | 28 ++--- .../arsc/chunk/xml/ResXmlStartElement.java | 19 ++- 9 files changed, 246 insertions(+), 87 deletions(-) diff --git a/src/main/java/com/reandroid/lib/apk/ApkJsonDecoder.java b/src/main/java/com/reandroid/lib/apk/ApkJsonDecoder.java index a15306c..1869798 100644 --- a/src/main/java/com/reandroid/lib/apk/ApkJsonDecoder.java +++ b/src/main/java/com/reandroid/lib/apk/ApkJsonDecoder.java @@ -38,7 +38,8 @@ public class ApkJsonDecoder { private void writeUncompressed(File dir) throws IOException { File file=toUncompressedJsonFile(dir); UncompressedFiles uncompressedFiles=new UncompressedFiles(); - uncompressedFiles.add(apkModule.getApkArchive()); + uncompressedFiles.addCommonExtensions(); + uncompressedFiles.addPath(apkModule.getApkArchive()); uncompressedFiles.toJson().write(file); } private void writeResources(File dir) throws IOException { diff --git a/src/main/java/com/reandroid/lib/apk/ApkModule.java b/src/main/java/com/reandroid/lib/apk/ApkModule.java index 9513f70..2863130 100644 --- a/src/main/java/com/reandroid/lib/apk/ApkModule.java +++ b/src/main/java/com/reandroid/lib/apk/ApkModule.java @@ -29,7 +29,19 @@ public class ApkModule { this.moduleName=moduleName; this.apkArchive=apkArchive; this.mUncompressedFiles=new UncompressedFiles(); - this.mUncompressedFiles.add(apkArchive); + this.mUncompressedFiles.addPath(apkArchive); + } + public boolean isBaseModule(){ + if(!hasAndroidManifestBlock()){ + return false; + } + AndroidManifestBlock manifestBlock; + try { + manifestBlock=getAndroidManifestBlock(); + } catch (IOException ignored) { + return false; + } + return manifestBlock.getMainActivity()!=null; } public String getModuleName(){ return moduleName; @@ -38,7 +50,19 @@ public class ApkModule { ZipArchive archive=new ZipArchive(); archive.addAll(getApkArchive().listInputSources()); UncompressedFiles uf=getUncompressedFiles(); + uf.setResRawDir("res/raw/"); uf.apply(archive); + int i=1; + for(InputSource inputSource:archive.listInputSources()){ + if(inputSource.getSort()==0){ + inputSource.setSort(i); + i++; + } + } + InputSource manifest=archive.getInputSource(AndroidManifestBlock.FILE_NAME); + if(manifest!=null){ + manifest.setSort(0); + } ZipSerializer serializer=new ZipSerializer(archive.listInputSources(), false); serializer.writeZip(file); } diff --git a/src/main/java/com/reandroid/lib/apk/ApkUtil.java b/src/main/java/com/reandroid/lib/apk/ApkUtil.java index 3af579a..8df8da9 100644 --- a/src/main/java/com/reandroid/lib/apk/ApkUtil.java +++ b/src/main/java/com/reandroid/lib/apk/ApkUtil.java @@ -112,4 +112,7 @@ public class ApkUtil { public static final String PACKAGE_JSON_FILE="package.json"; public static final String SPLIT_JSON_DIRECTORY="resources"; public static final String DEF_MODULE_NAME="base"; + public static final String NAME_value_type="value_type"; + public static final String NAME_data="data"; + public static final String NAME_is_array="is_array"; } diff --git a/src/main/java/com/reandroid/lib/apk/StringPoolBuilder.java b/src/main/java/com/reandroid/lib/apk/StringPoolBuilder.java index 8b7b378..f763dd0 100644 --- a/src/main/java/com/reandroid/lib/apk/StringPoolBuilder.java +++ b/src/main/java/com/reandroid/lib/apk/StringPoolBuilder.java @@ -4,6 +4,7 @@ import com.reandroid.lib.arsc.chunk.PackageBlock; import com.reandroid.lib.arsc.chunk.TableBlock; import com.reandroid.lib.arsc.pool.SpecStringPool; import com.reandroid.lib.arsc.pool.TableStringPool; +import com.reandroid.lib.arsc.value.ValueType; import com.reandroid.lib.json.JSONArray; import com.reandroid.lib.json.JSONException; import com.reandroid.lib.json.JSONObject; @@ -73,12 +74,12 @@ public class StringPoolBuilder { return mSpecNameMap.get(pkgId); } private void scan(JSONObject jsonObject){ - if(jsonObject.has("is_array")){ + if(jsonObject.has(ApkUtil.NAME_is_array)){ addSpecName(jsonObject.optString("name")); } - if(jsonObject.has("value_type")){ - if("STRING".equals(jsonObject.getString("value_type"))){ - String data= jsonObject.getString("data"); + if(jsonObject.has(ApkUtil.NAME_value_type)){ + if(ValueType.STRING.name().equals(jsonObject.getString(ApkUtil.NAME_value_type))){ + String data= jsonObject.getString(ApkUtil.NAME_data); addTableString(data); } return; diff --git a/src/main/java/com/reandroid/lib/apk/UncompressedFiles.java b/src/main/java/com/reandroid/lib/apk/UncompressedFiles.java index 1a45e25..1fbee82 100644 --- a/src/main/java/com/reandroid/lib/apk/UncompressedFiles.java +++ b/src/main/java/com/reandroid/lib/apk/UncompressedFiles.java @@ -4,6 +4,7 @@ import com.reandroid.archive.InputSource; import com.reandroid.archive.ZipArchive; import com.reandroid.lib.json.JSONArray; import com.reandroid.lib.json.JSONConvert; +import com.reandroid.lib.json.JSONObject; import java.io.File; import java.io.FileInputStream; @@ -12,10 +13,16 @@ import java.util.HashSet; import java.util.Set; import java.util.zip.ZipEntry; -public class UncompressedFiles implements JSONConvert { +public class UncompressedFiles implements JSONConvert { private final Set mPathList; + private final Set mExtensionList; + private String mResRawDir; public UncompressedFiles(){ this.mPathList=new HashSet<>(); + this.mExtensionList=new HashSet<>(); + } + public void setResRawDir(String resRawDir){ + this.mResRawDir=resRawDir; } public void apply(ZipArchive archive){ for(InputSource inputSource:archive.listInputSources()){ @@ -23,27 +30,60 @@ public class UncompressedFiles implements JSONConvert { } } public void apply(InputSource inputSource){ - if(contains(inputSource.getName()) || contains(inputSource.getAlias())){ + if(isUncompressed(inputSource.getAlias()) || isUncompressed(inputSource.getName())){ inputSource.setMethod(ZipEntry.STORED); }else { inputSource.setMethod(ZipEntry.DEFLATED); } } - public boolean contains(String path){ + public boolean isUncompressed(String path){ + if(path==null){ + return false; + } + if(containsPath(path)||containsExtension(path)||isResRawDir(path)){ + return true; + } + int i=path.indexOf('.'); + if(i<0){ + return false; + } + String extension=path.substring(i); + return containsExtension(extension); + } + private boolean isResRawDir(String path){ + String dir=mResRawDir; + if(dir==null||dir.length()==0){ + return false; + } + return path.startsWith(dir); + } + public boolean containsExtension(String extension){ + if(extension==null){ + return false; + } + if(mExtensionList.contains(extension)){ + return true; + } + if(!extension.startsWith(".")){ + return mExtensionList.contains("."+extension); + } + return mExtensionList.contains(extension.substring(1)); + } + public boolean containsPath(String path){ return mPathList.contains(path); } - public void add(ZipArchive zipArchive){ + public void addPath(ZipArchive zipArchive){ for(InputSource inputSource: zipArchive.listInputSources()){ - add(inputSource); + addPath(inputSource); } } - public void add(InputSource inputSource){ + public void addPath(InputSource inputSource){ if(inputSource.getMethod()!=ZipEntry.STORED){ return; } - add(inputSource.getAlias()); + addPath(inputSource.getAlias()); } - public void add(String path){ + public void addPath(String path){ if(path==null || path.length()==0){ return; } @@ -53,29 +93,68 @@ public class UncompressedFiles implements JSONConvert { } mPathList.add(path); } - public void clear(){ + public void addCommonExtensions(){ + for(String ext:COMMON_EXTENSIONS){ + addExtension(ext); + } + } + public void addExtension(String extension){ + if(extension==null || extension.length()==0){ + return; + } + mExtensionList.add(extension); + } + public void clearPaths(){ mPathList.clear(); } - @Override - public JSONArray toJson() { - return new JSONArray(mPathList); + public void clearExtensions(){ + mExtensionList.clear(); } @Override - public void fromJson(JSONArray json) { + public JSONObject toJson() { + JSONObject jsonObject = new JSONObject(); + jsonObject.put(NAME_extensions, new JSONArray(mExtensionList)); + jsonObject.put(NAME_paths, new JSONArray(mPathList)); + return jsonObject; + } + @Override + public void fromJson(JSONObject json) { + clearExtensions(); + clearPaths(); if(json==null){ return; } - int length = json.length(); - for(int i=0;i listActivities(){ + return listActivities(true); + } + public List listActivities(boolean includeActivityAlias){ + ResXmlElement application=getApplicationElement(); + if(application==null){ + return new ArrayList<>(); + } + List results = application.listElements(TAG_activity); + if(includeActivityAlias){ + results.addAll(application.listElements(TAG_activity_alias)); + } + return results; + } public List getUsesPermissions(){ List results=new ArrayList<>(); ResXmlElement manifestElement=getManifestElement(); if(manifestElement==null){ return results; } - List permissionList = manifestElement.searchElementsByTagName(TAG_uses_permission); + List permissionList = manifestElement.listElements(TAG_uses_permission); for(ResXmlElement permission:permissionList){ - ResXmlAttribute nameAttr = permission.searchAttributeById(ID_name); + ResXmlAttribute nameAttr = permission.searchAttributeByResourceId(ID_name); if(nameAttr==null){ continue; } @@ -39,9 +64,9 @@ public class AndroidManifestBlock extends ResXmlBlock{ if(manifestElement==null){ return null; } - List permissionList = manifestElement.searchElementsByTagName(TAG_uses_permission); + List permissionList = manifestElement.listElements(TAG_uses_permission); for(ResXmlElement permission:permissionList){ - ResXmlAttribute nameAttr = permission.searchAttributeById(ID_name); + ResXmlAttribute nameAttr = permission.searchAttributeByResourceId(ID_name); if(nameAttr==null){ continue; } @@ -121,7 +146,7 @@ public class AndroidManifestBlock extends ResXmlBlock{ if(manifestElement==null){ return false; } - ResXmlAttribute attribute= manifestElement.searchAttributeById(resId); + ResXmlAttribute attribute= manifestElement.searchAttributeByResourceId(resId); if(attribute==null){ return false; } @@ -147,7 +172,7 @@ public class AndroidManifestBlock extends ResXmlBlock{ if(manifestElement==null){ return false; } - ResXmlAttribute attribute= manifestElement.searchAttributeById(resId); + ResXmlAttribute attribute= manifestElement.searchAttributeByResourceId(resId); if(attribute==null){ return false; } @@ -181,14 +206,14 @@ public class AndroidManifestBlock extends ResXmlBlock{ } return attribute.getRawValue(); } - private ResXmlElement getApplicationElement(){ + public ResXmlElement getApplicationElement(){ ResXmlElement manifestElement=getManifestElement(); if(manifestElement==null){ return null; } return manifestElement.getElementByTagName(TAG_application); } - private ResXmlElement getManifestElement(){ + public ResXmlElement getManifestElement(){ ResXmlElement manifestElement=getResXmlElement(); if(manifestElement==null){ return null; @@ -231,19 +256,34 @@ public class AndroidManifestBlock extends ResXmlBlock{ manifestBlock.readBytes(inputStream); return manifestBlock; } - public static final String TAG_manifest ="manifest"; - public static final String TAG_uses_permission="uses-permission"; - public static final String TAG_application ="application"; + public static final String TAG_action = "action"; + public static final String TAG_activity = "activity"; + public static final String TAG_activity_alias = "activity-alias"; + public static final String TAG_application = "application"; + public static final String TAG_category = "category"; + public static final String TAG_data = "data"; + public static final String TAG_intent_filter = "intent-filter"; + public static final String TAG_manifest = "manifest"; + public static final String TAG_meta_data = "meta-data"; + public static final String TAG_package = "package"; + public static final String TAG_permission = "permission"; + public static final String TAG_provider = "provider"; + public static final String TAG_receiver = "receiver"; + public static final String TAG_service = "service"; + public static final String TAG_uses_feature = "uses-feature"; + public static final String TAG_uses_library = "uses-library"; + public static final String TAG_uses_permission = "uses-permission"; + public static final String TAG_uses_sdk = "uses-sdk"; - public static final String NAME_compileSdkVersion ="compileSdkVersion"; - public static final String NAME_compileSdkVersionCodename ="compileSdkVersionCodename"; + public static final String NAME_compileSdkVersion = "compileSdkVersion"; + public static final String NAME_compileSdkVersionCodename = "compileSdkVersionCodename"; public static final String NAME_installLocation="installLocation"; - public static final String NAME_PACKAGE ="package"; - public static final String NAME_platformBuildVersionCode="platformBuildVersionCode"; - public static final String NAME_platformBuildVersionName ="platformBuildVersionName"; - public static final String NAME_versionCode ="versionCode"; - public static final String NAME_versionName ="versionName"; - public static final String NAME_name ="name"; + public static final String NAME_PACKAGE = "package"; + public static final String NAME_platformBuildVersionCode = "platformBuildVersionCode"; + public static final String NAME_platformBuildVersionName = "platformBuildVersionName"; + public static final String NAME_versionCode = "versionCode"; + public static final String NAME_versionName = "versionName"; + public static final String NAME_name = "name"; public static final int ID_name = 0x01010003; public static final int ID_compileSdkVersion = 0x01010572; @@ -253,5 +293,7 @@ public class AndroidManifestBlock extends ResXmlBlock{ public static final int ID_configChanges = 0x0101001f; public static final int ID_screenOrientation = 0x0101001e; + public static final String VALUE_android_intent_action_MAIN = "android.intent.action.MAIN"; + public static final String FILE_NAME="AndroidManifest.xml"; } diff --git a/src/main/java/com/reandroid/lib/arsc/chunk/xml/ResXmlAttribute.java b/src/main/java/com/reandroid/lib/arsc/chunk/xml/ResXmlAttribute.java index 6d05059..5196ba6 100755 --- a/src/main/java/com/reandroid/lib/arsc/chunk/xml/ResXmlAttribute.java +++ b/src/main/java/com/reandroid/lib/arsc/chunk/xml/ResXmlAttribute.java @@ -36,34 +36,37 @@ public class ResXmlAttribute extends FixedBlockContainer addChild(5, mValueTypeByte); addChild(6, mRawValue); } - public int getNamespaceReference(){ + public String getUri(){ + return getString(getNamespaceReference()); + } + int getNamespaceReference(){ return mNamespaceReference.get(); } - public void setNamespaceReference(int ref){ + void setNamespaceReference(int ref){ mNamespaceReference.set(ref); } - public int getNameReference(){ + int getNameReference(){ return mNameReference.get(); } - public void setNameReference(int ref){ + void setNameReference(int ref){ mNameReference.set(ref); } - public int getValueStringReference(){ + int getValueStringReference(){ return mValueStringReference.get(); } - public void setValueStringReference(int ref){ + void setValueStringReference(int ref){ mValueStringReference.set(ref); } - public short getNameType(){ + short getNameType(){ return mNameType.get(); } - public void setNameType(short s){ + void setNameType(short s){ mNameType.set(s); } - public byte getValueTypeByte(){ + byte getValueTypeByte(){ return mValueTypeByte.get(); } - public void setValueTypeByte(byte b){ + void setValueTypeByte(byte b){ mValueTypeByte.set(b); } public int getRawValue(){ @@ -109,18 +112,7 @@ public class ResXmlAttribute extends FixedBlockContainer } return startNamespace.getPrefix(); } - public String getNamespace(){ - ResXmlElement xmlElement=getParentResXmlElement(); - if(xmlElement==null){ - return null; - } - ResXmlStartNamespace startNamespace=xmlElement.getStartNamespaceByUriRef(getNamespaceReference()); - if(startNamespace==null){ - return null; - } - return startNamespace.getUri(); - } - public ResXmlStartNamespace getStartNamespace(){ + ResXmlStartNamespace getStartNamespace(){ ResXmlElement xmlElement=getParentResXmlElement(); if(xmlElement==null){ return null; @@ -364,7 +356,7 @@ public class ResXmlAttribute extends FixedBlockContainer JSONObject jsonObject=new JSONObject(); jsonObject.put(NAME_name, getName()); jsonObject.put(NAME_id, getNameResourceID()); - jsonObject.put(NAME_namespace_uri, getNamespace()); + jsonObject.put(NAME_namespace_uri, getUri()); ValueType valueType=getValueType(); jsonObject.put(NAME_value_type, valueType.name()); if(valueType==ValueType.STRING){ @@ -432,9 +424,9 @@ public class ResXmlAttribute extends FixedBlockContainer builder.append("}"); return builder.toString(); } - static final String NAME_id="id"; - static final String NAME_value_type="value_type"; - static final String NAME_name="name"; - static final String NAME_namespace_uri ="namespace_uri"; - static final String NAME_data="data"; + static final String NAME_id = "id"; + public static final String NAME_value_type = "value_type"; + static final String NAME_name = "name"; + public static final String NAME_namespace_uri = "namespace_uri"; + public static final String NAME_data= "data"; } diff --git a/src/main/java/com/reandroid/lib/arsc/chunk/xml/ResXmlElement.java b/src/main/java/com/reandroid/lib/arsc/chunk/xml/ResXmlElement.java index b10f38a..a8ada68 100755 --- a/src/main/java/com/reandroid/lib/arsc/chunk/xml/ResXmlElement.java +++ b/src/main/java/com/reandroid/lib/arsc/chunk/xml/ResXmlElement.java @@ -90,18 +90,6 @@ public class ResXmlElement extends FixedBlockContainer implements JSONConvert searchElementsByTagName(String name){ - List results=new ArrayList<>(); - if(name==null){ - return results; - } - for(ResXmlElement child:listElements()){ - if(name.equals(child.getTag())||name.equals(child.getTagName())){ - results.add(child); - } - } - return results; - } public ResXmlAttribute searchAttributeByName(String name){ ResXmlStartElement startElement=getStartElement(); if(startElement!=null){ @@ -109,10 +97,10 @@ public class ResXmlElement extends FixedBlockContainer implements JSONConvert listElements(){ return mBody.getChildes(); } + public List listElements(String name){ + List results=new ArrayList<>(); + if(name==null){ + return results; + } + for(ResXmlElement element:listElements()){ + if(name.equals(element.getTag())||name.equals(element.getTagName())){ + results.add(element); + } + } + return results; + } public ResXmlElement getParentResXmlElement(){ Block parent=getParent(); while (parent!=null){ diff --git a/src/main/java/com/reandroid/lib/arsc/chunk/xml/ResXmlStartElement.java b/src/main/java/com/reandroid/lib/arsc/chunk/xml/ResXmlStartElement.java index 4987e98..4932614 100755 --- a/src/main/java/com/reandroid/lib/arsc/chunk/xml/ResXmlStartElement.java +++ b/src/main/java/com/reandroid/lib/arsc/chunk/xml/ResXmlStartElement.java @@ -31,6 +31,23 @@ public class ResXmlStartElement extends BaseXmlChunk { addChild(mClassAttribute); addChild(mAttributeArray); } + public ResXmlAttribute getAttribute(String uri, String name){ + if(name==null){ + return null; + } + for(ResXmlAttribute attribute:listResXmlAttributes()){ + if(name.equals(attribute.getName())||name.equals(attribute.getFullName())){ + if(uri!=null){ + if(uri.equals(attribute.getUri())){ + return attribute; + } + continue; + } + return attribute; + } + } + return null; + } public ResXmlAttribute searchAttributeByName(String name){ if(name==null){ return null; @@ -42,7 +59,7 @@ public class ResXmlStartElement extends BaseXmlChunk { } return null; } - public ResXmlAttribute searchAttributeById(int resourceId){ + public ResXmlAttribute searchAttributeByResourceId(int resourceId){ if(resourceId==0){ return null; }