1.Fix compatibility for Android M
2.SMAPI 3.4.0 3.Galaxy Store compat
This commit is contained in:
parent
20ec03caa2
commit
5734a01260
|
@ -10,7 +10,7 @@ android {
|
|||
applicationId "com.zane.smapiinstaller"
|
||||
minSdkVersion 19
|
||||
targetSdkVersion 28
|
||||
versionCode 21
|
||||
versionCode 23
|
||||
versionName "1.3.6"
|
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
|
@ -86,6 +86,7 @@ dependencies {
|
|||
implementation 'com.github.didikee:AndroidDonate:0.1.0'
|
||||
implementation 'com.hjq:language:3.0'
|
||||
implementation 'org.greenrobot:greendao:3.2.2'
|
||||
implementation 'net.sourceforge.streamsupport:android-retrostreams:1.7.1'
|
||||
|
||||
testImplementation 'junit:junit:4.12'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
|
||||
|
|
|
@ -51,8 +51,9 @@ import java.util.Collections;
|
|||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java9.util.Optional;
|
||||
import java.util.Set;
|
||||
import java9.util.stream.StreamSupport;
|
||||
|
||||
/**
|
||||
* Default implementation of {@link ApkSignerEngine}.
|
||||
|
@ -437,9 +438,8 @@ public class DefaultApkSignerEngine implements ApkSignerEngine {
|
|||
isDebuggable(entryName)) {
|
||||
|
||||
Optional<V1SchemeVerifier.NamedDigest> extractedDigest =
|
||||
V1SchemeVerifier.getDigestsToVerify(
|
||||
entry.getValue(), "-Digest", mMinSdkVersion, Integer.MAX_VALUE)
|
||||
.stream()
|
||||
StreamSupport.stream(V1SchemeVerifier.getDigestsToVerify(
|
||||
entry.getValue(), "-Digest", mMinSdkVersion, Integer.MAX_VALUE))
|
||||
.filter(d -> d.jcaDigestAlgorithm == alg)
|
||||
.findFirst();
|
||||
|
||||
|
|
|
@ -63,8 +63,10 @@ import java.util.concurrent.ForkJoinPool;
|
|||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
import java9.util.function.Supplier;
|
||||
import java9.util.stream.Collectors;
|
||||
|
||||
import java9.util.stream.StreamSupport;
|
||||
|
||||
public class ApkSigningBlockUtils {
|
||||
|
||||
|
@ -415,7 +417,7 @@ public class ApkSigningBlockUtils {
|
|||
DataSource centralDir,
|
||||
DataSource eocd) throws IOException, NoSuchAlgorithmException, DigestException {
|
||||
Map<ContentDigestAlgorithm, byte[]> contentDigests = new HashMap<>();
|
||||
Set<ContentDigestAlgorithm> oneMbChunkBasedAlgorithm = digestAlgorithms.stream()
|
||||
Set<ContentDigestAlgorithm> oneMbChunkBasedAlgorithm = StreamSupport.stream(digestAlgorithms)
|
||||
.filter(a -> a == ContentDigestAlgorithm.CHUNKED_SHA256 ||
|
||||
a == ContentDigestAlgorithm.CHUNKED_SHA512)
|
||||
.collect(Collectors.toSet());
|
||||
|
@ -1100,7 +1102,7 @@ public class ApkSigningBlockUtils {
|
|||
if (bestSigAlgorithmOnSdkVersion.isEmpty()) {
|
||||
throw new NoSupportedSignaturesException("No supported signature");
|
||||
}
|
||||
return bestSigAlgorithmOnSdkVersion.values().stream()
|
||||
return StreamSupport.stream(bestSigAlgorithmOnSdkVersion.values())
|
||||
.sorted((sig1, sig2) -> Integer.compare(
|
||||
sig1.algorithm.getId(), sig2.algorithm.getId()))
|
||||
.collect(Collectors.toList());
|
||||
|
|
|
@ -32,6 +32,9 @@ import com.android.apksig.internal.pkcs7.SignedData;
|
|||
import com.android.apksig.internal.pkcs7.SignerIdentifier;
|
||||
import com.android.apksig.internal.pkcs7.SignerInfo;
|
||||
import com.android.apksig.internal.util.Pair;
|
||||
|
||||
import net.fornwall.apksigner.Base64;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
|
@ -46,7 +49,6 @@ import java.security.SignatureException;
|
|||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Base64;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
@ -375,7 +377,7 @@ public abstract class V1SchemeSigner {
|
|||
Attributes entryAttrs = new Attributes();
|
||||
entryAttrs.putValue(
|
||||
entryDigestAttributeName,
|
||||
Base64.getEncoder().encodeToString(entryDigest));
|
||||
Base64.encode(entryDigest));
|
||||
ByteArrayOutputStream sectionOut = new ByteArrayOutputStream();
|
||||
byte[] sectionBytes;
|
||||
try {
|
||||
|
@ -448,7 +450,7 @@ public abstract class V1SchemeSigner {
|
|||
MessageDigest md = getMessageDigestInstance(manifestDigestAlgorithm);
|
||||
mainAttrs.putValue(
|
||||
getManifestDigestAttributeName(manifestDigestAlgorithm),
|
||||
Base64.getEncoder().encodeToString(md.digest(manifest.contents)));
|
||||
Base64.encode(md.digest(manifest.contents)));
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
try {
|
||||
SignatureFileWriter.writeMainSection(out, mainAttrs);
|
||||
|
@ -464,7 +466,7 @@ public abstract class V1SchemeSigner {
|
|||
Attributes attrs = new Attributes();
|
||||
attrs.putValue(
|
||||
entryDigestAttributeName,
|
||||
Base64.getEncoder().encodeToString(sectionDigest));
|
||||
Base64.encode(sectionDigest));
|
||||
|
||||
try {
|
||||
SignatureFileWriter.writeIndividualSection(out, sectionName, attrs);
|
||||
|
|
|
@ -47,6 +47,8 @@ import com.android.apksig.util.DataSinks;
|
|||
import com.android.apksig.util.DataSource;
|
||||
import com.android.apksig.zip.ZipFormatException;
|
||||
|
||||
import net.fornwall.apksigner.Base64;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
import java.nio.ByteBuffer;
|
||||
|
@ -61,8 +63,6 @@ import java.security.cert.CertificateException;
|
|||
import java.security.cert.X509Certificate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Base64;
|
||||
import java.util.Base64.Decoder;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
|
@ -1464,8 +1464,8 @@ public abstract class V1SchemeVerifier {
|
|||
V1SchemeSigner.MANIFEST_ENTRY_NAME,
|
||||
jcaDigestAlgorithm,
|
||||
mSignatureFileEntry.getName(),
|
||||
Base64.getEncoder().encodeToString(actual),
|
||||
Base64.getEncoder().encodeToString(expected));
|
||||
Base64.encode(actual),
|
||||
Base64.encode(expected));
|
||||
verified = false;
|
||||
}
|
||||
}
|
||||
|
@ -1506,8 +1506,8 @@ public abstract class V1SchemeVerifier {
|
|||
Issue.JAR_SIG_MANIFEST_MAIN_SECTION_DIGEST_DID_NOT_VERIFY,
|
||||
jcaDigestAlgorithm,
|
||||
mSignatureFileEntry.getName(),
|
||||
Base64.getEncoder().encodeToString(actual),
|
||||
Base64.getEncoder().encodeToString(expected));
|
||||
Base64.encode(actual),
|
||||
Base64.encode(expected));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1559,8 +1559,8 @@ public abstract class V1SchemeVerifier {
|
|||
entryName,
|
||||
jcaDigestAlgorithm,
|
||||
mSignatureFileEntry.getName(),
|
||||
Base64.getEncoder().encodeToString(actual),
|
||||
Base64.getEncoder().encodeToString(expected));
|
||||
Base64.encode(actual),
|
||||
Base64.encode(expected));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1635,7 +1635,6 @@ public abstract class V1SchemeVerifier {
|
|||
String digestAttrSuffix,
|
||||
int minSdkVersion,
|
||||
int maxSdkVersion) {
|
||||
Decoder base64Decoder = Base64.getDecoder();
|
||||
List<NamedDigest> result = new ArrayList<>(1);
|
||||
if (minSdkVersion < AndroidSdkVersion.JELLY_BEAN_MR2) {
|
||||
// Prior to JB MR2, Android platform's logic for picking a digest algorithm to verify is
|
||||
|
@ -1664,7 +1663,7 @@ public abstract class V1SchemeVerifier {
|
|||
continue;
|
||||
}
|
||||
// Supported digest algorithm
|
||||
result.add(new NamedDigest(alg, base64Decoder.decode(digestBase64)));
|
||||
result.add(new NamedDigest(alg, Base64.decode(digestBase64)));
|
||||
break;
|
||||
}
|
||||
// No supported digests found -- this will fail to verify on pre-JB MR2 Androids.
|
||||
|
@ -1683,7 +1682,7 @@ public abstract class V1SchemeVerifier {
|
|||
// Attribute not found
|
||||
continue;
|
||||
}
|
||||
byte[] digest = base64Decoder.decode(digestBase64);
|
||||
byte[] digest = Base64.decode(digestBase64);
|
||||
byte[] digestInResult = getDigest(result, alg);
|
||||
if ((digestInResult == null) || (!Arrays.equals(digestInResult, digest))) {
|
||||
result.add(new NamedDigest(alg, digest));
|
||||
|
@ -1902,8 +1901,8 @@ public abstract class V1SchemeVerifier {
|
|||
entryName,
|
||||
expectedDigest.jcaDigestAlgorithm,
|
||||
V1SchemeSigner.MANIFEST_ENTRY_NAME,
|
||||
Base64.getEncoder().encodeToString(actualDigest),
|
||||
Base64.getEncoder().encodeToString(expectedDigest.digest));
|
||||
Base64.encode(actualDigest),
|
||||
Base64.encode(expectedDigest.digest));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,6 +22,8 @@ import com.android.apksig.internal.asn1.ber.BerDataValueReader;
|
|||
import com.android.apksig.internal.asn1.ber.BerEncoding;
|
||||
import com.android.apksig.internal.asn1.ber.ByteBufferBerDataValueReader;
|
||||
import com.android.apksig.internal.util.ByteBufferUtils;
|
||||
import com.zane.smapiinstaller.utils.MathUtils;
|
||||
import com.zane.smapiinstaller.utils.ReflectionUtils;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
|
@ -311,7 +313,7 @@ public final class Asn1BerParser {
|
|||
|
||||
private static Asn1Type getContainerAsn1Type(Class<?> containerClass)
|
||||
throws Asn1DecodingException {
|
||||
Asn1Class containerAnnotation = containerClass.getDeclaredAnnotation(Asn1Class.class);
|
||||
Asn1Class containerAnnotation = ReflectionUtils.getDeclaredAnnotation(containerClass, Asn1Class.class);
|
||||
if (containerAnnotation == null) {
|
||||
throw new Asn1DecodingException(
|
||||
containerClass.getName() + " is not annotated with "
|
||||
|
@ -332,7 +334,13 @@ public final class Asn1BerParser {
|
|||
|
||||
private static Class<?> getElementType(Field field)
|
||||
throws Asn1DecodingException, ClassNotFoundException {
|
||||
String type = field.getGenericType().getTypeName();
|
||||
String type;
|
||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.P) {
|
||||
type = field.getGenericType().getTypeName();
|
||||
}
|
||||
else {
|
||||
type = field.getGenericType().toString();
|
||||
}
|
||||
int delimiterIndex = type.indexOf('<');
|
||||
if (delimiterIndex == -1) {
|
||||
throw new Asn1DecodingException("Not a container type: " + field.getGenericType());
|
||||
|
@ -508,7 +516,7 @@ public final class Asn1BerParser {
|
|||
private static int integerToInt(ByteBuffer encoded) throws Asn1DecodingException {
|
||||
BigInteger value = integerToBigInteger(encoded);
|
||||
try {
|
||||
return value.intValue();
|
||||
return MathUtils.intValueExact(value);
|
||||
} catch (ArithmeticException e) {
|
||||
throw new Asn1DecodingException(
|
||||
String.format("INTEGER cannot be represented as int: %1$d (0x%1$x)", value), e);
|
||||
|
@ -518,7 +526,7 @@ public final class Asn1BerParser {
|
|||
private static long integerToLong(ByteBuffer encoded) throws Asn1DecodingException {
|
||||
BigInteger value = integerToBigInteger(encoded);
|
||||
try {
|
||||
return value.longValue();
|
||||
return MathUtils.longValueExact(value);
|
||||
} catch (ArithmeticException e) {
|
||||
throw new Asn1DecodingException(
|
||||
String.format("INTEGER cannot be represented as long: %1$d (0x%1$x)", value),
|
||||
|
@ -531,7 +539,7 @@ public final class Asn1BerParser {
|
|||
Field[] declaredFields = containerClass.getDeclaredFields();
|
||||
List<AnnotatedField> result = new ArrayList<>(declaredFields.length);
|
||||
for (Field field : declaredFields) {
|
||||
Asn1Field annotation = field.getDeclaredAnnotation(Asn1Field.class);
|
||||
Asn1Field annotation = ReflectionUtils.getDeclaredAnnotation(field, Asn1Field.class);
|
||||
if (annotation == null) {
|
||||
continue;
|
||||
}
|
||||
|
@ -646,7 +654,7 @@ public final class Asn1BerParser {
|
|||
case SEQUENCE:
|
||||
{
|
||||
Asn1Class containerAnnotation =
|
||||
targetType.getDeclaredAnnotation(Asn1Class.class);
|
||||
ReflectionUtils.getDeclaredAnnotation(targetType, Asn1Class.class);
|
||||
if ((containerAnnotation != null)
|
||||
&& (containerAnnotation.type() == Asn1Type.SEQUENCE)) {
|
||||
return parseSequence(dataValue, targetType);
|
||||
|
@ -656,7 +664,7 @@ public final class Asn1BerParser {
|
|||
case CHOICE:
|
||||
{
|
||||
Asn1Class containerAnnotation =
|
||||
targetType.getDeclaredAnnotation(Asn1Class.class);
|
||||
ReflectionUtils.getDeclaredAnnotation(targetType, Asn1Class.class);
|
||||
if ((containerAnnotation != null)
|
||||
&& (containerAnnotation.type() == Asn1Type.CHOICE)) {
|
||||
return parseChoice(dataValue, targetType);
|
||||
|
|
|
@ -17,8 +17,11 @@
|
|||
package com.android.apksig.internal.asn1;
|
||||
|
||||
import com.android.apksig.internal.asn1.ber.BerEncoding;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.zane.smapiinstaller.utils.ReflectionUtils;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.math.BigInteger;
|
||||
|
@ -53,7 +56,7 @@ public final class Asn1DerEncoder {
|
|||
*/
|
||||
public static byte[] encode(Object container) throws Asn1EncodingException {
|
||||
Class<?> containerClass = container.getClass();
|
||||
Asn1Class containerAnnotation = containerClass.getDeclaredAnnotation(Asn1Class.class);
|
||||
Asn1Class containerAnnotation = ReflectionUtils.getDeclaredAnnotation(containerClass, Asn1Class.class);
|
||||
if (containerAnnotation == null) {
|
||||
throw new Asn1EncodingException(
|
||||
containerClass.getName() + " not annotated with " + Asn1Class.class.getName());
|
||||
|
@ -216,7 +219,7 @@ public final class Asn1DerEncoder {
|
|||
Field[] declaredFields = containerClass.getDeclaredFields();
|
||||
List<AnnotatedField> result = new ArrayList<>(declaredFields.length);
|
||||
for (Field field : declaredFields) {
|
||||
Asn1Field annotation = field.getDeclaredAnnotation(Asn1Field.class);
|
||||
Asn1Field annotation = ReflectionUtils.getDeclaredAnnotation(field, Asn1Field.class);
|
||||
if (annotation == null) {
|
||||
continue;
|
||||
}
|
||||
|
@ -561,7 +564,7 @@ public final class Asn1DerEncoder {
|
|||
case SEQUENCE:
|
||||
{
|
||||
Asn1Class containerAnnotation =
|
||||
sourceType.getDeclaredAnnotation(Asn1Class.class);
|
||||
ReflectionUtils.getDeclaredAnnotation(sourceType, Asn1Class.class);
|
||||
if ((containerAnnotation != null)
|
||||
&& (containerAnnotation.type() == Asn1Type.SEQUENCE)) {
|
||||
return toSequence(source);
|
||||
|
@ -571,7 +574,7 @@ public final class Asn1DerEncoder {
|
|||
case CHOICE:
|
||||
{
|
||||
Asn1Class containerAnnotation =
|
||||
sourceType.getDeclaredAnnotation(Asn1Class.class);
|
||||
ReflectionUtils.getDeclaredAnnotation(sourceType, Asn1Class.class);
|
||||
if ((containerAnnotation != null)
|
||||
&& (containerAnnotation.type() == Asn1Type.CHOICE)) {
|
||||
return toChoice(source);
|
||||
|
|
|
@ -18,11 +18,15 @@ package com.android.apksig.internal.util;
|
|||
|
||||
import com.android.apksig.util.DataSink;
|
||||
import com.android.apksig.util.DataSource;
|
||||
import com.zane.smapiinstaller.utils.MathUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
||||
import java9.util.stream.Stream;
|
||||
|
||||
/** Pseudo {@link DataSource} that chains the given {@link DataSource} as a continuous one. */
|
||||
public class ChainedDataSource implements DataSource {
|
||||
|
||||
|
@ -31,7 +35,7 @@ public class ChainedDataSource implements DataSource {
|
|||
|
||||
public ChainedDataSource(DataSource... sources) {
|
||||
mSources = sources;
|
||||
mTotalSize = Arrays.stream(sources).mapToLong(src -> src.size()).sum();
|
||||
mTotalSize = Stream.of(sources).mapToLong(src -> src.size()).sum();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -86,7 +90,7 @@ public class ChainedDataSource implements DataSource {
|
|||
ByteBuffer buffer = ByteBuffer.allocate(size);
|
||||
for (; i < mSources.length && buffer.hasRemaining(); i++) {
|
||||
long sizeToCopy = Math.min(mSources[i].size() - offset, buffer.remaining());
|
||||
mSources[i].copyTo(offset, Math.toIntExact(sizeToCopy), buffer);
|
||||
mSources[i].copyTo(offset, MathUtils.toIntExact(sizeToCopy), buffer);
|
||||
offset = 0; // may not be zero for the first source, but reset after that.
|
||||
}
|
||||
buffer.rewind();
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
|
||||
package com.android.apksig.internal.util;
|
||||
|
||||
import android.os.Build;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
@ -212,6 +214,8 @@ public class DelegatingX509Certificate extends X509Certificate {
|
|||
@Override
|
||||
public void verify(PublicKey key, Provider sigProvider) throws CertificateException,
|
||||
NoSuchAlgorithmException, InvalidKeyException, SignatureException {
|
||||
mDelegate.verify(key, sigProvider);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
mDelegate.verify(key, sigProvider);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ import com.android.apksig.internal.zip.ZipUtils;
|
|||
import com.android.apksig.util.DataSink;
|
||||
import com.android.apksig.util.DataSource;
|
||||
import com.android.apksig.util.DataSources;
|
||||
import com.zane.smapiinstaller.utils.MathUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
|
@ -155,7 +156,7 @@ public class VerityTreeBuilder {
|
|||
levelOffset[0] = 0;
|
||||
for (int i = 0; i < levelSize.size(); i++) {
|
||||
// We don't support verity tree if it is larger then Integer.MAX_VALUE.
|
||||
levelOffset[i + 1] = levelOffset[i] + Math.toIntExact(
|
||||
levelOffset[i + 1] = levelOffset[i] + MathUtils.toIntExact(
|
||||
levelSize.get(levelSize.size() - i - 1));
|
||||
}
|
||||
return levelOffset;
|
||||
|
|
|
@ -22,6 +22,8 @@ import com.android.apksig.internal.asn1.Asn1DerEncoder;
|
|||
import com.android.apksig.internal.asn1.Asn1EncodingException;
|
||||
import com.android.apksig.internal.x509.Certificate;
|
||||
|
||||
import net.fornwall.apksigner.Base64;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
@ -30,7 +32,6 @@ import java.security.cert.CertificateException;
|
|||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Base64;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
|
@ -261,7 +262,7 @@ public class X509CertificateUtils {
|
|||
+ "valid certificate footer");
|
||||
}
|
||||
}
|
||||
byte[] derEncoding = Base64.getDecoder().decode(pemEncoding.toString());
|
||||
byte[] derEncoding = Base64.decode(pemEncoding.toString());
|
||||
// consume any trailing whitespace in the byte buffer
|
||||
int nextEncodedChar = certificateBuffer.position();
|
||||
while (certificateBuffer.hasRemaining()) {
|
||||
|
|
|
@ -21,6 +21,10 @@ public class Constants {
|
|||
* 安装包目标包名
|
||||
*/
|
||||
public static final String TARGET_PACKAGE_NAME = "com.zane.stardewvalley";
|
||||
/**
|
||||
* 安装包目标包名
|
||||
*/
|
||||
public static final String TARGET_PACKAGE_NAME_SAMSUNG = "com.zane.stardewvalleysamsung";
|
||||
/**
|
||||
* DLC下载路径
|
||||
*/
|
||||
|
|
|
@ -161,7 +161,7 @@ public class ApkPatcher {
|
|||
case "package":
|
||||
if (packageName.get() == null) {
|
||||
packageName.set(strObj);
|
||||
attr.obj = Constants.TARGET_PACKAGE_NAME;
|
||||
attr.obj = strObj.replace(ManifestPatchConstants.APP_PACKAGE_NAME, Constants.TARGET_PACKAGE_NAME);
|
||||
}
|
||||
break;
|
||||
case "label":
|
||||
|
|
|
@ -29,15 +29,21 @@ public class GameLauncher {
|
|||
Activity context = CommonLogic.getActivityFromView(root);
|
||||
PackageManager packageManager = context.getPackageManager();
|
||||
try {
|
||||
PackageInfo packageInfo = packageManager.getPackageInfo(Constants.TARGET_PACKAGE_NAME, 0);
|
||||
PackageInfo packageInfo;
|
||||
try {
|
||||
packageInfo = packageManager.getPackageInfo(Constants.TARGET_PACKAGE_NAME, 0);
|
||||
} catch (PackageManager.NameNotFoundException ignored) {
|
||||
packageInfo = packageManager.getPackageInfo(Constants.TARGET_PACKAGE_NAME_SAMSUNG, 0);
|
||||
}
|
||||
if(!CommonLogic.unpackSmapiFiles(context, packageInfo.applicationInfo.publicSourceDir, true)) {
|
||||
DialogUtils.showAlertDialog(root, R.string.error, R.string.error_failed_to_repair);
|
||||
return;
|
||||
}
|
||||
ModAssetsManager modAssetsManager = new ModAssetsManager(root);
|
||||
PackageInfo finalPackageInfo = packageInfo;
|
||||
modAssetsManager.checkModEnvironment((isConfirm) -> {
|
||||
if(isConfirm) {
|
||||
Intent intent = packageManager.getLaunchIntentForPackage(Constants.TARGET_PACKAGE_NAME);
|
||||
Intent intent = packageManager.getLaunchIntentForPackage(finalPackageInfo.packageName);
|
||||
context.startActivity(intent);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
package com.zane.smapiinstaller.utils;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
|
||||
public class MathUtils {
|
||||
|
||||
/**
|
||||
* Returns the value of the {@code long} argument;
|
||||
* throwing an exception if the value overflows an {@code int}.
|
||||
*
|
||||
* @param value the long value
|
||||
* @return the argument as an int
|
||||
* @throws ArithmeticException if the {@code argument} overflows an int
|
||||
* @since 1.8
|
||||
*/
|
||||
public static int toIntExact(long value) {
|
||||
if ((int)value != value) {
|
||||
throw new ArithmeticException("integer overflow");
|
||||
}
|
||||
return (int)value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts this {@code BigInteger} to an {@code int}, checking
|
||||
* for lost information. If the value of this {@code BigInteger}
|
||||
* is out of the range of the {@code int} type, then an
|
||||
* {@code ArithmeticException} is thrown.
|
||||
*
|
||||
* @return this {@code BigInteger} converted to an {@code int}.
|
||||
* @throws ArithmeticException if the value of {@code this} will
|
||||
* not exactly fit in a {@code int}.
|
||||
* @see BigInteger#intValue
|
||||
* @since 1.8
|
||||
*/
|
||||
public static int intValueExact(BigInteger value) {
|
||||
if (value.bitLength() <= 31) {
|
||||
return value.intValue();
|
||||
} else {
|
||||
throw new ArithmeticException("BigInteger out of int range");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts this {@code BigInteger} to a {@code long}, checking
|
||||
* for lost information. If the value of this {@code BigInteger}
|
||||
* is out of the range of the {@code long} type, then an
|
||||
* {@code ArithmeticException} is thrown.
|
||||
*
|
||||
* @return this {@code BigInteger} converted to a {@code long}.
|
||||
* @throws ArithmeticException if the value of {@code this} will
|
||||
* not exactly fit in a {@code long}.
|
||||
* @see BigInteger#longValue
|
||||
* @since 1.8
|
||||
*/
|
||||
public static long longValueExact(BigInteger value) {
|
||||
if (value.bitLength() <= 63) {
|
||||
return value.longValue();
|
||||
} else {
|
||||
throw new ArithmeticException("BigInteger out of long range");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package com.zane.smapiinstaller.utils;
|
||||
|
||||
import android.os.Build;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
public class ReflectionUtils {
|
||||
public static <T extends Annotation> T getDeclaredAnnotation(Field targetField, Class<T> targetAnnotation) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
return targetField.getDeclaredAnnotation(targetAnnotation);
|
||||
}
|
||||
Annotation[] declaredAnnotations = targetField.getDeclaredAnnotations();
|
||||
for (Annotation annotation : declaredAnnotations) {
|
||||
if(targetAnnotation.isAssignableFrom(annotation.getClass())) {
|
||||
return (T) annotation;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static <T extends Annotation> T getDeclaredAnnotation(Class<?> targetClass, Class<T> targetAnnotation) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
return targetClass.getDeclaredAnnotation(targetAnnotation);
|
||||
}
|
||||
Annotation[] declaredAnnotations = targetClass.getDeclaredAnnotations();
|
||||
for (Annotation annotation : declaredAnnotations) {
|
||||
if(targetAnnotation.isAssignableFrom(annotation.getClass())) {
|
||||
return (T) annotation;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package net.fornwall.apksigner;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.spongycastle.util.encoders.Base64Encoder;
|
||||
|
||||
/** Base64 encoding handling in a portable way across Android and JSE. */
|
||||
public class Base64 {
|
||||
|
||||
public static String encode(byte[] data) {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
try {
|
||||
new Base64Encoder().encode(data, 0, data.length, baos);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return new String(baos.toByteArray());
|
||||
}
|
||||
|
||||
public static byte[] decode(String data) {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
try {
|
||||
new Base64Encoder().decode(data, baos);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return baos.toByteArray();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue