You need to enable JavaScript to run this app.
导航
SDK功能详解
最近更新时间:2025.04.16 15:38:44首次发布时间:2025.04.08 17:46:51
我的收藏
有用
有用
无用
无用

资源导入和配置

交付物列表

文件名称文件资源说明使用位置
EffectResourcetransitions.bundle转场资源轨道编辑转场
ModelResource.bundle模型资源各个特效依赖的模型
tone.bundle变声资源预览编辑变声面板
sound.bundle音效资源轨道编辑添加音效
sticker.bundle信息化贴纸资源预览编辑信息化贴纸面板
ve_effect.bundle特效资源预览编辑特效面板
ComposeMakeup.bundle美颜资源拍摄美颜面板
StickerResource.bundle人脸贴纸资源拍摄贴纸面板、预览编辑人脸贴纸面板
fonts.bundle字体资源预览编辑文字面板
music.bundle音乐资源拍摄、预览编辑、轨道编辑音乐面板

filter.bundle
ve_filter.bundle

滤镜资源

拍摄、预览编辑滤镜面板

duet.bundle合拍资源合拍模块
cutsame.bundle剪同款资源剪同款模块
Resource_icons素材相关icon和封面图所有资源对应的icon,面板展示时使用
Resource_videos剪同款预览视频剪同款用
Panel_configs配置文件各个面板层级关系配置,面板展示时使用
RemoteResource客户自行部署按需下载时使用用于服务器部署,素材内置时不需要关注
License鉴权文件用于应用鉴权
配置文件以及对应面板详细说明

EffectOne配置文件及面板对应关系

资源配置「在线&按需下载」

使用场景
  • 场景:点击某个功能项时才下载对应资源

  • 优点:减小包体;避免一次下载所有资源带来的长耗时问题

移动端配置
  • 资源包 EffectResource 无需内置到 App 工程

  • 自定义类实现接口EOResourceRequestBuilderProtocol,分别定义拉取配置请求、下载资源请求、icon加载url。在适当时机,SDK内部会调用该方法,获取对应请求

@protocol EOResourceRequestBuilderProtocol <NSObject>

@required
// 自定义请求对应面板配置数据的 Request
// 在请求面板配置时,会调用这个方法来获取 Request,随后发起请求
- (NSURLRequest * _Nullable)buildConfigURLRequestByPanelKey:(NSString * _Nullable)panelKey resourceInfo:(NSDictionary * _Nullable)resource;

// 自定义图片资源的请求url string
// 在加载每一张icon时,会调用该方法获取url。如果返回空值,那么SDK内部会在尝试在本地路径下获取图片文件
- (NSString * _Nullable)iconUrlString:(NSString * _Nullable)iconName panelKey:(NSString * _Nullable)panelKey;

// 自定义视频资源请求url string
// 获取视频url时,会优先使用该接口获取url
- (NSString * _Nullable)videoUrlString:(NSString * _Nullable)videoName panelKey:(NSString * _Nullable)panelKey;

// 自定义资源下载的 Request
// 资源下载时,对调用该方法,获取下载 Request
- (NSURLRequest * _Nullable)buildResourceDownloadRequestByRelativePath:(NSString * _Nullable)relativePath
                                                               isModel:(BOOL)isModel
                                                          resourceInfo:(NSDictionary * _Nullable)resource;
@end

class EOCustomRequestBuilderImpl: NSObject, EOResourceRequestBuilderProtocol {
    ...
}
  • 将自定义类对象设置给EOSDK
EOInjectContainer.shared().resourceRequestBuilderImpl = EOCustomRequestBuilderImpl()
  • 设置资源加载根路径,下载的资源也将置于该路径下
EOSDK.setResourceBaseDir(EOSDK.getEODocumentRootDir() + "/download_dir")
  • 设置加载模式为在线模式
EOSDK.useRemoteConfig(true, useRemoteResource: true)
服务端配置
  • 服务端需要部署的资源包括

    • 素材和模型资源:使用交付素材包中RemoteResource文件夹下的资源

    • 配置文件:使用交付素材包EffectResource中Panel_configs下的资源

    • icon:使用交付素材包EffectResource中Resource_icons中的资源

  • 根据客户端在 EOResourceRequestBuilderProtocol 实现类中的定义分别部署配置文件、资源、icon图标,确保请求和资源一一对应

TIPS
提供一个最简单的部署方式供参考:

  • 将交付道具包中的 RemoteResource、EffectResource/Panel_configs、EffectResource/Resource_icons 分别上传至文件服务器

  • 客户端在 EOResourceRequestBuilderProtocol 实现类中,分别指向对应资源即可

交付后,不要进行任何资源包的改动、解压、压缩等操作,否则会导致下载失败

资源导入和配置「在线&一次性下发」

使用场景
  • 场景:客户端一次性将资源、模型、icon、配置文件下载

  • 优点:减小包体;服务端部署简单;网络交互少

移动端配置
  • 资源包 EffectResource 无需内置到 App 工程

  • 客户端自行进行下载,在使用任何 SDK 工程之前,确保所有资源下载、解压完毕

  • 进行如下代码配置

let downloadDir = EOSDK.getEODocumentRootDir() + "/download_dir"

// 设置资源下载解压后的目标路径
EOSDK.setResourceBaseDir(EOSDK.defaultResourceDir(downloadDir))

// 设置配置文件下载解压后的目标路径
EOSDK.setResourceDefaultBuiltInConfig(EOSDK.defaultPanelConfigDir(downloadDir))

// 使用在线模式
EOSDK.useRemoteConfig(true, useRemoteResource: true)
服务端配置
  • 对齐客户端网络请求,提供资源包下载

