You need to enable JavaScript to run this app.
导航

【iOS-Swif】拍摄&基础编辑 含 UI 接入文档

最近更新时间2023.02.06 10:39:26

首次发布时间2023.02.06 10:39:26

Step1: Podfile配置

目前CK SDK不支持在pod中以动态库形式引入,所以如果您的项目在Podfile中添加了use_frameworks!,需要删掉。

# {zh} 请关闭use_frameworks! {en} Disable use_frameworks!
use_modular_headers!

# {zh} CKSDK目录与Podfile的相对路径 {en} CKSDK relative path to Podfile
$CKSDK_RELATIVE_PATH = "./CKSDK"

# {zh} 通用的 pods
def base_pods
  pod 'TTVideoEditor', '11.8.1.29-D',:source => 'https://github.com/volcengine/volcengine-specs.git'
  pod 'NLEPlatform', '0.5.2', :source => 'https://github.com/volcengine/volcengine-specs.git'
  pod 'DVEInject', '0.0.5', :source => 'https://github.com/volcengine/volcengine-specs.git'
  # supports
  pod 'CKi18n', :path => "#$CKSDK_RELATIVE_PATH/CKi18n", :modular_headers => false
  pod 'CKResource', :path => "#$CKSDK_RELATIVE_PATH/CKResource", :modular_headers => false
end

# {zh} 编辑
def editor_pods
  base_pods
  # 接入时,根据项目实际情况,调整相对路径
  pod 'NLEEditor', :subspecs => ['CKStandard'], :path => "#$CKSDK_RELATIVE_PATH/NLEEditor-iOS", :modular_headers => false
  pod 'DVETrackKit', :subspecs => ['CKStandard'], :path => "#$CKSDK_RELATIVE_PATH/DVETrackKit", :modular_headers => false
  pod 'DVEFoundationKit', :path => "#$CKSDK_RELATIVE_PATH/DVEFoundationKit", :modular_headers => false
  pod 'CKEditor', :subspecs => ['CKStandard'], :path => "#$CKSDK_RELATIVE_PATH/CKEditor", :modular_headers => false
  
  ################################### 第三方 ###################################
  pod 'SGPagingView', '1.7.1'
  pod 'lottie-ios', '2.5.3'
  pod 'FileMD5Hash'
  pod 'SDWebImage'
end

# {zh} 拍摄 {en} Recorder
def recorder_pods
    base_pods
    pod 'CKRRecorder', :subspecs => ['Arch'], :path => "#$CKSDK_RELATIVE_PATH/CKRRecorder", :modular_headers => false
end

target 'CKDemo-Swift' do
  # 基础编辑 & 拍摄
  editor_pods

  recorder_pods
end

# {zh} 修改一些编译参数,优化开发体验,可按需选择 {en} optional
post_install do |installer|
  installer.generated_projects.each do |project|
      project.targets.each do |target|
        target.build_configurations.each do |config|
          # {zh} 解决 Xcode14 编译问题 {en} [Xcode 14 build failed with manual code sign and app resource bundles](https://github.com/CocoaPods/CocoaPods/issues/11402)
          config.build_settings['CODE_SIGN_IDENTITY'] = '-'
          config.build_settings['CODE_SIGN_ENTITLEMENTS'] = '-'
          config.build_settings['CODE_SIGNING_REQUIRED'] = 'NO'
          config.build_settings['CODE_SIGNING_ALLOWED'] = 'NO'
        end
      end
      project.build_configurations.each do |config|
        config.build_settings['CLANG_WARN_DOCUMENTATION_COMMENTS'] = 'NO'
        # 禁止部分 warning
        config.build_settings['WARNING_CFLAGS'] = '-Wno-strict-prototypes -Wno-swift-name-attribute -Wno-comment -Wno-shorten-64-to-32 -Wno-unused-function -Wno-unused-variable -Wno-nullability -Wno-nullability-completeness -Wno-documentation -Wno-documentation-html -Wno-incomplete-umbrella'
        # 禁止全部 warning
        if project.targets.first.name.start_with?("NLEPlatform")
          config.build_settings['GCC_WARN_INHIBIT_ALL_WARNINGS'] = "YES"
        end
        # 减少 warning 造成的 Xcode 卡顿
        if project.targets.first.name.start_with?("NLEEditor") || project.targets.first.name.start_with?("DVETrackKit")
          config.build_settings['WARNING_CFLAGS'] = '-Wno-strict-prototypes -Wno-swift-name-attribute -Wno-comment -Wno-shorten-64-to-32 -Wno-unused-function -Wno-unused-variable -Wno-nullability -Wno-nullability-completeness -Wno-documentation -Wno-documentation-html -Wno-ambiguous-macro'
        end
      end
  end
