Android 集成指南

将 FlexUI SDK(AAR 包)集成到 Android 应用中的完整步骤。

参考项目demos/android-demo — 完整的 FlexUI + Agent Runtime 集成示例。


1. 环境要求

工具 版本要求
Android Studio Hedgehog+ (2023.1+)
Android SDK compileSdk 33+, minSdk 21+
Kotlin 1.8+
Gradle 7.2+
AGP 7.2.2
NDK 25.0.8775105(如需编译 native)

2. 引入 AAR 包

2.1 打包 AAR

在 FlexUI 项目根目录执行:

# Debug 构建
./build.sh pkg --platform android

# Release 构建
./build.sh pkg --platform android --release

产物位于 build/pkg-<date>/android/

文件 说明
flexui_engine.aar 原生渲染引擎(C++ DOM + JS 驱动 + 平台连接器),包含所有 native .so
agent_runtime.aar Agent 运行时库(LLM 对话、工具调用、卡片渲染,基于 Jetpack Compose)
as_apis.aar ASCF 小程序 API 实现层

2.2 复制 AAR 到项目

将 AAR 文件复制到 app/libs/ 目录:

cp build/pkg-*/android/*.aar <your-project>/app/libs/

2.3 配置 build.gradle

在 app 模块的 build.gradle 中:

// 如果项目使用 fat-aar 合并多个 AAR,可取消注释以下依赖
// AGP 7.4+ 已原生支持 AAR 合并,仅在 AGP < 7.4 时需要
// buildscript {
//     dependencies {
//         classpath 'com.github.kezong:fat-aar:1.3.8'
//     }
// }

// app/build.gradle
android {
    compileSdkVersion 33
    defaultConfig {
        minSdkVersion 21
        targetSdkVersion 33
        ndk {
            abiFilters 'arm64-v8a'  // 根据需要添加 'armeabi-v7a', 'x86', 'x86_64'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    kotlinOptions {
        jvmTarget = '1.8'
    }
    buildFeatures {
        compose = true
    }
    composeOptions {
        kotlinCompilerExtensionVersion = "1.4.7"
    }
}

dependencies {
    // FlexUI AARs
    implementation fileTree(dir: 'libs', include: ['flexui_engine.aar'])
    implementation fileTree(dir: 'libs', include: ['agent_runtime.aar'])
    implementation fileTree(dir: 'libs', include: ['as_apis.aar'])

    // 传递依赖(agent_runtime 需要)
    implementation 'androidx.compose.ui:ui:1.5.0'
    implementation 'androidx.compose.material3:material3:1.1.0'
    implementation 'androidx.compose.material:material-icons-extended:1.5.0'
    implementation 'androidx.compose.foundation:foundation:1.5.0'
    implementation 'androidx.compose.ui:ui-tooling-preview:1.5.0'
    implementation 'androidx.activity:activity-compose:1.7.2'
    implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.6.1'
    implementation 'androidx.appcompat:appcompat:1.6.1'

    // Ktor (HTTP client)
    implementation 'io.ktor:ktor-client-core:2.3.8'
    implementation 'io.ktor:ktor-client-android:2.3.8'
    implementation 'io.ktor:ktor-client-content-negotiation:2.3.8'
    implementation 'io.ktor:ktor-serialization-kotlinx-json:2.3.8'
    implementation 'io.ktor:ktor-client-logging:2.3.8'

    // Coroutines
    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3'

    // JSON
    implementation 'org.json:json:20230227'
}

3. 初始化引擎

3.1 Activity 中初始化 FlexUIEngine

参考 demos/android-demo/src/main/java/org/flexui/agentdemo/MainActivity.kt

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.tencent.mtt.hippy.HippyEngineContext
import com.tencent.mtt.hippy.flexui.FlexUIEngine
import com.tencent.mtt.hippy.flexui.FlexUIEngineConfig
import com.tencent.mtt.hippy.flexui.ContextHolder
import com.tencent.mtt.hippy.flexui.AccountProvider
import com.tencent.mtt.hippy.flexui.PaymentProvider
import com.tencent.mtt.hippy.modules.Promise
import com.tencent.mtt.hippy.modules.nativemodules.HippyNativeModuleBase

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // Step 1: 设置 Account/Payment Provider(可选)
        ContextHolder.accountProvider = object : AccountProvider {
            override fun login(params: Map<String, Any>, promise: Promise) {
                promise.resolve(mapOf("errMsg" to "login:ok"))
            }
        }
        ContextHolder.paymentProvider = object : PaymentProvider {
            override fun requestPayment(params: Map<String, Any>, promise: Promise) {
                promise.resolve(mapOf("errMsg" to "requestPayment:ok"))
            }
        }

        // Step 2: 初始化引擎
        FlexUIEngine.ensureInit(
            FlexUIEngineConfig(
                context = this,
                coreJSAssetsPath = "ascf/jsfwk.js",  // assets 中的 JS bundle 路径
                enableLog = true,
                debugMode = false,
                debugServerHost = "localhost:38989",
                modules = mapOf()  // 自定义 Native Module
            )
        )
    }

    override fun onDestroy() {
        super.onDestroy()
        FlexUIEngine.destroy()
    }
}

关键参数说明

参数 类型 说明
context Context Application 或 Activity Context
coreJSAssetsPath String assets 目录下 JS 引擎 bundle 的路径
enableLog Boolean 是否启用日志
debugMode Boolean 是否启用 CDP 调试模式
debugServerHost String CDP debug server 地址
modules Map<Class, Creator> 自定义 Native Module 注册表

3.2 assets 资源

将 JS bundle 文件放入 app/src/main/assets/ 目录(如 ascf/jsfwk.js)。


4. 使用 Agent Runtime

4.1 创建 AgentRuntime 实例

参考 demos/android-demo/src/main/java/org/flexui/agentdemo/MainActivity.kt

import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import org.flexui.agent.AgentRuntime
import org.flexui.agent.AgentRuntimeConfig

val config = AgentRuntimeConfig(
    baseUrl = "https://api.deepseek.com/v1",  // LLM API 地址
    apiKey = "your-api-key",                    // LLM API Key
    model = "deepseek-chat",                    // 模型名称
    skillsBasePath = "ascf-ai-demo/skills",     // assets 中 skills 路径
    baseBundlePath = "ascf-ai-demo",            // assets 中 bundle 路径
    maxIterations = 10,
)

val agentRuntime = AgentRuntime(config).apply {
    setContext(this@MainActivity)
}

CoroutineScope(Dispatchers.IO).launch {
    agentRuntime.initialize()
}

4.2 集成 AgentChatView(Compose)

import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.ComposeView
import org.flexui.agent.ui.AgentChatView

val composeView = ComposeView(this).apply {
    setContent {
        AgentChatView(
            agentRuntime = agentRuntime,
            modifier = Modifier.fillMaxSize(),
            startupMessage = "帮我点奶茶",
            onError = { error -> Log.e(TAG, "Agent error", error) }
        )
    }
}
setContentView(composeView)

4.3 注册 AscfAIModule(JS ↔ Native 桥接)

Agent 的 JS bundle 通过 AscfAIModule Native Module 与原生层通信。需要注册为 Hippy NativeModule 并设置 callJS 桥接:

import android.os.Handler
import android.os.Looper
import android.util.Log
import com.tencent.mtt.hippy.common.HippyArray
import com.tencent.mtt.hippy.common.HippyMap
import com.tencent.mtt.hippy.flexui.FlexUIEngine
import com.tencent.mtt.hippy.modules.HippyModulePromise
import com.tencent.mtt.hippy.modules.nativemodules.NativeCallback
import org.flexui.agent.modelcontext.AscfAIModule

private const val TAG = "AscfAIModule"

fun wireAscfAIModule(runtime: AgentRuntime) {
    val ascfModule = runtime.getAscfAIModule() ?: return

    FlexUIEngine.onReady {
        val engine = FlexUIEngine.hippyEngine ?: return@onReady
        val engineCtx = engine.engineContext ?: return@onReady
        val bridgeManager = engineCtx.bridgeManager ?: return@onReady

        // 设置 callJS
        val callJS: (String, Array<Any>) -> Unit = { method, args ->
            val params = HippyMap()
            val hippyArgs = HippyArray()
            args.forEach { hippyArgs.pushString(it.toString()) }
            params.pushObject("args", hippyArgs)
            bridgeManager.callJavaScriptModule(
                "__ascfCallbacks", method, params,
                HippyModulePromise.BridgeTransferType.BRIDGE_TRANSFER_TYPE_NORMAL
            )
        }

        // 设置 runScript
        val runScript: (String) -> Unit = { assetUri ->
            bridgeManager.runScriptFromUri(assetUri, false, "", object : NativeCallback(
                Handler(Looper.getMainLooper())
            ) {
                override fun Call(result: Long, message: Message?, action: String?, reason: String?) {
                    if (result == 0L) Log.i(TAG, "runScript OK: $assetUri")
                }
            })
        }

        ascfModule.setCallJSBridge(callJS, { _, _ -> "[]" }, runScript)
    }
}

5. API 概览

flexui_engine

说明
FlexUIEngine 引擎单例,ensureInit() 初始化,destroy() 销毁,onReady() 就绪回调
FlexUIEngineConfig 引擎配置(context、assets 路径、debug 模式等)
ContextHolder Account/Payment Provider 持有者
FlexUIView 引擎渲染 View
NativeRender 原生渲染器(内部类,消费方通常不直接使用,请通过 FlexUIEngine 操作)

agent_runtime

说明
AgentRuntime Agent 运行时主入口
AgentRuntimeConfig Agent 配置(LLM URL、API Key、bundle 路径等)
AgentChatView Compose 聊天 UI 组件
FlexCardView Compose FlexView 卡片渲染组件
AscfAIModule JS ↔ Native 桥接模块

as_apis

说明
ASAPIsModule ASCF 小程序 API 注册入口
StorageAPI 本地存储 API

6. 常见问题

SO 加载失败

现象UnsatisfiedLinkErrorjava.lang.RuntimeException: so library not found

解决

  1. 确认 AAR 包含对应 ABI 的 .so 文件:解压 AAR,检查 jni/ 目录
  2. 确认 build.gradleabiFilters 与实际设备匹配
  3. 确认 minSdkVersion >= 21

Compose 版本冲突

现象:编译报 Compose 相关类找不到或方法签名不匹配。

解决:确保 composeOptions.kotlinCompilerExtensionVersion 与 Compose 库版本兼容:

  • Compose UI 1.5.0 → Compose Compiler 1.4.7 (Kotlin 1.8.21)
  • Compose UI 1.6.0+ → Compose Compiler 1.5.x (Kotlin 1.9.x)

Gradle 同步失败

现象Could not resolve all files

解决

  1. 确认 AAR 文件在 app/libs/ 目录
  2. 确认 fileTreedir 路径正确
  3. 清理 Gradle 缓存:./gradlew clean --refresh-dependencies

调试日志

# adb logcat 过滤 FlexUI 相关日志
adb logcat -s FlexUI:V Hippy:V AgentRuntime:V