建议资源包下载格式为:直接将 EffectResource 压缩成 zip,作为下载的资源

资源导入和配置「内置」

使用场景
  • 场景:资源包均内置到工程中

  • 优点:离线使用,无需服务器部署

移动端配置
  • 将 EffectResource 文件夹直接放置到 EOLocalResources.bundle 里,打包到 App 中

  • 在使用任何 SDK 特效之前,做好如下配置

// 设置资源根路径
EOSDK.setResourceBaseDir(EOSDK.defaultResourceDir(localBundle().bundlePath))

// 设置配置文件根路径
EOSDK.setResourceDefaultBuiltInConfig(EOSDK.defaultPanelConfigDir(localBundle().bundlePath))

资源导入和配置「部分内置+部分在线」

使用场景
  • 场景:部分资源内置,来加快资源加载速度;其余资源部署到线上,减小包体

  • 优点:实现加载速度和包体之间的平衡

移动端配置
  • 参考「在线&按需下发」配置在线请求参数

  • 参考「内置」场景,将需要内置的资源包放置到工程中打包,设置内置资源路径

// 设置内置资源路径
EOSDK.setBuiltInResourceDir(localBundle().bundlePath)
  • 设置资源根路径。在线素材将被下载到这里,内置素材在使用之前也会拷贝到这里
// 设置资源根路径
EOSDK.setResourceBaseDir(EOSDK.defaultResourceDir(localBundle().bundlePath))
  • 设置配置文件加载路径,如果不配置,将会尝试从远端拉取配置文件
// 设置配置文件根路径
EOSDK.setResourceDefaultBuiltInConfig(EOSDK.defaultPanelConfigDir(localBundle().bundlePath))
  • 配置SDK使用在线模式
// 使用在线模式
EOSDK.useRemoteConfig(true, useRemoteResource: true)
服务端配置
  • 根据部署情况,参考「在线&按需下发」或者「在线&一次性下发」在服务端部署资源

设置内置资源(图标、国际化文案等)的根目录

// 设置外部资源路径,
let resourcePath = "外部资源路径"
EOSDK.setBuiltInResourceRootPath(resourcePath)

配置拍摄模块中用户录制的视频片段的缓存路径

  • 调用 EOSDK 这个类中的 setCustomRecoderCacheDir 方法,以下是示例方法:
private func setCustomRecoderCacheDir() {
        let documentsDirectory = FileManager.default.temporaryDirectory
        let customFolderPath = documentsDirectory.appendingPathComponent("CustomRecoderCacheDir")
        EOSDK.setCustomRecoderCacheDir(customFolderPath.path)
    }

鉴权配置

鉴权逻辑用于控制SDK功能的可用性,拥有对应的授权才能使用相应的功能。

鉴权相关接口说明(在线鉴权相关接口建设中,暂不可用)

类名字段与方法类型说明备注

EOAuthorizationConfig

isOnline

BOOL

True 表示在线鉴权,False表示离线鉴权

isOverseaBOOLTrue表示使用海外鉴权服务,False表示使用国内鉴权服务
licensePathForOfflineNSString*离线证书的绝对路径
licenseTokenForOnlineNSString*在线证书的token
EOAuthorization+ (instancetype)sharedInstance;获取EOAuthorization对象实例
-(void)makeAuthWithConfig:(EOAuthorizationConfig*)config completionHandler:(EOAuthCompletionHandler)completionHandler;进行鉴权,鉴权结果通过EOAuthCompletionHandler获取(其中在线鉴权是异步的)
- typedef void (^EOAuthCompletionHandler)(BOOL success, NSString* errMsg);获取鉴权结果,其中success表示鉴权是否成功,当失败时,通过errMsg获取错误信息可根据错误信息排查错误或者发给技术顾问协助排查

离线鉴权

如果选择离线鉴权方式,鉴权证书通常会跟随交付产物一同交付给客户,且通常放置在EOLocalResources\Resources\License\XXX.licbag ,找到该文件并在app的启动阶段添加鉴权逻辑,例如:

let config = EOAuthorizationConfig { initializer in
            //鉴权方式是离线鉴权
            initializer.isOnline = false            
            //设置离线证书所在的路径
            initializer.licensePathForOffline = //证书文件的路径
        }
        //开始鉴权
        EOAuthorization.sharedInstance().makeAuth(with: config) {isSuccess, errMsg in
            self.isAuthSucceeded = isSuccess
            //鉴权失败打印错误码
            if !self.isAuthSucceeded {
                print(errMsg)
            }
        }
    }

离线鉴权证书更新需要客户自行处理。

在线鉴权(建设中,当前只支持国内)

如果选择在线鉴权方式,需要根据客户所在区域(国内或海外)申请相应的鉴权服务token,在app的启动阶段添加鉴权逻辑,例如:

let config = EOAuthorizationConfig { initializer in
            //鉴权方式是在线鉴权
            initializer.isOnline = true  
            //使用海外鉴权服务
            initializer.isOversea = true          
            //设置在线鉴权的token
            initializer.licenseTokenForOnline = //token
        }
        //开始鉴权
        EOAuthorization.sharedInstance().makeAuth(with: config) {isSuccess, errMsg in
            self.isAuthSucceeded = isSuccess
            //鉴权失败打印错误码
            if !self.isAuthSucceeded {
                print(errMsg)
            }
        }
    }

在线鉴权证书更新无需客户处理。

拍摄组件使用与配置详解

  1. 设置项

