Макет PackageInfo.signatures с помощью строки отпечатка пальца SHA1 - PullRequest
0 голосов
/ 27 ноября 2018

Я реализовал проверку для несовместимого приложения в своем приложении для Android, сравнив имя пакета и подпись PackageInfo.Я получаю информацию об установленных пакетах по:

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 голосов
/ 26 июня 2019

Я полагаю, что вы можете добиться этого, выполнив что-то вроде этого:

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,потому что работа с подписями и их различными представлениями громоздка и подвержена ошибкам.

0 голосов
/ 27 ноября 2018

Я бы не рекомендовал издеваться над классами фреймворка, так как это будет хрупким.Вместо этого просто создайте свой собственный интерфейс для предоставления подписей и используйте реализацию, используемую в реальном приложении, которое опирается на платформу.Например:

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
}
...