使用签名构建设置 versionCode 的问题

Issues Setting versionCode with signed builds

我正在开发的应用不在 Play 商店中,它直接安装在用于特定项目的设备上。我们确实使用内部密钥库对应用程序进行签名。使用我们自己的网络服务将更新发送到设备,该服务会下载更新的 APK 并提示用户安装更新,如下所示。

Uri packageURI = Uri.parse("package:" + this.getPackageName());

Intent intent = new Intent(android.content.Intent.ACTION_VIEW, packageURI);

intent.setDataAndType(Uri.fromFile(new File(downloadPath + "/" + package_name)),
"application/vnd.android.package-archive");

this.startActivity(intent);

当我们开始使用 gradle 构建变体以允许轻松交换资产时,它的设置不正确,如下所示:

productFlavors {
    SampleProject {
        dimension "project"
        applicationId "companyID.SampleProject"
        versionCode = "2"
        versionName = "3.0.20180514.0"
        resValue "string", "app_name", "Sample Project"
    }
}

请注意版本代码和名称的分配不正确以及版本代码是字符串这一事实。

这实际上按原样工作,直到我们得到大于 9(两位数)的版本代码。这导致了以下(预期的)错误。

Cannot cast object '10' with class 'java.lang.String' to class 'java.lang.Integer'

这导致解决了以下项目的问题。

productFlavors {
    SampleProject {
        dimension "project"
        applicationId "companyID.SampleProject"
        versionCode 2
        versionName "3.0.20180514.0"
        resValue "string", "app_name", "Sample Project"
    }
}

这按预期工作,让我们转到版本代码 10 以上。

问题是此更改不允许在使用旧的不正确方法构建的应用程序的先前版本上安装更新。这样做时,安装几乎立即失败,只显示 "App not installed."

我已经测试确保没有其他任何改变,使用相同的密钥库和资产它仍然失败。我们一直在使用的修复方法是将版本代码保留为“9”并增加版本名称,但这并不理想。

如有任何建议,我们将不胜感激。这些项目的生命周期往往有限,而且更新不多,所以这不是一个大问题,但为现有项目修复它会很好,这样我们就可以继续增加两者。

编辑 这是 Logcat 尝试安装具有更正版本变体的已签名 APK 时出现的错误。

05-14 12:00:51.785 3958-5291/? E/Parcel: Class not found when unmarshalling: com.android.packageinstaller.InstallFlowAnalytics
java.lang.ClassNotFoundException: com.android.packageinstaller.InstallFlowAnalytics
    at java.lang.Class.classForName(Native Method)
    at java.lang.Class.forName(Class.java:324)
    at android.os.Parcel.readParcelableCreator(Parcel.java:2404)
    at android.os.Parcel.readParcelable(Parcel.java:2358)
    at android.os.Parcel.readValue(Parcel.java:2264)
    at android.os.Parcel.readArrayMapInternal(Parcel.java:2614)
    at android.os.BaseBundle.unparcel(BaseBundle.java:221)
    at android.os.BaseBundle.getString(BaseBundle.java:920)
    at android.content.Intent.getStringExtra(Intent.java:6200)
    at com.android.server.am.ActivityStackSupervisor.startActivityLocked(ActivityStackSupervisor.java:2752)
    at com.android.server.am.ActivityStackSupervisor.startActivityMayWait(ActivityStackSupervisor.java:2209)
    at com.android.server.am.ActivityManagerService.startActivityAsUser(ActivityManagerService.java:6401)
    at com.android.server.am.ActivityManagerService.startActivity(ActivityManagerService.java:6173)
    at android.app.ActivityManagerNative.onTransact(ActivityManagerNative.java:170)
    at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:4028)
    at android.os.Binder.execTransact(Binder.java:453)
 Caused by: java.lang.ClassNotFoundException: com.android.packageinstaller.InstallFlowAnalytics
    at java.lang.Class.classForName(Native Method)
    at java.lang.BootClassLoader.findClass(ClassLoader.java:781)
    at java.lang.BootClassLoader.loadClass(ClassLoader.java:841)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:469)
    at java.lang.Class.classForName(Native Method) 
    at java.lang.Class.forName(Class.java:324) 
    at android.os.Parcel.readParcelableCreator(Parcel.java:2404) 
    at android.os.Parcel.readParcelable(Parcel.java:2358) 
    at android.os.Parcel.readValue(Parcel.java:2264) 
    at android.os.Parcel.readArrayMapInternal(Parcel.java:2614) 
    at android.os.BaseBundle.unparcel(BaseBundle.java:221) 
    at android.os.BaseBundle.getString(BaseBundle.java:920) 
    at android.content.Intent.getStringExtra(Intent.java:6200) 
    at com.android.server.am.ActivityStackSupervisor.startActivityLocked(ActivityStackSupervisor.java:2752) 
    at com.android.server.am.ActivityStackSupervisor.startActivityMayWait(ActivityStackSupervisor.java:2209) 
    at com.android.server.am.ActivityManagerService.startActivityAsUser(ActivityManagerService.java:6401) 
    at com.android.server.am.ActivityManagerService.startActivity(ActivityManagerService.java:6173) 
    at android.app.ActivityManagerNative.onTransact(ActivityManagerNative.java:170) 
    at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:4028) 
    at android.os.Binder.execTransact(Binder.java:453) 
 Caused by: java.lang.NoClassDefFoundError: Class not found using the boot class loader; no stack trace available

根据对该错误的研究,我尝试安装的先前版本是几天前使用 Android Studio 构建的,中间没有重大更改或更新,并且仅使用 V1 签名上一个版本的情况。改回不正确的方式,将代码设置为 9 并仅递增版本名称可使更新正确安装。

这是我认为正在发生的事情。

如果我们有一个测试class这样:

public class MyClass {
    public static void main(String args[]) {
int anInt = '1';
        System.out.println("anInt  is = " + anInt);
    }
}
It runs with result `anInt  is = 49`

将“1”更改为“9”

It runs with result `anInt  is = 57`

将“9”更改为“10”

It fails (like your cast error): 

/MyClass.java:3: error: incompatible types: String cannot be converted to int
int anInt = "10";
            ^
1 error

So if you use your bug fixed code with a versionCode of 58 it should work.

这里有一个 snippet 所以你可以在 javascript 中自己尝试:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<html><head><script>
    $(function() {
      var anInt = ('1').charCodeAt(0);
      console.info("anInt is = " + anInt);
    });
  </script></head><body>
  function();
</body></html>