使用构造器模式,config 所有对外暴露的属性均为 readonly。统一通过对应的 initializer 来初始化。
EORecorderConfig 为配置容器,是拍摄页初始化参数。所有子配置均在该类下:

类名字段与方法类型说明备注

EORecorderConfig

modelPath

NSString

拍摄器使用的模型文件路径,默认值 EOBaseKit.modelResourceDir

cameraPositionAVCaptureDevicePosition拍摄器默认摄像头,默认前置 AVCaptureDevicePositionFront

videoResolution

EORecorderVideoResolution

拍摄器采集分辨率,有 540p/720p/1280p/4k 4种选择 采集分辨率与硬件设备有关,部分旧设备前置摄像头只能支持到 720p iPhone 7 以及之后的 iPhone 默认值 EORecorderVideoResolution1080p,旧设备默认值EORecorderVideoResolution720p

recorderViewControllerConfigEORecorderViewControllerConfig拍摄页 ViewController 配置类,可进行 UI 相关配置,例如侧边栏设置(详见 2. 侧边栏)

- (instancetype)initWithBlock:(void (^)(EORecorderConfigInitializer *))block

初始化函数,使用构造器模式,config 所有对外暴露的属性均为 readonly。统一通过对应的 initializer 来初始化。使用详见下面代码样例。

类定义:

@interface EORecorderConfig : NSObject

// 拍摄器使用的模型文件路径,默认值 EOBaseKit.modelResourceDir
@property (nonatomic, copy, readonly) NSString *modelPath;

// 拍摄器默认摄像头,默认前置 AVCaptureDevicePositionFront
@property (nonatomic, assign, readonly) AVCaptureDevicePosition cameraPosition;

// 拍摄器采集分辨率,有 540p/720p/1280p/4k 4种选择
// 采集分辨率与硬件设备有关,部分旧设备前置摄像头只能支持到 720p
// iPhone 7 以及之后的 iPhone 默认值 EORecorderVideoResolution1080p,
// 旧设备默认值 EORecorderVideoResolution720p
@property (nonatomic, assign, readonly) EORecorderVideoResolution videoResolution;

// 拍摄页 ViewController 配置类
@property (nonatomic, strong, readonly) EORecorderViewControllerConfig *recorderViewControllerConfig;

// 初始化函数
- (instancetype)initWithBlock:(void (^)(EORecorderConfigInitializer *))block;

@end

设置模型文件路径:

let config = EORecorderConfig { initializer in
    // 设置模型文件路径
    initializer.modelPath = EOBaseKit.modelResourceDir()
}

设置拍摄页 ViewController,拍摄一级页面设置类:

类名字段与方法类型说明备注

EORecorderViewControllerConfig

sideBarConfig

EORecorderSideBarConfig

侧边栏配置类

musicBarHiddenBOOL隐藏音乐栏,默认值 NO
stickerButtonHiddenBOOL隐藏人脸贴纸按钮,默认值 NO
albumButtonHiddenBOOL隐藏相册按钮,默认值 NO

-(instancetype)initWithInitializer:(EORecorderViewControllerConfigInitializer *)initializer

初始化函数

类定义:

@interface EORecorderViewControllerConfig : NSObject

// 侧边栏配置类
@property (nonatomic, strong, readonly) EORecorderSideBarConfig *sideBarConfig;

/// Top middle music bar visible
/// default `NO`
@property (nonatomic, assign) BOOL musicBarHidden;

/// Bottom left sticker button visible
/// default `NO`
@property (nonatomic, assign) BOOL stickerButtonHidden;

/// Bottom right sticker button visible
/// default `NO`
@property (nonatomic, assign) BOOL albumButtonHidden;

// 初始化函数
- (instancetype)initWithInitializer:(EORecorderViewControllerConfigInitializer *)initializer;

@end
  1. 侧边栏

侧边栏设置类:

类名字段与方法类型说明备注

EORecorderSideBarConfig

itemKeys

NSMutableArray

