跳到主要内容

导入媒体文件

准备设备热点、获取媒体列表,并导入所选的 MediaFileInfoModel

Animated workflow

设备到 App 的媒体导入路径

SDK 准备设备热点、返回可导入的媒体模型、下载所选文件,并可按需执行视频防抖处理。

SDK + 设备

配置热点

准备媒体传输使用的临时设备网络。

设备

进入传输模式

将已连接设备切换到媒体文件传输模式。

SDK

连接热点

等待热点开启,然后加入回调报告的 SSID。

SDK → 宿主 App

获取媒体信息

接收 SDK 返回的 MediaFileInfoModel,作为后续导入参数。

宿主 App

选择文件

从返回的媒体模型中选择文件,不要自行构造 ID。

宿主 App → SDK

开始导入

将所选模型传入 importMediaFiles 并持续跟踪任务进度。

设备 → App

下载文件

跟踪数据块、单文件、批次位置和传输速度。

字节 + 批次进度
可选阶段

视频防抖处理

可用时执行由 SDK 管理的可选后处理。

单文件进度
最终结果

完成导入

检查每个文件的导入结果,并按需保存临时文件。

防抖处理失败后,原始下载文件仍可能正常使用。

前提条件

  • 设备已连接,并遵循 DeviceMediaFileImportAPI
  • App 能够加入设备 Wi-Fi 热点,并具备所需的本地网络权限。
  • 保留返回的媒体模型;导入方法接收模型,而不是任意文件 ID 或目标路径。

使用 AI 辅助实现

使用 AI 开发

让 AI 帮助实现此工作流

使用官方“从 AIBuds 导入媒体”技能,根据你的 App 完成实现。

请阅读并遵循 https://docs-aibuds.github.io/zh-Hans/skills/import-aibuds-media,使用该技能在当前 iOS 项目中完成“从 AIBuds 导入媒体”,并验证结果。
查看官方技能

API 参考

框架

AIBuds.xcframework

导入

Swift
import AIBuds
import AIBudsFoundation

协议符号

符号用途
isVideoStabilizationAvailableSDK 管理的视频防抖处理当前是否可用。
fetchMediaFilesInfo准备传输模式并返回设备媒体信息。
importMediaFiles下载所选文件,并可选择对视频进行后处理。
cancelMediaFileImport取消传输或正在进行的后处理。
deleteMediaFile按文件名删除一个设备文件。
deleteAllMediaFiles删除设备中的全部媒体文件。

声明

以下声明保留 SDK 的多阶段回调契约。

Swift
/// Whether SDK-internal video stabilization is available for media file import.
///
/// Returns `true` only when a stabilization plugin is registered AND stabilization
/// is not explicitly disabled. When `false`, imported six-axis files will be
/// returned with `stabilizationStatus = .disabled` (or `.pluginUnavailable`),
/// allowing the app to handle stabilization itself.
var isVideoStabilizationAvailable: Bool

