Android 在同一设备上应用多个 APK“...包与同名的现有包冲突。”

Android Application multiple APKs on same device "...package conflicts with an existing package by the same name."

我正忙着为我们的 Android 应用程序获取新的构建过程。我想要两个不同的 APK,我可以在同一台设备上并排安装。但是,我收到一条错误消息,这对于处理不同 APK 配置的人来说似乎很常见。当我安装 .debug 版本后去安装 .release 版本的应用程序时,错误消息如下 -- "App not installed. The package conflicts with an existing package by the same name." 这是我的应用程序的 build.gradle 文件。

apply plugin: 'com.android.application'

Properties props;
if (project.hasProperty("AndroidProject.signing")
    && new File(project.property("AndroidProject.signing")).exists()) {

props = new Properties()
props.load(new 
FileInputStream(file(project.property("AndroidProject.signing"))))
}

android {
compileSdkVersion 25
buildToolsVersion '26.0.2'
useLibrary 'org.apache.http.legacy'
defaultConfig {
    minSdkVersion 15
    targetSdkVersion 25
    multiDexEnabled true
    versionCode 12
    versionName "2.4"
    ndk {
        abiFilters "armeabi-v7a", "x86", "mips"
    }
}
flavorDimensions "default"
lintOptions {
    abortOnError false
}
signingConfigs {
    release {
        if (props != null) {
            storeFile file(props['STORE_FILE'])
            storePassword props['STORE_PASSWORD']
            keyAlias props['KEY_ALIAS']
            keyPassword props['KEY_PASSWORD']
        } else {
            //Don't sign it with anything. APK will append "unsigned" to itself.
        }
    }
    debug {
        keyAlias 'debug'
        storeFile file('a file path not revealed')
        keyPassword 'debugandroid'
        storePassword 'debugandroid'
    }
}
buildTypes {
    debug {
        debuggable true
        applicationIdSuffix ".debug"
    }
    release {
        minifyEnabled false
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
        if (props != null) {
            signingConfig signingConfigs.release
        }
        debuggable false
        applicationIdSuffix ".release"
    }
}
packagingOptions {
    exclude 'META-INF/LICENSE'
    exclude 'META-INF/LGPL2.1'
    exclude 'META-INF/DEPENDENCIES'
    exclude 'META-INF/LICENSE.txt'
    exclude 'META-INF/license.txt'
    exclude 'META-INF/NOTICE'
    exclude 'META-INF/NOTICE.txt'
    exclude 'META-INF/notice.txt'
    exclude 'META-INF/ASL2.0'
}
compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8
}
}


dependencies {
//    implementation 'com.esri.arcgisruntime:arcgis-android:100.2.0'
implementation 'com.esri.arcgis.android:arcgis-android:10.2.9'
implementation project(':lucityREST')
implementation project(':lucityCore')
implementation project(':lucityAndroidCore')
implementation 'com.android.support:support-v4:25.4.0'
}

该项目的一些背景知识。这是从 ANT 到 Gradle 的转换。这个构建脚本的主要应用程序模块位于 3 个较小的模块之上。我已尝试解决问题的事情。

  1. 发布版本和调试版本完全不同,明确的 applicationIds。

  2. 使用 productFlavors 并尝试不同的 versionCodes、versionNames、applicationIds 等

  3. 切换密钥库只是为了看看它是否是某种签名问题。目前我有一个不是很重要的调试签名,它使用通过 android studio 生成的密钥库。此外,出于安全目的,我在另一台机器上维护的 .properties 文件中有发布密钥库信息,并在项目外部引用(未签入版本控制)。这些构建和应用程序都可以正常工作。

  4. 我分析了在 Android Studio 中生成的 .debug 和 .release APK。包名称反映了在构建脚本中使用 "applicationIdSuffix" 的更改。

我还尝试了其他小的调整和组织结构的方式,我认为这些方式与讨论没有真正相关,或者应该为问题负责。

有人知道是什么原因造成的吗?这是从 ANT 迁移的可能副作用吗?任何想法或想法将不胜感激。谢谢!

编辑 1:

这是我的调试 apk 上 运行 "appt dumb badging" 的结果。可以看到,包名反映了加了.debug后缀。

