通过SHA1指纹字符串模拟PackageInfo.signatures

时间:2018-11-27 14:23:34

标签: android testing kotlin signature

我已经通过比较程序包名称和PackageInfo的签名在我的android应用程序中实现了对不兼容应用程序的验证。我可以通过以下方式获取有关已安装软件包的信息:

val packages = context.ctx.packageManager.getInstalledPackages(PackageManager.GET_META_DATA or PackageManager.GET_SIGNATURES)

,然后只比较软件包名称和签名的字符串。我通过以下功能将PackageInfo.signatures转换为Hex:

fun bytesToHex(bytes: ByteArray): String {
        val hexArray = charArrayOf('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F')
        val hexChars = CharArray(bytes.size * 2)
        var v: Int
        for (j in bytes.indices) {
            v = bytes[j].toInt() and 0xFF
            hexChars[j * 2] = hexArray[v.ushr(4)]
            hexChars[j * 2 + 1] = hexArray[v and 0x0F]
        }
        return String(hexChars)
}

它工作正常。

现在,我想为此功能实现多个单元测试,并且遇到困难:如何模拟PackageInfo.signatures?如何将SHA1指纹字符串转换为android.content.pm.Signature?

2 个答案:

答案 0 :(得分:1)

我不建议模拟框架类,因为那样会很脆弱。相反,只需创建自己的接口来提供签名,并在依赖于框架的实际应用程序中使用一个实现。例如:

interface SignatureProvider {
    val signatures: List<String>
}

class AndroidSignatureProvider(private val packageManager: PackageManager): SignatureProvider {
    private val flags = PackageManager.GET_META_DATA or PackageManager.GET_SIGNATURES

    override val signatures: List<String>
        get() = packageManager.getInstalledPackages(flags)
           .flatMap { it.packageInfo.signatures.toList() }
           .map { it.toCharsString() }
}

然后在测试中,您可以模拟SignatureProvider以返回要测试的不同签名字符串:

private lateinit var signatureProvider: SignatureProvider

@Before fun setup() {
    signatureProvider = mock(SignatureProvider::class.java)
    doReturn(listOf("sigA", "sigB")).`when`(signatureProvider)`.signatures
}

答案 1 :(得分:0)

我相信您可以通过执行以下操作来实现:

final ShadowPackageManager packageManager = shadowOf(RuntimeEnvironment.application.getPackageManager());
packageManager.installPackage(getPackageInfo());
final PackageInfo packageInfo = packageManager.getInternalMutablePackageInfo(com.yourapp);
packageInfo.signatures = new Signature[1];
packageInfo.signatures[0] = new Signature("your_signature);

期望的格式是Signature#toChars()产生的格式。

现在,我同意@kcoppock,因为使用签名及其不同表示进行操作很麻烦且容易出错。