java判断APK是否使用了V2签名
可以使用以下代码判断APK是否使用了V2签名:
import java.io.IOException;
import java.security.cert.CertificateEncodingException;
import java.security.cert.X509Certificate;
import java.util.Collections;
import java.util.List;
import com.android.apksig.ApkSigner;
import com.android.apksig.ApkVerifier;
import com.android.apksig.ApkVerifier.Result;
import com.android.apksig.DefaultApkSignerEngine;
public class ApkVerifierUtils {
/**
* 验证APK是否使用了V2签名
*
* @param apkPath APK文件路径
* @return 是否使用了V2签名
*/
public static boolean isV2SignatureUsed(String apkPath) {
try {
// 构建ApkVerifier对象
ApkVerifier apkVerifier = new ApkVerifier.Builder().build();
// 读取APK文件
byte[] apkBytes = ApkVerifierUtils.readBytesFromFile(apkPath);
// 验证APK签名
Result result = apkVerifier.verify(apkBytes);
// 获取签名信息列表
List<ApkSigner> signers = result.getSigners();
// 判断是否使用了V2签名
for (ApkSigner signer : signers) {
DefaultApkSignerEngine signerEngine = (DefaultApkSignerEngine) signer.getSignerEngine();
List<X509Certificate> certificates = signerEngine.getCertificates();
for (X509Certificate certificate : certificates) {
if (certificate.getEncoded().length > 0) {
// 如果有V2签名,则返回true
return true;
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
// 如果没有V2签名,则返回false
return false;
}
/**
* 从文件中读取字节数组
*
* @param filePath 文件路径
* @return 字节数组
* @throws IOException
*/
public static byte[] readBytesFromFile(String filePath) throws IOException {
java.nio.file.Path path = java.nio.file.Paths.get(filePath);
return java.nio.file.Files.readAllBytes(path);
}
}
使用方法:
String apkPath = "path/to/your/app.apk";
boolean isV2SignatureUsed = ApkVerifierUtils.isV2SignatureUsed(apkPath);
System.out.println("isV2SignatureUsed: " + isV2SignatureUsed);
java服务端判断APK使用了V1还是V2签名
可以使用以下代码判断APK是否使用了V1或V2签名:
import java.io.IOException;
import java.security.cert.CertificateEncodingException;
import java.security.cert.X509Certificate;
import java.util.Collections;
import java.util.List;
import com.android.apksig.ApkSigner;
import com.android.apksig.ApkVerifier;
import com.android.apksig.ApkVerifier.Result;
import com.android.apksig.DefaultApkSignerEngine;
public class ApkVerifierUtils {
/**
* 验证APK是否使用了V1签名
*
* @param apkPath APK文件路径
* @return 是否使用了V1签名
*/
public static boolean isV1SignatureUsed(String apkPath) {
try {
// 构建ApkVerifier对象
ApkVerifier apkVerifier = new ApkVerifier.Builder().build();
// 读取APK文件
byte[] apkBytes = ApkVerifierUtils.readBytesFromFile(apkPath);
// 验证APK签名
Result result = apkVerifier.verify(apkBytes);
// 获取签名信息列表
List<ApkSigner> signers = result.getSigners();
// 判断是否使用了V1签名
for (ApkSigner signer : signers) {
DefaultApkSignerEngine signerEngine = (DefaultApkSignerEngine) signer.getSignerEngine();
List<X509Certificate> certificates = signerEngine.getCertificates();
for (X509Certificate certificate : certificates) {
if (certificate.getEncoded().length == 0) {
// 如果没有V1签名,则返回false
return false;
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
// 如果有V1签名,则返回true
return true;
}
/**
* 验证APK是否使用了V2签名
*
* @param apkPath APK文件路径
* @return 是否使用了V2签名
*/
public static boolean isV2SignatureUsed(String apkPath) {
try {
// 构建ApkVerifier对象
ApkVerifier apkVerifier = new ApkVerifier.Builder().build();
// 读取APK文件
byte[] apkBytes = ApkVerifierUtils.readBytesFromFile(apkPath);
// 验证APK签名
Result result = apkVerifier.verify(apkBytes);
// 获取签名信息列表
List<ApkSigner> signers = result.getSigners();
// 判断是否使用了V2签名
for (ApkSigner signer : signers) {
DefaultApkSignerEngine signerEngine = (DefaultApkSignerEngine) signer.getSignerEngine();
List<X509Certificate> certificates = signerEngine.getCertificates();
for (X509Certificate certificate : certificates) {
if (certificate.getEncoded().length > 0) {
// 如果有V2签名,则返回true
return true;
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
// 如果没有V2签名,则返回false
return false;
}
/**
* 从文件中读取字节数组
*
* @param filePath 文件路径
* @return 字节数组
* @throws IOException
*/
public static byte[] readBytesFromFile(String filePath) throws IOException {
java.nio.file.Path path = java.nio.file.Paths.get(filePath);
return java.nio.file.Files.readAllBytes(path);
}
}
使用方法:
String apkPath = "path/to/your/app.apk";
boolean isV1SignatureUsed = ApkVerifierUtils.isV1SignatureUsed(apkPath);
System.out.println("isV1SignatureUsed: " + isV1SignatureUsed);
boolean isV2SignatureUsed = ApkVerifierUtils.isV2SignatureUsed(apkPath);
System.out.println("isV2SignatureUsed: " + isV2SignatureUsed);
如果isV1SignatureUsed
为true
,说明APK使用了V1签名;如果isV2SignatureUsed
为true
,说明APK使用了V2签名;如果都为false
,说明APK没有签名或签名格式不支持。
com.android.apksig.ApkSigner 对应的maven坐标地址是什么
com.android.apksig.ApkSigner
类是Android SDK中的一部分,因此没有对应的 Maven 坐标。如果您需要使用该类,可以在您的项目中引入 Android SDK,并确保使用了包含该类的 SDK 版本。如果您使用的是 Gradle,可以在您的build.gradle
文件中添加以下依赖:
android {
// ...
buildToolsVersion "30.0.3"
}
dependencies {
// ...
implementation 'com.android.tools.build:apksig:4.1.0'
}
注意,com.android.apksig.ApkSigner
类所在的apksig
库是包含在com.android.tools.build:apksig
依赖中的。因此,您需要同时引入com.android.tools.build:apksig
和其它必要的 Android 库依赖。
不使用Android SDK 的情况下,如何单独使用com.android.apksig.ApkSigner
如果您不想使用 Android SDK,可以使用独立的 apksig
库。该库已经发布到 Maven 中央仓库,您可以通过以下 Maven 坐标来获取:
<dependency>
<groupId>com.android.tools.build</groupId>
<artifactId>apksig</artifactId>
<version>4.1.0</version>
</dependency>
或者通过以下 Gradle 依赖:
dependencies {
implementation 'com.android.tools.build:apksig:4.1.0'
}
在使用该库时,您需要自行处理 APK 签名的细节。以下是一个示例代码,用于验证 APK 是否使用了 V1 签名:
import java.io.IOException;
import java.security.cert.CertificateEncodingException;
import java.security.cert.X509Certificate;
import java.util.Collections;
import java.util.List;
import com.android.apksig.ApkSigner;
import com.android.apksig.ApkVerifier;
import com.android.apksig.ApkVerifier.Result;
import com.android.apksig.DefaultApkSignerEngine;
import com.android.apksig.apk.ApkFormatException;
public class ApkVerifierUtils {
/**
* 验证APK是否使用了V1签名
*
* @param apkPath APK文件路径
* @return 是否使用了V1签名
*/
public static boolean isV1SignatureUsed(String apkPath) {
try {
// 构建ApkVerifier对象
ApkVerifier apkVerifier = new ApkVerifier.Builder().build();
// 读取APK文件
byte[] apkBytes = ApkVerifierUtils.readBytesFromFile(apkPath);
// 验证APK签名
Result result = apkVerifier.verify(apkBytes);
// 获取签名信息列表
List<ApkSigner> signers = result.getSigners();
// 判断是否使用了V1签名
for (ApkSigner signer : signers) {
DefaultApkSignerEngine signerEngine = (DefaultApkSignerEngine) signer.getSignerEngine();
List<X509Certificate> certificates = signerEngine.getCertificates();
for (X509Certificate certificate : certificates) {
if (certificate.getEncoded().length == 0) {
// 如果没有V1签名,则返回false
return false;
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
// 如果有V1签名,则返回true
return true;
}
/**
* 从文件中读取字节数组
*
* @param filePath 文件路径
* @return 字节数组
* @throws IOException
*/
public static byte[] readBytesFromFile(String filePath) throws IOException {
java.nio.file.Path path = java.nio.file.Paths.get(filePath);
return java.nio.file.Files.readAllBytes(path);
}
}
使用方法:
String apkPath = "path/to/your/app.apk";
boolean isV1SignatureUsed = ApkVerifierUtils.isV1SignatureUsed(apkPath);
System.out.println("isV1SignatureUsed: " + isV1SignatureUsed);
如果isV1SignatureUsed
为true
,说明 APK 使用了 V1 签名。
C++编写Unicode编码 解码的工具类
以下是一个 C++ 工具类,用于实现 UTF-8 到 Unicode 编码的转换。该类实现了将 UTF-8 字符串转换为 Unicode 字符串和将 Unicode 字符串转换为 UTF-8 字符串的方法。
#include <string>
#include <vector>
#include <stdexcept>
class UnicodeUtils {
public:
/**
* 将 UTF-8 字符串转换为 Unicode 字符串
*
* @param utf8str UTF-8 字符串
* @return Unicode 字符串
*/
static std::wstring utf8ToUnicode(const std::string& utf8str) {
std::wstring result;
result.reserve(utf8str.size());
for (std::size_t i = 0; i < utf8str.size();) {
int ch = utf8str[i] & 0xFF;
if ((ch & 0x80) == 0) {
// 单字节字符
result += static_cast<wchar_t>(ch);
i += 1;
} else if ((ch & 0xE0) == 0xC0) {
// 双字节字符
if (i + 1 >= utf8str.size()) {
throw std::invalid_argument("Invalid UTF-8 string: truncated character");
}
int ch1 = utf8str[i + 1] & 0xFF;
if ((ch1 & 0xC0) != 0x80) {
throw std::invalid_argument("Invalid UTF-8 string: malformed character");
}
result += static_cast<wchar_t>(((ch & 0x1F) << 6) | (ch1 & 0x3F));
i += 2;
} else if ((ch & 0xF0) == 0xE0) {
// 三字节字符
if (i + 2 >= utf8str.size()) {
throw std::invalid_argument("Invalid UTF-8 string: truncated character");
}
int ch1 = utf8str[i + 1] & 0xFF;
int ch2 = utf8str[i + 2] & 0xFF;
if ((ch1 & 0xC0) != 0x80 || (ch2 & 0xC0) != 0x80) {
throw std::invalid_argument("Invalid UTF-8 string: malformed character");
}
result += static_cast<wchar_t>(((ch & 0x0F) << 12) | ((ch1 & 0x3F) << 6) | (ch2 & 0x3F));
i += 3;
} else {
// 四字节字符
if (i + 3 >= utf8str.size()) {
throw std::invalid_argument("Invalid UTF-8 string: truncated character");
}
int ch1 = utf8str[i + 1] & 0xFF;
int ch2 = utf8str[i + 2] & 0xFF;
int ch3 = utf8str[i + 3] & 0xFF;
if ((ch1 & 0xC0) != 0x80 || (ch2 & 0xC0) != 0x80 || (ch3 & 0xC0) != 0x80) {
throw std::invalid_argument("Invalid UTF-8 string: malformed character");
}
int codepoint = ((ch & 0x07) << 18) | ((ch1 & 0x3F) << 12) | ((ch2 & 0x3F) << 6) | (ch3 & 0x3F);
if (codepoint < 0x10000 || codepoint > 0x10FFFF) {
throw std::invalid_argument("Invalid UTF-8 string: code point out of range");
}
result += static_cast<wchar_t>(0xD7C0 + (codepoint >> 10));
result += static_cast<wchar_t>(0xDC00 + (codepoint & 0x03FF));
i += 4;
}
}
return result;
}
/**
* 将 Unicode 字符串转换为 UTF-8 字符串
*
* @param unicodeStr Unicode 字符串
* @return UTF-8 字符串
*/
static std::string unicodeToUtf8(const std::wstring& unicodeStr) {
std::string result;
result.reserve(unicodeStr.size() * 3);