EffectOne Android 功能详解
EffectOne初始化包含以下过程
AppSingleton.bindInstance(this)
配置模型路径、相册最大数、SDK图片加载、Log等的默认实现、相册默认值、图片编辑模式等,支持用户在宿主App中自定义。
把SampleCode中DefaultImageLoader.kt 文件直接复制到自己的工程当中使用即可。
// SampleCode中提供,可以直接复制过来。默认实现需要新增glide依赖 //implementation("com.github.bumptech.glide:glide:4.13.2") EffectOneSdk.imageLoader = DefaultImageLoader() //图片加载实现 EffectOneSdk.logger = DebugLogger() //Log实现 EffectOneSdk.modelPath = EOResourceManager.getModelRootPath() //模型路径 EffectOneSdk.photoEditingMode = PhotoEditingMode.MODE_PICTURE //图片编辑模式
将离线鉴权文件放置到宿主工程/app/src/main/assets/License/目录下
拷贝离线鉴权文件到App私有目录下
// 根据文件名,拷贝离线鉴权文件到App私有目录下 val licenseFileName = "com.volcengine.effectone.licbag" val licenseFile = File(EOUtils.pathUtil.internalLicense(), licenseFileName) if (!licenseFile.exists()) { EOUtils.fileUtil.copyAssetFile("license/${licenseFileName}", licenseFile.absolutePath) }
defaultConfig { ... applicationId = "com.volcengine.effectone" ... }
override fun prepareAndInit(callback: (Boolean, String) -> Unit) { coroutineScope.launch(Dispatchers.Main) { initConfigs() initResourceData() val authResult = withContext(Dispatchers.IO) { auth() } if (authResult.resCode != EOAuthErrCode.EO_SUCCESS) { EOToaster.show(AppSingleton.instance, authResult.resMsg) callback(false, "auth failed:${authResult.resMsg}") } else { callback(true, "auth success") } } }
EOQuickInitHelper.prepareAndInit{ isSuccess, msg -> authResult = isSuccess }
EffectOneSdk需要使用素材来完成贴纸、特效、滤镜等效果,为了方便使用提供了素材管理SDK-EOResourceManager,方便接入方管理和配置素材。对于绝大部分场景,接入方直接使用EOResourceManager来管理素材即可。
// 指定素材文件保存目录、素材使用语言 val config = EOResourceConfig.Builder() .setResourceSavePath(EOUtils.pathUtil.internalResource()) .setDomainConfig(domainConfig) //在线素材需要,离线素材不需要 .setSysLanguage(Locale.getDefault().language) .build() // 素材sdk初始化 EOResourceManager.init(config)
将Android下的资源交付物EffectResource文件下的内容,放置到EffectOne-Android/business/src/main/assets/EffectResource/里,目录结构如下:
将Android下的资源交付物EffectResource/Resource_icons文件下的内容,放置到EffectOne-Android/business/src/main/res/drawable-xxhdpi/里
加载面板配置文件内容
// 需要在EOQuickInitHelper initConfigs()里添加读取面板配置文件的实现,参考如下: DefaultLocalResourceLoader.instance.localConfigsLoader = object : LocalConfigsLoader { private val configsPathMap : Map<String, String> = mutableMapOf<EOResourcePanelKey, String>().apply { put(EOResourcePanelKey.PREVIEW_EDITOR_EFFECT, "Panel_configs/preview_editor_effect.json") put(EOResourcePanelKey.PREVIEW_EDITOR_FILTER, "Panel_configs/preview_editor_filter.json") put(EOResourcePanelKey.PREVIEW_EDITOR_FONT, "Panel_configs/preview_editor_font.json") put(EOResourcePanelKey.PREVIEW_EDITOR_INFO_STICKER, "Panel_configs/preview_editor_info_sticker.json") put(EOResourcePanelKey.PREVIEW_EDITOR_MUSIC, "Panel_configs/eo_music.json") put(EOResourcePanelKey.PREVIEW_EDITOR_STICKER, "Panel_configs/preview_editor_sticker.json") put(EOResourcePanelKey.PREVIEW_EDITOR_VOICE, "Panel_configs/preview_editor_tone.json") put(EOResourcePanelKey.RECORDER_BEAUTY, "Panel_configs/recorder_beauty.json") put(EOResourcePanelKey.RECORDER_FILTER, "Panel_configs/recorder_filter.json") put(EOResourcePanelKey.RECORDER_MUSIC, "Panel_configs/eo_music.json") put(EOResourcePanelKey.RECORDER_STICKER, "Panel_configs/recorder_sticker.json") put(EOResourcePanelKey.TRACK_EDITOR_MUSIC, "Panel_configs/eo_music.json") put(EOResourcePanelKey.TRACK_EDITOR_SOUND, "Panel_configs/track_editor_sound.json") put(EOResourcePanelKey.TRACK_EDITOR_TRANSITION, "Panel_configs/track_editor_transition.json") }.map { it.key.value to it.value }.toMap() override fun loadConfigs(panelKey: String, type: String): String? { val value = configsPathMap.getValue(panelKey) ?: return null // 从assets读取面板配置文件内容 return EOUtils.fileUtil.readJsonFromAssets(AppSingleton.instance, "${EOUtils.pathUtil.assetsResourcePath}/${value}") } }
通过配置 EffectOneSdk 中 photoEditingMode 的值,可以对 EffectOne 编辑图片文件的方式进行配置
默认会设置为图片编辑模式(MODE_PICTURE)
| 参数名 | 含义 | 类型 |
|---|---|---|
photoEditingMode | 图片编辑的模式 |
|
可以通过EffectOneSdk.activityManager来管理EffectOneSdk中的Activity,包含以下能力:
可以通过类名获取到对应的Activity实例
关闭EffectOne的指定Activity,并设置activity result。启动对应Activity的页面可以在onActivityResult中获取到对应的回调
interface IActivityManager { fun finishActivities(filter: ((activity: AppCompatActivity)-> Boolean)? = null, resultCode: Int? = null, result: Intent? = null) fun <T: AppCompatActivity> getActivity(clazz: Class<T>): AppCompatActivity? }
拍摄页初始化Sample
拍摄部分初始化,包含拍摄页整体初始化、通用面板配置以及美颜面板配置,可以参考以下Sample进行初始化
//Do record init in your activity before launch record class HostActivity: AppCompatActivity { ... override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) ... //拍摄模块整体配置 EffectOneConfigList.configure(RecorderInitConfig()> { it.finishAction = { activity, list, musicItem, ext -> EditorMainActivity.startEditorActivityFromRecord(activity, list.map { resourceItem -> com.volcengine.easyeditor.api.MediaItem( path = resourceItem.path, type = if (resourceItem.type == RecordMediaType.VIDEO) MediaType.VIDEO else MediaType.IMAGE, duration = resourceItem.duration, speed = resourceItem.speed ) } as ArrayList<com.volcengine.easyeditor.api.MediaItem>, null, musicItem, ext) } it.albumConfig = AlbumConfig( allEnable = true, imageEnable = true, videoEnable = true, maxSelectCount = EffectOneSdk.albumMaxSelectedCount, maxDuration = 60 * 60 * 1000L, // maxDuration Unit:ms finishClazz = StartEditorFinishImpl::class.java ) } EffectOneConfigList.configure(BeautyUIConfig()) { it.resourceLoader = DefaultLocalResourceLoader.instance it.defaultBeautyAction = { EOResourceManager.syncLoadConfigByPanelKey(EOResourcePanelKey.RECORDER_BEAUTY.value, true).tabs } } //编辑和拍摄通用面板配置 //滤镜面板 EffectOneConfigList.configure(FilterUIConfig()) { it.resourceLoader = DefaultLocalResourceLoader.instance } //人脸特效面板 EffectOneConfigList.configure(EOBaseStickerUIConfig()) { it.resourceLoader = DefaultLocalResourceLoader.instance } //音乐面板 EffectOneConfigList.configure(EOBaseMusicUIConfig()) { it.resourceLoader = DefaultLocalResourceLoader.instance } //美颜面板 EffectOneConfigList.configure(BeautyUIConfig()) { it.resourceLoader = DefaultLocalResourceLoader.instance it.defaultBeautyAction = { EOResourceManager.syncLoadConfigByPanelKey(EOResourcePanelKey.RECORDER_BEAUTY.value, true).tabs } } ... //启动拍摄页 startRecordBtn.setOnClickListener { val recordPermissions = mutableListOf<String>().apply { add(Manifest.permission.CAMERA) add(Manifest.permission.RECORD_AUDIO) } EOUtils.permission.checkPermissions(activity, recordPermissions, { EORecordActivity.startRecord(activity) }, { RecordUtils.showRecordPermissionTips(activity, it) }) } } ... } class StartEditorFinishImpl : IAlbumFinish { override suspend fun finishAction(activity: Activity, mediaList: List<IMaterialItem>, albumConfig: AlbumConfig) { EditorMainActivity.startEditorActivityFromAlbum(activity, mediaList.map { com.volcengine.easyeditor.api.MediaItem( path = it.path, type = if (it.isVideo()) MediaType.VIDEO else MediaType.IMAGE, duration = if (it.isVideo()) it.duration else 3000 ) } as ArrayList<com.volcengine.easyeditor.api.MediaItem>) } }
| 参数名 | 含义 | 类型 | 接入方实现 | 默认值 |
|---|---|---|---|---|
albumConfig | 相册页面的配置 | AlbumConfig
|
| 无 |
finishAction | 拍摄完成后回调操作 |
RecordMediaItem:拍摄视频/相册内容 |
| 无 |
defaultCameraDirection | 默认摄像头方向 | CameraFacingId
| 选择默认摄像头方向 | FACING_FRONT |
defaultResolution | 默认拍摄分辨率 | ResolutionId
| 选择默认分辨率 | RESOLUTION_1080 |
enableEffectStickerBtn | 是否显示人脸贴纸按钮 | Boolean | ||
enableAlbumBtn | 是否显示相册按钮 | Boolean | ||
selectModelFactory | 拍摄页底部拍摄模式选择工厂类 | 默认实现
可根据需求自定义所需的拍摄时长 |
val recordPermissions = mutableListOf<String>().apply { add(Manifest.permission.CAMERA) add(Manifest.permission.RECORD_AUDIO) } EOUtils.permission.checkPermissions(activity, recordPermissions) { EORecordActivity.startRecord(activity) }
启动拍摄页需要申请CAMERA和RECORD_AUDIO权限,如果宿主Activity继承自FragmentActivity,可以直接使用EOUtils.permission.checkPermissions(activity, recordPermissions)方法完成鉴权操作,如果不是,则需要接入方自己开发鉴权相关,请参考运行时权限申请相关文档。并在获得权限
后,调用 EORecordActivity.startRecord(activity) 启动拍摄页
https://developer.android.com/training/permissions/requesting?hl=zh-cn
| 参数 | 含义 | 类型 | 接入方实现 | 默认值 |
|---|---|---|---|---|
menuList | 侧边栏展示项 | List
| 可调整侧边栏Item顺序、删减侧边栏项 |
|
unfoldCount | 不折叠的数量,超过的item会被折叠 | Int | 选择默认不折叠数 | 5 |
| foldEnabled | 是否开启侧边栏可折叠功能 | Boolean | 控制是否可以开启侧边栏折叠功能 | true |
滤镜、人脸特效、音乐等面板,为拍摄和编辑共用。文档默认使用离线素材管理,如果需要使用其他的素材管理,可自行实现ResourceLoader。DefaultLocalResourceLoader的实现请参考Sample或者参考EffectOne Android 素材管理
//滤镜面板 EffectOneConfigList.configure(FilterUIConfig()> { it.resourceLoader = DefaultLocalResourceLoader.instance } //人脸特效面板 EffectOneConfigList.configure(EOBaseStickerUIConfig()> { it.resourceLoader = DefaultLocalResourceLoader.instance } //音乐面板 EffectOneConfigList.configure(EOBaseMusicUIConfig()> { it.resourceLoader = DefaultLocalResourceLoader.instance it.showInEditor = true // 在预览编辑中音乐UI的总开关 it.showInRecorder = true // 在拍摄中音乐UI的总开关 }
EffectOneConfigList.configure(BeautyUIConfig()> { it.resourceLoader = DefaultLocalResourceLoader.instance it.defaultBeautyAction = { //获取美颜配置中defaultOn = 1的item作为美颜默认项(sdk中会自动过滤,简单处理接入方直接传入整体美颜config即可) EOResourceManager.syncLoadConfigByPanelKey(EOResourcePanelKey.RECORDER_BEAUTY.value, true).tabs } }
EO120 版本额外新增合拍功能,具体业务层的实现如下:
启动相册选图器 -> 选择一个被合拍的视频文件 -> 跳转至拍摄页面进行合拍拍摄
EffectOneConfigList.configure((RecorderDuetUIConfig())) { it.resourceLoader = DefaultLocalResourceLoader.instance it.defaultDuetAction = { EOResourceManager.syncLoadConfigByPanelKey(EOResourcePanelKey.RECORDER_DUET.value, true).tabs } }
CoroutineScope(Dispatchers.IO).launch { loadDefaultDuet() } /** * 使用EOResourceManager对默认合拍布局资源进行加载 * @return : 返回加载结果(true: 加载成功;false: 加载失败) */ private suspend fun loadDefaultDuet() : Boolean { DefaultLocalResourceLoader.instance.loadResourceList(EOResourcePanelKey.RECORDER_DUET.value, "") val duetItems = EOResourceManager.syncLoadConfigByPanelKey( EOResourcePanelKey.RECORDER_DUET.value, true ).tabs.firstOrNull() duetItems?.subItems?.let { subItems -> if (subItems.isNotEmpty()) { DefaultLocalResourceLoader.instance.loadResourceItem(subItems.first()) return true } } return false }
val duetAlbumConfig = AlbumConfig( allEnable = false, imageEnable = false, videoEnable = true, // 只可选择视频类型的文件 maxSelectCount = 1, // 合拍中只能传入一个被合拍的视频文件 finishClazz = StartRecordFinishImpl::class.java, // 选图结束后将启动拍摄页 hintText = "(示例)请选择一段用于合拍的视频文件" ) // StartRecordFinishImpl 详情请参考[2.7.3合拍拍摄页面配置](https://bytedance.larkoffice.com/docx/Mfl3dOTcqoP4kAxf6BOcCjMLn5f#Qu2EdTnQDooGfUxaZJvclzton0b) class StartRecordFinishImpl : IAlbumFinish { override suspend fun finishAction(activity: Activity, mediaList: List<IMaterialItem>, albumConfig: AlbumConfig) { val videoPath = "" val audioPath = "" val bundle = Bundle() bundle.putBoolean("isDuet", true) bundle.putString("duetVideoPath", videoPath) bundle.putString("duetAudioPath", audioPath) EOQuickInitHelper.startRecorder(activity as FragmentActivity, bundle) if (!activity.isFinishing) { activity.finish() } } }
val albumPermissions = mutableListOf<String>().apply { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { add(Manifest.permission.READ_MEDIA_IMAGES) add(Manifest.permission.READ_MEDIA_VIDEO) add(Manifest.permission.READ_MEDIA_AUDIO) } else { add(Manifest.permission.READ_EXTERNAL_STORAGE) add(Manifest.permission.WRITE_EXTERNAL_STORAGE) } // 相机权限和音频录制权限用于选图结束后启动拍摄页 add(Manifest.permission.CAMERA) add(Manifest.permission.RECORD_AUDIO) } EOUtils.permission.checkPermissions(activity, albumPermissions, { AlbumEntrance.startChooseMedia( activity, 1001, duetAlbumConfig ) }, { AlbumEntrance.showAlbumPermissionTips(activity) })
通过合拍功能进入拍摄模块时,需要传入额外的Bundle配置项,来启动拍摄页中合拍相关的功能
| Bundle Key | 含义 | 类型 | 参考值 |
|---|---|---|---|
| isDuet | 是否启用合拍模式 | Boolean | true |
duetVideoPath | 被合拍视频文件的绝对路径 | String | 使用相册页传出的选中视频文件的路径 |
| duetAudioPath | 被合拍音频文件的绝对路径 | String | 如果选中视频文件中存在音轨,则可以同时传入选中视频文件的绝对路径 |
编辑部分初始化,主要包含预览编辑页面侧边栏、通用面板配置、编辑功能面板配置等
编辑页初始化Sample
从相册进入编辑页面与从拍摄进入编辑页面,流程上基本一致,只是参数不同。下面以从相册选择图片/视频之后进入编辑页面为例演示下启动编辑页面整体流程:
class HostActivity: AppCompatActivity { ... override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) ... // 编辑和拍摄通用面板配置 // 滤镜面板 EffectOneConfigList.configure(FilterUIConfig()> { it.resourceLoader = DefaultLocalResourceLoader.instance } // 人脸特效面板 EffectOneConfigList.configure(EOBaseStickerUIConfig()> { it.resourceLoader = DefaultLocalResourceLoader.instance } // 音乐/音效面板 EffectOneConfigList.configure(EOBaseMusicUIConfig()> { it.resourceLoader = DefaultLocalResourceLoader.instance } // 编辑功能面板配置 // 信息贴纸面板 EffectOneConfigList.configure(InfoStickerUIConfig()> { it.resourceLoader = DefaultLocalResourceLoader.instance } // 文本面板 EffectOneConfigList.configure(TextStickerUIConfig()> { it.resourceLoader = DefaultLocalResourceLoader.instance } // 动画特效面板 EffectOneConfigList.configure(EffectPanelUIConfig()> { it.resourceLoader = DefaultLocalResourceLoader.instance } // 录音-音色面板 EffectOneConfigList.configure(AudioFilterUIConfig()> { it.resourceLoader = DefaultLocalResourceLoader.instance } // 转场面板 EffectOneConfigList.configure(TransitionUIConfig()> { it.resourceLoader = DefaultLocalResourceLoader.instance } ... // 启动编辑页面 startEditorBtn.setOnClickListener { EditorMainActivity.startEditorActivityFromAlbum(activity = activity, list = arrayListOf<MediaItem>().apply { add( MediaItem( path = 媒体文件本地路径, type = 媒体文件类型(视频 / 图片), duration = 媒体文件时长 ) ) add( MediaItem( path = 媒体文件本地路径, type = 媒体文件类型(视频 / 图片), duration = 媒体文件时长 ) ) } ) } } ... }
| 参数 | 含义 | 类型 | 接入方实现 | 默认值 |
|---|---|---|---|---|
menuList | 侧边栏展示项 | List
| 可调整侧边栏Item顺序、删减侧边栏项 |
|
unfoldCount | 不折叠的数量,超过的item会被折叠 | Int | 选择默认不折叠数 | 5 |
| foldEnabled | 是否开启侧边栏可折叠功能 | Boolean | 控制是否可以开启侧边栏折叠功能 | true |
滤镜、人脸特效、音乐等面板,为拍摄和编辑共用。文档默认使用离线素材管理,如果需要使用其他的素材管理,可自行实现ResourceLoader。DefaultLocalResourceLoader的实现请参考Sample或者参考EffectOne Android 素材管理
// 滤镜面板 EffectOneConfigList.configure(FilterUIConfig()> { it.resourceLoader = DefaultLocalResourceLoader.instance } // 人脸特效面板 EffectOneConfigList.configure(EOBaseStickerUIConfig()> { it.resourceLoader = DefaultLocalResourceLoader.instance } // 音乐/音效面板 EffectOneConfigList.configure(EOBaseMusicUIConfig()> { it.resourceLoader = DefaultLocalResourceLoader.instance }
在编辑中,文档默认使用离线素材管理,如果需要使用其他的素材管理,可自行实现ResourceLoader。DefaultLocalResourceLoader的实现请参考Sample或者参考EffectOne Android 素材管理
// 信息贴纸面板 EffectOneConfigList.configure(InfoStickerUIConfig()) { it.resourceLoader = DefaultLocalResourceLoader.instance } // 文本面板 EffectOneConfigList.configure(TextStickerUIConfig()) { it.resourceLoader = DefaultLocalResourceLoader.instance } // 动画特效面板 EffectOneConfigList.configure(EffectPanelUIConfig()) { it.resourceLoader = DefaultLocalResourceLoader.instance } // 录音-音色面板 EffectOneConfigList.configure(AudioFilterUIConfig()) { it.resourceLoader = DefaultLocalResourceLoader.instance } // 转场面板 EffectOneConfigList.configure(TransitionUIConfig()) { it.resourceLoader = DefaultLocalResourceLoader.instance }
EO支持配置同一个编辑实例中,一些素材的最大个数,避免素材添加过多,引起性能问题。EO提供的默认值,适用于大部分中端机型。接入方可以根据业务需求,为低端设备配置更低的素材数
| 素材类型 | 参数名 | 默认值 | 备注 |
|---|---|---|---|
| 图片/文字/信息化贴纸 | EditorResourceCountConfig.maxStickerCount | 30 | 最大的贴纸数(文字+图片+信息化贴纸) |
| 音效 | EditorResourceCountConfig.maxSoundEffectCount | 30 | 轨道编辑面板最多可以添加的音效数目 |
EffectOneConfigList.configure(EditorResourceCountConfig()) { it.maxStickerCount = 30 it.maxSoundEffectCount = 30 }
EO在导入素材时支持配置默认画布比例,并支持在比例面板进行画布比例的切换。初始化配置为RatioConfig,支持以下6种比例设置,暂不支持拓展
| 比例值 | 介绍 |
|---|---|
| CanvasAspectRatio.RATIO_ORIGINAL | 设置画布的比例为第一段素材的比例 |
| CanvasAspectRatio.RATIO_9_16 | 设置画布比例 width:height 为 9:16 |
| CanvasAspectRatio.RATIO_3_4 | 设置画布比例 width:height 为 3:4 |
| CanvasAspectRatio.RATIO_1_1 | 设置画布比例 width:height 为 1:1 |
| CanvasAspectRatio.RATIO_4_3 | 设置画布比例 width:height 为 4:3 |
| CanvasAspectRatio.RATIO_16_9 | 设置画布比例 width:height 为 16:9 |
「高级剪辑」-> 「比例」面板中提供上述6个画幅比例的切换能力
//面板功能配置 EffectOneConfigList.configure(RatioConfig()) { it.defaultRatio = CanvasAspectRatio.RATIO_ORIGINAL }
启动相册也需要以下权限,如果宿主是FragmentActivity,可以用EffectOne封装好的权限工具直接申请
val albumPermissions = mutableListOf<String>().apply { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { add(Manifest.permission.READ_MEDIA_IMAGES) add(Manifest.permission.READ_MEDIA_VIDEO) add(Manifest.permission.READ_MEDIA_AUDIO) } else { add(Manifest.permission.READ_EXTERNAL_STORAGE) add(Manifest.permission.WRITE_EXTERNAL_STORAGE) } } EOUtils.permission.checkPermissions(activity, albumPermissions) { //call back after permission all granted }
如果不是FragmentActivity,则需要接入方自己开发鉴权相关,请参考运行时权限申请相关文档。并在获得权限后,启动相册
https://developer.android.com/training/permissions/requesting?hl=zh-cn
/** * 从相册页面选择素材之后,跳转到编辑页面 * @param activity 当前页面 * @param list [MediaItem] 类型的素材列表 * @param options 自定义的附加参数,方便添加转场或者共享元素动画 */ EditorMainActivity.startEditorActivityFromAlbum( activity: Activity, list: ArrayList<MediaItem>, options: Bundle? = null, )
/** * 从拍摄模块拍摄照片或视频之后,跳转到编辑页面 * @param activity 当前页面 * @param list [MediaItem] 类型的素材列表 * @param options 自定义的附加参数,方便添加转场或者共享元素动画 * @param musicItem [EOBaseMusicItem] 类型,拍摄时添加的背景音乐信息 */ EditorMainActivity.startEditorActivityFromRecord( activity: Activity, list: ArrayList<MediaItem>, options: Bundle? = null, musicItem: EOBaseMusicItem? = null, )
EffectOne支持将编辑中的视频保存成草稿,可以通过下方接口跳转草稿页预览草稿或者从草稿恢复视频编辑态
// 如何启动草稿页 EditorDraftActivity.startDraftActivity(activity)
Android UI 定制原理:Android利用apk打包中,同名资源冲突覆盖,支持客户在宿主中通过替换同名的drawable文件以及string、color对应的value,来进行UI定制化。EffectOneSDK中所有支持替换的资源,都会放在Sample中的default_res_files对应模块的目录下。根据EffectOneSDK的UI场景,目前的模块分为相册(album)、拍摄(camera)、编辑-预览编辑(previeweditor)、编辑-轨道编辑-(trackeditor)、基础组件(base)。
注:主页、导出页仅仅提供相关接口的SampleCode,用户需要自己参考实现,不在换皮的范围内
Effect one色卡
EffectOne SDK中所有可替换的颜色都可以在色卡中找到对应的key和色值。对应的资源文件,请参考Sample中的default_res_files/v_x_x/res/color/eo_color_card.xml
如果需要在宿主App中,替换不同的主题色,可以在宿主的res/values/目录下colors.xml中,将需要修改的色卡对应的Color Resource Item (
参考各模块UI标注
EffectOne SDK中除素材的文案外,所有可替换的文案都定义在对应模块的string.xml中,可以在Sample中找到,string.xml会根据模块放在对应的目录下。
如果需要在宿主App中,替换不同的文案(中英文),可以在宿主的res/values/和res/values-zh-rCn/目录下的strings.xml中,将需要修改的String Resource Item(
参考各模块UI标注
EffectOne SDK中除素材外,所有可替换的图标对应的默认drawable文件,可以在Sample中找到,drawable会根据模块放在对应的目录下。为了缩减包大小,EffectOneSDK中绝大部分的默认图标,格式为svg。我们支持也支持用户使用PNG、JPG、WEBP等常见图片格式进行替换
如果需要在宿主App中,替换不同的图标,可以在宿主的drwable目录下(如果是3x的png,需要在drawable-xxhdpi目录下),创建同名的图片文件(文件名相同即可,后缀可以不同,默认为svg导入的.xml)。如何导入svg图片,请参考https://developer.android.com/studio/write/vector-asset-studio。原始图片文件,会存放在default_res_files中对应模块下的drawable文件夹下。
参考各模块UI标注
注意:标注文档中给出的图标建议尺寸单位是3x的图片像素,需要在使用png/jpg/webp等格式图片进行同名替换,并存放在drawable-xxhdpi目录下。如果使用svg进行替换,需要换算为dp。具体dp值可以使用3x像素值除以3或者参考对应资源文件中的svg。svg的xml文件需要放在宿主的drawable目录下
依赖和接入流程,请参考Effectone接入文档-Android。快速接入使用.gradle配置工程,kottlin+Android原生FragmentActivity方式接入。其他语言和框架的接入,可以参考下文,替换快速接入中对应的模块
如果接入方的宿主不是FragmentActivity而是ComponentActivity,EOQuickInitHelper中提供的Android运行时权限相关接口,无法使用,接入方可以参考EOQuickInitHelper.kt的源码,自行实现相关能力。https://developer.android.com/training/permissions/requesting?hl=zh-cn
public class SampleApplication extends Application { @Override public void onCreate() { super.onCreate(); ... EOQuickInitHelper.INSTANCE.setLicenseFileName("20231023_20241023_com.volcengine.effectone_union.licbag"); EOQuickInitHelper.INSTANCE.initApplication(this); } }
public class JavaActivity extends FragmentActivity { private View startRecordBtn; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); startRecordBtn = findViewById(R.id.sample_start_recorder); startRecordBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { EOQuickInitHelper.INSTANCE.prepareAndInit(JavaActivity.this, new Function1<Boolean, Unit>() { @Override public Unit invoke(Boolean it) { if (it) { EOQuickInitHelper.INSTANCE.startRecorder(JavaActivity.this); } else { EOToaster.INSTANCE.show(JavaActivity.this, "Auth Fail", Toast.LENGTH_SHORT); } return null; } }); } }); } }
无Java版本的导出页源码,接入方可以参考SampleCode中kottlin版本的导出页源码以及导出接口文档,自行实现
EffectOne-Android 视频导出接口介绍
.gradle.kts和.gradle对应关系,参考官方文档Example 30:https://docs.gradle.org/8.4/userguide/declaring_repositories.html
//如果使用的是.kts文件进行如下配置 dependencyResolutionManagement { ... repositories { ... maven("https://artifact.bytedance.com/repository/thrall_ck/") { credentials { username = MAVEN_USER_NAME password = MAVEN_PASS_WORD } authentication { create<BasicAuthentication>("basic") } } maven("https://artifact.bytedance.com/repository/thrall_cv/") { credentials { username = MAVEN_USER_NAME password = MAVEN_PASS_WORD } authentication { create<BasicAuthentication>("basic") } } } }
... val effectOneVersion="1.0.0"//对应的effectOneSdk版本号 dependencies { api("com.volcengine.effectone:editor-ui:${effectOneVersion}") api("com.volcengine.effectone:recorder-ui:${effectOneVersion}") //素材加载SDK api("com.volcengine.effectone:base-resource:${effectOneVersion}") //上述三个SDK公用同一个版本号 implementation("com.github.bumptech.glide:glide:4.13.2")// 默认图片库依赖(DefaultImageLoader),可选 implementation("androidx.appcompat:appcompat:1.3.0") //根据宿主环境自行选择版本,推荐1.3.0 } android { ... defaultConfig { ... vectorDrawables.useSupportLibrary = true //支持vetorDrawable,当你需要替换EffectOne中的svg图片时使用 applicationId = "com.volcengine.effectone" //确保包名和授权的包名一致,内测鉴权文件使用此包名 } packaging { ... jniLibs { useLegacyPackaging = true } jniLibs.pickFirsts.add("lib/arm64-v8a/libc++_shared.so") jniLibs.pickFirsts.add("lib/armeabi-v7a/libc++_shared.so") } }
android.useAndroidX=true android.enableJetifier=true
EffectOneSDK的拍摄和剪辑页面,采用内置UI的方式,因此对于Compose接入几乎没有区别。如果接入方宿主不是FragmentActivity,需要自行实现Android运行时权限申请。导出页的高级功能和UI,需要接入方自己开发。下边提供下JectPack Compose接入相关SampleCode
Componet的gradle配置以及Application初始化和普通UI接入无区别
class HostActivity : FragmentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { SampleEffectStudioRecommendTheme { // A surface container using the 'background' color from the theme Surface( modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background ) { Main("Android") } } } } } @Composable fun Main(name: String, modifier: Modifier = Modifier) { Box( modifier = Modifier.fillMaxSize(), ) { val activity = LocalContext.current as FragmentActivity Button(onClick = { EOQuickInitHelper.prepareAndInit(activity) { EOQuickInitHelper.startRecorder(activity) } }, modifier = Modifier.align(Alignment.Center)) { Text( text = "Start Recorder", modifier = modifier ) } } }
同Android原生View接入