让「小程序」跑起真正的原生代码:ComboNative 多进程原生小程序运行时 · Alpha 首发
一个 Android 动态化框架:每个小程序都是原生 Kotlin/Compose、运行在独立进程、可与宿主各自独立混淆加固。框架运行时约 347 KB,一个功能完整的小程序包可低至 32.8 KB,内含三个小程序的完整 demo(release)仅 7.74 MB。
主库暂未开源,但已发布至 Maven Central,现开放 Alpha 抢先体验,可直接接入试用。本文较长,建议按小标题按需跳读:从「为什么做」到「怎么用」再到「边界在哪」,一次讲透。


TL;DR(30 秒速览)
如果你没时间读完全文,记住这几点就够了:
- 它是什么 :一个 Android 动态化框架。每个「小程序」都是原生 Kotlin/Compose 代码 ,运行在独立子进程里,由宿主 App 动态下发、加载、治理。
- 它解决什么 :传统单进程插件化的三大死结------不能独立混淆加固、内存泄漏难根治、崩溃会传染;同时又不像 JS 小程序那样有性能与能力天花板。
- 凭什么能做到 :跨进程只走 AIDL 契约、只传字节不传类名 (→ 双方各自独立加固);每个小程序一个进程、关闭即杀进程 (→ 内存不泄漏、崩溃不传染);构建期静态生成占坑进程、0 Hook AMS/PMS(→ 稳定、随版本兼容)。
- 有多轻 :框架运行时约 347 KB ;一个功能完整的记账小程序
.cbp仅 32.8 KB ;含 3 个小程序的完整 demo(release)7.74 MB,框架本体占比 <5%。 - 适合谁 :车机 / 座舱 / TV / 行业 PDA / Kiosk / 定制 ROM 等受控终端 ,以及需要代码资产保护 + 动态下发原生功能的第一方 / 合作方生态。
- 不适合谁 :允许匿名任意第三方上传原生代码的开放市场(它不是强沙箱);iOS / 跨端;Google Play 内动态加载 Play 外可执行代码。
- 现在能做什么 :主库暂未开源,但四个库已上 Maven Central 、示例仓库已开源,可直接接入体验,欢迎参与 Alpha 众测。
🚀 立即体验(不想读长文?先上手)
| 入口 | 链接 |
|---|---|
| 📥 示例 App 下载(免构建,装上就能玩) | https://130.94.11.104:17558/down/9yiZ75pfO4QR.apk |
🧩 示例小程序 .cbp 下载 |
小程序① · 小程序② · 小程序③ |
| 🔗 示例开源仓库(宿主 + 3 个原生小程序,可独立克隆构建) | github.com/lnzz123/com... |
| 📚 Maven 接入 | io.github.lnzz123:combonative-engine:0.1.0-alpha01(及 abi/runtime/mini-sdk) |
| 🧰 打包插件(Gradle Plugin Portal) | io.github.lnzz123.combonative-packer:0.1.0-alpha01 |
觉得有意思,欢迎点个 ⭐ Star、提 Issue,一起参与 Alpha 众测。想了解「它为什么这么设计」,继续往下读。
目录
- 一个真实的两难:先讲个故事
- 背景:为什么要做 ComboNative
- 它与 ComboLite 的关系
- 设计目标与核心取舍(含三方对比)
- 核心机制(原理层面)
- 轻量化:可复现的体积数据
- 十分钟实战:从宿主集成到跑起第一个小程序
- 真实安全边界与适用场景
- 选型:ComboLite 还是 ComboNative
- 常见问题 FAQ
- 当前状态
- 抢先体验与资源
〇、一个真实的两难:先讲个故事
设想你在做一台车机(或智能座舱 / 一体机 / 行业 PDA,任选其一)。产品经理提了三个看似平常、实则互相打架的需求:
- 要能动态下发功能。 车卖出去之后,「充电地图」「会员商城」「第三方生态应用」得能远程更新、按需安装,不可能每次都整机 OTA。
- 要原生的体验和能力。 中控大屏上任何一处卡顿、掉帧都会被放大成「这车真廉价」;而且要用到蓝牙、CAN、定位、摄像头这些底层能力,套一层 JS 容器既慢又处处受限。
- 要稳,还要安全。 车机开机就是几个月不重启;任何一个第三方模块的崩溃或内存泄漏,都不能影响到主 HMI;合作方的模块不能随便读你不想给的东西,你自家的核心代码也不能被轻易逆向。
于是你在两条老路之间反复横跳:
- 选 JS / 跨端小程序 ?满足了「动态下发 + 沙箱安全」,但性能和底层能力这关过不去,产品体验被容器拖住。
- 选 传统原生插件化 ?性能和能力都有了,但不能给插件独立加固 (一混淆就崩)、插件崩溃会掀翻整个中控 、长时间运行内存越吃越多------对一台几个月不重启的设备,这几乎是定时炸弹。而且很多方案还在 Hook 系统私有 API,每次大版本升级都心惊胆战。
你会发现,没有一条现成的路能同时满足这三点。 这个「原生 vs 动态 vs 隔离」的三角矛盾,正是我做 ComboNative 的起点。它不试图重新发明 Android,而是重新组织 Android 已有的能力------用「多进程 + 静态占坑 + 窄契约」把这三个角落一次性照顾到。下面从头讲起。
一、背景:为什么要做 ComboNative
在做出 ComboNative 之前,我维护的是上一代单进程插件化框架 ComboLite(0 Hook / 0 反射、Compose-first,已开源并上线 Maven Central)。ComboLite 把单进程插件化的「干净加载」做到了相当完整的程度,但在推向企业级、生产级场景时,暴露出三个长在架构地基上、靠打补丁难以根治的结构性限制:
- 难以独立混淆加固。 单进程插件化的本质是宿主与插件共享同一 ClassLoader、按类的全限定名(FQCN)在运行期互相链接。一旦对任一侧开启混淆/加固,类名被重命名后跨模块符号即无法解析。这使得「核心代码资产保护」------企业付费意愿最强的诉求之一------在该模型下基本无解。
- 内存泄漏难以根治。 插件卸载依赖手动清理引用(ClassLoader、资源、静态持有、回调等),任一环节遗漏即造成泄漏。对车机、机顶盒、行业终端等长时间不重启的设备尤为致命。
- 崩溃会传染。 插件与宿主同进程运行,一处未捕获异常可导致整个应用崩溃。
结论很明确:这些问题在单进程模型内已无太多优化空间,需要从进程模型层面重做。ComboNative 由此而来------它并非 ComboLite 的版本升级,而是同一技术脉络下、针对上述结构性缺陷重新设计的下一代运行时。
二、它与 ComboLite 的关系
| 维度 | ComboLite(单进程) | ComboNative(多进程) |
|---|---|---|
| 模型 | 单进程插件化,共享 ClassLoader,按 FQCN 跨插件链接 | 多进程「原生小程序」运行时,独立进程 + 独立 ClassLoader |
| 混淆加固 | 跨插件按类名链接,难以独立混淆 | 跨进程只走契约、不传类名,宿主与小程序各自独立混淆加固 |
| 崩溃 | 插件崩溃波及宿主 | 子进程崩溃隔离 + 崩溃熔断 |
| 内存 | 卸载靠清理引用,易泄漏 | 关闭即杀进程,由操作系统整体回收 |
| 开源 | 已开源、已上 Maven Central | 主库暂未开源(已上 Maven,开放 Alpha 体验) |
| 成熟度 | 相对成熟,可用于生产 | 0.1.0-alpha01,抢先体验阶段 |
有两点想说明:
ComboLite 将持续保持开源。 它的纯净类加载、AAR→APK 打包插件、全局类索引、依赖图与链式重启等实现均可公开研读,是一份完整的插件化工程参考。对希望深入理解动态化原理的开发者,在读懂单进程模型的能力边界后,完全可以沿「多进程 + IPC 契约」的方向自行实现一套类似 ComboNative 的运行时。
ComboNative 主库暂不开源(考虑到其仍处于 Alpha 阶段及后续商业化规划),但框架的四个库已发布至 Maven、并提供完整的开源示例仓库,可先行接入体验。
三、设计目标与核心取舍
行业内的 Android 动态化长期在两类方案间权衡:
- JS 小程序 / 跨端容器:沙箱安全、跨端一致、生态成熟;代价是 UI 经渲染桥、逻辑跨 JS↔Native 边界序列化,性能存在上限,底层能力受容器方开放节奏制约。
- 传统原生插件化:性能接近原生;代价是前述的混淆、泄漏、崩溃传染问题,且许多方案依赖 Hook AMS/PMS 等系统私有 API。
ComboNative 的设计目标是取二者之长:以原生方式执行、以小程序方式下发与治理,并从架构层面消解上述缺陷。其核心设计与对应收益如下:
| 目标 | 实现方式 | 收益 |
|---|---|---|
| 独立混淆加固 | 跨进程仅传 apiId + 序列化字节,从不传类名 |
宿主与小程序可分别混淆、分别加固 |
| 崩溃隔离 | 每个小程序运行于独立子进程 | 崩溃只影响自身,宿主无感,另有熔断兜底 |
| 内存可控 | 关闭小程序即终止其进程 | 内存交由操作系统整体回收,杜绝泄漏累积 |
| 不依赖系统私有 API | 构建期静态生成占坑组件与占坑进程 | 0 Hook AMS/PMS,全程公开 API,版本兼容性可控 |
安全模型需如实说明:ComboNative 采用受控准入 + 越权拦截 + 进程隔离 ,并非强沙箱。小程序与宿主同 UID,原生代码可访问该进程可达的底层资源。因此它面向第一方 / 合作方,以及经签名白名单 + 审核准入的半可信生态,而非匿名任意第三方的开放市场。第七节会专门展开边界。
三方对比:JS 小程序 / 传统插件化 / ComboNative
把三条路放在一起看,取舍一目了然:
| 维度 | JS 小程序 / 跨端容器 | 传统原生插件化 | ComboNative |
|---|---|---|---|
| 执行方式 | JS + 渲染桥 | 原生 | 原生 Kotlin/Compose |
| 性能上限 | 受桥与序列化限制 | 原生 | 原生 |
| 底层能力 | 受容器开放节奏制约 | 完整 | 完整(含 NDK) |
| 崩溃隔离 | 容器级隔离 | ❌ 同进程传染 | ✅ 进程级隔离 + 熔断 |
| 内存治理 | 容器回收 | ❌ 手动清理易泄漏 | ✅ 关闭即杀进程 |
| 独立混淆加固 | 不涉及(JS) | ❌ 按类名链接难混淆 | ✅ 只传字节,可独立加固 |
| 是否 Hook 系统 | 否 | 多数需 Hook AMS/PMS | ✅ 0 Hook,全公开 API |
| 安全强度 | 强沙箱 | 弱 | 受控准入 + 拦截 + 隔离(非强沙箱) |
| 适用面 | 开放生态、跨端 | 通用 App 动态化 | 受控 / 半可信终端 |
一句话读懂这张表:JS 小程序赢在「安全 + 跨端」,传统插件化赢在「原生性能」,而 ComboNative 想在「原生性能」的基础上,把「隔离 + 内存治理 + 代码保护」也一起拿下------代价是它只面向来源可控的受控生态,且用一定的跨进程开销与资源占用作为交换。
四、核心机制(原理层面,不涉及内部实现)
4.1 占坑进程池:0 Hook 的多进程
Android 四大组件无法在运行期动态创建,系统只识别打包前 manifest 中静态声明的组件,android:process=":mpN" 亦由 manifest 决定。传统插件化为让插件组件被系统调度,普遍采用 Hook AMS/PMS + 占坑组件欺骗系统 的方案------能用,但依赖系统私有 API,每逢大版本升级都要重新适配。
ComboNative 的取向是不 Hook、不欺骗系统,只用公开 API,把动态性从「运行期骗系统」前移到「构建期造槽位」:
构建期预声明 N 组「占坑」组件、每组绑定一个独立进程
:mp1...:mpN;运行期需要运行小程序时,从进程池挑一个空闲槽位拉起;关闭时终止该进程、归还槽位。
这里的关键是:槽位是同质的、空的、通用的 ------不绑定任何具体小程序,如同酒店房间,谁来了都能住进去,走了就腾空。占坑组件、进程声明及配套 manifest 全部由构建期的 Gradle 插件自动生成,开发者无需手写。

