电商导购app移动端架构:组件化与插件化在多平台适配中的实践

电商导购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开发者团队,转载请注明出处!

相关推荐
u01092727112 小时前
C++中的策略模式变体
开发语言·c++·算法
雨季66613 小时前
构建 OpenHarmony 简易文字行数统计器:用字符串分割实现纯文本结构感知
开发语言·前端·javascript·flutter·ui·dart
雨季66613 小时前
Flutter 三端应用实战:OpenHarmony 简易倒序文本查看器开发指南
开发语言·javascript·flutter·ui
进击的小头13 小时前
行为型模式:策略模式的C语言实战指南
c语言·开发语言·策略模式
天马379813 小时前
Canvas 倾斜矩形绘制波浪效果
开发语言·前端·javascript
Tansmjs14 小时前
C++与GPU计算(CUDA)
开发语言·c++·算法
qx0914 小时前
esm模块与commonjs模块相互调用的方法
开发语言·前端·javascript
Suchadar14 小时前
if判断语句——Python
开发语言·python
莫问前路漫漫15 小时前
WinMerge v2.16.41 中文绿色版深度解析:文件对比与合并的全能工具
java·开发语言·python·jdk·ai编程
beginner.zs15 小时前
注意力革命:Transformer架构深度解析与全景应用
深度学习·架构·transformer