AI 特效平台(下文简称 Ebox)是一站式 AI 特效应用开发与素材管理平台,专注于为企业及开发者提供从应用创建、页面配置、素材管理下发到授权交付的全链路解决方案, 详请见:AI特效平台(Ebox)使用手册。
Ebox Android SDK 封装了 EBox 平台 API ,方便 Android App 快速接入 Ebox 平台,获取素材并使用。
在对应版本Sample中的ebox-module模块中获取到ebox sdk的aar文件集成到项目中.

在AndroidManifest中添加网络权限
<uses-permission android:name="android.permission.INTERNET" />
EBox Android SDK 接口定义在 EBoxSDKManager 中,下面详细介绍常用接口
EBoxSDKManager.init(eboxResourceConfig, context)
某些自定义场景,单独创建实例
| 参数 | 类型 | 说明 |
|---|---|---|
| resourceConfig | EBoxResourceConfig | EBoxSDK进行初始化时需要进行的各项配置 |
| context | Context | 上下文 |
//绑定ApplicationContext AppSingleton.instance = this.application val levelConfig = LevelConfig( "null", Build.MANUFACTURER, Locale.getDefault().language, Locale.getDefault().country, "" ) //初始化EBoxConfig val eboxConfig = EBoxConfig( appId = "", appSecret = "", appVersion = "", levelConfig = levelConfig ) val eboxResourceConfig = EBoxResourceConfig.Builder() //设置Config相关信息 .setAppConfig(eboxConfig) //配置是否读取在线资源 .setEnableOnline(true) //配置网络代理,这里可以替换为自己的网络实现 .setNetWorker(DefaultNetWorker()) //设置素材存储根路径,不设可以用EO默认值 .setResourceSavePath("your resource download dir") //设置模型存储的根路径,不设可以用EO默认值 .setModelDir("your resource download dir") //设置具体请求的实现,直接使用EBoxRemoteRequestBuilder即可 .setRequestBuilder(EBoxRemoteRequestBuilder(eboxConfig)) .build() //初始化 EBoxSDKManager.init(eboxResourceConfig, AppSingleton.instance)
//同步接口 fun getPageConfig(): String //异步接口 fun getPageConfig(onSuccess: (String) -> Unit)
获取页面配置
| 类型 | 说明 |
|---|---|
| String | 在EBox平台配置的自定义数据 |
fun getBusinessList(bizKeys: List<String>, schemeMap: Map<String, String>? = null): Map<String, List<BizConfigItem>>
获取业务列表数据
| 参数 | 类型 | 说明 |
|---|---|---|
| bizKeys | List | 业务列表标识 |
schemeMap | Map<String, String> | Key:bizKey
|
| 类型 | 说明 |
|---|---|
Map<String, List | key:key为请求时的每个key |
val bizKeys = listof("key1","key2","key3") val schemeMap = mutableMapOf<String, String>() schemeMap.put("key1", "https") schemeMap.put("key2", "https") schemeMap.put("key3", "eboxlocal") //key1 key2 请求服务端 //key3 读取本地数据 val result = EBoxSDKManager.getBusinessList(bizKeys, schemeMap)
fun getResourceItemInfo(resId: String): EBoxResItem?
获取单个素材项数据
| 参数 | 类型 | 说明 |
|---|---|---|
| resId | String | 素材标识 |
| 类型 | 说明 |
|---|---|
| EBoxResItem | 素材项数据的描述信息 |
val eBoxResItem = EBoxSDKManager.getResourceItemInfo(resId) data class EBoxResItem( //资源ID val resId: String = "", //资源名称 val name: String = "", //资源的md5 val md5: String = "", //资源的下载链接,下载后会和下发的md5进行比对 val url: String = "", //资源的封面链接 val coverUrl: String = "", //资源类型 val type: String = "", //资源依赖的模型 val requirements: Requirements? = null )
fun getResourceList(isOnline: Boolean): List<EBoxResItem>?
获取素材列表数据
| 参数 | 类型 | 说明 |
|---|---|---|
isOnline | Boolean | 获取在线/离线素材列表 |
| 类型 | 说明 |
|---|---|
| List | 该应用下所有素材的信息 |
val result = EBoxSDKManager.getResourceList(true)
fun getResourceItem(resId: String): EBoxResItem?
加载资源,在线资源可能会下载,离线资源仅拷贝
| 参数 | 类型 | 说明 |
|---|---|---|
| resId | String | 素材标识 |
| 类型 | 说明 |
|---|---|
| EBoxResItem | 下载好的素材描述信息 |
//耗时方法,需要执行在子线程 val eboxResItem = EBoxSDKManager.getResourceItem(resId)
//同步方法 fun loadModel(obfuscatedNames: List<String>, sdkVersion: String): Boolean //异步方法 fun loadModel(obfuscatedNames: List<String>, sdkVersion: String, onSuccess: (Boolean) -> Unit)
加载模型文件,在线模型可能会下载,离线模型仅拷贝
| 参数 | 类型 | 说明 |
|---|---|---|
| names | List | 模型名集合 |
| sdkVersion | String | 特效sdk版本号 |
| 类型 | 说明 |
|---|---|
| Boolean | 加载成功过返回true,加载失败返回false |
val success = EBoxSDKManager.loadModel(obfuscatedNames,sdkVersion)
fun checkResourceReady(resId: String): Boolean
检查素材项是否准备好
| 参数 | 类型 | 说明 |
|---|---|---|
| resId | String | 素材标识 |
| 类型 | 说明 |
|---|---|
Boolean | true:素材存在 |
val res = EBoxSDKManager.checkResourceReady(resId)
EBoxErrCode
| 错误码 | 定义 | 说明 |
|---|---|---|
| 0 | EO_RESOURCE_SUCCESS | 获取素材成功 |
| 1001 | EO_ERR_RESPONSE | 网络请求错误 |
| 1002 | EO_ERR_PARSE | 数据解析错误 |
| 1003 | EO_ERR_VERIFY | 数据md5验证错误 |
| 1004 | EO_ERR_UNZIP | 文件解压错误 |
| 1005 | EO_ERR_MERGE | 本地、远端数据融合错误 |
| 1006 | EO_ERR_DOWNLOAD | 下载错误 |
| 1007 | EO_ERR_LOCAL_CONFIG_NOT_FOUND | 本地面板Json未发现 |
| 1008 | EO_ERR_LOCAL_CONFIG_PARSE | 本地面板Json解析失败 |
| 1009 | RESOURCE_ID_NOT_FORMAT | 素材ID不合法 |
| 1010 | RESOURCE_TOKEN_FETCH_FAIL | 获取token失败 |
| 1011 | RESOURCE_MD5_CHECK_FAIL | 素材md5校验失败 |
| 1012 | RESOURCE_DOWNLOAD_FAIL | 素材加载失败 |
| 1013 | RESOURCE_DOWNLOAD_MODEL_FAIL | 模型资源加载失败 |
| 1014 | RESOURCE_RES_ID_INVALID | 素材ID不存在 |
| 1015 | RESOURCE_ILLEGAL_URL | URL不合法 |
| 1016 | RESOURCE_NOT_READY | 资源没有就绪 |
| 1017 | RESOURCE_ILLEGAL_FILE | 资源文件不合法 |
| 1201 | ILLEGAL_CONFIG | 配置错误 |
| 1999 | UNKNOWN | 未知错误 |
ebox ├── page.json // 应用的页面配置 ├── material_list.json // 离线素材列表 ├── business_list // 离线业务列表目录 │ ├── beauty.json │ ├── ... ├── material // 离线素材,按类型分子目录存放 │ ├── native_effect // 贴纸素材包目录 │ │ ├── 爱心飘落_xx.zip │ │ ├── ... │ ├── ... ├── model // 模型文件目录 │ ├── algo_ggl1pqh_v11.1.model │ ├── ... ├── icon // 图标文件目录 │ ├── 爱心飘落_xx.png │ ├── ...
{ "item_list": [ // 素材项列表 { "id": 1522471938, // 素材 ID "md5": "1ede5dd06c9d317fdccc0a280d01e098", // 素材包文件 md5 "name": "reshape_v8_lite", // 素材包名 "requirements": { // 依赖项 "models": [ // 算法模型列表 { "md5": "3ca5c7f74a8b9088762b718d5a1418c8", // 模型文件 md5 "name": "algo_ggl1pqh_v11.1.model", // 模型名 "url": "eboxlocal://EffectResource/ebox/model/algo_ggl1pqh_v11.1.model" // 模型地址,本地文件 url scheme 为 eboxlocal,path 为包含离线文件根目录 /ebox 内相的对路径 }, // ... ] }, "type": "native_beauty", // 素材类型 "url": "eboxlocal://EffectResource/ebox/material/native_beauty/reshape_v8_lite_1522471938.zip" // 素材地址,本地文件 url scheme 为 eboxlocal,path 为包含离线文件根目录 /ebox 内相的对路径 }, // ... ] }
{ "item_list": [ // 业务项列表 { "config": "", // 业务项扩展字段 "cover": "eboxlocal://EffectResource/ebox/icon/%E7%88%B1%E5%BF%83%E9%A3%98%E8%90%BD_1522486530.png", // 业务项图标地址,本地文件 url scheme 为 eboxlocal,path 为包含离线文件根目录 /ebox 内相的对路径 "extend_id": "", // 业务项扩展 ID "material_ref_ids": [ // 关联的素材 ID 1522486530 ], "name": "爱心飘落" // 业务项名字 }, // ... ] }
场景:部分素材内置,来加快素材加载速度;其余素材托管在 EBox 平台按需下载,减小包体
优点:实现加载速度和包体之间的平衡;使用 EBox 平台管理素材,无需服务端开发
从应用 sample code 中获取离线文件 ebox 目录,文件位置参考相关应用文档,例如 cv 应用查看移动端v4.8.0 AI特效平台(Ebox)Sample Code使用指南体验离线素材部分
离线文件根目录 ebox 下保留 material_list.json 以及 material 目录中需要内置的素材包、model 目录中需要内置的模型文件,其它文件都删掉
material_list.json 文件中仅保留需要内置的项
将ebox文件夹放到assets/EffectResource目录下,如图

val eboxResourceConfig = EBoxResourceConfig.Builder() // 在线功能开启 .setEnableOnline(true) .setNetWorker(DefaultNetWorker()) // 设置素材存储目录,不设置走默认 .setResourceSavePath("your resource download dir") // 设置模型存储的根路径 .setModelDir("your model download dir") .setRequestBuilder(EBoxRemoteRequestBuilder(eboxConfig)) .build() EBoxSDKManager.init(eboxResourceConfig, AppSingleton.instance)
如果需要把素材部署在自己的服务器上,不使用 AI 特效平台(Ebox)素材线上服务,考虑下面的接入方式
场景:部分资源内置,来加快素材加载速度;其余素材部署到线上
优点:减小包体,按需加载
从应用 sample code 中获取离线文件 ebox 目录,文件位置参考相关应用文档,例如 cv 应用查看 移动端v4.8.0 AI特效平台(Ebox)Sample Code使用指南 体验离线素材部分
离线文件根目录 ebox 下保留 material_list.json 以及 material 目录中需要内置的素材包、model 目录中需要内置的模型文件,其它文件都删掉
material_list.json 文件中仅保留需要内置的项
将ebox文件夹放到assets/EffectResource目录下
在使用特效之前,做好如下配置
val eboxResourceConfig = EBoxResourceConfig.Builder() // 在线功能开启 .setEnableOnline(true) // 配置网络代理,这里可以替换为自己的网络实现 .setNetWorker(DefaultNetWorker()) // 设置素材存储目录,不设置走默认 .setResourceSavePath("your resource download dir") // 设置模型存储的根路径,不设置走默认 .setModelDir("your model download dir") // 设置 MockRequestBuilder .setRequestBuilder(EboxMockRequestBuilder()) .build() EBoxSDKManager.init(eboxResourceConfig, AppSingleton.instance)
为了方便理解,下方提供一个简单的 mock server 和 EboxMockRequestBuilder,用来演示如何部署在线素材(环境为mac系统,python3,保证测试手机和电脑在相同的wifi环境下)
# EffectResource 为 ebox 目录的父目录 cd ~/Downloads/EffectResource # 在本机的 ip 上 8000 端口,启动 SimpleHttpServer python3 -m http.server 8000
# 使用ifconfig 查看电脑的ip ipconfig getifaddr en0
例如步骤2 中获取的 ip 地址是 192.168.50.52,服务端口是 8000,执行下面命令
# 把脚本拷贝到 EffectResource 目录 cp replace_domain.py ~/Downloads/EffectResource/ # 执行转换 # src:本地 domain # tar:mock server domain # dir:ebox 文件夹位置 python3 replace_domain.py --src eboxlocal://EffectResource --tar http://192.168.50.52:8000 --dir ./ebox

到此,完成了 server 数据的 mock
<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" > <!-- 添加网络访问权限 --> <uses-permission android:name="android.permission.INTERNET" /> <application android:usesCleartextTraffic="true" ...
// ip:port,参考上文的 mock server class EboxMockRequestBuilder(private val host: String = "http://192.168.50.52:8000/") : IRequestBuilder { companion object { const val TAG = "EBoxRemoteRequestBuilder" const val PATH_BIZ_CONFIG = "/ebox/business_list/" const val PATH_RESOURCE_MATERIAL_LIST = "/ebox/material_list.json" const val PATH_PAGE_CONFIG = "/ebox/page.json" } private fun getEBoxDomain(scheme: String?): String { return host } // 下载素材、模型、icon 等 @SuppressLint("UseKtx") override fun <T> buildDownloadResourceRequest(sourceItem: FetchSource<T>): RequestInfo { val uri = Uri.parse(sourceItem.getUrl()) return if (uri.scheme == EBOX_LOCAL) { RequestInfo( uri.scheme ?: "", "${uri.host}${uri.path}", RequestType.GET, ) } else { RequestInfo( getEBoxDomain(""), uri.path!!, RequestType.GET, ) } } // 获取素材列表 override fun buildResMaterialListRequest(resScheme: String?, pageNumber: Int, pageSize: Int): RequestInfo { val scheme = if (EBoxSDKManager.resourceConfig.enableOnline) { resScheme } else { EBOX_LOCAL } val resHeaderMap = createCommonHeaderMap() val requestPath = if (scheme == EBOX_LOCAL) { "${EBoxSDKManager.resourceConfig.offlineRootPath}/material_list.json" } else { PATH_RESOURCE_MATERIAL_LIST } return RequestInfo( getEBoxDomain(scheme), requestPath, RequestType.GET, resHeaderMap ) } // 获取单个素材,查缺补漏用,mock不必实现 override fun buildResItemRequest(resId: String, resScheme: String?): RequestInfo { val resHeaderMap = createCommonHeaderMap() return RequestInfo( getEBoxDomain(""), "", RequestType.GET, resHeaderMap ) } // 获取业务列表 override fun buildBizConfigRequest(bizId: String, bizScheme: String?): RequestInfo { val scheme = if (EBoxSDKManager.resourceConfig.enableOnline) { bizScheme } else { EBOX_LOCAL } val bizHeaderMap = createCommonHeaderMap() val requestPath = if (scheme == EBOX_LOCAL) { "${EBoxSDKManager.resourceConfig.offlineRootPath}/business_list/${bizId}.json" } else { "${PATH_BIZ_CONFIG}${bizId}.json" } return RequestInfo( getEBoxDomain(scheme), requestPath, RequestType.GET, bizHeaderMap ) } // 获取页面配置 override fun buildPageConfigRequest(): RequestInfo { val scheme = if (EBoxSDKManager.resourceConfig.enableOnline) { EBOX_ONLINE } else { EBOX_LOCAL } val requestPath = if (scheme == EBOX_LOCAL) { "${EBoxSDKManager.resourceConfig.offlineRootPath}/page.json" } else { PATH_PAGE_CONFIG } val bizHeaderMap = createCommonHeaderMap() return RequestInfo( getEBoxDomain(scheme), requestPath, RequestType.GET, bizHeaderMap ) } // 获取模型信息,查缺补漏用,mock不必实现 override fun buildModelObfuscatedRequest( obfuscatedNames: List<String>, sdkVersion: String ): RequestInfo { val resHeaderMap = createCommonHeaderMap() return RequestInfo( getEBoxDomain(""), "", RequestType.GET, resHeaderMap ) } private fun createCommonHeaderMap(): MutableMap<String, String> { val headerMap = mutableMapOf<String, String>() return headerMap } }
如果之前运行过,建议先删除 sample 应用,避免之前有离线加载的素材影响测试,然后重新编译运行 sample code。可以根据之前运行 python 服务器的 terminal 输出的日志,来判断是否访问了 mock server 上的资源。Server 端日志大概如下:
素材包文件相同 (md5 已有)情况优先使用内置的,否则会下载远端的覆盖
想要在 UI 展示前提前加载的素材,可以提前通过素材 ID 调用素材加载接口提前加载,示例代码:
val resIds = arrayOf("123", "456", "789") //耗时方法,需要执行在子线程 for (resId in resIds) { EBoxSDKManager.getResourceItem(resId) }
目前没有自动清理的策略,需要使用方按需手动清理。缓存路径为初始化接口传入的路径。
注意资源缓存有依赖关系(素材依赖算法模型),如需清理,建议在没有使用时整体全部清理,业务再按需加载