/// Fetch media files info from the device.
///
/// - Parameters:
///   - configureHotspotStartingHandler: A closure that is called when the hotspot configuration starts.
///   - hotspotConfigureCompletionHandler: A closure that is called when the hotspot configuration completes.
///   - success: `true` if the configuration succeeded; otherwise `false`.
///   - error: An `NSError` object that describes the error that occurred, or `nil` if the operation was successful.
///   - enterFileTransferModeStartingHandler: A closure that is called when the file transfer mode entry starts.
///   - enterFileTransferModeCompletedHandler: A closure that is called when the file transfer mode entry completes.
///   - success: `true` if entering file transfer mode succeeded; otherwise `false`.
///   - error: An `NSError` object that describes the error that occurred, or `nil` if the operation was successful.
///   - waitingForHotspotOpenHandler: A closure that is called when the device is waiting for the hotspot to open.
///   - connectDeviceHotspotStartingHandler: A closure that is called when the device hotspot connection starts.
///   - ssid: The SSID of the device hotspot.
///   - deviceHotspotConnectCompletionHandler: A closure that is called when the device hotspot connection completes.
///   - success: `true` if the connection succeeded; otherwise `false`.
///   - error: An `NSError` object that describes the error that occurred, or `nil` if the operation was successful.
///   - completionHandler: A closure that is called when the fetch media files info operation completes.
///   - success: `true` if the operation was successful; otherwise `false`.
///   - mediaFiles: The media file info models to be imported.
///   - error: An `NSError` object that describes the error that occurred, or `nil` if the operation was successful.
func fetchMediaFilesInfo(
    configureHotspotStartingHandler: AIBudsMediaFileImportConfigureHotspotStartingHandler?,
    hotspotConfigureCompletionHandler: AIBudsMediaFileImportHotspotConfigureCompletionHandler?,
    enterFileTransferModeStartingHandler: AIBudsEnterMediaFileTransferModeStartingHandler?,
    enterFileTransferModeCompletedHandler: AIBudsEnterMediaFileTransferModeCompletionHandler?,
    waitingForHotspotOpenHandler: AIBudsMediaFileImportStartingToWaitForHotspotOpenHandler?,
    connectDeviceHotspotStartingHandler: AIBudsMediaFileImportConnectDeviceHotspotStartingHandler?,
    deviceHotspotConnectCompletionHandler: AIBudsMediaFileImportDeviceHotspotConnectCompletionHandler?,
    completionHandler: AIBudsMediaFileImportFetchMediaFilesInfoCompletionHandler?
)

/// Import media files from the device.
///
/// The import process consists of two phases: file transfer (downloading the media files
/// from the device) followed by an optional video stabilization post-processing phase.
/// Progress callbacks are provided for each phase so the caller can report status to the user.
///
/// - Parameters:
///   - mediaFiles: The media file info models to be imported.
///   - dataChunkHandler: A closure that is called whenever a data chunk is received during the file transfer.
///   - dataChunk: The received data chunk; `nil` if an error occurred.
///   - taskId: The unique identifier for the current file import task.
///   - fileUrl: The URL of the file being imported.
///   - fileSize: The total size of the file in bytes.
///   - transferredSize: The number of bytes that have been transferred so far.
///   - error: An `NSError` object that describes the error that occurred, or `nil` if the operation was successful.
///   - singleTransferStartingHandler: A closure that is called when a single file transfer starts.
///   - mediaFile: The media file info model of the file that is starting to be imported.
///   - singleTransferCompletionHandler: A closure that is called when a single file transfer completes.
///   - success: `true` if the file transfer succeeded; otherwise `false`.
///   - importedMediaFile: The local result model for this transfer, including metadata, downloaded local URL, optional playable stabilized URL, and possible error.
///   - error: An `NSError` object that describes the error that occurred, or `nil` if the operation was successful.
///   - transferSpeedHandler: A closure that is called when the file transfer speed changes.
///   - speed: The current transfer speed in bytes per second.
///   - transferBatchProgressHandler: A closure that is called when the file transfer batch progress changes.
///   - fileIndex: The index of the current file in the batch.
///   - totalFileCount: The total number of files in the batch.
///   - videoStabilizationPhaseBeginHandler: A closure that is called when the video stabilization post-processing phase begins.
///   - videoStabilizationSingleFileProgressHandler: A closure that is called to report progress during the stabilization of an individual video file.
///   - mediaFile: The imported media file model representing the video being stabilized.
///   - progress: The current stabilization progress, in the range `0.0` to `1.0`.
///   - videoStabilizationSingleFileCompletionHandler: A closure that is called when a single video file finishes stabilization (success or failure).
///   - mediaFile: The imported media file model with updated stabilization status.
///   - success: Whether the stabilization succeeded for this file.
///   - videoStabilizationBatchProgressHandler: A closure that is called to report batch progress when stabilizing multiple video files.
///   - fileIndex: The zero-based index of the current file being processed in the batch.
///   - totalFileCount: The total number of files in the stabilization batch.
///   - videoStabilizationPhaseFinishHandler: A closure that is called when the entire video stabilization post-processing phase finishes.
///   - completionHandler: A closure that is called when the import operation completes.
///   - success: `true` if all requested files were downloaded successfully; otherwise `false`.
///   - mediaFiles: The successfully imported files. A post-processing failure falls back to the original file and is reported by the corresponding result model.
///   - error: An `NSError` object that describes the download or local-file error when `success` is `false`, or `nil` if the operation was successful.
func importMediaFiles(
    _ mediaFiles: [MediaFileInfoModel],
    dataChunkHandler: AIBudsMediaFileImportDataChunkHandler?,
    singleTransferStartingHandler: AIBudsMediaFileImportSingleTransferStartingHandler?,
    singleTransferCompletionHandler: AIBudsMediaFileImportSingleTransferCompletionHandler?,
    transferSpeedHandler: AIBudsMediaFileImportTransferSpeedHandler?,
    transferBatchProgressHandler: AIBudsMediaFileImportTransferBatchProgressHandler?,
    videoStabilizationPhaseBeginHandler: AIBudsVideoStabilizationPhaseBeginHandler?,
    videoStabilizationSingleFileProgressHandler: AIBudsVideoStabilizationProgressHandler?,
    videoStabilizationSingleFileCompletionHandler: AIBudsVideoStabilizationSingleFileCompletionHandler?,
    videoStabilizationBatchProgressHandler: AIBudsVideoStabilizationBatchProgressHandler?,
    videoStabilizationPhaseFinishHandler: AIBudsVideoStabilizationPhaseFinishHandler?,
    completionHandler: AIBudsMediaFileImportCompletionHandler?
)

