logo

YouTubePlayerKit

一个 Swift 包,可以轻松播放 YouTube 视频。

Swift Version Platforms
Build and Test Status Documentation Twitter Mastodon

Example application

import SwiftUI
import YouTubePlayerKit

struct ContentView: View {

    var body: some View {
        //  WWDC 2019 Keynote
        YouTubePlayerView(
            "https://youtube.com/watch?v=psL_5RIBqnY"
        )
    }

}

特性

示例

查看示例应用程序,了解 YouTubePlayerKit 的实际应用。只需打开 Example/Example.xcodeproj 并运行 "Example" scheme。

安装

要使用 Apple 的 Swift Package Manager 进行集成,请将以下内容作为依赖项添加到您的 Package.swift

dependencies: [
    .package(url: "https://github.com/SvenTiigi/YouTubePlayerKit.git", from: "2.0.0")
]

或者导航到您的 Xcode 项目,然后选择 Swift Packages,单击“+”图标并搜索 YouTubePlayerKit

注意

将 YouTubePlayerKit 集成到 macOS 或 Mac Catalyst 目标时,请务必在“Signing & Capabilities”部分中启用“Outgoing Connections (Client)”。

App Store 审核

向 App Store 提交包含 YouTubePlayerKit 的应用程序时,请务必在审核备注中添加指向 YouTube API 服务条款 的链接。

https://developers.google.com/youtube/terms/api-services-terms-of-service

局限性

用法

提示

请参阅 YouTubePlayerKit 文档 以获取完整概述。

使用 SwiftUI 时,可以通过声明 YouTubePlayerView 轻松显示 YouTubePlayer

import SwiftUI
import YouTubePlayerKit

struct ContentView: View {

    let youTubePlayer: YouTubePlayer = "https://youtube.com/watch?v=psL_5RIBqnY"

    var body: some View {
        YouTubePlayerView(self.youTubePlayer) { state in
            // An optional overlay view for the current state of the player
            switch state {
            case .idle:
                ProgressView()
            case .ready:
                EmptyView()
            case .error(let error):
                ContentUnavailableView(
                    "Error",
                    systemImage: "exclamationmark.triangle.fill",
                    description: Text("YouTube player couldn't be loaded: \(error)")
                )
            }
        }
        // Optionally react to specific updates such as the fullscreen state
        .onReceive(
            self.youTubePlayer.fullscreenStatePublisher
        ) { fullscreenState in
            if fullscreenState.isFullscreen {
                // ...
            }
        }
    }

}

提示

您可以选择使用 @StateObject@ObservedObject 标记 YouTubePlayer,以便在源、参数或 isLoggingEnabled 更改时自动更新您的视图。

使用 UIKitAppKit 时,您可以使用 YouTubePlayerViewControllerYouTubePlayerHostingView

import UIKit
import YouTubePlayerKit

let youTubePlayerViewController = YouTubePlayerViewController(
    player: "https://youtube.com/watch?v=psL_5RIBqnY"
)

let youTubePlayerHostingView = YouTubePlayerHostingView(
    player: "https://youtube.com/watch?v=psL_5RIBqnY"
)

// Access the player on both instances via the `.player` property
// Example: youTubePlayerViewController.player

YouTubePlayer

YouTubePlayer 是播放特定 YouTube 视频并与底层 YouTube iFrame API 交互的核心对象。

如前面的示例所示,您可以使用字符串文字初始化播放器

let youTubePlayer: YouTubePlayer = "https://youtube.com/watch?v=psL_5RIBqnY"

要完全控制,您可以使用 YouTubePlayer.SourceYouTubePlayer.ParametersYouTubePlayer.Configuration 初始化 YouTubePlayer

let youTubePlayer = YouTubePlayer(
    // Possible values: .video, .videos, .playlist, .channel
    source: .video(id: "psL_5RIBqnY"),
    // The parameters of the player
    parameters: .init(
        autoPlay: true,
        showControls: true,
        loopEnabled: true,
        startTime: .init(value: 5, unit: .minutes),
        // ...
    ),
    // The configuration of the underlying web view
    configuration: .init(
        fullscreenMode: .system,
        allowsInlineMediaPlayback: true,
        customUserAgent: "MyCustomUserAgent",
        // ...
    )
)

要区分参数和配置,请理解参数控制 YouTube 播放器的行为和样式,而配置与底层 web 视图相关联。 实例化后无法修改配置;但是,可以更新参数,如下所示

youTubePlayer.parameters.showControls = false

警告

在运行时更新 YouTubePlayer.Parameters 将导致播放器重新加载。

YouTubePlayer.Source 是一个枚举,允许您指定应加载/提示哪个 YouTube 源。

// A single video
let video: YouTubePlayer.Source = .video(id: "psL_5RIBqnY")

// Series of videos
let videos: YouTubePlayer.Source = .videos(ids: ["w87fOAG8fjk", "RXeOiIDNNek", "psL_5RIBqnY"])

