如何获取Android设备所有已安装应用Base APK的哈希值?
获取所有已安装应用Base APK哈希值的可行方案
好问题!你完全不需要依赖SecurityLog(以及它要求的设备所有者权限和应用启动触发条件),直接读取APK文件并计算哈希值就能实现需求。下面是具体的实现思路和代码示例:
核心思路
- 获取已安装应用列表:通过
PackageManager获取设备上所有已安装应用的PackageInfo,从中提取Base APK的文件路径。 - 计算APK文件哈希:针对每个APK文件,使用Java/Kotlin标准库的
MessageDigest类计算指定算法(如SHA-256)的哈希值。
步骤实现
1. 添加必要权限
在AndroidManifest.xml中添加权限,确保能获取所有已安装应用的信息:
<!-- Android 11+ 必须声明此权限才能获取所有已安装应用 --> <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" tools:ignore="QueryAllPackagesPermission" />
注意:在Google Play上架时,需要说明使用
QUERY_ALL_PACKAGES权限的必要性,否则可能被拒绝。如果只需要查询特定应用,可以用<queries>标签替代,避免申请该权限。
2. 代码实现示例
以下是Kotlin和Java版本的代码,你可以根据项目需求选择:
Java版本
import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.os.Bundle; import android.util.Log; import androidx.appcompat.app.AppCompatActivity; import java.io.FileInputStream; import java.io.IOException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.List; public class MainActivity extends AppCompatActivity { private static final String TAG = "APKHashUtils"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 建议在后台线程执行,避免主线程阻塞 new Thread(this::fetchAllApkHashes).start(); } private void fetchAllApkHashes() { PackageManager pm = getPackageManager(); List<PackageInfo> installedApps = pm.getInstalledPackages(PackageManager.GET_META_DATA); for (PackageInfo appInfo : installedApps) { String packageName = appInfo.packageName; String apkPath = appInfo.applicationInfo.sourceDir; String sha256Hash = calculateFileHash(apkPath, "SHA-256"); if (sha256Hash != null) { Log.d(TAG, String.format("包名: %s | SHA-256哈希: %s", packageName, sha256Hash)); } else { Log.w(TAG, "无法计算哈希值: " + packageName); } } } private String calculateFileHash(String filePath, String algorithm) { try (FileInputStream fis = new FileInputStream(filePath)) { MessageDigest digest = MessageDigest.getInstance(algorithm); byte[] buffer = new byte[8192]; int bytesRead; while ((bytesRead = fis.read(buffer)) != -1) { digest.update(buffer, 0, bytesRead); } byte[] hashBytes = digest.digest(); StringBuilder hexBuilder = new StringBuilder(); for (byte b : hashBytes) { String hex = Integer.toHexString(0xFF & b); if (hex.length() == 1) hexBuilder.append('0'); hexBuilder.append(hex); } return hexBuilder.toString(); } catch (NoSuchAlgorithmException | IOException e) { e.printStackTrace(); return null; } } }
Kotlin版本
import android.content.pm.PackageInfo import android.content.pm.PackageManager import android.os.Bundle import android.util.Log import androidx.appcompat.app.AppCompatActivity import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import java.io.FileInputStream import java.security.MessageDigest class MainActivity : AppCompatActivity() { private val TAG = "APKHashUtils" override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // 使用协程在后台执行 GlobalScope.launch(Dispatchers.Main) { fetchAllApkHashes() } } private suspend fun fetchAllApkHashes() = withContext(Dispatchers.IO) { val pm = packageManager val installedApps = pm.getInstalledPackages(PackageManager.GET_META_DATA) installedApps.forEach { appInfo -> val packageName = appInfo.packageName val apkPath = appInfo.applicationInfo.sourceDir val sha256Hash = calculateFileHash(apkPath, "SHA-256") sha256Hash?.let { Log.d(TAG, "包名: $packageName | SHA-256哈希: $it") } ?: run { Log.w(TAG, "无法计算哈希值: $packageName") } } } private fun calculateFileHash(filePath: String, algorithm: String): String? { return try { val digest = MessageDigest.getInstance(algorithm) FileInputStream(filePath).use { fis -> val buffer = ByteArray(8192) var bytesRead: Int while (fis.read(buffer).also { bytesRead = it } != -1) { digest.update(buffer, 0, bytesRead) } } val hashBytes = digest.digest() hashBytes.joinToString("") { "%02x".format(it) } } catch (e: Exception) { e.printStackTrace() null } } }
注意事项
- 性能优化:计算大量APK的哈希值会消耗CPU和时间,务必在后台线程(如协程、AsyncTask、WorkManager)中执行,避免主线程阻塞导致ANR。
- 哈希算法选择:推荐使用SHA-256(安全性较高),如果只是用于APK识别,MD5或SHA-1也可以,但不建议用于安全验证场景。
- 系统应用访问:部分系统应用的APK路径可能存在权限限制,无法读取,但绝大多数第三方应用和普通系统应用都能正常获取。
内容的提问来源于stack exchange,提问作者Teun
相关产品推荐
相关产品推荐

