电商导购app移动端架构:组件化与插件化在多平台适配中的实践
大家好,我是省赚客APP研发者阿宝!"省赚客"作为聚娃科技旗下的高佣金导购平台,需同时支持华为、小米、OPPO等应用商店及自有H5渠道,且不同渠道对UI风格、功能模块、广告策略有差异化要求。为提升开发效率与包体控制能力,我们采用"组件化 + 插件化"混合架构,核心功能以AAR组件形式集成,渠道专属逻辑通过动态插件加载,实现一套代码、多端灵活发布。
组件化分层设计
我们将工程拆分为以下模块:
:app:宿主壳工程,仅包含基础配置与启动逻辑:base:公共基础库(网络、日志、埋点):user:用户中心组件:task:任务广场组件:rebate:返利明细组件:channel-api:渠道抽象接口
各业务组件通过implementation project(':xxx')方式依赖,编译期集成。
gradle
// app/build.gradle
dependencies {
implementation project(':base')
implementation project(':user')
implementation project(':task')
implementation project(':rebate')
}
组件间通信采用路由框架,避免直接依赖:
java
// juwatech.cn.base.router.Router
public class Router {
public static void navigate(Context context, String path) {
if ("/task/list".equals(path)) {
Intent intent = new Intent(context, TaskListActivity.class);
context.startActivity(intent);
} else if ("/rebate/detail".equals(path)) {
Intent intent = new Intent(context, RebateDetailActivity.class);
context.startActivity(intent);
}
}
}
渠道插件化:动态加载差异化逻辑
对于华为渠道需接入Push Kit、小米渠道需定制弹窗样式等场景,我们将渠道逻辑封装为独立插件APK,运行时动态加载。
定义统一接口:
java
// juwatech.cn.channel.api.ChannelPlugin
package juwatech.cn.channel.api;
import android.content.Context;
public interface ChannelPlugin {
void init(Context context);
String getChannelName();
boolean shouldShowCustomPopup();
}
华为插件实现:
java
// 华为插件工程 huawei-plugin/src/main/java/juwatech/cn/plugin/huawei/HuaweiChannelImpl.java
package juwatech.cn.plugin.huawei;
import juwatech.cn.channel.api.ChannelPlugin;
import android.content.Context;
import com.huawei.hms.api.HuaweiApiClient;
public class HuaweiChannelImpl implements ChannelPlugin {
@Override
public void init(Context context) {
HuaweiApiClient client = new HuaweiApiClient.Builder(context).build();
// 初始化Push Kit
}
@Override
public String getChannelName() {
return "huawei";
}
@Override
public boolean shouldShowCustomPopup() {
return true; // 华为渠道显示定制弹窗
}
}
宿主App通过DexClassLoader加载插件:
java
// juwatech.cn.app.PluginLoader
public class PluginLoader {
private static ChannelPlugin instance;
public static void loadPlugin(Context context, String pluginPath) {
try {
DexClassLoader loader = new DexClassLoader(
pluginPath,
context.getDir("dex", Context.MODE_PRIVATE).getAbsolutePath(),
null,
context.getClassLoader()
);
Class<?> clazz = loader.loadClass("juwatech.cn.plugin." + getChannelSuffix() + ".HuaweiChannelImpl");
instance = (ChannelPlugin) clazz.getDeclaredConstructor().newInstance();
instance.init(context);
} catch (Exception e) {
Log.e("PluginLoader", "Failed to load plugin", e);
}
}
public static ChannelPlugin get() {
return instance;
}
}
插件APK由CI流水线按渠道单独构建,下发至CDN,App启动时根据设备信息下载对应插件。
资源隔离与混淆兼容
为避免插件与宿主资源ID冲突,所有插件使用固定packageId:
xml
<!-- huawei-plugin/AndroidManifest.xml -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="juwatech.cn.plugin.huawei"
android:sharedUserId="juwatech.uid">
并在build.gradle中指定:
gradle
android {
aaptOptions {
additionalParameters "--package-id", "0x7F"
}
}
同时,宿主开启minifyEnabled时,保留插件接口类:
proguard
# app/proguard-rules.pro
-keep interface juwatech.cn.channel.api.**
-keep class juwatech.cn.plugin.** { *; }
多平台构建自动化
通过Gradle变体实现一键打包多渠道:
gradle
// app/build.gradle
flavorDimensions "channel"
productFlavors {
huawei {
dimension "channel"
buildConfigField "String", "PLUGIN_URL", "\"https://cdn.juwatech.cn/plugins/huawei_v1.apk\""
}
xiaomi {
dimension "channel"
buildConfigField "String", "PLUGIN_URL", "\"https://cdn.juwatech.cn/plugins/xiaomi_v1.apk\""
}
defaultChannel {
dimension "channel"
buildConfigField "String", "PLUGIN_URL", "\"\""
}
}
CI脚本自动上传插件并更新URL:
bash
# build_plugin.sh
./gradlew :huawei-plugin:assembleRelease
aws s3 cp huawei-plugin-release.apk s3://juwatech-cdn/plugins/huawei_v$(date +%s).apk
性能与稳定性保障
插件加载失败时降级至通用逻辑:
java
// juwatech.cn.app.MainActivity
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String pluginUrl = BuildConfig.PLUGIN_URL;
if (!TextUtils.isEmpty(pluginUrl)) {
PluginDownloader.downloadAndLoad(this, pluginUrl);
}
// 无论插件是否加载成功,均正常启动主界面
setContentView(R.layout.activity_main);
}
// 使用时判空
if (PluginLoader.get() != null && PluginLoader.get().shouldShowCustomPopup()) {
showHuaweiPopup();
} else {
showDefaultPopup();
}
通过组件化解耦与插件化动态扩展,"省赚客"App包体减少35%,渠道适配周期从3天缩短至2小时。
本文著作权归聚娃科技省赚客app开发者团队,转载请注明出处!