代价需要如实说明:并发运行的小程序数量上限 = 预声明的槽位数 ;launchMode 等静态属性对同质槽位统一。这是「不 Hook、只用公开 API」这条路必然的权衡------用可控的资源开销与灵活性约束,换长期的稳定性与版本兼容性。
4.2 AIDL 契约:只传字节、不传类名
多进程解决了隔离,但也带来通信问题。ComboNative 的答案是一层 AIDL + Parcelable 契约,并定下一条贯穿始终的铁律:
跨进程仅传递
apiId、apiVersion与序列化后的payload字节;不传递Class、类全名,也不传递任意可序列化对象。
宿主与小程序之间流动的永远是「数据」,而非「类型」。正因为两端从不按类名互相引用 ,宿主可以任意混淆自己的类、小程序也可以任意混淆自己的类,互不影响------这就是 ComboLite 做不到、而 ComboNative 能做到「独立混淆加固」的根本原因。 契约面越窄、越稳定,两端的演进就越自由。
此外,请求携带 apiVersion,能力可按兼容区间向后兼容地演进;宿主为每个小程序创建绑定其真实身份的通信端,调用方伪造身份字段会被真实身份覆盖。
4.3 四大组件跨进程代理
小程序内可正常使用 Activity、Service(含前台服务)、BroadcastReceiver、ContentProvider,均由占坑组件承载:
- Activity 由占坑
ProxyActivity承载,支持进程内栈式导航与startActivityForResult结果回传; - Service 由每槽位的代理池承载,支持前台服务(Android 14+ 的
foregroundServiceType由宿主静态声明); - 静态广播由宿主主进程接收后唤醒目标小程序进程再转发;
- ContentProvider 由宿主按 authority 路由并重写 URI 后转发至小程序进程,Cursor 结果经
CursorWindow共享内存跨进程返回。
4.4 大 payload 的 fd 旁路
Binder 单次事务缓冲有限(约 1 MB 且与并发事务共享),大数据内联会触发 TransactionTooLargeException。ComboNative 在 IPC 边界做了处理:当 payload 超过 128 KiB ,自动改用 ParcelFileDescriptor 管道旁路(Binder 中仅传一个 fd),对业务代码完全透明,无需手动分片。
4.5 准入、熔断与进程回收
- 安装准入 :解析
.cbp元数据 → 签名白名单校验 → 版本比较(默认拒绝降级、升级校验签名一致防替换)→ 事务化落盘,启动可恢复; - 崩溃熔断:滑动窗口内崩溃次数达阈值即自动禁用该小程序,之后可一键恢复;
- 进程健康:Binder death 探测子进程存活,任务哨兵在最近任务被移除时可靠回收进程与槽位。
架构概览