侧边栏元素 key 数组,默认提供下面 6 个元素,支持调整展示顺序,暂不支持新增自定义元素 默认值 @[ EORecordBarItemRotateCameraKey, // 翻转摄像头 EORecordBarItemFlashKey, // 闪光灯 EORecordBarItemTimerKey, // 倒计时 EORecordBarItemFiltersKey, // 滤镜 EORecordBarItemBeautyKey, // 美颜 EORecordBarItemSpeedKey, // 倍速 ]

unfoldCountNSUInteger从顶部开始计数,不折叠的元素数量
foldEnabledBOOL侧边栏折叠功能开关,默认值 YES

类定义:

@interface EORecorderSideBarConfig : NSObject

// 侧边栏元素 key 数组,默认提供下面 6 个元素,支持调整展示顺序,暂不支持新增自定义元素
// 默认值 @[
//     EORecordBarItemRotateCameraKey, // 翻转摄像头
//     EORecordBarItemFlashKey, // 闪光灯
//     EORecordBarItemTimerKey, // 倒计时
//     EORecordBarItemFiltersKey, // 滤镜
//     EORecordBarItemBeautyKey, // 美颜
//     EORecordBarItemSpeedKey, // 倍速
// ]
@property (nonatomic, strong) NSMutableArray<EORecordSideBarItemKey> *itemKeys;

// 从顶部开始计数,不折叠的元素数量
@property (nonatomic, assign) NSUInteger unfoldCount;

/// Control the fold mode for sidebar
/// default is `YES`
@property (nonatomic, assign) BOOL foldEnabled;

@end

使用例子:

let config = EORecorderConfig { initializer in    
    initializer.configRecorderViewController { recorderVCInitializer in
        // 调整侧边栏功能按钮顺序
        recorderVCInitializer.sideBarConfig.itemKeys.exchangeObject(at: 0, withObjectAt: 1)
    }
}
  1. 回调

回调协议:

协议名/类名字段与方法类型说明备注

EORecorderViewControllerDelegate

- (void)recorderViewController:(EORecorderViewController *)recorderViewController didFinishRecordingMediaWithInfo:(EORecordInfo *)info

拍摄完成回调,回调数据封装在EORecordInfo 实例中

这里可以取到录制的视频(非编辑)

- (void)recorderViewControllerDidCancel:(EORecorderViewController *)recorderViewController拍摄页关闭回调。如果实现了这个方法,SDK 内部不会 dismiss,需要调用方处理

-(void)recorderViewControllerDidTapAlbum:(EORecorderViewController *)recorderViewController

拍摄页相册按钮回调

EORecordInfo

mediaAssets

NSArray<id> *

media 数据

backgroundMusic

id

拍摄页选择的背景音乐

sourceEORecordInfoSource数据来源,相机/相册
coverImageUIImage *mediaAssets 中第一个数据的第一帧图片

协议定义:

@protocol EORecorderViewControllerDelegate <NSObject>

@optional
- (void)recorderViewController:(EORecorderViewController *)recorderViewController didFinishRecordingMediaWithInfo:(EORecordInfo *)info;
- (void)recorderViewControllerDidCancel:(EORecorderViewController *)recorderViewController;
- (void)recorderViewControllerDidTapAlbum:(EORecorderViewController *)recorderViewController;

@end

使用例子:

extension EffectOneModule: EORecorderViewControllerDelegate {
    func recorderViewControllerDidTapAlbum(_ recorderViewController: EORecorderViewController) {
        self.recorderVC = recorderViewController

        guard let resourcePicker = EOInjectContainer.shared().resourcePickerSharedImpl else {
            return
        }
        
        resourcePicker.pickResourcesFromRecorder { [weak self] resources, error, cancel in
            guard !resources.isEmpty else {
                return;
            }
            
            let info = EORecordInfo()
            info.mediaAssets = resources
            info.source = .album
            
            if let presenter = self?.topMostViewController() {
                self?.showEditorViewController(info: info, presenter: presenter)
            }
        }
    }
    
    func recorderViewController(_ recorderViewController: EORecorderViewController, didFinishRecordingMediaWith info: EORecordInfo) {
        self.recorderVC = recorderViewController
        
        self.showEditorViewController(info: info, presenter: recorderViewController)
    }
}
  1. Navigation push

SDK 默认使用 present 方式展示 UI,V1.1.0 新增 navigation push 支持。代码样例:

EORecorderViewController.requestMediaAuth { [weak self] granted in
    guard granted else {
        self?.showToast("Request media auth failed")
        return
    }
    guard let strongSelf = self else {
        return
    }
    
    do {
        let recorderViewController = try EORecorderViewController(config: config)
        recorderViewController.delegate = strongSelf
        strongSelf.parentVC.navigationController?.pushViewController(recorderViewController, animated: true)
    } catch {
        self?.showToast("show recorder failed: \(error)")
    }
}
  1. 合拍功能

    1. 功能介绍:

      合拍功能是选择一个本地视频之后,调起相机功能,并通过一个资源包来控制合拍视频与相机画面在预览视图中的布局。本地视频会在开拍时开始播放,拍摄结束后停止播放,合拍图像会跟相机图像在相关布局下一起记录到拍摄的视频中。

    2. 前置条件

      1. 需要有本地视频和合拍布局资源包。

        1. 本地视频可以从服务器下载也可以在相册选取。

        2. 资源包需要提前下载到本地,bundle名字为 duet.bundle ,如有采购交付资源中会包含。

      2. 相机权限及麦克风权限

    3. 接口介绍

      1. 从相册选取视频

        EOResourcePickerImpl ,可以通过工具类获取

        //1
        EOInjectContainer.shared().resourcePickerSharedImpl
        //2
        - (void)pickVideoForDuetWithCompletion:(nonnull EOResourcePickerCompletion)completion;
        
      2. 创建合拍控制器

      EODuetViewController:

      + (void)startDuetWithConfig:(EORecorderConfig *)config
                        presenter:(UIViewController *)presenter
                     duetVideoURL:(NSURL *)videoURL
                         delegate:(id<EORecorderViewControllerDelegate> _Nullable)delegate
                       completion:(void (^)(NSError * _Nullable error))completion;
      

      EORecorderConfig:
          musicBarHidden 属性会被设置为 true;
          sideConfig 中会增加 barItemMicKey 和 barItemDuetLayoutKey;其中 barItemMicKey 用于增加麦克风的开关,barItemDuetLayoutKey 用于增加合拍布局的入口。

      let config = EORecorderConfig { initializer in
                  // config recorder if needed
                  
                  initializer.configRecorderViewController { recorderVCInitializer in
                      // config recoderViewController if needed
                      
                      recorderVCInitializer.musicBarHidden = true
                      if let stickerButtonHidden: Bool = DebugConfig.value(forKey: "recorderStickerButtonHidden") {
                          recorderVCInitializer.stickerButtonHidden = stickerButtonHidden
                      }
                      if let albumButtonHidden: Bool = DebugConfig.value(forKey: "recorderAlbumButtonHidden") {
                          recorderVCInitializer.albumButtonHidden = albumButtonHidden
                      }
                      var sideConfig = EORecorderSideBarConfig()
                      sideConfig.itemKeys = [EORecordSideBarItemKey.barItemRotateCameraKey,
                                             EORecordSideBarItemKey.barItemFlashKey,
                                             EORecordSideBarItemKey.barItemMicKey,
                                             EORecordSideBarItemKey.barItemDuetLayoutKey,
                                             EORecordSideBarItemKey.barItemTimerKey,
                                             EORecordSideBarItemKey.barItemFiltersKey,
                                             EORecordSideBarItemKey.barItemBeautyKey,
                                             EORecordSideBarItemKey.barItemSpeedKey,]
                      recorderVCInitializer.sideBarConfig = sideConfig
                  }
              }
      
    4. 接入样例

      1. 相册选取

        public func showDuetViewController() {
                if !self.isAuthSucceeded {
                    self.showToast("authority is failed!,please check it.")
                    return
                }
                
                EOAlbumHelper.eoCheckAlbumAuthorized { [weak self] in
                    guard let resourcePicker = EOInjectContainer.shared().resourcePickerSharedImpl else {
                        return
                    }
                    
                    resourcePicker.pickVideoForDuet(completion: { [weak self] resources, error, cancel in
                        if let resorce = resources.first {
                            self?.gotoDuetViewController(withVideoURL: resorce.url!)
                        }
                        
                    })
                    
                } restrictedOrDenied: { [weak self] in
                    self?.showAlert(withTitle: NSLocalizedString("eo_home_camera_album_unauth_alert_title", comment: ""),
                                          message: NSLocalizedString("eo_home_camera_album_unauth_alert_message", comment: ""),
                                          cancelTitle: NSLocalizedString("eo_home_camera_unauth_alert_cancel", comment: ""),
                                          confirmTitle: NSLocalizedString("eo_home_camera_unauth_alert_confirm", comment: ""),
                                          cancelHandler: nil,
                                          confirmHandler: {
                        if #available(iOS 10.0, *) {
                            UIApplication.shared.open(URL(string: UIApplication.openSettingsURLString)!, options: [:]) { success in
                                // Completion handler
                            }
                        } else {
                            UIApplication.shared.openURL(URL(string: UIApplication.openSettingsURLString)!)
                        }
                    })
                }
        
                
            }
        
      2. 进入合拍

      public func gotoDuetViewController(withVideoURL videoURL:URL) {
              if !self.isAuthSucceeded {
                  self.showToast("authority is failed!,please check it.")
                  return
              }
              
              updateImageEditingEnabledIfNeeded()
                      
              let config = EORecorderConfig { initializer in
                  // config recorder if needed
                  
                  initializer.configRecorderViewController { recorderVCInitializer in
                      // config recoderViewController if needed
                      
                      recorderVCInitializer.musicBarHidden = true
                      if let stickerButtonHidden: Bool = DebugConfig.value(forKey: "recorderStickerButtonHidden") {
                          recorderVCInitializer.stickerButtonHidden = stickerButtonHidden
                      }
                      if let albumButtonHidden: Bool = DebugConfig.value(forKey: "recorderAlbumButtonHidden") {
                          recorderVCInitializer.albumButtonHidden = albumButtonHidden
                      }
                      var sideConfig = EORecorderSideBarConfig()
                      sideConfig.itemKeys = [EORecordSideBarItemKey.barItemRotateCameraKey,
                                             EORecordSideBarItemKey.barItemFlashKey,
                                             EORecordSideBarItemKey.barItemMicKey,
                                             EORecordSideBarItemKey.barItemDuetLayoutKey,
                                             EORecordSideBarItemKey.barItemTimerKey,
                                             EORecordSideBarItemKey.barItemFiltersKey,
                                             EORecordSideBarItemKey.barItemBeautyKey,
                                             EORecordSideBarItemKey.barItemSpeedKey,]
                      recorderVCInitializer.sideBarConfig = sideConfig
                  }
              }
              
              EODuetViewController.startDuet(with: config, presenter: self.parentVC,duetVideoURL:videoURL, delegate: self, completion: { [weak self] error in
                  if let err = error as? NSError, let presenter = self?.parentVC {
                      self?.showErrorAlert(err, presenter: presenter)
                  }
              })
          }
      


