Giter Club home page Giter Club logo

arsclib's Introduction

ARSCLib

Android binary resources read/write java library

This library is developed based on AOSP structure of androidfw/ResourceTypes.h , to totally replace aapt/aapt2

Read, write, modify and create

  • Resource table (resources.arsc)
  • Binary xml files (AndroidManifest.xml & resource xml)

Convert from/to json string (for obfuscated resources)

  • Decodes resources to readable json
  • Encodes/Builds sources in json format to binary resources

Convert from/to XML string (for un-obfuscated resources)

  • Decodes resources to source code
  • Encodes/Builds source XML to binary resources
NOTES:

1- Decoding resources to XML requires all source names should be un-obfuscated and valid

2- User of this lib is assumed to have good knowledge of android source XML syntax, thus during encoding/building it does not validate or throw XML syntax errors as often as aapt/aapt2. For example, you are allowed to set wrong values on some places and doesn't prevent from successful building. On AndroidManifest.xml you can set package="Wrong 😂 (package) name!" then you have to know such values are acceptable by android devices.

Example application

Check this tool developed using this library https://github.com/REAndroid/APKEditor

Works on all java supported platforms (Android, Linux, Mac, Windows)

  • Maven
repositories {
   mavenCentral()
}
dependencies {
   implementation("io.github.reandroid:ARSCLib:+")
}
  • Jar
dependencies {
    implementation(files("$rootProject.projectDir/libs/ARSCLib.jar"))
}

Build jar

git clone https://github.com/REAndroid/ARSCLib.git
cd ARSCLib
./gradlew jar
# Built jar will be placed ./build/libs/ARSCLib-x.x.x.jar

Examples

Java example
import com.reandroid.apk.AndroidFrameworks;
import com.reandroid.apk.ApkModule;
import com.reandroid.apk.FrameworkApk;
import com.reandroid.archive.ByteInputSource;
import com.reandroid.arsc.chunk.PackageBlock;
import com.reandroid.arsc.chunk.TableBlock;
import com.reandroid.arsc.chunk.xml.AndroidManifestBlock;
import com.reandroid.arsc.chunk.xml.ResXmlAttribute;
import com.reandroid.arsc.chunk.xml.ResXmlElement;
import com.reandroid.arsc.coder.EncodeResult;
import com.reandroid.arsc.coder.ValueCoder;
import com.reandroid.arsc.value.Entry;

import java.io.File;
import java.io.IOException;

public class ARSCLibExample {

    public static void createNewApk() throws IOException {

        ApkModule apkModule = new ApkModule();

        TableBlock tableBlock = new TableBlock();
        AndroidManifestBlock manifest = new AndroidManifestBlock();

        apkModule.setTableBlock(tableBlock);
        apkModule.setManifest(manifest);

        FrameworkApk framework = apkModule.initializeAndroidFramework(
                AndroidFrameworks.getLatest().getVersionCode());

        PackageBlock packageBlock = tableBlock.newPackage(0x7f, "com.example");

        Entry appIcon = packageBlock.getOrCreate("", "drawable", "ic_launcher");

        EncodeResult color = ValueCoder.encode("#006400");
        appIcon.setValueAsRaw(color.valueType, color.value);

        Entry appNameDefault = packageBlock.getOrCreate("", "string", "app_name");
        appNameDefault.setValueAsString("My Application");

        Entry appNameDe = packageBlock.getOrCreate("-de", "string", "app_name");
        appNameDe.setValueAsString("Meine Bewerbung");

        Entry appNameRu = packageBlock.getOrCreate("-ru-rRU", "string", "app_name");
        appNameRu.setValueAsString("Мое заявление");

        manifest.setPackageName("com.example");
        manifest.setVersionCode(100);
        manifest.setVersionName("1.0.0");
        manifest.setIconResourceId(appIcon.getResourceId());
        manifest.setCompileSdkVersion(framework.getVersionCode());
        manifest.setCompileSdkVersionCodename(framework.getVersionName());
        manifest.setPlatformBuildVersionCode(framework.getVersionCode());
        manifest.setPlatformBuildVersionName(framework.getVersionName());

        manifest.addUsesPermission("android.permission.INTERNET");
        manifest.addUsesPermission("android.permission.READ_EXTERNAL_STORAGE");

        //all appName entries created above have the same resource ids
        manifest.setApplicationLabel(appNameDefault.getResourceId());

        ResXmlElement mainActivity = manifest.getOrCreateMainActivity("android.app.Activity");
        ResXmlAttribute labelAttribute = mainActivity
                .getOrCreateAndroidAttribute(AndroidManifestBlock.NAME_label, AndroidManifestBlock.ID_label);
        labelAttribute.setValueAsString("Hello World");

        //Android os requires at least one dex file on base apk
        ByteInputSource dummyDex = new ByteInputSource(new byte[0], "classes.dex");
        apkModule.add(dummyDex);

        File outFile = new File("test_out.apk");
        apkModule.writeApk(outFile);
        //Sign and install
    }
}

arsclib's People

Contributors

axelen123 avatar eirv avatar kikfox avatar kirlif avatar reandroid avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

arsclib's Issues

`ResXmlDocument#decodeToXml()` is not processing namespaces correctly