package: name='com.lucity.tablet2.debug' versionCode='12' versionName='2.4' platformBuildVersionName=''
sdkVersion:'15'
targetSdkVersion:'25'
uses-permission: name='android.permission.INTERNET'
uses-permission: name='android.permission.ACCESS_NETWORK_STATE'
uses-permission: name='android.permission.ACCESS_FINE_LOCATION'
uses-permission: name='android.permission.ACCESS_COARSE_LOCATION'
uses-permission: name='android.permission.WRITE_EXTERNAL_STORAGE'
uses-permission: name='android.permission.READ_PHONE_STATE'
uses-permission: name='android.permission.ACCESS_WIFI_STATE'
application-label:'Lucity 2.0 - QA'
application-icon-160:'res/drawable-hdpi-v4/lucity_launcher.png'
application-icon-240:'res/drawable-hdpi-v4/lucity_launcher.png'
application-icon-320:'res/drawable-xhdpi-v4/lucity_launcher.png'
application-icon-480:'res/drawable-xxhdpi-v4/lucity_launcher.png'
application: label='Lucity 2.0 - QA' icon='res/drawable-hdpi-v4/lucity_launcher.png'
application-debuggable
launchable-activity: name='com.lucity.tablet2.ui.login2.ClientPickerActivity'  label='Lucity 2.0 - QA' icon=''
uses-permission: name='android.permission.READ_EXTERNAL_STORAGE'
uses-implied-permission: name='android.permission.READ_EXTERNAL_STORAGE' reason='requested WRITE_EXTERNAL_STORAGE'
feature-group: label=''
  uses-gl-es: '0x20000'
  uses-feature-not-required: name='android.hardware.location'
  uses-feature-not-required: name='android.hardware.location.gps'
  uses-feature-not-required: name='android.hardware.location.network'
  uses-feature-not-required: name='android.hardware.wifi'
  uses-feature: name='android.hardware.faketouch'
  uses-implied-feature: name='android.hardware.faketouch' reason='default feature for all apps'
  uses-feature: name='android.hardware.screen.landscape'
  uses-implied-feature: name='android.hardware.screen.landscape' reason='one or more activities have specified a landscape orientation'
main
other-activities
other-services
supports-screens: 'small' 'normal' 'large' 'xlarge'
supports-any-density: 'true'
locales: '--_--'
densities: '160' '240' '320' '480'
native-code: 'armeabi-v7a' 'x86'

Android 应用程序由包名称标识,例如 com.foo.bar。您一次只能在一台设备上安装一个具有给定包名称的应用程序。如果您希望发布版本和调试版本都安装在同一台设备上,则需要为它们指定不同的包名称,例如 com.foo.barcom.foo.bar.debug.

在 gradle 中,这称为 applicationId

您的 gradle 文件中的 applicationIdSuffix 设置似乎没有发挥正确的作用。

如果您在 APK 上通过命令行 aapt dump badging 使用 aapt 工具,您可以看到实际写入 APK 的包名称,也许还能看到问题出在哪里,因为它看起来像未使用后缀。

Android 是 linux 基本系统,每个应用程序都像新用户,不同用户不允许使用相同的应用程序 ID。因此,要更改同一个应用程序的 ID,例如登台和生产应用程序。 您可以在 gradle

中添加构建类型
android {                                                    
    buildTypes {
    release {
        resValue "string", "app_name", "App"
        buildConfigField "boolean", "is_prod", "true"
    }
    debug {
        applicationIdSuffix ".debug"
        resValue "string", "app_name", "App staging"
        buildConfigField "boolean", "is_prod", "false"
    }
  }                                                                      
}                                                                                   

将在包名中添加.debug。

好的,排除了明显的答案,是时候去挖掘 android 的源代码了,这些都可以在 source.android.com.

找到

我发现使用带有前缀 site:android.googlesource.com 的 google 搜索最容易做到这一点。所以 searching for the error message we find this message has name "install_failed_conflict". We want to find this in java files, so we search for "install_failed_conflict" and java and find InstallAppProgress gives this error whenever it gets PackageInstaller.STATUS_FAILURE_CONFLICT. We then search for STATUS_FAILURE_CONFLICT (this would be quicker if you had the android source in your IDE) and find that PackageManager actually uses this code for lots of things.

  • 已经存在(显然),而且
  • INSTALL_FAILED_UPDATE_INCOMPATIBLE
  • INSTALL_FAILED_SHARED_USER_INCOMPATIBLE
  • INSTALL_FAILED_REPLACE_COULDNT_DELETE
  • INSTALL_FAILED_CONFLICTING_PROVIDER
  • INSTALL_FAILED_DUPLICATE_PERMISSION

我不知道所有这些到底是什么意思(但我可以继续查看源代码以找出答案),但是否有可能其中之一适用于您的 APK?也许重复许可?

我的最大猜测是this code,我想知道你的调试包和你的发布包是否有冲突的供应商?