编辑组件使用与配置详解

  1. 设置项

EOEditorConfig
  使用构造器模式,config 所有对外暴露的属性均为 readonly。统一通过对应的 initializer 来初始化。
  EOEditorConfig 为配置容器,是编辑页初始化参数。所有子配置均在该类下:

类名字段与方法类型说明备注

EOEditorConfig

videoEditorConfig

EOVideoEditorViewControllerConfig

编辑页 ViewController 配置类,可进行 UI 相关配置,例如侧边栏设置(详见 b. 侧边栏)

- (instancetype)initWithBlock:(void (^)(EOEditorConfigInitializer *))block;

初始化函数,使用构造器模式,config 所有对外暴露的属性均为 readonly。统一通过对应的 initializer 来初始化。使用详见下面代码样例。

类定义:

@interface EOEditorConfig : NSObject

@property (nonatomic, strong, readonly) EOVideoEditorViewControllerConfig *videoEditorConfig;

- (instancetype)initWithBlock:(void (^)(EOEditorConfigInitializer *))block NS_DESIGNATED_INITIALIZER;

@end

设置编辑页ViewController,编辑一级页面设置类:

类名字段与方法类型说明备注

EOVideoEditorViewControllerConfig

sideBarConfig

EOEditorSideBarConfig

侧边栏配置类

musicBarHiddenBOOL隐藏音乐栏,默认值 NO
textAndInfoStickerMaxLimitNSInteger文字和信息贴纸最大使用数量,默认值30
soundEffectMaxLimitNSInteger音效最大使用数量,默认值30