/// Cancel media file import from the device or cancel active post-processing.
///
/// - Parameters:
///   - completion: A closure that is called when the operation completes.
///   - success: `true` if the operation was successful; otherwise `false`.
///   - statusCode: The status code returned by the device. `nil` if the operation failed.
///   - error: An `NSError` object that describes the error that occurred, or `nil` if the operation was successful.
func cancelMediaFileImport(_ completion: AIBudsStatusCodeCompletionHandler?)

/// Requests the device to delete a specific media file.
///
/// - Parameters:
///   - fileName: The name of the file to delete.
///   - completion: A closure that is called when the operation completes.
///   - success: `true` if the operation was successful; otherwise `false`.
///   - statusCode: The status code returned by the device. `nil` if the operation failed.
///   - error: An `NSError` object that describes the error that occurred, or `nil` if the operation was successful.
func deleteMediaFile(_ fileName: String, completion: AIBudsStatusCodeCompletionHandler?)

/// Requests the device to delete all media files.
///
/// - Parameters:
///   - completion: A closure that is called when the operation completes.
///   - success: `true` if the operation was successful; otherwise `false`.
///   - statusCode: The status code returned by the device. `nil` if the operation failed.
///   - error: An `NSError` object that describes the error that occurred, or `nil` if the operation was successful.
func deleteAllMediaFiles(_ completion: AIBudsStatusCodeCompletionHandler?)

返回值

这些成员不会直接返回操作结果,结果通过完成和进度处理器传递。fetchMediaFilesInfo 提供 MediaFileInfoModel,供 importMediaFiles 使用;取消和删除操作还会提供可选的设备状态码。

使用示例

示例遵循 Demo 的两阶段“获取—导入”流程,清晰呈现每个阶段,同时将 UI 展示交由宿主 App 处理。

Swift
guard let device = device as? DeviceMediaFileImportAPI else { return }