ResXmlDocument xmlBlock = new ResXmlDocument();
try (BlockReader reader = new BlockReader(byteBuffer.array())) {
    xmlBlock.readBytes(reader);
    xmlBlock.setPackageBlock(getFrameworkPackageBlock());
    return xmlBlock.decodeToXml();
}

For Google Play Services, it's throwing an IllegalArgumentException.

java.lang.IllegalArgumentException: Namespace not found for prefix: ns2
	at com.reandroid.xml.XMLElement.setName(XMLElement.java:397)
	at com.reandroid.xml.XMLElement.setName(XMLElement.java:377)
	at com.reandroid.xml.XMLElement.<init>(XMLElement.java:42)
	at com.reandroid.arsc.chunk.xml.ResXmlElement.decodeToXml(ResXmlElement.java:1430)
	at com.reandroid.arsc.chunk.xml.ResXmlElement.decodeToXml(ResXmlElement.java:1452)
	at com.reandroid.arsc.chunk.xml.ResXmlDocument.decodeToXml(ResXmlDocument.java:488)
	at io.github.muntashirakon.AppManager.apk.parser.AndroidBinXmlDecoder.decodeToXml(AndroidBinXmlDecoder.java:5)

Styled strings merging.

In the merging process, StyleArray of BaseStringPool is populated from the base package only.
The other modules should participate.

How to use

what are the commands make the readme.me good

`NullPointerException` when building strings with styles for `TableStringPool`

Issue

Exception in thread "main" java.lang.NullPointerException: Cannot invoke "com.reandroid.arsc.item.StyleItem.addStylePiece(int, int, int)" because "styleItem" is null
	at com.reandroid.apk.xmlencoder.ValuesStringPoolBuilder.buildWithStyles(ValuesStringPoolBuilder.java:72)
	at com.reandroid.apk.xmlencoder.ValuesStringPoolBuilder.addTo(ValuesStringPoolBuilder.java:40)
	at com.reandroid.apk.xmlencoder.RESEncoder.preloadStringPool(RESEncoder.java:152)
	at com.reandroid.apk.xmlencoder.RESEncoder.scanResourceFiles(RESEncoder.java:69)
	at com.reandroid.apk.xmlencoder.RESEncoder.scanDirectory(RESEncoder.java:61)
	at com.reandroid.apk.ApkModuleXmlEncoder.scanDirectory(ApkModuleXmlEncoder.java:38)
	at com.reandroid.apkeditor.compile.Builder.buildXml(Builder.java:74)
	at com.reandroid.apkeditor.compile.Builder.run(Builder.java:42)
	at com.reandroid.apkeditor.compile.Builder.execute(Builder.java:144)
	at com.reandroid.apkeditor.Main.execute(Main.java:60)
	at com.reandroid.apkeditor.Main.main(Main.java:38)

Reproduction steps

This issue can be reproduced by using APKEditor:

  1. d -t xml -i YouTube_18.03.36.apk -o YouTube
  2. b -i YouTube -o Build

Preserve original signature scheme v2, v3, v4 in modded APK

Discussed in REAndroid/APKEditor#3

Originally posted by sourvodka2023 January 8, 2023
Is it possible the original signature scheme (APK Sig Block 42PK) hidden in the APK can be extracted for later use and put it back in APK again? just to make a modded APK with original signature (Modders usually call it an unsigned APK), in order to be able to login with Google for rooted devices with CorePatch module?

This is how it looks like in hex editor, it's at near the bottom, but I don't understand much how it works in hex
image

For example with preserving original signature:

  1. Extract APK Sig Block 42PK as a file using APKEditor
  2. Modify files in APK without decompiling. Some tools require APK modification, so just decompiling apk wouldn't work
  3. Put back APK Sig Block 42PK block in APK using APKEditor

The problem with unsigned APK:
When making changes in an APK using ordinary zip utility like Winrar, it removes the (APK Sig Block 42PK) completely, breaking Google login on Android 9 and above because Android 9 expect signature scheme v2, v3, v4 (APK Sig Block 42PK). Android 8 and below ignores it and read signature scheme v1 (RSA, SF and MF files in META-INF). Also signature scheme v1 is getting deprecated, some APK doesn't come with v1 anymore

To install unsigned APK:
Install Xposed and CorePatch https://github.com/LSPosed/CorePatch

Format float

com.reandroid.arsc.decoder.ComplexUtil$Radix.formatFloat(ComplexUtil.java:156)

try { value = Float.parseFloat(result); } catch (NumberFormatException ignored) { }

Example log:
java.lang.NumberFormatException: For input string: "115,199982"

Decompilation error array.xml