end

在CocoaPods 1.5.0之后,引入Swift pod也不再强制要求打开use_frameworks!,并可使用use_modular_headers!来支持module。可参考:https://blog.cocoapods.org/CocoaPods-1.5.0/。

如果您有一些pod组件必须以动态库形式引入,可在Podfile中参考如下方式处理:

dynamic_frameworks = ['Alamofire','SnapKit']

pre_install do |installer|
 # Pod::Installer::Xcode::TargetValidator.send(:define_method, :verify_no_static_framework_transitive_dependencies) {}
  installer.pod_targets.each do |target|
    if dynamic_frameworks.include?(target.name)
      def target.build_type
        Pod::BuildType.dynamic_framework
      end
    end
  end
end

Step2: Copy CK SDK

将CK SDK copy到您项目与Podfile同级的目录下(与上面Podfile中的配置匹配)


Step3: 工程配置

  1. 关闭bitcode

    1. 进入 TARGETS > Project Name >Build Setting

    2. 选择 All ,搜索 bitcode

    3. Enable Bitcode 选择 NO

  1. 配置需要使用系统权限

    1. 找到项目中的 info.plist 文件

    2. 点击 【 + 】 添加音频和视频设备权限:

      1. Privacy - Microphone Usage Description ,并填入使用麦克风的原因( Value )

      2. Privacy - Camera Usage Description ,并填入使用摄像头的原因( Value )

      3. Privacy - Media Library Usage Description,并填入使用播放原因( Value )

      4. Privacy - Photo Library Additions Usage Description,并填入使用相册原因( Value )

      5. Privacy - Photo Library Usage Description,并填入使用相册的原因( Value )



Step4: SDK初始化及使用

  1. 创建桥接文件

YourApp-Swift-Bridging-Header,并将以下头文件导入

// YourApp-Swift-Bridging-Header

#import <CKEditor/CKEditor.h>
#import <DVEFoundationKit/UIViewController+Private.h>
#import <CKEditor/CKRResourceLoader.h>

// recorder
#import <CKRRecorder/CKRRecorderViewController.h>

// duet
#import <CKRRecorder/CKRResourcePicker.h>
#import <CKRRecorder/CKRDuetViewController.h>

// edit
#import <CKRRecorder/CKRResourcePicker.h>
#import <NLEEditor/DVEUIFactory.h>

// draft
#import <CKEditor/CKEDraftBoxController.h>

// result callback
#import <NLEEditor/DVEVCContextExternalInjectProtocol.h>
  1. 初始化SDK并配置License等

    将我们提供给您的资源替换到以下三个目录中,执行pod install然后初始化