device.fetchMediaFilesInfo(
    configureHotspotStartingHandler: {
        print("Configuring hotspot")
    },
    hotspotConfigureCompletionHandler: { success, error in
        print(
            success
                ? "Hotspot configured"
                : "Configuration failed: \(error?.localizedDescription ?? "Unknown error")")
    },
    enterFileTransferModeStartingHandler: {
        print("Entering file transfer mode")
    },
    enterFileTransferModeCompletedHandler: { success, error in
        print(
            success
                ? "File transfer mode ready"
                : "Transfer mode failed: \(error?.localizedDescription ?? "Unknown error")")
    },
    waitingForHotspotOpenHandler: {
        print("Waiting for the device hotspot")
    },
    connectDeviceHotspotStartingHandler: { ssid in
        print("Connecting to \(ssid)")
    },
    deviceHotspotConnectCompletionHandler: { success, error in
        print(
            success
                ? "Device hotspot connected"
                : "Connection failed: \(error?.localizedDescription ?? "Unknown error")")
    },
    completionHandler: { success, mediaFiles, error in
        guard success, !mediaFiles.isEmpty else {
            print(error?.localizedDescription ?? "No media available")
            return
        }

        device.importMediaFiles(
            mediaFiles,
            dataChunkHandler: { _, taskID, fileURL, fileSize, transferredSize, error in
                guard error == nil, fileSize > 0 else { return }
                let progress = Double(transferredSize) / Double(fileSize)
                print("\(taskID): \(fileURL) \(Int(progress * 100))%")
            },
            singleTransferStartingHandler: { mediaFile in
                print("Starting \(mediaFile.fileName)")
            },
            singleTransferCompletionHandler: { success, importedFile, error in
                print(
                    success
                        ? "Downloaded \(importedFile.metadata.fileName)"
                        : "Download failed: \(error?.localizedDescription ?? "Unknown error")")
            },
            transferSpeedHandler: { bytesPerSecond in
                print("Transfer speed: \(bytesPerSecond) B/s")
            },
            transferBatchProgressHandler: { index, total in
                print("Transfer file \(index + 1) of \(total)")
            },
            videoStabilizationPhaseBeginHandler: {
                print("Video stabilization started")
            },
            videoStabilizationSingleFileProgressHandler: { file, progress in
                print("Stabilizing \(file.metadata.fileName): \(Int(progress * 100))%")
            },
            videoStabilizationSingleFileCompletionHandler: { file, success in
                print(
                    "Stabilization \(success ? "completed" : "failed") for \(file.metadata.fileName)"
                )
            },
            videoStabilizationBatchProgressHandler: { index, total in
                print("Stabilization file \(index + 1) of \(total)")
            },
            videoStabilizationPhaseFinishHandler: {
                print("Video stabilization finished")
            },
            completionHandler: { success, importedFiles, error in
                print(
                    success
                        ? "Imported \(importedFiles.count) files"
                        : (error?.localizedDescription ?? "Import failed"))
            }
        )
    }
)

取消导入或删除媒体

Swift
device.cancelMediaFileImport { success, statusCode, error in
    print(success ? "Import cancelled" : (error?.localizedDescription ?? "Cancel failed"))
}

device.deleteMediaFile("example.mp4") { success, statusCode, error in
    print(success ? "File deleted" : (error?.localizedDescription ?? "Delete failed"))
}

device.deleteAllMediaFiles { success, statusCode, error in
    print(success ? "All media deleted" : (error?.localizedDescription ?? "Delete failed"))
}

错误处理

在 UI 中将热点配置、进入传输模式、热点连接、文件下载和视频防抖处理视为独立阶段。防抖处理失败不代表原始文件下载失败;应检查每个导入结果模型,并在可播放的防抖文件 URL 不可用时使用原始本地 URL。

不要推断未公开的状态码含义。在 SDK 发布状态码契约前,取消和删除操作应以 successerror 作为主要结果。

最佳实践

  1. 开始流程前检查协议遵循情况。
  2. 将返回的 MediaFileInfoModel(由 fetchMediaFilesInfo 获取)传给 importMediaFiles,不要用自定义 ID 替代。
  3. 在 UI 中分别呈现热点配置、进入传输模式、热点连接、下载和防抖处理阶段。
  4. 进度回调可能来自其他队列,因此 UI 更新应派发到主队列。
  5. 若文件需要跨会话保留,应将其从 SDK 临时位置复制到 App 管理的持久存储中。
  6. 传输进行期间应阻止重复导入请求,并在适当场景提供取消操作。

注意事项

  • isVideoStabilizationAvailablefalse 时仍可导入文件,仅 SDK 管理的视频防抖处理不可用。
  • 防抖处理失败后,原始本地文件仍可能可用。请检查每个 ImportedMediaFileModel
  • deleteMediaFile 需要设备文件名,而不是 App 本地文件 URL。