When decompiling the attached apk, ARSCLib crashes with NPE :(
From what I was able to understand - ARSCLib uses BagDecoderCommon instead of BarDecoderArray when processing arrays.xml
Stacktrace:

java.lang.NullPointerException: Cannot invoke "String.indexOf(int)" because "value" is null
        at com.android.org.kxml2.io.KXmlSerializer.attribute(KXmlSerializer.java:432)
        at com.reandroid.apk.xmldecoder.EntryWriterSerializer.attribute(EntryWriterSerializer.java:52)
        at com.reandroid.apk.xmldecoder.EntryWriterSerializer.attribute(EntryWriterSerializer.java:23)
        at com.reandroid.apk.xmldecoder.BagDecoderCommon.decode(BagDecoderCommon.java:52)
        at com.reandroid.apk.xmldecoder.BagDecoderCommon.decode(BagDecoderCommon.java:24)
        at com.reandroid.apk.xmldecoder.DecoderResTableEntryMap.decode(DecoderResTableEntryMap.java:39)
        at com.reandroid.apk.xmldecoder.XMLEntryDecoder.decode(XMLEntryDecoder.java:61)
        at com.reandroid.apk.xmldecoder.XMLEntryDecoder.decode(XMLEntryDecoder.java:87)
        at com.reandroid.apk.xmldecoder.XMLEntryDecoderSerializer.decode(XMLEntryDecoderSerializer.java:56)
        at com.reandroid.apk.xmldecoder.XMLEntryDecoderSerializer.decodeUniqueConfigs(XMLEntryDecoderSerializer.java:50)
        at com.reandroid.apk.xmldecoder.XMLEntryDecoderSerializer.decode(XMLEntryDecoderSerializer.java:42)
        at com.reandroid.apk.ApkModuleXmlDecoder.decodeValues(ApkModuleXmlDecoder.java:298)
        at com.reandroid.apk.ApkModuleXmlDecoder.decodeValues(ApkModuleXmlDecoder.java:294)
        at com.reandroid.apk.ApkModuleXmlDecoder.decodeValues(ApkModuleXmlDecoder.java:282)
        at com.reandroid.apk.ApkModuleXmlDecoder.decodeResourceTable(ApkModuleXmlDecoder.java:63)
        at com.reandroid.apk.ApkModuleDecoder.decode(ApkModuleDecoder.java:48)

Version: 1.2.0
APK: https://drive.google.com/file/d/1Osi6k_DRKK7D8a_X9v5ZzHRespn2UDPt/view?usp=sharing

error 1.2.0 and master

java.lang.NullPointerException: Cannot invoke "String.indexOf(int)" because "value" is null
at com.android.org.kxml2.io.KXmlSerializer.attribute(KXmlSerializer.java:432)
at com.reandroid.apk.xmldecoder.EntryWriterSerializer.attribute(EntryWriterSerializer.java:52)
at com.reandroid.apk.xmldecoder.EntryWriterSerializer.attribute(EntryWriterSerializer.java:23)
at com.reandroid.apk.xmldecoder.BagDecoderCommon.decode(BagDecoderCommon.java:52)
at com.reandroid.apk.xmldecoder.BagDecoderCommon.decode(BagDecoderCommon.java:24)
at com.reandroid.apk.xmldecoder.DecoderResTableEntryMap.decode(DecoderResTableEntryMap.java:39)
at com.reandroid.apk.xmldecoder.XMLEntryDecoder.decode(XMLEntryDecoder.java:61)
at com.reandroid.apk.xmldecoder.XMLEntryDecoder.decode(XMLEntryDecoder.java:87)
at com.reandroid.apk.xmldecoder.XMLEntryDecoderSerializer.decode(XMLEntryDecoderSerializer.java:56)
at com.reandroid.apk.xmldecoder.XMLEntryDecoderSerializer.decodeUniqueConfigs(XMLEntryDecoderSerializer.java:50)
at com.reandroid.apk.xmldecoder.XMLEntryDecoderSerializer.decode(XMLEntryDecoderSerializer.java:42)
at com.reandroid.apk.ApkModuleXmlDecoder.decodeValues(ApkModuleXmlDecoder.java:298)
at com.reandroid.apk.ApkModuleXmlDecoder.decodeValues(ApkModuleXmlDecoder.java:294)
at com.reandroid.apk.ApkModuleXmlDecoder.decodeValues(ApkModuleXmlDecoder.java:282)
at com.reandroid.apk.ApkModuleXmlDecoder.decodeResourceTable(ApkModuleXmlDecoder.java:63)
at com.reandroid.apk.ApkModuleDecoder.decode(ApkModuleDecoder.java:48)

XMLEncodeSource is trimming XML attribute values

Example input

<?xml version="1.0" encoding="utf-8"?>
<manifest
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:versionCode="50001204"
  android:versionName="5.0.1.204"
  android:compileSdkVersion="28"
  android:compileSdkVersionCodename="9"
  package="com.android.activity.test"
  platformBuildVersionCode="50001204"
  platformBuildVersionName="5.0.1.204">
  <application>
    <activity
      android:label=" "
      android:name="com.android.activity.EmptyActivity"
      android:exported="false"
      android:screenOrientation="portrait"
      android:configChanges="keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize">
      <meta-data
        android:name="hwc-theme"
        android:value="androidhwext:style/Theme.Emui">
      </meta-data>
    </activity>
  </application>
</manifest>

Example output (after converting the above into binary XML and then converted back)

<?xml version="1.0" encoding="utf-8"?>
<manifest
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:versionCode="50001204"
  android:versionName="5.0.1.204"
  android:compileSdkVersion="28"
  android:compileSdkVersionCodename="9"
  package="com.android.activity.test"
  platformBuildVersionCode="50001204"
  platformBuildVersionName="5.0.1.204">
  <application>
    <activity
      android:label=""
      android:name="com.android.activity.EmptyActivity"
      android:exported="false"
      android:screenOrientation="portrait"
      android:configChanges="keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize">
      <meta-data
        android:name="hwc-theme"
        android:value="androidhwext:style/Theme.Emui">
      </meta-data>
    </activity>
  </application>
</manifest>

What to look for
Look at the line 13 of each XML file above. The first one had an space but the second one didn't.

Code for converting binary XML

    private static byte[] encode(@NonNull XMLSource xmlSource) throws IOException {
        EncodeMaterials encodeMaterials = new EncodeMaterials();
        FrameworkApk frameworkApk = AndroidFrameworks.getLatest();
        encodeMaterials.addFramework(frameworkApk);
        Collection<PackageBlock> packageBlocks = frameworkApk.getTableBlock().listPackages();
        if (packageBlocks.size() < 1) {
            throw new IOException("Framework apk does not contain any packages!");
        }
        PackageBlock packageBlock = packageBlocks.iterator().next();
        encodeMaterials.setCurrentPackage(packageBlock);
        XMLEncodeSource xmlEncodeSource = new XMLEncodeSource(encodeMaterials, xmlSource);
        return xmlEncodeSource.getResXmlBlock().getBytes();
    }

Crash due to unsupported regular expression in Android

Caused by: java.util.regex.PatternSyntaxException: Syntax error in regexp pattern near index 8:
^\s*(?<A>https?://[^:\s]+)(:(?<B>([^:/\s]+)))?\s*$
        ^
  at java.util.regex.Pattern.compileImpl(Native Method)
  at java.util.regex.Pattern.compile(Pattern.java:411)
  at java.util.regex.Pattern.<init>(Pattern.java:394)
  at java.util.regex.Pattern.compile(Pattern.java:381)
  at com.reandroid.xml.SchemaAttr.<clinit>(SchemaAttr.java:123)
  ... 17 more

PS: This appears to be a Android/ICU4C limitation

Add tests

Test the library using unit tests. This will help the maintainers as well as developers:

  1. Prevent issues due to regression by ensuring continuous testing via GitHub actions, for example
  2. Developers can quickly understand how to use the library by looking at the tests.

Slow apk merging for large resource.arsc files

When the resource.arsc file of base.apk is very large, such as 10-20MB.
Merge apks will take a significant amount of time, especially when running on Android devices.
I found that the following area can be optimized. If the baseModule exists, it can be directly used as the root node of Merge.
Instead of creating a new module and merging the baseModule.

public class ApkBundle {
    ...

    public ApkModule mergeModules() throws IOException {
        List<ApkModule> moduleList=getApkModuleList();
        if(moduleList.size()==0){
            throw new FileNotFoundException("Nothing to merge, empty modules");
        }

        // This place can be optimized, Use the baseMode when it present in aps dir as the mergeRoot module instead of create a new module.
        ApkModule result=new ApkModule(generateMergedModuleName(), new APKArchive());
        result.setAPKLogger(apkLogger);

        mergeStringPools(result);

        ApkModule base=getBaseModule();
        if(base==null){
            base=getLargestTableModule();
        }
        result.merge(base);
        for(ApkModule module:moduleList){
            if(module==base){
                continue;
            }
            result.merge(module);
        }
        if(result.hasTableBlock()){
            TableBlock tableBlock=result.getTableBlock();
            tableBlock.sortPackages();
            tableBlock.refresh();
        }
        result.getApkArchive().sortApkFiles();
        return result;
    }

    ...
}

I have made some rough modifications, there may be issues

public ApkModule mergeModules() throws IOException {
         List<ApkModule> moduleList = getApkModuleList();
         if (moduleList.size() == 0) {
             throw new FileNotFoundException("Nothing to merge, empty modules");
         }

         ApkModule result = getBaseModule();
         if (result == null) {
             result = getLargestTableModule();
         }

         result.setModuleName(generateMergedModuleName());
         result.setAPKLogger(apkLogger);

         mergeStringPools(result);

         for (ApkModule module : moduleList) {
             if (module == result) {
                 continue;
             }
             result.merge(module);
         }
         if (result.hasTableBlock()) {
             TableBlock tableBlock = result.getTableBlock();
             tableBlock.sortPackages();
             tableBlock.refresh();
         }
         result.getApkArchive().sortApkFiles();
         return result;
     }

NPE in xml decoder

When trying to decompile in xml mode (in json mode, everything is ok), the attached apk crashes with an error (stack trace from apkeditor)

Exception in thread "main" java.lang.NullPointerException: Cannot invoke "String.indexOf(int)" because "value" is null                                                                                                                                                                            
        at com.android.org.kxml2.io.KXmlSerializer.attribute(KXmlSerializer.java:432)
        at com.reandroid.arsc.coder.xml.XmlCoder$BagChild.decodeStyle(XmlCoder.java:439)
        at com.reandroid.arsc.coder.xml.XmlCoder$BagChild.decode(XmlCoder.java:384)
        at com.reandroid.arsc.coder.xml.XmlCoder$ValuesXml.decodeBag(XmlCoder.java:157)
        at com.reandroid.arsc.coder.xml.XmlCoder$ValuesXml.decode(XmlCoder.java:146)
        at com.reandroid.arsc.coder.xml.XmlCoder$ValuesXml.decode(XmlCoder.java:127)
        at com.reandroid.arsc.coder.xml.XmlCoder$ValuesXml.decode(XmlCoder.java:118)
        at com.reandroid.arsc.coder.xml.XmlCoder$ValuesXml.decodePackage(XmlCoder.java:108)
        at com.reandroid.arsc.coder.xml.XmlCoder$ValuesXml.decodeTable(XmlCoder.java:90)
        at com.reandroid.arsc.coder.xml.XmlCoder$ValuesXml.decodeTable(XmlCoder.java:83)
        at com.reandroid.apk.ApkModuleXmlDecoder.decodeValues(ApkModuleXmlDecoder.java:273)
        at com.reandroid.apk.ApkModuleXmlDecoder.decodeResourceTable(ApkModuleXmlDecoder.java:60)
        at com.reandroid.apk.ApkModuleDecoder.decode(ApkModuleDecoder.java:48)
        at com.reandroid.apkeditor.decompile.Decompiler.run(Decompiler.java:62)
        at com.reandroid.apkeditor.decompile.Decompiler.execute(Decompiler.java:127)
        at com.reandroid.apkeditor.Main.execute(Main.java:81)
        at com.reandroid.apkeditor.Main.execute(Main.java:64)
        at com.reandroid.apkeditor.Main.main(Main.java:36)

APK: https://mega.nz/file/Ax82ESYQ#yhKTPKpplRqhqQcmGPKmlKO2lPR4AY3R3L1fOlOIfqE

Framework

Don't use targetSdkVersion for select version framework. Need use compileSdkVersion

Use xmlpull-style parser and serialiser

This is just what I've felt while using the library and only my expert opinion. I can also help you implementing this if you choose to do this.

The use of xmlpull-style parser and serialiser is quite common in Android ecosystem. The framework itself uses this library for parsing both normal and binary XML (newly introduced in Android 12) files. So, it allows greater control such as easy to convert between one XML format to another by simultaneous use of parser and serialiser. This also make it easier to separate reading and writing the XML contents. So, I propose, possibly, creating a wrapper around the XMLDocument class.

XXP3

Duplicate class org.xmlpull.v1.XmlPullParser found in modules ARSCLib-1.2.3 (io.github.reandroid:ARSCLib:1.2.3) and xpp3-1.1.4c (xpp3:xpp3:1.1.4c)

Please use dependencies or rename package name

debug

how can we debug by exporting an apk file?

Merge apk error use the latest commit ` d8ef9db`

Merge apk error use the latest commit d8ef9db


W  java.lang.IllegalArgumentException: java.io.EOFException: Finished reading: 0
W  	at com.reandroid.apk.ApkModule.getTableBlock(ApkModule.java:523)
W  	at com.reandroid.apk.ApkModule.getTableBlock(ApkModule.java:530)
W  	at com.reandroid.apk.ApkModule.getVolatileTableStringPool(ApkModule.java:597)
W  	at com.reandroid.apk.ApkBundle.mergeStringPools(ApkBundle.java:81)
W  	at com.reandroid.apk.ApkBundle.mergeModules(ApkBundle.java:44)
W  	at com.xiaoyv.manager.tool.apk.editor.merge.ApkMerger.run(ApkMerger.kt:62)
W  	at com.xiaoyv.manager.tool.apk.editor.merge.ApkMerger$Companion.merge(ApkMerger.kt:245)
W  	at com.xiaoyv.manager.tool.apk.editor.merge.ApkMerger$Companion.merge(ApkMerger.kt:214)
W  	at com.xiaoyv.manager.ui.file.FileSelectorViewModel$mergeApksFile$2$1.invokeSuspend(FileSelectorViewModel.kt:300)
W  	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
W  	at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
W  	at kotlinx.coroutines.internal.LimitedDispatcher.run(LimitedDispatcher.kt:42)
W  	at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:95)
W  	at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:570)
W  	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750)
W  	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:677)
W  	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:664)
W  Caused by: java.io.EOFException: Finished reading: 0
W  	at com.reandroid.arsc.io.BlockReader.readFully(BlockReader.java:204)
W  	at com.reandroid.arsc.io.BlockReader.readFully(BlockReader.java:187)
W  	at com.reandroid.arsc.item.BlockItem.onReadBytes(BlockItem.java:100)
W  	at com.reandroid.arsc.base.Block.readBytes(Block.java:48)
W  	at com.reandroid.arsc.base.BlockContainer.onReadBytes(BlockContainer.java:149)
W  	at com.reandroid.arsc.header.HeaderBlock.onReadBytes(HeaderBlock.java:151)
W  	at com.reandroid.arsc.base.Block.readBytes(Block.java:48)
W  	at com.reandroid.arsc.base.BlockContainer.onReadBytes(BlockContainer.java:149)
W  	at com.reandroid.arsc.chunk.Chunk.onReadBytes(Chunk.java:59)
W  	at com.reandroid.arsc.base.Block.readBytes(Block.java:48)
W  	at com.reandroid.arsc.chunk.TableBlock.onReadBytes(TableBlock.java:147)
W  	at com.reandroid.arsc.base.Block.readBytes(Block.java:48)
W  	at com.reandroid.arsc.chunk.TableBlock.readBytes(TableBlock.java:161)
W  	at com.reandroid.arsc.chunk.TableBlock.load(TableBlock.java:326)
W  	at com.reandroid.apk.ApkModule.loadTableBlock(ApkModule.java:615)
W  	at com.reandroid.apk.ApkModule.getTableBlock(ApkModule.java:517)
W  	... 16 more