```objectivec

func initCKSDK() {
let config = CKEditorEngineConfig.default()
config.veLicensePath = Bundle.main.path(forResource: "com.bytedance.solution.ck.licbag", ofType: "") ?? ""
config.veAppKey = "iWwiXvXhlN"
config.veToken = "cJ75jX6c9m8eObgQif7okMgb3U2398MrE1DCr1LH1neWx3x4BkL5hIqlRwbrC1Hf6aVQRcvSWrFuXbf8ROmHIHTz1X5daYyh6Gmb+J/cI1deUayXIgmE2KUIlYyjMgDHL0gbyUNl6+XJhspB1nZP6tHyDfBhSISdQ5Aq6/1zqilrPYJSjo547IkdVg2xfuhDACrbgs1iu9LqI7pHDc+JEOSTYuHA3Fe5aVyVkwBRqBNf1EgrsgMtZ1W1U2GAZpLMQke7DUvB7WDaAb+GdZSAcovLM8WjGzZiIV4Cj6YTFYBtNH3WfM15954YRcS1rOeYhPmZN7/N6yYmBBz3OZKx/sD8OyFk5cY6Q9PdaqDF14qPhUIy0rqX79tqxNwyOLnKYWR+e/8nrG2N8NDef9BZ7dDSREVkgiDl8ELmDgKYzraUxyy5MOV1hbITl6nieiuI/oeVu0z3snytsDt4yMyOdsaT3acngkJJhHX3tz2dh+R5v2diJW6+VsybE6166eJm5swVLAxqdn1wcQuPX64hKHXuc6SssjwddRKqMgKrCzHrGdW5IJKQC25lOdY4ENMnSV8HwRUaaEZQJPBIyC605H6VQCDwUTHGL4VKu5enIA/itdoYJY8lJ9YQ7ZSWFZO21gTaAPhEj1JuuToYg6wh9xIPgFhKbpLknJzweKKxyzgtM3Ndf6Z4czyFrCKhJgZm+yEkl5/CplXWJ/MZT2tH9yIjnZlySfUHZFwJtB78MNdrxd3p+ux/me2CK70uvSBAB7pXautnEEpQdkQ3TDSJEgMvMN1QGZ09LaDPOINWjH2xl2aNCFMkB7Q5p1AqJFu69tZjzwRorFvLETwJNpBXZSP9M660/86y5MRPhvbFgWIrZwhM6/sf66/3MoRyz5cmwQ9fiYNheTCPLs+TVAkvKulQFZnSF2PgcuEBgqFCR03pcS2wn6C/QjMbIIa8B26aImgPzBzi9WqEjZjoVrb1OxkkSsJZFpvLWXr1YQslRut4sR9zldy1BijVN2AJdKnP2D1Zu9za/HodeX7dskbe2tiTX4xbfNCFPbAvubtI9UlOMsTOTdmnG7GRPykSsEO1fPmIEx0YeSlf6M1whjRzPQhhhqs3cnn8QbhDcpRj/Big3+PWeNf7c+vPjPBSYbXIYS2cNE5grP56/1Pv+VqftNMQP5dHIQJ7A1iXPabP0VPsgrlpH5KnBe/bX4jDLgP4FUWG4jl/YroGO0ETSwUWboldc6ia45pgcOCibQ9Gx/PmGdP2JzYx6QyImo3TwbDrhWhCMqYtKgwpPo+UD9lh4Q=="

/// {zh} 可选配置:根据需要的功能,联系火山引擎提供  {en} Optional: According to the required functions, contact Volcano Engine to provide
    config.subtitleAppId = ""
    config.subtitleToken = ""
    config.volcAccessKey = ""
    config.volcSecretKey = ""

    CKEditorEngine.shared().start(with: config)
}
3. #### 跳转页面
	

    ```objectivec
