将两个独立的 Android 项目合二为一是一个比较复杂的过程,不能简单地复制粘贴。
最推荐、最标准的方法是将其中一个项目作为一个模块 (Module)导入到另一个主项目 (Main Project)中。
这里有一个分步指南,假设您有两个项目:
- 项目 A:作为主 App(保留原来的样子)。
- 项目 B:作为功能模块被合并进 A。
第一步:准备工作(非常重要)
- 备份:在做任何操作前,请把两个项目的代码都单独备份一份!
- 统一环境:检查两个项目的
build.gradle。compileSdkVersion、minSdkVersion、targetSdkVersion最好保持一致。- 使用的 Gradle 插件版本最好一致。
- 注意:如果您之前的项目还在用 Support 库,而另一个项目用了 AndroidX,合并时会非常痛苦。建议先确保两者都使用相同的依赖体系。
第二步:将项目 B 转换为“库模块”
您不能在一个 App 里包含另一个完整的 App,您必须把项目 B 变成一个“库 (Library)”。
复制文件:
- 在项目 A 的根目录下,创建一个新文件夹(例如命名为
module_b)。 - 将项目 B 中
app目录下的所有内容(src, build.gradle, proguard-rules 等)复制到这个新文件夹module_b中。
- 在项目 A 的根目录下,创建一个新文件夹(例如命名为
修改 B 的 build.gradle:
打开module_b/build.gradle文件:- 修改插件:将
apply plugin: 'com.android.application'改为apply plugin: 'com.android.library'。 - 删除 applicationId:在
defaultConfig块中,删除applicationId "com.example.xxx"这一行(库模块不能有包名 ID)。 - 保留资源前缀(可选但推荐):为了防止资源冲突,可以加一行
resourcePrefix "module_b_",强制要求该模块的资源以此开头(这只是检查,不是自动重命名)。
- 修改插件:将
修改 B 的 AndroidManifest.xml:
打开module_b/src/main/AndroidManifest.xml:- 移除 Launcher Intent:找到原本的入口 Activity,删除包含
android.intent.action.MAIN和android.intent.category.LAUNCHER的<intent-filter>。 - 原因:合并后,主 App 只能有一个启动图标。
- 保留包名:
<manifest package="com.example.projectb">这个包名必须保留,作为代码引用的路径。
- 移除 Launcher Intent:找到原本的入口 Activity,删除包含
第三步:在项目 A 中引入模块 B
注册模块:
打开项目 A 根目录下的settings.gradle,添加:include':app',':module_b'添加依赖:
打开项目 A 的app/build.gradle,在dependencies中添加:dependencies{// ... 其他依赖implementationproject(':module_b')}同步 Gradle:点击 Sync Now。如果配置正确,项目 B 现在就是项目 A 的一部分了。
第四步:解决冲突(最耗时的部分)
合并过程中,99% 的概率会遇到以下冲突:
1. 资源命名冲突 (Resource Merge Conflicts)
如果两个项目都有同名的资源文件(例如activity_main.xml,strings.xml中的app_name,color.xml中的colorPrimary),Gradle 会报错或主项目会覆盖子项目的资源。
- 解决方法:手动重命名模块 B 中的资源。
- 例如:把 B 的
activity_main.xml改为activity_b_main.xml。 - 把 B 的
strings.xml里的字段加上前缀,如b_app_name。 - 提示:可以使用 Android Studio 的
Refactor -> Rename(Shift+F6) 功能自动更新所有引用。
- 例如:把 B 的
2. ButterKnife / R.id 问题(针对您之前的代码)
您使用了ButterKnife。在Library 模块中,资源 ID (R.id.xxx)不是常量 (final)。
- 问题:您不能在库模块的
switch (view.getId())语句中使用case R.id.xxx:,也不能在注解@BindView(R.id.xxx)中直接使用(取决于 ButterKnife 版本)。 - 解决方法:
- 将
switch-case改为if-else。 - 对于 ButterKnife,您需要使用
R2生成器,或者按照 ButterKnife 文档配置 Library 模式。
- 将
3. 依赖包冲突
如果项目 A 用了Glide 4.1.0,项目 B 用了Glide 3.7.0,合并时会冲突。
- 解决方法:统一两个模块
build.gradle中的第三方库版本。
4. Application 初始化逻辑
如果项目 B 原本在MyApplication的onCreate里初始化了一些 SDK(如地图、推送),这些代码现在不会自动运行了。
- 解决方法:把项目 B 的初始化代码移动到项目 A 的
Application类中。
第五步:代码调用
现在合并完成了,您可以在项目 A 的代码中跳转到项目 B 的页面:
// 在项目 A 的某个按钮点击事件中Intentintent=newIntent(MainActivity.this,com.projectb.SomeActivity.class);startActivity(intent);总结建议
- 如果两个项目非常庞大且耦合度高:以上步骤会非常痛苦。这种情况下,有时候不如保留两个独立 App,通过
Intent相互唤起,或者使用 DeepLink 跳转。 - 如果项目 B 只是几个功能页面:手动把代码文件(Java类)和资源文件(XML)拷贝过去,然后手动修复报错,可能比配置 Module 更快。
强烈建议先备份,然后一步步解决 Gradle 报错,不要急于求成。