Failure [INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION: Failed to parse /data/app/vmdl479469645.tmp/base.apk: length=31; index=31]

修改了 manifest.xml 和 resource.asrc 之后打包。

Failed to parse /data/app/vmdl479469645.tmp/0_jdh________________
java.lang.ArrayIndexOutOfBoundsException: length=31; index=31
at android.content.res.StringBlock.getSequence(StringBlock.java:107)
at android.content.res.XmlBlock$Parser.getAttributeValue(XmlBlock.java:233)
at android.content.res.XmlBlock$Parser.getAttributeValue(XmlBlock.java:262)
at android.content.pm.parsing.ApkLiteParseUtils.parsePackageSplitNames(ApkLiteParseUtils.java:668)
at android.content.pm.parsing.ApkLiteParseUtils.parseApkLite(ApkLiteParseUtils.java:405)
at android.content.pm.parsing.ApkLiteParseUtils.parseApkLiteInner(ApkLiteParseUtils.java:385)
at android.content.pm.parsing.ApkLiteParseUtils.parseApkLite(ApkLiteParseUtils.java:329)
at com.android.server.pm.PackageInstallerSession.validateApkInstallLocked(PackageInstallerSession.java:2730)
at com.android.server.pm.PackageInstallerSession.streamValidateAndCommit(PackageInstallerSession.java:1848)
at com.android.server.pm.PackageInstallerSession.handleStreamValidateAndCommit(PackageInstallerSession.java:1696)
at com.android.server.pm.PackageInstallerSession.-$$Nest$mhandleStreamValidateAndCommit(Unknown Source:0)
at com.android.server.pm.PackageInstallerSession$4.handleMessage(PackageInstallerSession.java:727)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loopOnce(Looper.java:201)
at android.os.Looper.loop(Looper.java:288)
at android.os.HandlerThread.run(HandlerThread.java:67)

