【问题标题】:Mock PackageInfo.signatures by SHA1 fingerprint string通过 SHA1 指纹字符串模拟 PackageInfo.signatures
【发布时间】:2018-11-27 14:23:33
【问题描述】:

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

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

然后只比较包名称和签名的字符串。我通过这个函数将 PackageInfo.signatures 转换为十六进制:

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?

【问题讨论】:

    标签: android testing kotlin signature


    【解决方案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
    }
    

    【讨论】:

      【解决方案2】:

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

      testPackage() {
         final ShadowPackageManager packageManager = shadowOf(RuntimeEnvironment.application.getPackageManager());
         packageManager.installPackage(getPackageInfo(com.yourapp));
         final PackageInfo packageInfo = packageManager.getInternalMutablePackageInfo(com.yourapp);
         packageInfo.signatures = new Signature[1];
         packageInfo.signatures[0] = new Signature("your_signature");
      }
      
      private static PackageInfo getPackageInfo(String packageName) {
          final PackageInfoBuilder builder = PackageInfoBuilder.newBuilder();
          builder.setPackageName(packageName);
          return builder.build();
      }
      

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

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

      【讨论】:

      • getPackageInfo() 方法来自哪里
      • @Sp4Rx 我将编辑我的答案以添加该方法
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-12-03
      • 1970-01-01
      • 2020-01-04
      • 1970-01-01
      • 2018-06-27
      • 1970-01-01
      • 2019-05-06
      相关资源
      最近更新 更多