五、轻量化:可复现的体积数据
数据口径:0.1.0-alpha01,release / R8 混淆后。所有数字均可在开源示例仓库一键复现(命令见第十一节)。
5.1 框架运行时:约 347 KB
| 模块 | AAR 体积 | 作用 |
|---|---|---|
combonative-abi |
66.9 KB | 契约层(AIDL + 序列化模型) |
combonative-engine |
202.4 KB | 宿主主进程引擎:调度、API 桥、安装准入 |
combonative-runtime |
53.7 KB | 子进程运行时:dex 加载、占坑组件、资源加载 |
combonative-mini-sdk |
23.9 KB | 小程序开发面(运行期由宿主提供) |
| 合计 | ≈ 347 KB |
打包插件
combonative-packer(165 KB)不计入------它只在构建期运行,不进运行时 APK。
5.2 单个小程序包:低至 32.8 KB
| 小程序 | 形态 | .cbp(release) |
.cbp(debug) |
|---|---|---|---|
miniapp-ledgerbook |
纯逻辑 + 轻量 UI(记账) | 32.8 KB | 44.8 KB |
miniapp-minihub |
纯 Compose UI | 97.7 KB | 141.7 KB |
miniapp-imagelab |
含 NDK 原生图像处理 | 429.0 KB | 497.0 KB |
一个功能完整的记账小程序只有 32.8 KB。⚠️ 但不应把「几十 KB」当成所有小程序的恒定指标------体积取决于代码量、UI 复杂度、是否带 NDK 等,以上是特定示例、特定版本、特定口径的实测值。