Repacked APK crash on runtime

Hi, thank you for your great library and your good support.
I am using ARSCLib v1.2.0 to add an XML file, edit resources.arsc, edit manifest of multiple APKs. there is no problem in all APKs except one of them, when I repack this specific APK, even without any edit, just decompile and build, the app crash on runtime as follows:

 E  FATAL EXCEPTION: main
    Process: a.a.myapplication, PID: 2683
    java.lang.RuntimeException: Unable to instantiate application android.support.multidex.MultiDexApplication package a.a.myapplication: java.lang.ClassNotFoundException: Didn't find class "android.support.multidex.MultiDexApplication" on path: DexPathList[[zip file "/data/app/~~jiNlAldBI9zriYWq2RGs0w==/a.a.myapplication-t3lmIin-UCSOuRv7-T9tfQ==/base.apk"],nativeLibraryDirectories=[/data/app/~~jiNlAldBI9zriYWq2RGs0w==/a.a.myapplication-t3lmIin-UCSOuRv7-T9tfQ==/lib/arm64, /system/lib64, /system/system_ext/lib64]]
    	at android.app.LoadedApk.makeApplicationInner(LoadedApk.java:1573)
    	at android.app.LoadedApk.makeApplicationInner(LoadedApk.java:1502)
    	at android.app.ActivityThread.handleBindApplication(ActivityThread.java:7553)
    	at android.app.ActivityThread.-$$Nest$mhandleBindApplication(Unknown Source:0)
    	at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2400)
    	at android.os.Handler.dispatchMessage(Handler.java:106)
    	at android.os.Looper.loopOnce(Looper.java:226)
    	at android.os.Looper.loop(Looper.java:313)
    	at android.app.ActivityThread.main(ActivityThread.java:8757)
    	at java.lang.reflect.Method.invoke(Native Method)
    	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:571)
    	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1067)
    Caused by: java.lang.ClassNotFoundException: Didn't find class "android.support.multidex.MultiDexApplication" on path: DexPathList[[zip file "/data/app/~~jiNlAldBI9zriYWq2RGs0w==/a.a.myapplication-t3lmIin-UCSOuRv7-T9tfQ==/base.apk"],nativeLibraryDirectories=[/data/app/~~jiNlAldBI9zriYWq2RGs0w==/a.a.myapplication-t3lmIin-UCSOuRv7-T9tfQ==/lib/arm64, /system/lib64, /system/system_ext/lib64]]
    	at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:259)
    	at java.lang.ClassLoader.loadClass(ClassLoader.java:379)
    	at java.lang.ClassLoader.loadClass(ClassLoader.java:312)
    	at android.app.AppComponentFactory.instantiateApplication(AppComponentFactory.java:76)
    	at androidx.core.app.CoreComponentFactory.instantiateApplication(CoreComponentFactory.java:52)
    	at android.app.Instrumentation.newApplication(Instrumentation.java:1232)
    	at android.app.LoadedApk.makeApplicationInner(LoadedApk.java:1565)
    	at android.app.LoadedApk.makeApplicationInner(LoadedApk.java:1502) 
    	at android.app.ActivityThread.handleBindApplication(ActivityThread.java:7553) 
    	at android.app.ActivityThread.-$$Nest$mhandleBindApplication(Unknown Source:0) 
    	at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2400) 
    	at android.os.Handler.dispatchMessage(Handler.java:106) 
    	at android.os.Looper.loopOnce(Looper.java:226) 
    	at android.os.Looper.loop(Looper.java:313) 
    	at android.app.ActivityThread.main(ActivityThread.java:8757) 
    	at java.lang.reflect.Method.invoke(Native Method) 
    	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:571) 
    	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1067)  

