PAYATHON 2026

集成支付宝支付时 demo 无法运行并提示 Manifest merger failed

支付阿杰

结论

Manifest merger failed 并不是支付宝 SDK 的具体报错,而是 Android 在合并多个 AndroidManifest.xml 时发现了冲突。具体原因通常写在这条提示之前,例如属性重复、组件声明冲突、minSdkVersion 不兼容,或者 Android 12 要求组件显式声明 android:exported。

排查时应先找到日志中的第一条具体冲突,再修改对应的 Manifest 或依赖配置。仅凭最后一行无法判断根因:

ERROR: Manifest merger failed with multiple errors, see logs

先定位具体冲突

在 Android Studio 的 Build 窗口中展开完整日志,然后向上查找这些关键词:

uses-sdk
Attribute
android:exported
provider
authorities
appComponentFactory
Suggestion: add 'tools:replace'

也可以打开应用模块的 AndroidManifest.xml,切换到 Merged Manifest 页面。这里会标出每个节点来自当前项目、支付宝 demo,还是某个第三方依赖。

如需查看更完整的合并日志,可在项目根目录执行:

./gradlew app:processDebugMainManifest --info

如果模块名或构建变体不是 app、debug,需要换成项目中的实际名称。

合并报告通常位于模块的构建目录中。具体路径会随 Android Gradle Plugin 版本变化,可以在 build/outputs/logs/ 或构建日志给出的路径中查找。

常见原因及处理方法

1. Manifest 属性重复或取值不同

例如,主工程和依赖都声明了 android:allowBackup,但设置的值不同:

Attribute application@allowBackup value=(false)
is also present at ... value=(true)

确认主工程应该采用哪个值后,在根节点声明 tools 命名空间,并使用 tools:replace:

<manifest
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <application
        android:name=".App"
        android:allowBackup="false"
        tools:replace="android:allowBackup">
        ...
    </application>

</manifest>

如果日志还提示 android:label、android:theme 等属性存在冲突,可以根据实际需要添加:

<application
    android:label="@string/app_name"
    android:theme="@style/AppTheme"
    tools:replace="android:label,android:theme">

不要一看到日志建议,就把所有属性都放进 tools:replace。这样可能掩盖依赖中的真实配置,甚至导致组件行为异常。

2. Android 12 缺少 android:exported

当项目的 targetSdkVersion 为 31 或更高时,带有 <intent-filter> 的 activity、service 或 receiver 必须明确声明 android:exported。

例如,启动页需要允许系统启动:

<activity
    android:name=".MainActivity"
    android:exported="true">

    <intent-filter>
        <action android:name="android.intent.action.MAIN" />

        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

只供应用内部使用的组件通常设为:

<receiver
    android:name=".InternalReceiver"
    android:exported="false">
    <intent-filter>
        ...
    </intent-filter>
</receiver>

具体使用 true 还是 false,取决于组件是否需要被其他应用或系统调用,不能全部设置成同一个值。

如果缺少声明的组件来自旧版依赖,应优先升级该依赖。把依赖中的组件复制到主 Manifest 中覆盖,只适合作为兼容处理,而且要先确认组件的实际用途。

3. minSdkVersion 与依赖要求不一致

典型日志如下:

uses-sdk:minSdkVersion 19 cannot be smaller than version 21 declared in library

这说明某个依赖要求的最低 Android 版本高于当前应用配置。可以在模块级 build.gradle 中提高 minSdk:

android {
    defaultConfig {
        minSdk 21
    }
}

使用 Kotlin DSL 时:

android {
    defaultConfig {
        minSdk = 21
    }
}

如果应用必须支持更低版本,应改用支持该版本的 SDK,不要直接添加:

<uses-sdk tools:overrideLibrary="..."/>

tools:overrideLibrary 只能绕过合并检查,无法保证 SDK 在低版本设备上正常运行,仍可能引发运行时崩溃。

4. AndroidX 与旧 Support Library 混用

较老的支付 demo 可能还在依赖 com.android.support:*,而当前工程已经使用 AndroidX。两者混用经常会引发 appComponentFactory 等 Manifest 冲突。

先在 gradle.properties 中确认以下配置:

android.useAndroidX=true
android.enableJetifier=true

再检查项目依赖,避免同时存在:

com.android.support:*
androidx.*

如果 demo 版本较旧,建议把支付集成代码迁入新建的 AndroidX 工程,并使用与当前工程兼容的 SDK 依赖。长期维护旧 demo 的整套构建配置往往会带来更多兼容问题。

临时覆盖 appComponentFactory 有时能让合并通过,但这通常只是掩盖 AndroidX 与 Support Library 混用的问题,不适合作为首选方案。

5. provider 的 authorities 重复

如果 demo 和主工程使用了相同的固定 authorities,安装或 Manifest 合并时可能发生冲突。可以使用应用 ID 占位符来保证唯一性:

<provider
    android:name="androidx.core.content.FileProvider"
    android:authorities="${applicationId}.fileprovider"
    android:exported="false"
    android:grantUriPermissions="true">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/file_paths" />
</provider>

不要在多个应用中写死同一个值,例如:

android:authorities="com.example.fileprovider"

还要检查项目中是否重复声明了同一个 FileProvider。如果两项声明用途相同,应只保留一项;如果用途不同,则要分别使用不同的 authorities。

6. 同一个组件被重复声明

主工程、demo 模块或第三方库可能重复声明同一个 activity、service、receiver 或 provider,而且各自的属性并不一致。

确认某项声明确实不需要后,可以使用 tools:node="remove" 删除依赖带入的节点:

<activity
    android:name="com.example.demo.DuplicateActivity"
    tools:node="remove" />

也可以明确替换整个节点:

<activity
    android:name="com.example.demo.PaymentActivity"
    android:exported="false"
    tools:node="replace" />

tools:node="replace" 会用当前节点替代依赖中的完整声明。原节点里的 intent-filter、权限和其他属性可能同时丢失,因此使用前要在 Merged Manifest 中核对最终结果。

推荐排查顺序

  1. 查看完整构建日志,找到第一条带有文件路径和行号的冲突。
  2. 在 Merged Manifest 中确认各项冲突声明分别来自哪里。
  3. 检查 demo 使用的 Android Gradle Plugin、Gradle、compileSdk、minSdk 和 AndroidX 配置是否与本机环境兼容。
  4. 优先升级过旧的支付宝 SDK 或其他依赖。
  5. 确实需要由主工程覆盖时,再使用 tools:replace、tools:remove 或 tools:node。
  6. 重新同步并构建,再次检查合并后的 Manifest。

修改完成后,可以执行:

./gradlew clean
./gradlew app:assembleDebug

如果仍然失败,需要提供 Manifest merger failed 上方的完整冲突段落,而不只是最后一行。排查时最有用的信息包括冲突属性、两个来源文件及其行号,以及日志给出的 Suggestion。

备注:内容仅供参考。