@IBAction func goRecord(_ sender: Any) {
        let vc = CKRRecorderViewController()
        vc.injectedContainer = CustomServiceContainer()
        let nav = UINavigationController.init(rootViewController: vc)
        nav.modalPresentationStyle = .fullScreen
        present(nav, animated: true)
    }
    
    @IBAction func goDuet(_ sender: Any) {
        CKRResourcePicker().pickResources { [weak self] resources, error, cancel in
            let vc = CKRDuetViewController()
            let model = resources.first
            guard let url = model?.url() else { return }
            vc.duetURL = url
            vc.injectedContainer = CustomServiceContainer()
            let nav = UINavigationController.init(rootViewController: vc)
            nav.modalPresentationStyle = .fullScreen
            nav.modalPresentationStyle = .fullScreen
            self?.present(nav, animated: true)
        }
    }
    
    @IBAction func goEdit(_ sender: Any) {
        CKRResourcePicker().pickResources { [weak self] resources, error, cancel in
            if resources.count <= 0 { return }
            let vc = DVEUIFactory.createDVEViewController(withResources: resources, injectService: CustomServiceContainer())
            self?.navigationController?.pushViewController(vc, animated: true)
        }
    }
    
    @IBAction func goDraft(_ sender: Any) {
        let vc = CKEDraftBoxController()
        vc.serviceInjectContainer = CustomServiceContainer()
        self.present(vc, animated: true)
    }
  1. 获取导出的视频url

如下新增一个回调类,在editorDidExportedVideo中获取导出的视频

import UIKit

@objc class CustomServiceContainer: NSObject, DVEVCContextExternalInjectProtocol {
    lazy var resourceLoader: DVEResourceLoaderProtocol = {
        return CKRResourceLoader()
    }()
    lazy var eventDelagate: DVEEditorEventProtocol = {
        return CustomEditorEventDelegate()
    }()
    
    func provideResourceLoader() -> DVEResourceLoaderProtocol {
        resourceLoader
    }
    
    func provideEditorEvent() -> DVEEditorEventProtocol {
        eventDelagate
    }
}

class CustomEditorEventDelegate: NSObject, DVEEditorEventProtocol {
    func editorDidExportedVideo(_ viewController: UIViewController, result success: Bool, videoURL url: URL?, draftID: String) {
        if success, let url = url {
            // Here you can process the video on demand
            UISaveVideoAtPathToSavedPhotosAlbum(url.path, nil, nil, nil)
        }
        //  And then close SDK
        viewController.dve_close(animated: true)
    }
}

Demo

暂时无法在飞书文档外展示此内容

English Version

Step1: Podfile Config

CK SDK does not support imported as dynamic frameworks currently, so if your project adds use_frameworks! in the Podfile, you need to delete it.

# {zh} 请关闭use_frameworks! {en} Disable use_frameworks!
use_modular_headers!

# {zh} CKSDK目录与Podfile的相对路径 {en} CKSDK relative path to Podfile
$CKSDK_RELATIVE_PATH = "./CKSDK"

# {zh} 通用的 pods
def base_pods
  pod 'TTVideoEditor', '11.8.1.29-D',:source => 'https://github.com/volcengine/volcengine-specs.git'
  pod 'NLEPlatform', '0.5.2', :source => 'https://github.com/volcengine/volcengine-specs.git'
  pod 'DVEInject', '0.0.5', :source => 'https://github.com/volcengine/volcengine-specs.git'
  # supports
  pod 'CKi18n', :path => "#$CKSDK_RELATIVE_PATH/CKi18n", :modular_headers => false
  pod 'CKResource', :path => "#$CKSDK_RELATIVE_PATH/CKResource", :modular_headers => false
end

# {zh} 编辑
def editor_pods
  base_pods
  # 接入时,根据项目实际情况,调整相对路径
  pod 'NLEEditor', :subspecs => ['CKStandard'], :path => "#$CKSDK_RELATIVE_PATH/NLEEditor-iOS", :modular_headers => false
  pod 'DVETrackKit', :subspecs => ['CKStandard'], :path => "#$CKSDK_RELATIVE_PATH/DVETrackKit", :modular_headers => false
  pod 'DVEFoundationKit', :path => "#$CKSDK_RELATIVE_PATH/DVEFoundationKit", :modular_headers => false
  pod 'CKEditor', :subspecs => ['CKStandard'], :path => "#$CKSDK_RELATIVE_PATH/CKEditor", :modular_headers => false
  
  ################################### 第三方 ###################################
  pod 'SGPagingView', '1.7.1'
  pod 'lottie-ios', '2.5.3'
  pod 'FileMD5Hash'
  pod 'SDWebImage'