There is no difference in dex files, and the class "android.support.multidex.MultiDexApplication" not exists in the original APK too, the resources.arsc binary files have some small differences, but I don't find any difference when opening them in android studio.
The class "android.support.multidex.MultiDexApplication" is in the manifest application tag:

<application
        android:theme="@ref/0x7f1101d2"
        android:label="@ref/0x7f10001c"
        android:icon="@ref/0x7f0d0000"
        android:name="android.support.multidex.MultiDexApplication"
        android:debuggable="true"
        android:allowBackup="true"
        android:largeHeap="true"
        android:supportsRtl="true"
        android:fullBackupContent="@ref/0x7f130000"
        android:usesCleartextTraffic="true"
        android:roundIcon="@ref/0x7f0d0001"
        android:appComponentFactory="androidx.core.app.CoreComponentFactory"
        android:dataExtractionRules="@ref/0x7f130001"
        android:requestLegacyExternalStorage="true">

Force Close Application After add or edit strings or xml in resources.arsc

After the changes in the resources.arsc file (adding a new string or a new XML)

After compiling the Android application, the application encounters a force close error

the edited application loses its name and its icon after editing and compiling with the new resources.arsc file.

In the logs section, the error is as follows

java.lang.RuntimeException: Unable to get provider androidx.startup.InitializationProvider: android.content.res.Resources$NotFoundException: String resource ID #0x7f0f001b
at android.app.ActivityThread.installProvider(ActivityThread.java:5858)