- (instancetype)initWith:(EOVideoEditorViewControllerConfigInitializer *)initializer;

初始化函数

类定义:

@interface EOVideoEditorViewControllerConfig : NSObject

@property (nonatomic, strong, readonly) EOEditorSideBarConfig *sideBarConfig;

@property (nonatomic, assign) BOOL musicBarHidden;

@property (nonatomic, assign, readonly) NSInteger textAndInfoStickerMaxLimit;

@property (nonatomic, assign, readonly) NSInteger soundEffectMaxLimit;

- (instancetype)initWith:(EOVideoEditorViewControllerConfigInitializer *)initializer;

@end

EOEditorSceneConfig
  EOEditorSceneConfig用于配置进入编辑页的场景:

类名字段与方法类型说明备注

EOEditorSceneConfig

draftModel

EOSDKDraftModel

草稿模型,用于从草稿再次进入编辑的场景。

resources

NSArray<id>

用于拍摄或者从相册选择素材后进入编辑的场景

backgroundMusicid拍摄场景下选择的BGM
coverImageUIImage拍摄场景下首帧画面,优化跳转体验
previewContentModeEOEditorPreviewContentMode视频显示模式

ratio

EOEditorVideoRatio

配置视频画布比例,默认为EOEditorVideoRatio9_16。

EOEditorVideoRatioOriginal :基于第一个素材的比例
EOEditorVideoRatio9_16:宽高比9:16
EOEditorVideoRatio3_4:宽高比3:4
EOEditorVideoRatio1_1:宽高比1:1
EOEditorVideoRatio4_3:宽高比4:3
EOEditorVideoRatio16_9:宽高比16:9

  • 如果从草稿恢复,可以给draftModel赋值

  • 如果从拍摄页进入编辑,可以将从拍摄页得到的媒体数据设置给resources/backgroundMusic/coverImage这几个字段

@interface EOEditorSceneConfig : NSObject

/// Restore from draft
@property (nonatomic, strong) EOSDKDraftModel *draftModel;

/// Resources from Recorder or Album
@property (nonatomic, copy) NSArray<id<EOMediaAssetProtocol>> *resources;

/// Selected BGM Resource from Recorder
@property (nonatomic, strong, nullable) id<EOResourceProtocol> backgroundMusic;

/// First resource thumbnail from Recorder
@property (nonatomic, strong, nullable) UIImage *coverImage;

/// Default is `EOEditorPreviewContentModeAspectFit`
@property (nonatomic, assign) EOEditorPreviewContentMode previewContentMode;

@end

  1. 侧边栏

侧边栏设置类:

类名字段与方法类型说明备注

EOEditorSideBarConfig

itemKeys

NSMutableArray