end

# {zh} 拍摄 {en} Recorder
def recorder_pods
    base_pods
    pod 'CKRRecorder', :subspecs => ['Arch'], :path => "#$CKSDK_RELATIVE_PATH/CKRRecorder", :modular_headers => false
end

target 'CKDemo-Swift' do
  # 基础编辑 & 拍摄
  editor_pods

  recorder_pods
end

# {zh} 修改一些编译参数,优化开发体验,可按需选择 {en} optional
post_install do |installer|
  installer.generated_projects.each do |project|
      project.targets.each do |target|
        target.build_configurations.each do |config|
          # {zh} 解决 Xcode14 编译问题 {en} [Xcode 14 build failed with manual code sign and app resource bundles](https://github.com/CocoaPods/CocoaPods/issues/11402)
          config.build_settings['CODE_SIGN_IDENTITY'] = '-'
          config.build_settings['CODE_SIGN_ENTITLEMENTS'] = '-'
          config.build_settings['CODE_SIGNING_REQUIRED'] = 'NO'
          config.build_settings['CODE_SIGNING_ALLOWED'] = 'NO'
        end
      end
      project.build_configurations.each do |config|
        config.build_settings['CLANG_WARN_DOCUMENTATION_COMMENTS'] = 'NO'
        # 禁止部分 warning
        config.build_settings['WARNING_CFLAGS'] = '-Wno-strict-prototypes -Wno-swift-name-attribute -Wno-comment -Wno-shorten-64-to-32 -Wno-unused-function -Wno-unused-variable -Wno-nullability -Wno-nullability-completeness -Wno-documentation -Wno-documentation-html -Wno-incomplete-umbrella'
        # 禁止全部 warning
        if project.targets.first.name.start_with?("NLEPlatform")
          config.build_settings['GCC_WARN_INHIBIT_ALL_WARNINGS'] = "YES"
        end
        # 减少 warning 造成的 Xcode 卡顿
        if project.targets.first.name.start_with?("NLEEditor") || project.targets.first.name.start_with?("DVETrackKit")
          config.build_settings['WARNING_CFLAGS'] = '-Wno-strict-prototypes -Wno-swift-name-attribute -Wno-comment -Wno-shorten-64-to-32 -Wno-unused-function -Wno-unused-variable -Wno-nullability -Wno-nullability-completeness -Wno-documentation -Wno-documentation-html -Wno-ambiguous-macro'
        end
      end
  end
end

After CocoaPods 1.5.0, dependency of Swift pod is no longer need to enable use_frameworks! in Podfile, and can use use_modular_headers! to support modules. Refer to:https://blog.cocoapods.org/CocoaPods-1.5.0/

If you have some pods that must be imported as dynamic frameworks, you can refer to the following methods in Podfile:

dynamic_frameworks = ['Alamofire','SnapKit']

pre_install do |installer|
 # Pod::Installer::Xcode::TargetValidator.send(:define_method, :verify_no_static_framework_transitive_dependencies) {}
  installer.pod_targets.each do |target|
    if dynamic_frameworks.include?(target.name)
      def target.build_type
        Pod::BuildType.dynamic_framework
      end
    end
  end
end

Step2: Copy CK SDK

Copy the CK SDK to the directory of your project at the same level as the Podfile (matching the configuration in the Podfile above)