Orginal Apk

https://dl.dropboxusercontent.com/s/y72kyqk8alakz0u/app-release_original.apk?dl=0

Modified Apk

https://dl.dropboxusercontent.com/s/3fyhod67lgvfv1v/app-release-modified.apk?dl=0

aapt or aapt2?

Hi,
I've discovered this library while trying to find a solution for this issue: MuntashirAkon/AppManager#951

However, it appears that it is unable to parse the AndroidManifest.xml mentioned in the issue just like any other libraries (apksig, jadx, apk-parser, etc.), and throws the following error:

java.io.IOException: Not ResXmlBlock: NULL(0x0000){Header=8, Chunk=15756}
	at com.reandroid.lib.arsc.chunk.xml.ResXmlBlock.onReadBytes(ResXmlBlock.java:95)
	at com.reandroid.lib.arsc.base.Block.readBytes(Block.java:38)

If it were strictly based on aapt2 source (which includes the same parser that is included in modern Android OS), it should've been able to parse the file.

Here's the file for reference: AndroidManifest.xml.pdf (remove .pdf extension)

Thanks.

PS: This is how it was fixed in LSPatch: LSPosed/LSPatch@c41be02

Add xml file to apk

Hi, thank you for your great library.
I want to add a new XML file to APK without decompiling the whole APK XML files.
just copy the XML to APK (we have default and v22 version for this resource), index the XML files in resources.arsc, and also modify AndroidManifest and reference this XML in meta-data tag.
I tried doing this as follows:

  1. Copy two versions of my XML file (default and v22) to package manually using Winrar to [xml, xml-v22] directories (my APK is not obfuscated).
  2. index the XML using this code (using some classes from ApkEditor project):
ApkModule module=ApkModule.loadApkFile(inputFile);
TableBlock tableBlock = module.getTableBlock();
PackageBlock packageBlock = tableBlock.getPackageBlockById(0x7f);
Entry newEntry = packageBlock.getOrCreate("", "xml", "config");
newEntry.setValueAsString("res/xml/"+ newEntry.getName() +".xml");
Entry newV22Entry = packageBlock.getOrCreate("-v22", "xml", "config");
newV22Entry.setValueAsString("res/xml-v22/"+ newV22Entry.getName() +".xml");
EntryGroup newEntryGroup = new EntryGroup(newEntry.getResourceId());
newEntryGroup.add(newEntry);
newEntryGroup.add(newV22Entry);
packageBlock.getEntriesGroupMap().put(newEntry.getResourceId(), newEntryGroup);
  1. reference to this XML in the manifest:
