mirror of
https://github.com/revanced/Apktool.git
synced 2024-10-20 04:19:55 +02:00
feat: merge iBotPeaches/Apktool
This commit is contained in:
commit
9443f6fefb
28
.github/workflows/analyze.yml
vendored
Normal file
28
.github/workflows/analyze.yml
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
name: Analyze
|
||||
on:
|
||||
push:
|
||||
branches: [master]
|
||||
pull_request:
|
||||
branches: [master]
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v2
|
||||
with:
|
||||
languages: java
|
||||
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v2
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v2
|
19
.github/workflows/build.yml
vendored
19
.github/workflows/build.yml
vendored
@ -98,22 +98,3 @@ jobs:
|
||||
with:
|
||||
name: apktool.jar
|
||||
path: brut.apktool/apktool-cli/build/libs/apktool-*-small.jar
|
||||
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: [ 'java' ]
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v1
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v1
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v1
|
||||
|
@ -253,6 +253,11 @@ original as they were.
|
||||
As cheesy as it is, just follow this [downloading](https://source.android.com/source/downloading.html) link in order
|
||||
to get the source downloaded. This is no small download, expect to use 150-250GB.
|
||||
|
||||
Some optimization techniques for a smaller clone:
|
||||
|
||||
* `~/bin/repo init -u https://android.googlesource.com/platform/manifest -b master --partial-clone` - Partial clone
|
||||
* `repo sync -c` - Only current branch
|
||||
|
||||
After that, you need to build AOSP via this [documentation](https://source.android.com/source/building.html) guide. Now
|
||||
we aren't building the entire AOSP package, the initial build is to just see if you are capable of building it.
|
||||
|
||||
|
11
ROADMAP.md
11
ROADMAP.md
@ -49,3 +49,14 @@ Folks have requested running Apktool on device itself. This has been a challenge
|
||||
that would be placed on the aapt2/aapt binaries.
|
||||
|
||||
Suggestions: [#2811](https://github.com/iBotPeaches/Apktool/issues/2811)
|
||||
|
||||
## Split APK Support
|
||||
Applications are further getting split on qualifiers. Apktool has been built on the assumption of one apk.
|
||||
|
||||
Suggestions: [#2283](https://github.com/iBotPeaches/Apktool/issues/2283), [#2218](https://github.com/iBotPeaches/Apktool/issues/2218), [#2880](https://github.com/iBotPeaches/Apktool/issues/2880)
|
||||
|
||||
## Dummy Resources
|
||||
Folks want the ability to stop the auto generation of dummy resources.
|
||||
|
||||
Suggestions: [#2683](https://github.com/iBotPeaches/Apktool/issues/2683), [#2104](https://github.com/iBotPeaches/Apktool/issues/2104)
|
||||
Pull Request(s): [#2463](https://github.com/iBotPeaches/Apktool/pull/2463)
|
||||
|
@ -337,7 +337,7 @@ public class Androlib {
|
||||
throw new AndrolibException(ex.getMessage());
|
||||
}
|
||||
}
|
||||
LOGGER.fine("Built apk...");
|
||||
LOGGER.fine("Built apk into: " + outFile.getPath());
|
||||
}
|
||||
|
||||
private void buildManifestFile(File appDir, File manifest, File manifestOriginal)
|
||||
|
@ -67,6 +67,9 @@ final public class AndrolibResources {
|
||||
ResPackage pkg;
|
||||
|
||||
switch (pkgs.length) {
|
||||
case 0:
|
||||
pkg = null;
|
||||
break;
|
||||
case 1:
|
||||
pkg = pkgs[0];
|
||||
break;
|
||||
|
@ -104,13 +104,13 @@ public class ResValueFactory {
|
||||
return new ResPluralsValue(parentVal, items);
|
||||
}
|
||||
|
||||
if (ResTypeSpec.RES_TYPE_NAME_STYLES.equals(resTypeName)) {
|
||||
return new ResStyleValue(parentVal, items, this);
|
||||
}
|
||||
|
||||
if (ResTypeSpec.RES_TYPE_NAME_ATTR.equals(resTypeName)) {
|
||||
return new ResAttr(parentVal, 0, null, null, null);
|
||||
}
|
||||
|
||||
if (resTypeName.startsWith(ResTypeSpec.RES_TYPE_NAME_STYLES)) {
|
||||
return new ResStyleValue(parentVal, items, this);
|
||||
}
|
||||
|
||||
throw new AndrolibException("unsupported res type name for bags. Found: " + resTypeName);
|
||||
}
|
||||
|
@ -33,6 +33,7 @@ import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
@ -159,7 +160,7 @@ public class ARSCDecoder {
|
||||
for (int i = 0; i < libraryCount; i++) {
|
||||
packageId = mIn.readInt();
|
||||
packageName = mIn.readNullEndedString(128, true);
|
||||
LOGGER.fine(String.format("Decoding Shared Library (%s), pkgId: %d", packageName, packageId));
|
||||
LOGGER.fine(String.format("Decoding Shared Library (%s), pkgId: %d", packageName, packageId));
|
||||
}
|
||||
|
||||
while(nextChunk().type == Header.XML_TYPE_TYPE) {
|
||||
@ -232,7 +233,7 @@ public class ARSCDecoder {
|
||||
mFlagsOffsets.add(new FlagsOffset(mCountIn.getCount(), entryCount));
|
||||
}
|
||||
|
||||
/* flags */mIn.skipBytes(entryCount * 4);
|
||||
/* flags */mIn.skipBytes(entryCount * 4);
|
||||
mTypeSpec = new ResTypeSpec(mTypeNames.getString(id - 1), mResTable, mPkg, id, entryCount);
|
||||
mPkg.addType(mTypeSpec);
|
||||
return mTypeSpec;
|
||||
@ -250,8 +251,7 @@ public class ARSCDecoder {
|
||||
/* reserved */mIn.skipBytes(2);
|
||||
int entryCount = mIn.readInt();
|
||||
int entriesStart = mIn.readInt();
|
||||
mMissingResSpecs = new boolean[entryCount];
|
||||
Arrays.fill(mMissingResSpecs, true);
|
||||
mMissingResSpecMap = new LinkedHashMap();
|
||||
|
||||
ResConfigFlags flags = readConfigFlags();
|
||||
int position = (mHeader.startPosition + entriesStart) - (entryCount * 4);
|
||||
@ -263,10 +263,18 @@ public class ARSCDecoder {
|
||||
mIn.skipBytes(position - mCountIn.getCount());
|
||||
}
|
||||
|
||||
if (typeFlags == 1) {
|
||||
LOGGER.fine("Sparse type flags detected: " + mTypeSpec.getName());
|
||||
if ((typeFlags & 0x01) != 0) {
|
||||
LOGGER.fine("Sparse type flags detected: " + mTypeSpec.getName());
|
||||
}
|
||||
|
||||
HashMap<Integer, Integer> entryOffsetMap = new LinkedHashMap();
|
||||
for (int i = 0; i < entryCount; i++) {
|
||||
if ((typeFlags & 0x01) != 0) {
|
||||
entryOffsetMap.put(mIn.readUnsignedShort(), mIn.readUnsignedShort());
|
||||
} else {
|
||||
entryOffsetMap.put(i, mIn.readInt());
|
||||
}
|
||||
}
|
||||
int[] entryOffsets = mIn.readIntArray(entryCount);
|
||||
|
||||
if (flags.isInvalid) {
|
||||
String resName = mTypeSpec.getName() + flags.getQualifiers();
|
||||
@ -278,23 +286,15 @@ public class ARSCDecoder {
|
||||
}
|
||||
|
||||
mType = flags.isInvalid && !mKeepBroken ? null : mPkg.getOrCreateConfig(flags);
|
||||
HashMap<Integer, EntryData> offsetsToEntryData = new HashMap<>();
|
||||
|
||||
for (int offset : entryOffsets) {
|
||||
if (offset == -1 || offsetsToEntryData.containsKey(offset)) {
|
||||
for (int i : entryOffsetMap.keySet()) {
|
||||
int offset = entryOffsetMap.get(i);
|
||||
if (offset == -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
offsetsToEntryData.put(offset, readEntryData());
|
||||
}
|
||||
|
||||
for (int i = 0; i < entryOffsets.length; i++) {
|
||||
if (entryOffsets[i] != -1) {
|
||||
mMissingResSpecs[i] = false;
|
||||
mResId = (mResId & 0xffff0000) | i;
|
||||
EntryData entryData = offsetsToEntryData.get(entryOffsets[i]);
|
||||
readEntry(entryData);
|
||||
}
|
||||
mMissingResSpecMap.put(i, false);
|
||||
mResId = (mResId & 0xffff0000) | i;
|
||||
readEntry(readEntryData());
|
||||
}
|
||||
|
||||
return mType;
|
||||
@ -384,8 +384,8 @@ public class ARSCDecoder {
|
||||
}
|
||||
|
||||
private ResIntBasedValue readValue() throws IOException, AndrolibException {
|
||||
/* size */mIn.skipCheckShort((short) 8);
|
||||
/* zero */mIn.skipCheckByte((byte) 0);
|
||||
/* size */mIn.skipCheckShort((short) 8);
|
||||
/* zero */mIn.skipCheckByte((byte) 0);
|
||||
byte type = mIn.readByte();
|
||||
int data = mIn.readInt();
|
||||
|
||||
@ -418,13 +418,13 @@ public class ARSCDecoder {
|
||||
byte keyboard = mIn.readByte();
|
||||
byte navigation = mIn.readByte();
|
||||
byte inputFlags = mIn.readByte();
|
||||
/* inputPad0 */mIn.skipBytes(1);
|
||||
/* inputPad0 */mIn.skipBytes(1);
|
||||
|
||||
short screenWidth = mIn.readShort();
|
||||
short screenHeight = mIn.readShort();
|
||||
|
||||
short sdkVersion = mIn.readShort();
|
||||
/* minorVersion, now must always be 0 */mIn.skipBytes(2);
|
||||
/* minorVersion, now must always be 0 */mIn.skipBytes(2);
|
||||
|
||||
byte screenLayout = 0;
|
||||
byte uiMode = 0;
|
||||
@ -533,14 +533,12 @@ public class ARSCDecoder {
|
||||
private void addMissingResSpecs() throws AndrolibException {
|
||||
int resId = mResId & 0xffff0000;
|
||||
|
||||
for (int i = 0; i < mMissingResSpecs.length; i++) {
|
||||
if (!mMissingResSpecs[i]) {
|
||||
continue;
|
||||
}
|
||||
for (int i : mMissingResSpecMap.keySet()) {
|
||||
if (mMissingResSpecMap.get(i)) continue;
|
||||
|
||||
ResResSpec spec = new ResResSpec(new ResID(resId | i), "APKTOOL_DUMMY_" + Integer.toHexString(i), mPkg, mTypeSpec);
|
||||
|
||||
// If we already have this resID dont add it again.
|
||||
// If we already have this resID don't add it again.
|
||||
if (! mPkg.hasResSpec(new ResID(resId | i))) {
|
||||
mPkg.addResSpec(spec);
|
||||
mTypeSpec.addResSpec(spec);
|
||||
@ -598,7 +596,7 @@ public class ARSCDecoder {
|
||||
private ResType mType;
|
||||
private int mResId;
|
||||
private int mTypeIdOffset = 0;
|
||||
private boolean[] mMissingResSpecs;
|
||||
private HashMap<Integer, Boolean> mMissingResSpecMap;
|
||||
private final HashMap<Integer, ResTypeSpec> mResTypeSpecs = new HashMap<>();
|
||||
|
||||
private final static short ENTRY_FLAG_COMPLEX = 0x0001;
|
||||
@ -685,7 +683,7 @@ public class ARSCDecoder {
|
||||
throw new AndrolibException("Arsc file contains zero packages");
|
||||
} else if (mPackages.length != 1) {
|
||||
int id = findPackageWithMostResSpecs();
|
||||
LOGGER.fine("Arsc file contains multiple packages. Using package "
|
||||
LOGGER.fine("Arsc file contains multiple packages. Using package "
|
||||
+ mPackages[id].getName() + " as default.");
|
||||
|
||||
return mPackages[id];
|
||||
@ -714,4 +712,4 @@ public class ARSCDecoder {
|
||||
private final FlagsOffset[] mFlagsOffsets;
|
||||
private final ResTable mResTable;
|
||||
}
|
||||
}
|
||||
}
|
@ -336,16 +336,26 @@ public class AXmlResourceParser implements XmlResourceParser {
|
||||
}
|
||||
|
||||
String value = m_strings.getString(name);
|
||||
String namespace = getAttributeNamespace(index);
|
||||
|
||||
// some attributes will return "", we must rely on the resource_id and refer to the frameworks
|
||||
// to match the resource id to the name. ex: 0x101021C = versionName
|
||||
if (value.length() == 0 || android_ns.equals(getAttributeNamespace(index))) {
|
||||
// If attribute name is lacking or a private namespace emerges,
|
||||
// retrieve the exact attribute name by its id.
|
||||
if (value == null || value.length() == 0) {
|
||||
try {
|
||||
int resourceId = getAttributeNameResource(index);
|
||||
if (resourceId != 0) {
|
||||
value = mAttrDecoder.decodeManifestAttr(getAttributeNameResource(index));
|
||||
value = mAttrDecoder.decodeManifestAttr(getAttributeNameResource(index));
|
||||
if (value == null) {
|
||||
value = "";
|
||||
}
|
||||
} catch (AndrolibException | NullPointerException ignored) {}
|
||||
} catch (AndrolibException e) {
|
||||
value = "";
|
||||
}
|
||||
} else if (! namespace.equals(android_ns)) {
|
||||
try {
|
||||
String obfuscatedName = mAttrDecoder.decodeManifestAttr(getAttributeNameResource(index));
|
||||
if (! (obfuscatedName == null || obfuscatedName.equals(value))) {
|
||||
value = obfuscatedName;
|
||||
}
|
||||
} catch (AndrolibException ignored) {}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
@ -381,11 +391,27 @@ public class AXmlResourceParser implements XmlResourceParser {
|
||||
|
||||
if (mAttrDecoder != null) {
|
||||
try {
|
||||
String value = valueRaw == -1 ? null : ResXmlEncoders.escapeXmlChars(m_strings.getString(valueRaw));
|
||||
String obfuscatedValue = mAttrDecoder.decodeManifestAttr(valueData);
|
||||
|
||||
if (! (value == null || obfuscatedValue == null)) {
|
||||
int slashPos = value.lastIndexOf("/");
|
||||
|
||||
if (slashPos != -1) {
|
||||
// Handle a value with a format of "@yyy/xxx"
|
||||
String dir = value.substring(0, slashPos);
|
||||
value = dir + "/"+ obfuscatedValue;
|
||||
} else if (! value.equals(obfuscatedValue)) {
|
||||
value = obfuscatedValue;
|
||||
}
|
||||
}
|
||||
|
||||
return mAttrDecoder.decode(
|
||||
valueType,
|
||||
valueData,
|
||||
valueRaw == -1 ? null : ResXmlEncoders.escapeXmlChars(m_strings.getString(valueRaw)),
|
||||
getAttributeNameResource(index));
|
||||
valueType,
|
||||
valueData,
|
||||
value,
|
||||
getAttributeNameResource(index)
|
||||
);
|
||||
} catch (AndrolibException ex) {
|
||||
setFirstError(ex);
|
||||
LOGGER.log(Level.WARNING, String.format("Could not decode attr value, using undecoded value "
|
||||
@ -807,9 +833,9 @@ public class AXmlResourceParser implements XmlResourceParser {
|
||||
if (m_strings == null) {
|
||||
m_reader.skipCheckInt(CHUNK_AXML_FILE, CHUNK_AXML_FILE_BROKEN);
|
||||
|
||||
/*
|
||||
* chunkSize
|
||||
*/
|
||||
/*
|
||||
* chunkSize
|
||||
*/
|
||||
m_reader.skipInt();
|
||||
m_strings = StringBlock.read(m_reader);
|
||||
m_namespaces.increaseDepth();
|
||||
@ -863,9 +889,9 @@ public class AXmlResourceParser implements XmlResourceParser {
|
||||
}
|
||||
|
||||
// Common header.
|
||||
/* chunkSize */m_reader.skipInt();
|
||||
/* chunkSize */m_reader.skipInt();
|
||||
int lineNumber = m_reader.readInt();
|
||||
/* 0xFFFFFFFF */m_reader.skipInt();
|
||||
/* 0xFFFFFFFF */m_reader.skipInt();
|
||||
|
||||
if (chunkType == CHUNK_XML_START_NAMESPACE || chunkType == CHUNK_XML_END_NAMESPACE) {
|
||||
if (chunkType == CHUNK_XML_START_NAMESPACE) {
|
||||
@ -873,8 +899,8 @@ public class AXmlResourceParser implements XmlResourceParser {
|
||||
int uri = m_reader.readInt();
|
||||
m_namespaces.push(prefix, uri);
|
||||
} else {
|
||||
/* prefix */m_reader.skipInt();
|
||||
/* uri */m_reader.skipInt();
|
||||
/* prefix */m_reader.skipInt();
|
||||
/* uri */m_reader.skipInt();
|
||||
m_namespaces.pop();
|
||||
}
|
||||
continue;
|
||||
@ -885,7 +911,7 @@ public class AXmlResourceParser implements XmlResourceParser {
|
||||
if (chunkType == CHUNK_XML_START_TAG) {
|
||||
m_namespaceUri = m_reader.readInt();
|
||||
m_name = m_reader.readInt();
|
||||
/* flags? */m_reader.skipInt();
|
||||
/* flags? */m_reader.skipInt();
|
||||
int attributeCount = m_reader.readInt();
|
||||
m_idAttribute = (attributeCount >>> 16) - 1;
|
||||
attributeCount &= 0xFFFF;
|
||||
@ -912,8 +938,8 @@ public class AXmlResourceParser implements XmlResourceParser {
|
||||
|
||||
if (chunkType == CHUNK_XML_TEXT) {
|
||||
m_name = m_reader.readInt();
|
||||
/* ? */m_reader.skipInt();
|
||||
/* ? */m_reader.skipInt();
|
||||
/* ? */m_reader.skipInt();
|
||||
/* ? */m_reader.skipInt();
|
||||
m_event = TEXT;
|
||||
break;
|
||||
}
|
||||
@ -927,10 +953,10 @@ public class AXmlResourceParser implements XmlResourceParser {
|
||||
}
|
||||
|
||||
// ///////////////////////////////// data
|
||||
/*
|
||||
* All values are essentially indices, e.g. m_name is an index of name in
|
||||
* m_strings.
|
||||
*/
|
||||
/*
|
||||
* All values are essentially indices, e.g. m_name is an index of name in
|
||||
* m_strings.
|
||||
*/
|
||||
private ExtDataInput m_reader;
|
||||
private ResAttrDecoder mAttrDecoder;
|
||||
private AndrolibException mFirstError;
|
||||
|
@ -37,6 +37,9 @@ public class AndroidManifestResourceParser extends AXmlResourceParser {
|
||||
@Override
|
||||
public String getAttributeValue(int index) {
|
||||
String value = super.getAttributeValue(index);
|
||||
if (value == null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
if (!isNumericStringMetadataAttributeValue(index, value)) {
|
||||
return value;
|
||||
@ -46,7 +49,7 @@ public class AndroidManifestResourceParser extends AXmlResourceParser {
|
||||
// Otherwise, when the decoded app is rebuilt, aapt will incorrectly encode
|
||||
// the value as an int or float (depending on aapt version), breaking the original
|
||||
// app functionality.
|
||||
return "\\ " + super.getAttributeValue(index).trim();
|
||||
return "\\ " + value.trim();
|
||||
}
|
||||
|
||||
private boolean isNumericStringMetadataAttributeValue(int index, String value) {
|
||||
|
@ -18,6 +18,7 @@ package brut.androlib.res.decoder;
|
||||
|
||||
import brut.androlib.AndrolibException;
|
||||
import brut.androlib.err.UndefinedResObjectException;
|
||||
import brut.androlib.res.data.ResID;
|
||||
import brut.androlib.res.data.ResPackage;
|
||||
import brut.androlib.res.data.ResResSpec;
|
||||
import brut.androlib.res.data.value.ResAttr;
|
||||
@ -48,10 +49,24 @@ public class ResAttrDecoder {
|
||||
throws AndrolibException {
|
||||
|
||||
if (attrResId != 0) {
|
||||
ResResSpec resResSpec = getCurrentPackage().getResTable().getResSpec(attrResId);
|
||||
int attrId = attrResId;
|
||||
|
||||
if (resResSpec != null) {
|
||||
return resResSpec.getName();
|
||||
// See also: brut.androlib.res.data.ResTable.getResSpec
|
||||
if (attrId >> 24 == 0) {
|
||||
ResPackage pkg = getCurrentPackage();
|
||||
int packageId = pkg.getId();
|
||||
int pkgId = (packageId == 0 ? 2 : packageId);
|
||||
attrId = (0xFF000000 & (pkgId << 24)) | attrId;
|
||||
}
|
||||
|
||||
// Retrieve the ResSpec in a package by id
|
||||
ResID resId = new ResID(attrId);
|
||||
ResPackage pkg = getCurrentPackage();
|
||||
if (pkg.hasResSpec(resId)) {
|
||||
ResResSpec resResSpec = pkg.getResSpec(resId);
|
||||
if (resResSpec != null) {
|
||||
return resResSpec.getName();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -129,6 +129,10 @@ public final class ResXmlPatcher {
|
||||
* Creates a modified network security config file that is more permissive
|
||||
*
|
||||
* @param file network security config file
|
||||
* @throws TransformerException XML file could not be edited
|
||||
* @throws IOException XML file could not be located
|
||||
* @throws SAXException XML file could not be read
|
||||
* @throws ParserConfigurationException XML nodes could be written
|
||||
*/
|
||||
public static void modNetworkSecurityConfig(File file)
|
||||
throws ParserConfigurationException, TransformerException, IOException, SAXException {
|
||||
@ -184,13 +188,10 @@ public final class ResXmlPatcher {
|
||||
for (int i = 0; i < nodes.getLength(); i++) {
|
||||
Node node = nodes.item(i);
|
||||
NamedNodeMap attrs = node.getAttributes();
|
||||
Node provider = attrs.getNamedItem("android:authorities");
|
||||
|
||||
if (attrs != null) {
|
||||
Node provider = attrs.getNamedItem("android:authorities");
|
||||
|
||||
if (provider != null) {
|
||||
saved = isSaved(file, saved, provider);
|
||||
}
|
||||
if (provider != null) {
|
||||
saved = isSaved(file, saved, provider);
|
||||
}
|
||||
}
|
||||
|
||||
@ -204,13 +205,10 @@ public final class ResXmlPatcher {
|
||||
for (int i = 0; i < nodes.getLength(); i++) {
|
||||
Node node = nodes.item(i);
|
||||
NamedNodeMap attrs = node.getAttributes();
|
||||
Node provider = attrs.getNamedItem("android:scheme");
|
||||
|
||||
if (attrs != null) {
|
||||
Node provider = attrs.getNamedItem("android:scheme");
|
||||
|
||||
if (provider != null) {
|
||||
saved = isSaved(file, saved, provider);
|
||||
}
|
||||
if (provider != null) {
|
||||
saved = isSaved(file, saved, provider);
|
||||
}
|
||||
}
|
||||
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -6,7 +6,7 @@ chcp 65001 2>nul >nul
|
||||
set java_exe=java.exe
|
||||
|
||||
if defined JAVA_HOME (
|
||||
set java_exe="%JAVA_HOME%\bin\java.exe"
|
||||
set "java_exe=%JAVA_HOME%\bin\java.exe"
|
||||
)
|
||||
|
||||
rem Find the highest version .jar available in the same directory as the script
|
||||
@ -36,7 +36,7 @@ if "%ATTR:~0,1%"=="-" if "%~x1"==".apk" (
|
||||
)
|
||||
|
||||
:load
|
||||
%java_exe% -jar -Duser.language=en -Dfile.encoding=UTF8 "%~dp0%BASENAME%%max%.jar" %fastCommand% %*
|
||||
"%java_exe%" -jar -Duser.language=en -Dfile.encoding=UTF8 "%~dp0%BASENAME%%max%.jar" %fastCommand% %*
|
||||
|
||||
rem Pause when ran non interactively
|
||||
for /f "tokens=2" %%# in ("%cmdcmdline%") do if /i "%%#" equ "/c" pause
|
||||
|
Loading…
Reference in New Issue
Block a user