Step3: Project Config

  1. Disable bitcode

    1. TARGETS > Project Name >Build Setting

    2. Select All ,search bitcode

    3. Enable Bitcode: NO

  1. Configure the system permissions that need to be used

    1. Find the info.plist in your project

    2. Click 【 + 】 to add privacy usage description

      1. Privacy - Microphone Usage Description ,并填入使用麦克风的原因( Value )

      2. Privacy - Camera Usage Description ,并填入使用摄像头的原因( Value )

      3. Privacy - Media Library Usage Description,并填入使用播放原因( Value )

      4. Privacy - Photo Library Additions Usage Description,并填入使用相册原因( Value )

      5. Privacy - Photo Library Usage Description,并填入使用相册的原因( Value )



Step4: SDK initialization and usage

  1. Create a bridging file

YourApp-Swift-Bridging-Header. Import the following header files

// YourApp-Swift-Bridging-Header

#import <CKEditor/CKEditor.h>
#import <DVEFoundationKit/UIViewController+Private.h>
#import <CKEditor/CKRResourceLoader.h>

// recorder
#import <CKRRecorder/CKRRecorderViewController.h>

// duet
#import <CKRRecorder/CKRResourcePicker.h>
#import <CKRRecorder/CKRDuetViewController.h>

// edit
#import <CKRRecorder/CKRResourcePicker.h>
#import <NLEEditor/DVEUIFactory.h>

// draft
#import <CKEditor/CKEDraftBoxController.h>

// result callback
#import <NLEEditor/DVEVCContextExternalInjectProtocol.h>
  1. Initialize the SDK and configure the license, etc.

    Replace the resources we provide you into the following three directories, execute pod install and then initialize

```objectivec

func initCKSDK() {
let config = CKEditorEngineConfig.default()
config.veLicensePath = Bundle.main.path(forResource: "com.bytedance.solution.ck.licbag", ofType: "") ?? ""
config.veAppKey = "iWwiXvXhlN"
config.veToken = "cJ75jX6c9m8eObgQif7okMgb3U2398MrE1DCr1LH1neWx3x4BkL5hIqlRwbrC1Hf6aVQRcvSWrFuXbf8ROmHIHTz1X5daYyh6Gmb+J/cI1deUayXIgmE2KUIlYyjMgDHL0gbyUNl6+XJhspB1nZP6tHyDfBhSISdQ5Aq6/1zqilrPYJSjo547IkdVg2xfuhDACrbgs1iu9LqI7pHDc+JEOSTYuHA3Fe5aVyVkwBRqBNf1EgrsgMtZ1W1U2GAZpLMQke7DUvB7WDaAb+GdZSAcovLM8WjGzZiIV4Cj6YTFYBtNH3WfM15954YRcS1rOeYhPmZN7/N6yYmBBz3OZKx/sD8OyFk5cY6Q9PdaqDF14qPhUIy0rqX79tqxNwyOLnKYWR+e/8nrG2N8NDef9BZ7dDSREVkgiDl8ELmDgKYzraUxyy5MOV1hbITl6nieiuI/oeVu0z3snytsDt4yMyOdsaT3acngkJJhHX3tz2dh+R5v2diJW6+VsybE6166eJm5swVLAxqdn1wcQuPX64hKHXuc6SssjwddRKqMgKrCzHrGdW5IJKQC25lOdY4ENMnSV8HwRUaaEZQJPBIyC605H6VQCDwUTHGL4VKu5enIA/itdoYJY8lJ9YQ7ZSWFZO21gTaAPhEj1JuuToYg6wh9xIPgFhKbpLknJzweKKxyzgtM3Ndf6Z4czyFrCKhJgZm+yEkl5/CplXWJ/MZT2tH9yIjnZlySfUHZFwJtB78MNdrxd3p+ux/me2CK70uvSBAB7pXautnEEpQdkQ3TDSJEgMvMN1QGZ09LaDPOINWjH2xl2aNCFMkB7Q5p1AqJFu69tZjzwRorFvLETwJNpBXZSP9M660/86y5MRPhvbFgWIrZwhM6/sf66/3MoRyz5cmwQ9fiYNheTCPLs+TVAkvKulQFZnSF2PgcuEBgqFCR03pcS2wn6C/QjMbIIa8B26aImgPzBzi9WqEjZjoVrb1OxkkSsJZFpvLWXr1YQslRut4sR9zldy1BijVN2AJdKnP2D1Zu9za/HodeX7dskbe2tiTX4xbfNCFPbAvubtI9UlOMsTOTdmnG7GRPykSsEO1fPmIEx0YeSlf6M1whjRzPQhhhqs3cnn8QbhDcpRj/Big3+PWeNf7c+vPjPBSYbXIYS2cNE5grP56/1Pv+VqftNMQP5dHIQJ7A1iXPabP0VPsgrlpH5KnBe/bX4jDLgP4FUWG4jl/YroGO0ETSwUWboldc6ia45pgcOCibQ9Gx/PmGdP2JzYx6QyImo3TwbDrhWhCMqYtKgwpPo+UD9lh4Q=="

/// {zh} 可选配置:根据需要的功能,联系火山引擎提供  {en} Optional: According to the required functions, contact Volcano Engine to provide
    config.subtitleAppId = ""
    config.subtitleToken = ""
    config.volcAccessKey = ""
    config.volcSecretKey = ""

    CKEditorEngine.shared().start(with: config)
}
3. #### Jump to pages of SDK
	

After SDK initialized.

    ```objectivec