侧边栏元素 key 数组,默认提供下面 7 个元素,支持调整展示顺序,暂不支持新增自定义元素 默认值 @[ EOEditorBarItemKeyClip, // 剪辑 EOEditorBarItemKeyText, // 文本 EOEditorBarItemKeySticker, // 信息贴纸 EOEditorBarItemKeyFilter, // 滤镜 EOEditorBarItemKeyEffect, // 特效 EOEditorBarItemKeyFaceSticker, // 人脸特效
EOEditorBarItemKeyVoice // 音效 ]

unfoldCountNSUInteger从顶部开始计数,不折叠的元素数量
foldEnabledBOOL侧边栏折叠功能开关,默认值 YES

@interface EOEditorSideBarConfig : NSObject

/// Array of keys that presenting right side bar items.
/// Could change the order. Custom new items not supported yet.
/// default order: [ 
///     EOEditorBarItemKeyClip,
///     EOEditorBarItemKeyText,
///     EOEditorBarItemKeySticker,
///     EOEditorBarItemKeyFilter,
///     EOEditorBarItemKeyEffect,
///     EOEditorBarItemKeyFaceSticker,
///     EOEditorBarItemKeyVoice
/// ]
@property (nonatomic, strong) NSMutableArray<EOEditorBarItemKey> *itemKeys;

/// The number of side bar items that would not be folded,
/// count from the first object of `itemKeys`
/// default is `5`
@property (nonatomic, assign) NSUInteger unfoldCount;

/// Control the fold mode for sidebar
/// default is `YES`
@property (nonatomic, assign) BOOL foldEnabled;

@end

使用例子:

let config = EOEditorConfig { initializer in
    initializer.configVideoEditorViewController { editorVCInitializer in
        // 调整侧边栏功能按钮顺序
        editorVCInitializer.sideBarConfig.itemKeys.exchangeObject(at: 0, withObjectAt: 1)
    }
}

let sceneConfig = EOEditorSceneConfig()
sceneConfig.resources = info.mediaAssets
sceneConfig.backgroundMusic = info.backgroundMusic
sceneConfig.coverImage = info.coverImage

// 如果想使用本地资源直接进入编辑,也可以如下构造一个遵循EOMediaAssetProtocol协议的模型,并设置给sceneConfig.resources
// let asset = EOMediaAssetDefaultImpl()
// asset.url = URL(fileURLWithPath: Bundle.main.path(forResource: "localVideo", ofType: "mp4") ?? "");
// sceneConfig.resources = [asset]

EOVideoEditorViewController.startEditor(with: config, sceneConfig: sceneConfig, presenter: presenter, delegate: self) { [weak self, weak presenter] error in
    if let err = error as? NSError, let vc = presenter {
        self?.showErrorAlert(err, presenter: vc)
    }
};
  1. 图片编辑

V1.1.0 新增图片编辑功能,默认开启。全局配置类:

类名字段与方法类型说明备注
EOBusinessConfigimageEditingEnabledBOOL图片编辑功能开关,默认值 YES
@interface EOBusinessConfig : NSObject

/// Single image could be editing as image mode or shot video mode,
/// set `YES` to let editor process and export the input image as image, otherwise as video.
/// default `YES`
@property (nonatomic, assign) BOOL imageEditingEnabled;

@end

使用例子:

// disable image editing
EOSDK.businessConfig().imageEditingEnabled = false
  1. Navigation push

SDK 默认使用 present 方式展示 UI,V1.1.0 新增 navigation push 支持。代码样例:

if let editorViewController = EOVideoEditorViewController(config: config, sceneConfig: sceneConfig) {
    editorViewController.delegate = self
    presenter.navigationController?.pushViewController(editorViewController, animated: true)
} else {
    self.showToast("show editor failed")
}

草稿组件使用与配置详解

草稿页面
V1.1.0 接口变更,草稿页面不在sdk内部调起编辑页,需要调用者实现EODraftBoxControllerDelegate,收到draftBoxController:didSelectDraft: 消息后自行调起

@protocol EODraftBoxControllerDelegate <NSObject>
@optional
- (void)draftBoxControllerDidCancel:(EODraftBoxController *)draftBoxController;
- (void)draftBoxController:(EODraftBoxController *)draftBoxController didSelectDraft:(EOSDKDraftModel *)draftModel;
@end

@interface EODraftBoxController : UIViewController

@property (nonatomic, weak) id<EODraftBoxControllerDelegate> delegate;

+ (void)presentDraftVCDelegate:(id<EODraftBoxControllerDelegate>)delegate;

//presentVC 基于该控制器进行present,presentVC需要为置顶VC
+ (void)presentDraftVCDelegate:(id<EODraftBoxControllerDelegate>)delegate presentVC:(UIViewController *)presentVC;

@end

实现delegate例子

extension EffectOneModule: EODraftBoxControllerDelegate {
    func draftBoxController(_ draftBoxController: EODraftBoxController, didSelectDraft draftModel: EOSDKDraftModel) {
        self.showEditorViewController(.draft(draftModel), presenter: draftBoxController)
    }
}

调起方式

//第一种方式
EODraftBoxController.presentDraftVCDelegate(self)
//第二种方式
EODraftBoxController.presentDraftVCDelegate(self, presentVC: viewController)

相册组件使用与配置详解

该组件是EffectOneSDK提供的一个独立组件,支持多选、单选、图片预览、视频预览、图片裁剪等功能,可用于其他需要相册业务中。

相册主要类说明

DAKResourcePicker
说明:负责相册的调用
/// 调用相册
/// - 参数:
///   - config: 相册配置
///   - completion: 相册调用结束回调
- (void)pickResourceWithConfig:(DAKResourcePickerConfig *)config
                    completion:(DAKResourcePickerCompletion)completion;
DAKResourcePickerConfig
相册配置类,可根据业务需要配置

部分属性说明如下

属性类型描述说明默认值注意

hintText

NSString

相册列表底部文案

{zh}:你可以选择图片和视频
{en}:You can select both photos and videos

使用的是文本key为:eo_album_tips

minDurationNSUInteger最小视频时长,单位是毫秒默认是 100 毫秒
maxDurationNSUInteger最大视频时长,单位是毫秒默认是 60 * 60 * 1000 毫秒
maxSelectCountNSUInteger选择相册资源的最大个数默认是 35
minSelectCountNSUInteger选择相册资源的最小个数默认是 1
imageEnableBOOL是否允许选择图片默认 YES
videoEnableBOOL是否允许选择视频默认 YES
allEnableBOOL是否允许选择图片和视频默认 YES
showGifBOOL是否显示gif图默认 YES
singleSelectBOOL是否是单选默认 NO
canRepeatBOOL相册资源是否允许重复选择默认 YES
gifMaxFileSizeCGFloatgif图文件支持的最大值,单位:MB默认150MB
gifPixelWidthMaxCGFloatgif图分辨率宽度支持的最大值默认1920
gifPixelHeightMaxCGFloatgif图分辨率长度支持的最大值默认1920
/// 相册列表底部文案
@property (nonatomic, copy) NSString *hintText;

/// 最小视频时长,单位是毫秒,默认是 100 毫秒
@property (nonatomic, assign) NSUInteger minDuration;

/// 最大视频时长,单位是毫秒, 默认是 60 *  60  * 1000 毫秒
@property (nonatomic, assign) NSUInteger maxDuration;

/// 选择相册资源的最大个数, 默认是 35
@property (nonatomic, assign) NSUInteger maxSelectCount;

/// 选择相册资源的最小个数, 默认是 1
@property (nonatomic, assign) NSUInteger minSelectCount;

/// 是否允许选择图片, 默认YES
@property (nonatomic, assign) BOOL imageEnable;

/// 是否允许选择视频, 默认YES
@property (nonatomic, assign) BOOL videoEnable;

/// 是否允许选择图片和相册, 默认YES
@property (nonatomic, assign) BOOL allEnable;

/// 是否显示gif图, 默认YES
@property (nonatomic, assign) BOOL showGif;

/// 是否是单选, 默认 NO
@property (nonatomic, assign) BOOL singleSelect;

/// 相册资源是否允许重复选择,默认YES
@property (nonatomic, assign) BOOL canRepeat;

/// Maximum size of GIF image memory,unit is MB, default max is 150MB,that is 150 *  1024  * 1024 bytes
@property (nonatomic, assign) CGFloat gifMaxFileSize;

/// Maximum pixel width of GIF image, default max is 1920
@property (nonatomic, assign) CGFloat gifPixelWidthMax;

/// Maximum pixel height of GIF image, default max is 1920
@property (nonatomic, assign) CGFloat gifPixelHeightMax;
DAKResourcePickerModelProtocol
选中相册完成后回调数组元素类型协议

使用到函数说明

函数名描述说明拓展

-(DVEAlbumAssetMediaType)type;

获取相册资源的类型

返回 DVEAlbumAssetMediaType 枚举类型,DVEAlbumAssetMediaTypeVideo 是 视频类型
DVEAlbumAssetMediaTypeImage 是图片类型

-(NSData *)imageData;相册资源二进制数据
-(NSURL *)videoURL;相册资源的地址路径
DAKResourcePickerModel
遵守DAKResourcePickerModelProtocol协议,选中相册完成后回调数组元素

使用属性说明

属性描述说明拓展

type

获取相册资源的类型

返回 DVEAlbumAssetMediaType 枚举类型,DVEAlbumAssetMediaTypeVideo 是 视频类型
DVEAlbumAssetMediaTypeImage 是图片类型

imageData相册资源二进制数据
videoURL相册资源的地址路径
调用相册样例
// 首选声明DAKResourcePicker对象
    private lazy var resourcePicker = {
        return DAKResourcePicker()
    }()
    // 调用相册
    let config = DAKResourcePickerConfig()
    //不支持单选
    config.singleSelect = false
    //选择视频、图片
    config.pickType = .imageVideo
    resourcePicker.pickResource(with: config) { [weak self] resources in
         //用户根据自己业务逻辑处理相册回调结果
    }

视频导出组件使用与配置详解

导出界面考虑到客户一般都会定制,因此将这部分代码以开源的形式放入sample中共客户参考和复用(参考EffectOneSDK交付清单),代码中演示了sdk关于导出的接口调用;当然也可以在你自己的导出组件中直接调用相应的接口,详细的接口说明见文档 视频导出接口介绍

全局配置相关接口

// 清理素材资源,会把通过{EOSDK#setResourceBaseDir}设置的文件夹下的内容删除
[EOSDK clearResource];

UI定制

EffectOneSDK是包含UI的音视频拍摄与编辑SDK,其UI支持部分定制能力,包括更换主题色、文案与icon。

主题色:色卡

  1. 色卡颜色表格:Effect one色卡

EffectOne SDK中所有可替换的颜色都可以在色卡中找到对应的key和色值。

  1. 如何自定义主题色

SDK 内部优先读取自定义颜色,没有自定义的使用内部默认颜色,可通过以下API进行自定义主题色设置。颜色名字必须与色卡表格定义的一致。(备注:darklight 为颜色风格预留字段,当前版本只使用了dark,暂不支持切换,自定义设置填写相同的色值即可。)

EOSDK.setColorDictionary([
    "Primary" : [
        "dark" : "FF0ECDEB", //ARGB
        "light": "FF0ECDEB"
    ],
    "Secondary" : [
        "dark" : "FF0ECDEB",
        "light": "FF0ECDEB"
    ],
]);
  1. 如何查找UI中对应控件的色卡key-value

参考各模块UI标注

文案

SDK依据文案对应的key进行替换,注意不要修改key名称。

  1. 如何自定义文案

(1)直接修改本地文案文件:打开目录EOLocalResources\BuiltInResource\Strings,找到EffectOne-en.strings和EffectOne-zh.strings,参考各模块UI标注 进行修改
(2)通过代码设置:SDK内部优先读取代码设置的文案,参考各模块UI标注 找到要替换的文案的key,示例如下:

//如果需要增加其他语言,可通过以下函数获取语言的key,例如中文"zh"
    func getLanguageCode() -> String? {
        let currentLanguage = Locale.preferredLanguages.first
        let components = currentLanguage?.components(separatedBy: "-")
        return components?.first
    }
    
EOSDK.setLocalizationDictionary([
    "zh" : [
        "eo_previeweditor_pop_discard" : "你好", 
        "eo_previeweditor_pop_discard_change": "你好"
    ],
    "en" : [
        "eo_previeweditor_pop_discard" : "hello", 
        "eo_previeweditor_pop_discard_change": "hello"
    ],
]);

Icon

SDK依据icon文件的名称进行替换,注意不要修改icon名称。

  1. 如何自定义icon

(1)直接替换本地Icon文件:打开目录EOLocalResources\BuiltInResource\Icons,EOLocalResources\BuiltInResource\Albums和EOLocalResources\BuiltInResource\Animations,参考各模块UI标注 找到对应的文件进行替换,
(2)通过代码设置:SDK内部优先读取代码设置的icon,参考各模块UI标注 找到要替换的icon的名称,示例如下:

var imageDictionary: [String: UIImage] = [:]
let image1 = UIImage(named: "image1")
imageDictionary["eo_album_list_bar_back"] = image1!

let image2 = UIImage(named: "image2")
imageDictionary["eo_album_list_delete"] = image2!

EOSDK.setIconDictionary(imageDictionary);

各模块UI标注

基础组件

基础组件客户可更换UI范围

拍摄

拍摄部分客户可更换UI范围 V1.4.0

预览编辑

预览编辑客户可更换UI范围-140

轨道编辑

轨道编辑客户可更换UI范围

草稿

草稿箱客户可更换UI范围

音乐

音乐&音效&音乐音量面板客户可更换UI范围-140

相册

相册部分客户可更换UI范围