为什么能这么小? 核心是「不重复打包宿主已有的东西」:小程序对框架 SDK 用 compileOnly(运行期由宿主提供,不进 .cbp),且不重复打包宿主已具备的 Compose / AndroidX 等公共依赖,.cbp 只装它自身独有的代码与资源。就像入住一间配齐家具的公寓,只需带自己的行李。
5.3 宿主整包:7.74 MB,框架占比不足 5%
| 构建类型 | 宿主 APK 体积 |
|---|---|
| release(R8) | 7.74 MB |
| debug | 11.02 MB |
这 7.74 MB 里绝大部分是 Compose / Material3 / AndroidX 等常规依赖(任何 Compose 应用都要带),四个框架运行时 AAR 合计约 347 KB、占比不足 5% 。也就是说,ComboNative 几乎不给宿主「增重」,整包大小主要由你自己的业务 UI 依赖决定。
六、十分钟实战:从宿主集成到跑起第一个小程序
以下代码均为公开 SDK 的使用方式(非主库内部实现),可对照开源示例仓库操作。前提:JDK 17、AGP 8.12+、Kotlin 2.2+、minSdk 24 / compileSdk 36。
6.1 配置宿主(一次性)
宿主 App 模块 build.gradle.kts:
kotlin
plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")
id("org.jetbrains.kotlin.plugin.compose")
id("io.github.lnzz123.combonative-packer") version "0.1.0-alpha01"
}
dependencies {
implementation("io.github.lnzz123:combonative-engine:0.1.0-alpha01")
}
comboNativeHost {
miniApps {
enabled.set(true) // 自动把小程序打进 assets/miniapps/
buildType.set(com.combonative.packer.PackageBuildType.DEBUG)
dir.set("miniapps")
}
slots {
enabled.set(true)
count.set(3) // 并发运行小程序上限
servicesPerSlot.set(2)
}
}
根项目 build.gradle.kts 声明要打包的小程序与签名:
kotlin
plugins { id("io.github.lnzz123.combonative-packer") version "0.1.0-alpha01" }
combonativePacker {
modules { module(":my-miniapp") }
signing {
keystorePath.set("/path/to/your.jks")
keystorePassword.set("..."); keyAlias.set("..."); keyPassword.set("...")
}
}
用生成的槽位清单初始化引擎(Application.onCreate):
kotlin
class HostApp : Application() {
override fun onCreate() {
super.onCreate()
ComboNative.initialize(
application = this,
config = ComboNativeConfig(
slots = com.combonative.generated.GeneratedProcessSlots.SLOTS,
hostApiProviders = listOf(/* 见 6.3 */),
enforceSignature = false, // 调试期可关;生产必须 true
),
)
}
}
占坑组件由 packer 注入合并 manifest,无需手写;宿主 manifest 只需声明
android:name=".HostApp"与自己的 launcher。
6.2 开发一个小程序(标准 Android Library)
kotlin
// :my-miniapp/build.gradle.kts
android {
namespace = "com.example.mymini" // ← 这就是小程序的唯一 ID
compileSdk = 36
defaultConfig { minSdk = 24 }
buildFeatures { compose = true }
}
dependencies {
compileOnly("io.github.lnzz123:combonative-mini-sdk:0.1.0-alpha01") // 黄金法则:compileOnly
implementation("androidx.compose.material3:material3:<version>")
}
入口类继承 MiniApp,基类 UI 中立:
kotlin
class MyMiniApp : MiniApp() {
override fun onCreateView(context: Context): View =
ComposeView(context).apply {
setContent { MiniTheme { Text("Hello from my first MiniApp!") } }
}
}
manifest 元数据(复用标准清单字段:包名=唯一 ID、label=展示名、versionCode/Name=版本):
xml
<manifest android:versionCode="1" android:versionName="1.0.0">
<application android:label="我的第一个小程序">
<meta-data android:name="combonative.miniapp.entryClass"
android:value="com.example.mymini.MyMiniApp" />
<meta-data android:name="combonative.miniapp.hostApis"
android:value="account.getToken;ui.toast" /> <!-- 申请的宿主 API,分号分隔 -->
</application>
</manifest>
6.3(可选)宿主暴露能力给小程序
能力目录完全由宿主定义,框架不内置:
kotlin
// 宿主侧
private class AccountTokenProvider : HostApiProvider {
override val apiId = "account.getToken"
override fun handle(request: HostApiRequest) =
HostApiResponse(HostApiResponse.ResultCode.OK, "token-for-${request.callerMiniId}".toByteArray())
}
// 小程序侧
val token = hostApi.invoke("account.getToken", apiVersion = 1).payload?.decodeToString()
授权分 NORMAL / DANGEROUS(需用户授权)/ HOST_SIGNATURE(仅同签名可用)三档。
6.4 构建、安装、运行
bash
./gradlew :<你的宿主模块>:assembleDebug # 自动把 .cbp 注入宿主 assets
unzip -l <宿主 APK 路径> | grep -i cbp # 验证 .cbp 已进入 APK
宿主里释放 → 安装 → 启动:
kotlin
ComboNative.installFromPackage(file, forceOverwrite = true) // 调试期强制覆盖
ComboNative.launch(activity, "com.example.mymini") // miniId = 包名
生产语义应改用
ComboNative.showInstallConfirm(context, file)拉起安装确认页(展示名称/版本/申请 API/签名风险),用户确认后再落盘。
运行后:系统拉起 :mp0 子进程渲染出界面;系统「最近任务」里宿主与小程序各占一张卡片;划走小程序卡片,任务哨兵可靠回收该子进程。
🎬【视频 · 建议放】20~30 秒「进程隔离」硬核演示(最有说服力,强烈建议):①启动小程序 → 打开系统「最近任务」,展示宿主与小程序各占一张卡片 ;②在小程序里故意触发一个崩溃 → 小程序进程消失,宿主界面纹丝不动 ;③划走小程序卡片 → 用
adb shell ps | grep :mp或开发者选项「正在运行的服务」展示子进程被回收。这段「崩了也不连累宿主」的对比是全篇最强的技术背书。🖼️【截图 · 可选】Android Studio Profiler 或
adb shell ps中出现独立:mp0子进程的截图,佐证「真·多进程」。
到这里,你已跑通完整闭环------你会发现,开发一个小程序,和开发一个普通 Android Library 模块几乎没有区别。
七、真实安全边界与适用场景
与其把安全说成万能,不如把「能做到什么、做不到什么」讲清楚。
7.1 三层安全模型
- 受控准入:签名白名单(不在白名单直接拒绝)、版本校验(默认拒绝降级、升级校验签名一致防替换)、安装确认页透明展示申请权限;
- 越权拦截 :小程序访问能力的唯一通道是宿主 API 桥,一次调用依次校验「API 是否注册 → 版本是否匹配 → manifest 是否声明 → 是否已授权 → 审计 → 分发」;授权分
NORMAL/DANGEROUS/HOST_SIGNATURE三档,其中HOST_SIGNATURE让某些能力只开放给同签名的自家小程序;身份由服务端按真实身份绑定,不可伪造; - 进程隔离:崩溃隔离(子进程崩溃不影响宿主)、崩溃熔断(反复崩溃自动禁用)、进程回收(Binder death 探测 + 任务哨兵)。
7.2 必须诚实说明的边界
- 同 UID,不是强隔离。 小程序进程与宿主同 UID,原生代码能访问该进程可达的底层资源。进程隔离保证的是稳定性隔离 (崩溃/内存/生命周期),不是 OS 级安全沙箱 ;API 白名单拦得住「经 API 桥的越权调用」,拦不住蓄意的原生越权。
- 因此不适合匿名第三方开放市场。 若要「允许互联网上任意匿名开发者上传原生模块直接运行」,需要的是 OS 级强沙箱(独立 UID / seccomp / SELinux),这不是 ComboNative 的定位。它的价值前提是来源可控。
- 另:Android-only;不适合在 Google Play 内动态加载 Play 外可执行代码。
7.3 适用与不适用
✅ 适用: 车机 / 智能座舱、智能电视、行业 PDA、Kiosk、自动售货机等受控终端;定制 ROM、受控侧载平台;需要代码资产保护并动态下发原生功能的第一方 / 合作方生态;经签名白名单 + 审核准入的半可信小程序生态。
❌ 暂不适用: 匿名任意第三方上传原生模块的开放市场;需要 iOS / 跨端的场景;Google Play 内动态加载 Play 外可执行代码的场景。
举几个场景为什么适配:车机长时间不重启,进程隔离 + 关闭即回收根治泄漏,单模块崩溃不影响主 HMI;OTA 只需下发几十 KB 的 .cbp,无需整包升级;定制 ROM 以签名白名单构建半可信生态、第一方模块独立加固保护代码资产。
八、选型:ComboLite 还是 ComboNative
| 维度 | ComboLite(单进程) | ComboNative(多进程) |
|---|---|---|
| 调用开销 | 进程内直接调用,极低 | 跨进程 IPC,有序列化/Binder 开销 |
| 混淆加固 | 难以独立混淆 | 各自独立混淆加固 |
| 崩溃影响 | 波及宿主 | 隔离 + 熔断 |
| 内存 | 卸载易泄漏 | 关闭即杀进程回收 |
| 并发/资源 | 不受槽位限制、更省内存 | 受槽位数限制、常驻内存更高 |
| 成熟度 | 相对成熟、已开源 | Alpha、主库暂未开源 |
一句话判断法:你最怕的是「性能开销」还是「隔离与代码保护」?
- 消费级 App、要成熟稳定、怕开销、模块多 → ComboLite;
- 受控终端、要独立加固 / 崩溃隔离 / 内存不泄漏、来源可控 → ComboNative。
给 ComboLite 现有用户:不必急着迁移,它会继续开源维护。但如果你已撞上「想加固却一混淆就崩 / 内存持续上涨 / 一个插件崩溃带崩整个 App」这几堵墙,那正是 ComboNative 从架构层面要解决的问题------可先用开源示例评估「跨进程开销」是否可接受,再决定引入。
九、常见问题 FAQ
Q1:多进程听起来很重,每个小程序一个进程,内存吃得消吗? A:进程确实有常驻内存成本,这正是「并发上限 = 槽位数」这条设计的由来------你按设备资源预声明合适的槽位数,而非无限开进程。换来的是「关闭即杀进程、内存整体回收」,对长时间运行的设备反而更稳。资源受限时可减少槽位数;相比单进程,它用可控的内存换隔离与不泄漏,是一笔明确的权衡。
Q2:跨进程 IPC 的开销会不会拖慢小程序? A:UI 渲染、业务逻辑都在小程序自己的进程内原生执行,不过桥;只有「调用宿主能力」时才走一次 IPC。也就是说,开销只发生在明确的能力调用点上,而不是每一帧、每一次交互。大数据还有 fd 旁路兜底。对交互极其频繁、延迟极敏感的场景,可参考第八节选型建议。
Q3:小程序能用 Compose 吗?能用 NDK / .so 吗? A:都能。小程序是原生 Android Library,Compose、传统 View、Kotlin/Java、NDK 原生代码都支持。示例里的 miniapp-imagelab 就带了 NDK 图像处理。
Q4:.cbp 能像 APK 一样直接安装吗? A:不能,也不应该。.cbp 是 ComboNative 宿主专用的加载格式,只能由宿主安装、加载、运行,系统不会把它当独立 App。这是设计使然。
Q5:主库不开源,我接入了会不会被「锁死」? A:框架四个库已发布在 Maven Central,可正常依赖;示例仓库完全开源,接入方式、DSL、API 都是公开的。此外上一代 ComboLite 完整开源,原理与实现均可研读。你能清楚看到「怎么接、怎么用」,不存在黑盒锁定。
Q6:它和 Google 官方的 Dynamic Feature Module(动态功能模块)有什么区别? A:官方动态模块面向 Google Play 分发、由 Play 在安装期/按需 下发,仍运行在同进程、同 App 内,不提供进程隔离与独立加固,也依赖 Play 渠道。ComboNative 面向受控终端 / 自有分发,提供进程级隔离与独立加固,运行期由宿主自主治理,不依赖 Play。
Q7:现在是 Alpha,能上生产吗? A:建议先在非关键路径或内部项目试用、评估,欢迎参与众测反馈。API 在 Alpha 阶段仍可能调整,走向 1.0 的过程会尽量收敛并给出迁移说明。
Q8:iOS / 跨端支持吗? A:不支持,ComboNative 是 Android-only。需要跨端请考虑 JS / 跨端容器方案。
十、当前状态
- 版本:
0.1.0-alpha01; - 四个运行时库已发布 Maven Central ,打包插件已上 Gradle Plugin Portal;
- 示例仓库已开源,含宿主 demo + 三个小程序,覆盖 Compose、纯逻辑、NDK 三类形态;
- 完整中英文文档(快速开始 / 宿主集成 / 打包 / 核心 API / 组件 / 架构 / 安全 / 排障 / 性能与体积)。
发现问题欢迎提 Issue(附最小复现),或通过文末渠道联系我。你的反馈会直接影响它走向 1.0 的样子。
十一、抢先体验与资源
主库暂未开源,但已上传至 Maven,可直接接入体验,并欢迎在真实项目中试用、反馈问题与需求,帮我一起把它打磨到生产可用。
- 📥 示例 App 下载 (免构建直接体验):https://130.94.11.104:17558/down/9yiZ75pfO4QR.apk
- 🧩 示例小程序
.cbp下载 : - 🔗 示例开源仓库 (宿主 App + 三个原生小程序,可独立克隆构建):github.com/lnzz123/com...
- 🧩 ComboLite(上一代,已开源,可研读 / 借鉴) :github.com/lnzz123/Com...
- 📚 Maven 坐标 :
io.github.lnzz123:combonative-engine:0.1.0-alpha01(及abi/runtime/mini-sdk) - 🧰 打包插件 (Gradle Plugin Portal):
io.github.lnzz123.combonative-packer:0.1.0-alpha01
一键复现文中体积数据:
bash
git clone --recurse-submodules https://github.com/lnzz123/combonative-samples.git
cd combonative-samples
export ANDROID_HOME=/path/to/android-sdk
./gradlew :host-demo:assembleRelease # 宿主整包
./gradlew buildAllReleaseMiniApps # 各小程序 .cbp(release / R8)
ls -la build/outputs/mini-app-packages/release/*.cbp
如果这套「原生 + 多进程 + 可独立加固」的思路对上了你的场景,欢迎试用、提 Issue、点个 Star;如果你更想搞懂它背后的原理、甚至自己造一套,也欢迎从开源的 ComboLite 读起。你的每一条反馈,都会直接影响它走向 1.0 的样子。
📌 本文所有数据基于
0.1.0-alpha01、release/R8 口径实测,随版本演进可能变化;Alpha 阶段 API 仍可能调整。