@IBAction func goRecord(_ sender: Any) {
        let vc = CKRRecorderViewController()
        vc.injectedContainer = CustomServiceContainer()
        let nav = UINavigationController.init(rootViewController: vc)
        nav.modalPresentationStyle = .fullScreen
        present(nav, animated: true)
    }
    
    @IBAction func goDuet(_ sender: Any) {
        CKRResourcePicker().pickResources { [weak self] resources, error, cancel in
            let vc = CKRDuetViewController()
            let model = resources.first
            guard let url = model?.url() else { return }
            vc.duetURL = url
            vc.injectedContainer = CustomServiceContainer()
            let nav = UINavigationController.init(rootViewController: vc)
            nav.modalPresentationStyle = .fullScreen
            nav.modalPresentationStyle = .fullScreen
            self?.present(nav, animated: true)
        }
    }
    
    @IBAction func goEdit(_ sender: Any) {
        CKRResourcePicker().pickResources { [weak self] resources, error, cancel in
            if resources.count <= 0 { return }
            let vc = DVEUIFactory.createDVEViewController(withResources: resources, injectService: CustomServiceContainer())
            self?.navigationController?.pushViewController(vc, animated: true)
        }
    }
    
    @IBAction func goDraft(_ sender: Any) {
        let vc = CKEDraftBoxController()
        vc.serviceInjectContainer = CustomServiceContainer()
        self.present(vc, animated: true)
    }
  1. Get the exported video url

Add a callback class as follows to get the exported video in the function: editorDidExportedVideo

import UIKit

@objc class CustomServiceContainer: NSObject, DVEVCContextExternalInjectProtocol {
    lazy var resourceLoader: DVEResourceLoaderProtocol = {
        return CKRResourceLoader()
    }()
    lazy var eventDelagate: DVEEditorEventProtocol = {
        return CustomEditorEventDelegate()
    }()
    
    func provideResourceLoader() -> DVEResourceLoaderProtocol {
        resourceLoader
    }
    
    func provideEditorEvent() -> DVEEditorEventProtocol {
        eventDelagate
    }
}

class CustomEditorEventDelegate: NSObject, DVEEditorEventProtocol {
    func editorDidExportedVideo(_ viewController: UIViewController, result success: Bool, videoURL url: URL?, draftID: String) {
        if success, let url = url {
            // Here you can process the video on demand
            UISaveVideoAtPathToSavedPhotosAlbum(url.path, nil, nil, nil)
        }
        //  And then close SDK
        viewController.dve_close(animated: true)
    }
}

Demo

暂时无法在飞书文档外展示此内容