AndroidManifestBlock manifest = module.getAndroidManifestBlock();
ResXmlElement applicationTag = manifest.getApplicationElement();
List<ResXmlElement> appElements = applicationTag.listElements();
for (ResXmlElement element: appElements) {
    if (element.getAttributeAt(0).getValueString().equals("MyService")) {
        ResXmlElement metaData = element.getElementByTagName("meta-data");
        for (ResXmlAttribute att: metaData.listAttributes()) {
            if (att.getName().equals(AndroidManifestBlock.NAME_resource)) {
                att.setData(newEntry.getResourceId());
            }
        }
    }
}
  1. package APK:
Util.addApkEditorInfo(module, getClass().getSimpleName());
String message = module.refreshTable();
if(message != null){
    log(message);
}
message = module.refreshManifest();
if(message != null){
    log(message);
}

log("Writing apk ...");
module.writeApk(outputFile, this);
log("Saved to: "+outputFile);
log("Done");

Because there is no document, I wrote this code by trial and error and I know there are a lot of problems there. and finally, the generated APK looks ok but my config for MyService is not applied. probably there are problems in encoding and obfuscation. also, I don't know what to do if the APK is obfuscated?!

Also, I tried to solve my problem using this issue and it works. but I want to prevent decoding the whole of APK resources.

[feature request] ninepatch support

would it be possible to add (read-only) support for the binary version of .9.png?
for an interface, could probably use something as simple as a function that returns an RGB byte array for a .9.png file and width+height of the result, though would probably want some intermediary type that would reduce the amount of operations that need to be performed when re-scaling.

EDIT: got no use for this anymore, closing

Set indentation for attributes in new lines

There is an option to set indentation for child tags in XMLDocument but no option to set indentation for new line attributes and they are at present calculated at XMLElement#appendAttributesIndentText(Writer). It might be better to provide an option to set indentations instead of calculating them. For example, instead of providing an argument boolean newLineAttributes, you can provide int attributeIndentation whose negative value (e.g. -1) would imply no new line and any positive number would imply the amount of indentation.

Thanks.

[XML] String attributes not updated properly

AndroidManifest.xml

    <?xml version="1.0" encoding="utf-8"?>
    <manifest
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:versionCode="1"
        android:versionName="1.0"
        android:compileSdkVersion="28"
        android:compileSdkVersionCodename="9"
        package="com.web2apk"
        platformBuildVersionCode="28"
        platformBuildVersionName="9"
        >
        <uses-sdk
	        android:minSdkVersion="16"
	        android:targetSdkVersion="27"
	        >
        </uses-sdk>
        <uses-permission
	        android:name="android.permission.INTERNET"
	        >
        </uses-permission>
        <application
	        android:label="@7F040000"
	        android:icon="@7F030000"
	        android:allowBackup="true"
	        android:supportsRtl="true"
	        android:usesCleartextTraffic="true"
	        >
	        <activity
		        android:name="com.web2apk.MainActivity"
		        android:screenOrientation="6"
		        >
		        <intent-filter
			        >
			        <action
				        android:name="android.intent.action.MAIN"
				        >
			        </action>
			        <category
				        android:name="android.intent.category.LAUNCHER"
				        >
			        </category>
		        </intent-filter>
	        </activity>
        </application>
    </manifest>

i want to set packagename = "com.web2apk.main"

    AndroidManifestBlock manifestBlock = AndroidManifestBlock.load(new File("AndroidManifest.xml"));

    String oldpack = manifestBlock.getPackageName();
    System.out.println( manifestBlock.getPackageName());
    manifestBlock.setPackageName("com.web2apk.main");


    manifestBlock.refresh();

    manifestBlock.writeBytes(new File("out.xml"));;

output use xml2axml

   <?xml version="1.0" encoding="utf-8"?>
  <manifest
      xmlns:android="http://schemas.android.com/apk/res/android"
      android:versionCode="1"
      android:versionName="1.0"
      android:compileSdkVersion="28"
      android:compileSdkVersionCodename="9"
      package=""
      platformBuildVersionCode="28"
      platformBuildVersionName="9"
      >
      <uses-sdk
	      android:minSdkVersion="16"
	      android:targetSdkVersion="27"
	      >
      </uses-sdk>
      <uses-permission
	      android:name="android.permission.INTERNET"
	      >
      </uses-permission>
      <application
	      android:label="@7F040000"
	      android:icon="@7F030000"
	      android:debuggable="true"
	      android:allowBackup="true"
	      android:supportsRtl="true"
	      android:usesCleartextTraffic="true"
	      >
	      <activity
		      android:name="com.web2apk.MainActivity"
		      android:screenOrientation="6"
		      >
		      <intent-filter
			      >
			      <action
				      android:name="android.intent.action.MAIN"
				      >
			      </action>
			      <category
				      android:name="android.intent.category.LAUNCHER"
				      >
			      </category>
		      </intent-filter>
	      </activity>
      </application>
  </manifest>

Change package name

Hello good time

I want to change the package of an application for testing

and install the original and edited version side by side

For this, I changed the manifest and a series of elements such as the provider and receiver and meta data
and package element

Using your library, I also changed the resource table (resources.arsc) of the package with this code

 PackageBlock packageBlock = tableBlock.getPackageArray().get(0);

                packageBlock.setPackageName("com.example.app);
    

But again, when installing the edited version next to the original application

The following error is seen
App not installed as package conflicts with an existing package
Thank you for your guidance

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.