// Playlist
let playlist: YouTubePlayer.Source = .playlist(id: "PLHFlHpPjgk72Si7r1kLGt1_aD3aJDu092")

// Channel
let channel: YouTubePlayer.Source = .channel(name: "GoogleDevelopers")

您也可以使用 URL 初始化源。

let source: YouTubePlayer.Source? = .init(urlString: "https://youtube.com/watch?v=psL_5RIBqnY")

注意

URL 解析逻辑旨在处理大多数已知的 YouTube URL 格式,但可能存在一些它未涵盖的变体。

API

YouTubePlayer 允许您访问底层的 YouTube Player iFrame API 以播放、暂停、查找、检索视频信息等等。

大多数 API 都是 asyncthrowable 函数。

// Pauses the currently playing video
try await youTubePlayer.pause()

提示

请参阅 文档 以获取可用 API 的完整概述。

如果发生错误,大多数函数都会抛出 YouTubePlayer.APIError。 这使您可以轻松地检查错误的原因、任何底层错误以及执行的 JavaScript 及其响应。

do {
    try await youTubePlayer.setCaptions(fontSize: .small)
} catch {
    print(
        "Failed to set captions font size",
        error.reason,
        error.underlyingError,
        error.javaScript,
        error.javaScriptResponse
    )
}

此外,还有几个 Publisher 可用于响应播放器的更改

// Observe playback metadata
let cancellable = youTubePlayer
    .playbackMetadataPublisher
    .sink { playbackMetadata in
        // ...
    }

视频缩略图

您可以通过 YouTubeVideoThumbnail 对象加载 YouTube 视频缩略图。

// Initialize an instance of YouTubeVideoThumbnail
let videoThumbnail = YouTubeVideoThumbnail(
    videoID: "psL_5RIBqnY",
    // Choose between default, medium, high, standard, maximum
    resolution: .high
)

// Retrieve the URL, if available
let url: URL? = videoThumbnail.url

// Retrieve the image, if available.
let image: YouTubeVideoThumbnail.Image? = try await videoThumbnail.image()

此外,播放器允许您轻松检索当前加载视频的缩略图 URL 和图像。

// Returns the video thumbnail URL of the currently loaded video
try await youTubePlayer.getVideoThumbnailURL()

/// Returns the video thumbnail of the currently loaded video
try await youTubePlayer.getVideoThumbnailImage(resolution: .maximum)

日志记录

如果您希望更深入地了解 YouTube Player iFrame JavaScript API 的底层通信,您可以通过 isLogginEnabled 参数启用播放器的日志记录。

YouTubePlayer 利用 统一日志记录系统 (OSLog) 来记录有关播放器选项、JavaScript 事件和评估的信息。

// Enable or disable logging during initialization
let youTubePlayer = YouTubePlayer(
    source: [
        "w87fOAG8fjk",
        "RXeOiIDNNek",
        "psL_5RIBqnY"
    ],
    isLoggingEnabled: true
)

// To update during runtime update the isLoggingEnabled property
youTubePlayer.isLoggingEnabled = false

// Additionally, you can retrieve an instance of the logger if logging is enabled.
let logger: Logger? = youTubePlayer.logger()

高级

您可以通过以下发布者观察来自底层 YouTube Player iFrame API 的 YouTubePlayer.Event 的传入流。

let cancellable = youTubePlayer
    .eventPublisher
    .sink { event in
        switch event.name {
        case .playbackQualityChange:
            break
        case .autoplayBlocked:
            break
        default:
            break
        }
    }

重要提示

YouTubePlayerKit 支持官方和非官方/未记录的事件。 请参阅 YouTubePlayer.Event.Name 枚举以了解更多详细信息。

要在 YouTube 播放器 JavaScript 实例上运行 自定义 JavaScript

try await youTubePlayer.evaluate(
    javaScript: "\(.youTubePlayer).play()"
)

注意

\(.youTubePlayer) 的自定义字符串插值是 YouTube 播放器 JavaScript 变量的占位符。

或者,您可以使用以下便捷函数直接调用 YouTube 播放器 JavaScript 对象上的函数

try await youTubePlayer.evaluate(
    javaScript: .youTubePlayer(
        functionName: "setLoop",
        parameters: [
            true
        ]
    )
)

如果您希望进一步自定义底层 HTML,您可以在初始化播放器实例时配置 YouTubePlayer.HTMLBuilder

let youTubePlayer = YouTubePlayer(
    source: .video(id: "psL_5RIBqnY"),
    configuration: .init(
        htmlBuilder: .init(
            youTubePlayerJavaScriptVariableName: "youtubePlayer",
            youTubePlayerEventCallbackURLScheme: "youtubeplayer",
            youTubePlayerEventCallbackDataParameterName: "data",
            youTubePlayerIframeAPISourceURL: .init(string: "https://www.youtube.com/iframe_api")!,
            htmlProvider: { htmlBuilder, jsonEncodedYouTubePlayerOptions in
                // TODO: Return custom HTML string
            }
        )
    )
)

致谢