This commit is contained in:
REAndroid 2022-12-09 14:37:16 -05:00
parent 1cf9ed2535
commit 0b2f3815db
9 changed files with 246 additions and 87 deletions

View File

@ -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 {

View File

@ -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);
}

View File

@ -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";
}

View File

@ -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;

View File

@ -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<JSONArray> {
public class UncompressedFiles implements JSONConvert<JSONObject> {
private final Set<String> mPathList;
private final Set<String> 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<JSONArray> {
}
}
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<JSONArray> {
}
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();
JSONArray extensions = json.optJSONArray(NAME_extensions);
if(extensions!=null){
int length = extensions.length();
for(int i=0;i<length;i++){
this.add(json.getString(i));
this.addExtension(extensions.getString(i));
}
}
JSONArray paths = json.optJSONArray(NAME_paths);
if(paths!=null){
int length = paths.length();
for(int i=0;i<length;i++){
this.addPath(paths.getString(i));
}
}
}
public void fromJson(File jsonFile) throws IOException {
if(!jsonFile.isFile()){
return;
}
JSONArray jsonArray=new JSONArray(new FileInputStream(jsonFile));
fromJson(jsonArray);
JSONObject jsonObject=new JSONObject(new FileInputStream(jsonFile));
fromJson(jsonObject);
}
public static final String JSON_FILE = "uncompressed-files.json";
public static final String NAME_paths = "paths";
public static final String NAME_extensions = "extensions";
public static String[] COMMON_EXTENSIONS=new String[]{
".png",
".jpg",
".mp3",
".mp4",
".wav",
".webp",
};
}

View File

@ -15,15 +15,40 @@ public class AndroidManifestBlock extends ResXmlBlock{
public AndroidManifestBlock(){
super();
}
public ResXmlElement getMainActivity(){
for(ResXmlElement activity:listActivities()){
for(ResXmlElement intentFilter:activity.listElements(TAG_intent_filter)){
ResXmlAttribute attribute = intentFilter.searchAttributeByResourceId(ID_name);
if(VALUE_android_intent_action_MAIN.equals(attribute.getValueAsString())){
return activity;
}
}
}
return null;
}
public List<ResXmlElement> listActivities(){
return listActivities(true);
}
public List<ResXmlElement> listActivities(boolean includeActivityAlias){
ResXmlElement application=getApplicationElement();
if(application==null){
return new ArrayList<>();
}
List<ResXmlElement> results = application.listElements(TAG_activity);
if(includeActivityAlias){
results.addAll(application.listElements(TAG_activity_alias));
}
return results;
}
public List<String> getUsesPermissions(){
List<String> results=new ArrayList<>();
ResXmlElement manifestElement=getManifestElement();
if(manifestElement==null){
return results;
}
List<ResXmlElement> permissionList = manifestElement.searchElementsByTagName(TAG_uses_permission);
List<ResXmlElement> 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<ResXmlElement> permissionList = manifestElement.searchElementsByTagName(TAG_uses_permission);
List<ResXmlElement> 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,9 +256,24 @@ 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_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";
@ -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";
}

View File

@ -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){
@ -433,8 +425,8 @@ public class ResXmlAttribute extends FixedBlockContainer
return builder.toString();
}
static final String NAME_id = "id";
static final String NAME_value_type="value_type";
public 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";
public static final String NAME_namespace_uri = "namespace_uri";
public static final String NAME_data= "data";
}

View File

@ -90,18 +90,6 @@ public class ResXmlElement extends FixedBlockContainer implements JSONConvert<JS
}
return null;
}
public List<ResXmlElement> searchElementsByTagName(String name){
List<ResXmlElement> 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<JS
}
return null;
}
public ResXmlAttribute searchAttributeById(int resourceId){
public ResXmlAttribute searchAttributeByResourceId(int resourceId){
ResXmlStartElement startElement=getStartElement();
if(startElement!=null){
return startElement.searchAttributeById(resourceId);
return startElement.searchAttributeByResourceId(resourceId);
}
return null;
}
@ -207,6 +195,18 @@ public class ResXmlElement extends FixedBlockContainer implements JSONConvert<JS
public List<ResXmlElement> listElements(){
return mBody.getChildes();
}
public List<ResXmlElement> listElements(String name){
List<ResXmlElement> 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){

View File

@ -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;
}