1. Tổng quan
Lớp học lập trình này sẽ hướng dẫn bạn cách sửa đổi một ứng dụng video hiện có dành cho iOS để truyền nội dung trên một thiết bị hỗ trợ Google Cast.
Google Cast là gì?
Google Cast cho phép người dùng truyền nội dung từ thiết bị di động sang TV. Sau đó, người dùng có thể sử dụng thiết bị di động làm điều khiển từ xa để phát nội dung nghe nhìn trên TV.
SDK Google Cast cho phép bạn mở rộng ứng dụng để điều khiển các thiết bị hỗ trợ Google Cast (chẳng hạn như TV hoặc hệ thống âm thanh). SDK Cast cho phép bạn thêm các thành phần giao diện người dùng cần thiết dựa trên Danh sách kiểm tra thiết kế Google Cast.
Danh sách kiểm tra thiết kế Google Cast được cung cấp để mang lại trải nghiệm đơn giản và dễ dự đoán cho người dùng Cast trên tất cả các nền tảng được hỗ trợ.
Chúng ta sẽ xây dựng những gì?
Khi hoàn thành lớp học lập trình này, bạn sẽ có một ứng dụng video dành cho iOS có thể Truyền video đến thiết bị Google Cast.
Kiến thức bạn sẽ học được
- Cách thêm SDK Google Cast vào ứng dụng video mẫu.
- Cách thêm nút Truyền để chọn thiết bị Google Cast.
- Cách kết nối với một Thiết bị truyền và khởi chạy bộ thu nội dung đa phương tiện.
- Cách truyền video.
- Cách thêm bộ điều khiển Cast Mini vào ứng dụng của bạn.
- Cách thêm bộ điều khiển mở rộng.
- Cách cung cấp lớp phủ giới thiệu.
- Cách tuỳ chỉnh tiện ích Truyền.
- Cách tích hợp Cast Connect
Bạn cần có
- Xcode mới nhất.
- Một thiết bị di động chạy iOS 9 trở lên (hoặc Trình mô phỏng Xcode).
- Cáp dữ liệu USB để kết nối thiết bị di động với máy tính phát triển (nếu bạn đang sử dụng thiết bị).
- Một thiết bị Google Cast như Chromecast hoặc Android TV được định cấu hình có kết nối Internet.
- TV hoặc màn hình có đầu vào HDMI.
- Bạn cần có Chromecast có Google TV để kiểm tra quá trình tích hợp Cast Connect nhưng không bắt buộc trong phần còn lại của lớp học lập trình này. Nếu bạn chưa có dịch vụ hỗ trợ Cast Connect, vui lòng bỏ qua bước Thêm tính năng hỗ trợ Cast Connect ở cuối hướng dẫn này.
Trải nghiệm
- Bạn sẽ cần phải có kiến thức trước về phát triển iOS.
- Bạn cũng cần có kiến thức trước đây về việc xem TV :)
Bạn sẽ sử dụng hướng dẫn này như thế nào?
Bạn đánh giá trải nghiệm xây dựng ứng dụng iOS của mình như thế nào?
Bạn đánh giá trải nghiệm xem TV của mình ở mức nào?
2. Nhận mã mẫu
Bạn có thể tải tất cả mã mẫu xuống máy tính...
và giải nén tệp zip đã tải xuống.
3. Chạy ứng dụng mẫu
Trước tiên, hãy cùng xem ứng dụng mẫu hoàn chỉnh sẽ có giao diện như thế nào. Ứng dụng này là một trình phát video cơ bản. Người dùng có thể chọn một video trong danh sách rồi phát video đó trên thiết bị hoặc Truyền video đó đến một thiết bị Google Cast.
Sau khi bạn tải mã xuống, các hướng dẫn sau đây mô tả cách mở và chạy ứng dụng mẫu hoàn chỉnh trong Xcode:
Câu hỏi thường gặp
Thiết lập CocoaPods
Để thiết lập CocoaPods, hãy chuyển đến bảng điều khiển của bạn và cài đặt bằng Ruby mặc định có trên macOS:
sudo gem install cocoapods
Nếu bạn gặp vấn đề, hãy tham khảo tài liệu chính thức để tải xuống và cài đặt trình quản lý phần phụ thuộc.
Thiết lập dự án
- Chuyển đến dòng lệnh và chuyển đến thư mục của lớp học lập trình.
- Cài đặt các phần phụ thuộc từ Podfile.
cd app-done pod update pod install
- Mở Xcode rồi chọn Open another project... (Mở một dự án khác).
- Chọn tệp
CastVideos-ios.xcworkspace
từ thư mụcapp-done
trong thư mục mã mẫu.
Chạy ứng dụng
Chọn mục tiêu và trình mô phỏng, sau đó chạy ứng dụng:
Bạn sẽ thấy ứng dụng video xuất hiện sau vài giây.
Hãy nhớ nhấp vào "Cho phép" khi thông báo xuất hiện về việc chấp nhận kết nối mạng đến. Biểu tượng Truyền sẽ không xuất hiện nếu bạn không chấp nhận lựa chọn này.
Nhấp vào nút Truyền và chọn thiết bị Google Cast của bạn.
Chọn một video, nhấp vào nút phát.
Video sẽ bắt đầu phát trên thiết bị Google Cast của bạn.
Bộ điều khiển mở rộng sẽ xuất hiện. Bạn có thể dùng nút phát/tạm dừng để điều khiển quá trình phát.
Quay lại danh sách video.
Một tay điều khiển thu nhỏ hiện ra ở cuối màn hình.
Nhấp vào nút tạm dừng trên bộ điều khiển nhỏ để tạm dừng video trên bộ thu. Nhấp vào nút phát trong bộ điều khiển thu nhỏ để tiếp tục phát lại video.
Nhấp vào nút Truyền để dừng truyền đến thiết bị Google Cast.
4. Chuẩn bị dự án khởi động
Chúng tôi cần thêm tính năng hỗ trợ cho Google Cast vào ứng dụng khởi động mà bạn đã tải xuống. Dưới đây là một số thuật ngữ của Google Cast mà chúng ta sẽ sử dụng trong lớp học lập trình này:
- một ứng dụng của người gửi chạy trên thiết bị di động hoặc máy tính xách tay
- ứng dụng receiver (trình nhận) chạy trên thiết bị Google Cast.
Thiết lập dự án
Bây giờ, bạn đã sẵn sàng tạo dự án dựa trên dự án khởi đầu bằng Xcode:
- Chuyển đến dòng lệnh và chuyển đến thư mục của lớp học lập trình.
- Cài đặt các phần phụ thuộc từ Podfile.
cd app-start pod update pod install
- Mở Xcode rồi chọn Open another project... (Mở một dự án khác).
- Chọn tệp
CastVideos-ios.xcworkspace
trong thư mụcapp-start
trong thư mục mã mẫu.
Thiết kế ứng dụng
Ứng dụng tìm nạp danh sách video từ một máy chủ web từ xa và cung cấp danh sách để người dùng duyệt xem. Người dùng có thể chọn một video để xem chi tiết hoặc phát video đó trên thiết bị di động.
Ứng dụng này bao gồm hai trình điều khiển thành phần hiển thị chính: MediaTableViewController
và MediaViewController.
MediaTableViewController
UITableViewController này hiển thị danh sách các video từ một thực thể MediaListModel
. Danh sách video và siêu dữ liệu liên quan được lưu trữ trên máy chủ từ xa dưới dạng tệp JSON. MediaListModel
tìm nạp JSON này và xử lý để tạo danh sách các đối tượng MediaItem
.
Đối tượng MediaItem
mô hình hoá một video và siêu dữ liệu liên quan, chẳng hạn như tiêu đề, nội dung mô tả, URL của hình ảnh và URL của luồng.
MediaTableViewController
tạo một thực thể MediaListModel
, sau đó tự đăng ký làm MediaListModelDelegate
để được thông báo khi siêu dữ liệu nội dung nghe nhìn được tải xuống để có thể tải chế độ xem theo bảng.
Người dùng sẽ thấy một danh sách hình thu nhỏ video kèm theo nội dung mô tả ngắn cho mỗi video. Khi bạn chọn một mục, MediaItem
tương ứng sẽ được truyền đến MediaViewController
.
MediaViewController
Bộ điều khiển chế độ xem này hiển thị siêu dữ liệu về một video cụ thể và cho phép người dùng phát video đó trên thiết bị di động.
Trình điều khiển chế độ xem lưu trữ một LocalPlayerView
, một số chế độ điều khiển nội dung nghe nhìn và một vùng văn bản để hiển thị nội dung mô tả của video đã chọn. Trình phát che phần trên cùng của màn hình, chừa chỗ trống cho mô tả chi tiết của video bên dưới Người dùng có thể phát/tạm dừng hoặc tìm kiếm phát lại video cục bộ.
Câu hỏi thường gặp
5. Thêm nút Truyền
Ứng dụng hỗ trợ Cast sẽ hiển thị nút Truyền trong mỗi bộ điều khiển chế độ xem của ứng dụng đó. Khi nhấp vào nút Truyền, người dùng sẽ thấy danh sách các thiết bị Cast mà họ có thể chọn. Nếu người dùng đang phát nội dung cục bộ trên thiết bị gửi, thì việc chọn một thiết bị Truyền sẽ bắt đầu hoặc tiếp tục phát trên thiết bị Truyền đó. Bất cứ lúc nào trong phiên Truyền, người dùng có thể nhấp vào nút Truyền và ngừng truyền ứng dụng của bạn đến thiết bị Truyền. Người dùng phải kết nối hoặc ngắt kết nối khỏi Thiết bị truyền khi đang ở bất kỳ màn hình nào của ứng dụng, như được mô tả trong Danh sách kiểm tra thiết kế của Google Cast.
Cấu hình
Dự án bắt đầu yêu cầu các phần phụ thuộc và chế độ thiết lập Xcode giống như đối với ứng dụng mẫu đã hoàn thành. Quay lại phần đó rồi làm theo các bước tương tự để thêm GoogleCast.framework
vào dự án khởi động ứng dụng.
Khởi chạy
Khung Cast có một đối tượng singleton toàn cục, GCKCastContext
, điều phối tất cả hoạt động của khung. Bạn phải khởi chạy đối tượng này sớm trong vòng đời của ứng dụng, thường là trong phương thức application(_:didFinishLaunchingWithOptions:)
của ứng dụng uỷ quyền, để quá trình tiếp tục phiên tự động khi khởi động lại ứng dụng gửi có thể kích hoạt đúng cách và quá trình quét thiết bị có thể bắt đầu.
Bạn phải cung cấp đối tượng GCKCastOptions
khi khởi tạo GCKCastContext
. Lớp này chứa các tuỳ chọn ảnh hưởng đến hành vi của khung. Quan trọng nhất trong số này là ID ứng dụng nhận, dùng để lọc kết quả khám phá thiết bị Truyền và để khởi chạy ứng dụng nhận khi phiên Truyền bắt đầu.
Phương thức application(_:didFinishLaunchingWithOptions:)
cũng là một nơi phù hợp để thiết lập một trình uỷ quyền ghi nhật ký nhằm nhận thông báo ghi nhật ký từ khung Cast. Các thông tin này có thể hữu ích khi gỡ lỗi và khắc phục sự cố.
Khi phát triển ứng dụng hỗ trợ Cast của riêng mình, bạn phải đăng ký làm nhà phát triển Cast và sau đó lấy ID ứng dụng cho ứng dụng của mình. Đối với lớp học lập trình này, chúng ta sẽ sử dụng mã ứng dụng mẫu.
Thêm mã sau vào AppDelegate.swift
để khởi chạy GCKCastContext
bằng ID ứng dụng từ giá trị mặc định của người dùng và thêm trình ghi nhật ký cho khung Google Cast:
import GoogleCast
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
fileprivate var enableSDKLogging = true
...
func application(_: UIApplication,
didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
...
let options = GCKCastOptions(discoveryCriteria: GCKDiscoveryCriteria(applicationID: kReceiverAppID))
options.physicalVolumeButtonsWillControlDeviceVolume = true
GCKCastContext.setSharedInstanceWith(options)
window?.clipsToBounds = true
setupCastLogging()
...
}
...
func setupCastLogging() {
let logFilter = GCKLoggerFilter()
let classesToLog = ["GCKDeviceScanner", "GCKDeviceProvider", "GCKDiscoveryManager", "GCKCastChannel",
"GCKMediaControlChannel", "GCKUICastButton", "GCKUIMediaController", "NSMutableDictionary"]
logFilter.setLoggingLevel(.verbose, forClasses: classesToLog)
GCKLogger.sharedInstance().filter = logFilter
GCKLogger.sharedInstance().delegate = self
}
}
...
// MARK: - GCKLoggerDelegate
extension AppDelegate: GCKLoggerDelegate {
func logMessage(_ message: String,
at _: GCKLoggerLevel,
fromFunction function: String,
location: String) {
if enableSDKLogging {
// Send SDK's log messages directly to the console.
print("\(location): \(function) - \(message)")
}
}
}
Nút truyền
Giờ đây, khi GCKCastContext
đã được khởi chạy, chúng ta cần thêm nút Truyền để cho phép người dùng chọn một thiết bị Truyền. Cast SDK cung cấp một thành phần nút Truyền có tên là GCKUICastButton
dưới dạng lớp con UIButton
. Bạn có thể thêm nút này vào thanh tiêu đề của ứng dụng bằng cách gói nút này trong UIBarButtonItem
. Chúng ta cần thêm nút Truyền vào cả MediaTableViewController
và MediaViewController
.
Thêm mã sau vào MediaTableViewController.swift
và MediaViewController.swift
:
import GoogleCast
@objc(MediaTableViewController)
class MediaTableViewController: UITableViewController, GCKSessionManagerListener,
MediaListModelDelegate, GCKRequestDelegate {
private var castButton: GCKUICastButton!
...
override func viewDidLoad() {
print("MediaTableViewController - viewDidLoad")
super.viewDidLoad()
...
castButton = GCKUICastButton(frame: CGRect(x: CGFloat(0), y: CGFloat(0),
width: CGFloat(24), height: CGFloat(24)))
// Overwrite the UIAppearance theme in the AppDelegate.
castButton.tintColor = UIColor.white
navigationItem.rightBarButtonItem = UIBarButtonItem(customView: castButton)
...
}
...
}
Tiếp theo, hãy thêm mã sau vào MediaViewController.swift
:
import GoogleCast
@objc(MediaViewController)
class MediaViewController: UIViewController, GCKSessionManagerListener, GCKRemoteMediaClientListener,
LocalPlayerViewDelegate, GCKRequestDelegate {
private var castButton: GCKUICastButton!
...
override func viewDidLoad() {
super.viewDidLoad()
print("in MediaViewController viewDidLoad")
...
castButton = GCKUICastButton(frame: CGRect(x: CGFloat(0), y: CGFloat(0),
width: CGFloat(24), height: CGFloat(24)))
// Overwrite the UIAppearance theme in the AppDelegate.
castButton.tintColor = UIColor.white
navigationItem.rightBarButtonItem = UIBarButtonItem(customView: castButton)
...
}
...
}
Bây giờ, hãy chạy ứng dụng. Bạn sẽ thấy một nút Truyền trong thanh điều hướng của ứng dụng. Khi bạn nhấp vào nút này, các thiết bị Truyền trên mạng cục bộ của bạn sẽ được liệt kê. Tính năng khám phá thiết bị được GCKCastContext
quản lý tự động. Chọn Thiết bị truyền của bạn và ứng dụng bộ nhận mẫu sẽ tải trên Thiết bị truyền. Bạn có thể di chuyển giữa hoạt động duyệt web và hoạt động của trình phát trên máy. Trạng thái của nút Truyền luôn được đồng bộ hoá.
Chúng tôi chưa kết nối tính năng hỗ trợ phát nội dung nghe nhìn nào, vì vậy, bạn chưa thể phát video trên thiết bị truyền. Nhấp vào nút Truyền để dừng truyền.
6. Đang truyền nội dung video
Chúng tôi sẽ mở rộng ứng dụng mẫu để có thể phát video từ xa trên thiết bị truyền. Để làm được điều đó, chúng ta cần theo dõi nhiều sự kiện do khung Cast tạo ra.
Đang truyền nội dung nghe nhìn
Nhìn chung, nếu bạn muốn phát nội dung nghe nhìn trên thiết bị Cast, thì những điều sau đây cần xảy ra:
- Tạo một đối tượng
GCKMediaInformation
từ SDK Truyền để mô hình hoá một mục nội dung đa phương tiện. - Người dùng kết nối với thiết bị Cast để chạy ứng dụng receiver.
- Tải đối tượng
GCKMediaInformation
vào trình thu nhận và phát nội dung. - Theo dõi trạng thái của nội dung nghe nhìn.
- Gửi lệnh phát đến bộ thu dựa trên hoạt động tương tác của người dùng.
Bước 1 là liên kết một đối tượng với một đối tượng khác; GCKMediaInformation
là nội dung mà SDK truyền phát hiểu được và MediaItem
là nội dung đóng gói của ứng dụng cho một mục nội dung nghe nhìn; chúng ta có thể dễ dàng liên kết MediaItem
với GCKMediaInformation
. Chúng ta đã thực hiện Bước 2 trong phần trước. Bước 3 là dễ dàng thực hiện với SDK Truyền.
Ứng dụng mẫu MediaViewController
đã phân biệt giữa chế độ phát cục bộ và từ xa bằng cách sử dụng enum này:
enum PlaybackMode: Int {
case none = 0
case local
case remote
}
private var playbackMode = PlaybackMode.none
Trong lớp học lập trình này, bạn không cần phải hiểu chính xác cách hoạt động của tất cả logic người chơi mẫu. Điều quan trọng là phải hiểu rằng trình phát đa phương tiện của ứng dụng sẽ phải được sửa đổi để nhận biết hai vị trí phát lại theo cách tương tự.
Hiện tại, trình phát cục bộ luôn ở trạng thái phát cục bộ vì chưa biết gì về trạng thái Truyền. Chúng ta cần cập nhật giao diện người dùng dựa trên quá trình chuyển đổi trạng thái diễn ra trong khung Truyền. Ví dụ: nếu bắt đầu truyền, chúng ta cần dừng chế độ phát cục bộ và tắt một số chế độ điều khiển. Tương tự, nếu dừng truyền khi đang ở trong trình điều khiển thành phần hiển thị này, chúng ta cần chuyển sang chế độ phát cục bộ. Để xử lý vấn đề đó, chúng ta cần theo dõi nhiều sự kiện do khung Cast tạo ra.
Quản lý phiên truyền
Đối với khung Truyền, phiên Truyền sẽ kết hợp các bước kết nối với thiết bị, khởi chạy (hoặc tham gia), kết nối với ứng dụng nhận và khởi tạo kênh điều khiển nội dung nghe nhìn nếu thích hợp. Kênh điều khiển nội dung nghe nhìn là cách khung Cast gửi và nhận thông báo từ trình phát nội dung nghe nhìn của bộ thu.
Phiên Truyền sẽ tự động bắt đầu khi người dùng chọn một thiết bị trong nút Truyền và sẽ tự động dừng khi người dùng ngắt kết nối. Khung Cast cũng tự động xử lý việc kết nối lại với phiên của trình nhận do các vấn đề về mạng.
Các phiên truyền được quản lý bởi GCKSessionManager
. Bạn có thể truy cập vào phiên truyền này thông qua GCKCastContext.sharedInstance().sessionManager
. Bạn có thể dùng các lệnh gọi lại GCKSessionManagerListener
để theo dõi các sự kiện trong phiên, chẳng hạn như tạo, tạm ngưng, tiếp tục và chấm dứt.
Trước tiên, chúng ta cần đăng ký trình nghe phiên và khởi tạo một số biến:
class MediaViewController: UIViewController, GCKSessionManagerListener,
GCKRemoteMediaClientListener, LocalPlayerViewDelegate, GCKRequestDelegate {
...
private var sessionManager: GCKSessionManager!
...
required init?(coder: NSCoder) {
super.init(coder: coder)
sessionManager = GCKCastContext.sharedInstance().sessionManager
...
}
override func viewWillAppear(_ animated: Bool) {
...
let hasConnectedSession: Bool = (sessionManager.hasConnectedSession())
if hasConnectedSession, (playbackMode != .remote) {
populateMediaInfo(false, playPosition: 0)
switchToRemotePlayback()
} else if sessionManager.currentSession == nil, (playbackMode != .local) {
switchToLocalPlayback()
}
sessionManager.add(self)
...
}
override func viewWillDisappear(_ animated: Bool) {
...
sessionManager.remove(self)
sessionManager.currentCastSession?.remoteMediaClient?.remove(self)
...
super.viewWillDisappear(animated)
}
func switchToLocalPlayback() {
...
sessionManager.currentCastSession?.remoteMediaClient?.remove(self)
...
}
func switchToRemotePlayback() {
...
sessionManager.currentCastSession?.remoteMediaClient?.add(self)
...
}
// MARK: - GCKSessionManagerListener
func sessionManager(_: GCKSessionManager, didStart session: GCKSession) {
print("MediaViewController: sessionManager didStartSession \(session)")
setQueueButtonVisible(true)
switchToRemotePlayback()
}
func sessionManager(_: GCKSessionManager, didResumeSession session: GCKSession) {
print("MediaViewController: sessionManager didResumeSession \(session)")
setQueueButtonVisible(true)
switchToRemotePlayback()
}
func sessionManager(_: GCKSessionManager, didEnd _: GCKSession, withError error: Error?) {
print("session ended with error: \(String(describing: error))")
let message = "The Casting session has ended.\n\(String(describing: error))"
if let window = appDelegate?.window {
Toast.displayMessage(message, for: 3, in: window)
}
setQueueButtonVisible(false)
switchToLocalPlayback()
}
func sessionManager(_: GCKSessionManager, didFailToStartSessionWithError error: Error?) {
if let error = error {
showAlert(withTitle: "Failed to start a session", message: error.localizedDescription)
}
setQueueButtonVisible(false)
}
func sessionManager(_: GCKSessionManager,
didFailToResumeSession _: GCKSession, withError _: Error?) {
if let window = UIApplication.shared.delegate?.window {
Toast.displayMessage("The Casting session could not be resumed.",
for: 3, in: window)
}
setQueueButtonVisible(false)
switchToLocalPlayback()
}
...
}
Trong MediaViewController
, chúng tôi muốn biết khi nào chúng ta kết nối hoặc bị ngắt kết nối khỏi Thiết bị truyền để có thể chuyển sang hoặc từ trình phát cục bộ. Xin lưu ý rằng khả năng kết nối không chỉ bị gián đoạn bởi phiên bản ứng dụng chạy trên thiết bị di động của bạn, mà còn có thể bị gián đoạn bởi một phiên bản khác của ứng dụng (hoặc một ứng dụng khác) chạy trên một thiết bị di động khác.
Phiên hiện đang hoạt động có thể truy cập được bằng tài khoản GCKCastContext.sharedInstance().sessionManager.currentCastSession
. Các phiên hoạt động được tạo và thu gọn tự động theo cử chỉ của người dùng từ hộp thoại Truyền.
Đang tải nội dung nghe nhìn
Trong SDK truyền, GCKRemoteMediaClient
cung cấp một tập hợp các API thuận tiện để quản lý việc phát nội dung đa phương tiện từ xa trên thiết bị nhận. Đối với GCKCastSession
hỗ trợ phát nội dung đa phương tiện, SDK sẽ tự động tạo một thực thể của GCKRemoteMediaClient
. Thuộc tính này có thể được truy cập dưới dạng thuộc tính remoteMediaClient
của thực thể GCKCastSession
.
Thêm mã sau vào MediaViewController.swift
để tải video đang được chọn trên bộ thu:
@objc(MediaViewController)
class MediaViewController: UIViewController, GCKSessionManagerListener,
GCKRemoteMediaClientListener, LocalPlayerViewDelegate, GCKRequestDelegate {
...
@objc func playSelectedItemRemotely() {
loadSelectedItem(byAppending: false)
}
/**
* Loads the currently selected item in the current cast media session.
* @param appending If YES, the item is appended to the current queue if there
* is one. If NO, or if
* there is no queue, a new queue containing only the selected item is created.
*/
func loadSelectedItem(byAppending appending: Bool) {
print("enqueue item \(String(describing: mediaInfo))")
if let remoteMediaClient = sessionManager.currentCastSession?.remoteMediaClient {
let mediaQueueItemBuilder = GCKMediaQueueItemBuilder()
mediaQueueItemBuilder.mediaInformation = mediaInfo
mediaQueueItemBuilder.autoplay = true
mediaQueueItemBuilder.preloadTime = TimeInterval(UserDefaults.standard.integer(forKey: kPrefPreloadTime))
let mediaQueueItem = mediaQueueItemBuilder.build()
if appending {
let request = remoteMediaClient.queueInsert(mediaQueueItem, beforeItemWithID: kGCKMediaQueueInvalidItemID)
request.delegate = self
} else {
let queueDataBuilder = GCKMediaQueueDataBuilder(queueType: .generic)
queueDataBuilder.items = [mediaQueueItem]
queueDataBuilder.repeatMode = remoteMediaClient.mediaStatus?.queueRepeatMode ?? .off
let mediaLoadRequestDataBuilder = GCKMediaLoadRequestDataBuilder()
mediaLoadRequestDataBuilder.mediaInformation = mediaInfo
mediaLoadRequestDataBuilder.queueData = queueDataBuilder.build()
let request = remoteMediaClient.loadMedia(with: mediaLoadRequestDataBuilder.build())
request.delegate = self
}
}
}
...
}
Bây giờ, hãy cập nhật nhiều phương thức hiện có để sử dụng logic Phiên truyền để hỗ trợ phát từ xa:
required init?(coder: NSCoder) {
super.init(coder: coder)
...
castMediaController = GCKUIMediaController()
...
}
func switchToLocalPlayback() {
print("switchToLocalPlayback")
if playbackMode == .local {
return
}
setQueueButtonVisible(false)
var playPosition: TimeInterval = 0
var paused: Bool = false
var ended: Bool = false
if playbackMode == .remote {
playPosition = castMediaController.lastKnownStreamPosition
paused = (castMediaController.lastKnownPlayerState == .paused)
ended = (castMediaController.lastKnownPlayerState == .idle)
print("last player state: \(castMediaController.lastKnownPlayerState), ended: \(ended)")
}
populateMediaInfo((!paused && !ended), playPosition: playPosition)
sessionManager.currentCastSession?.remoteMediaClient?.remove(self)
playbackMode = .local
}
func switchToRemotePlayback() {
print("switchToRemotePlayback; mediaInfo is \(String(describing: mediaInfo))")
if playbackMode == .remote {
return
}
// If we were playing locally, load the local media on the remote player
if playbackMode == .local, (_localPlayerView.playerState != .stopped), (mediaInfo != nil) {
print("loading media: \(String(describing: mediaInfo))")
let paused: Bool = (_localPlayerView.playerState == .paused)
let mediaQueueItemBuilder = GCKMediaQueueItemBuilder()
mediaQueueItemBuilder.mediaInformation = mediaInfo
mediaQueueItemBuilder.autoplay = !paused
mediaQueueItemBuilder.preloadTime = TimeInterval(UserDefaults.standard.integer(forKey: kPrefPreloadTime))
mediaQueueItemBuilder.startTime = _localPlayerView.streamPosition ?? 0
let mediaQueueItem = mediaQueueItemBuilder.build()
let queueDataBuilder = GCKMediaQueueDataBuilder(queueType: .generic)
queueDataBuilder.items = [mediaQueueItem]
queueDataBuilder.repeatMode = .off
let mediaLoadRequestDataBuilder = GCKMediaLoadRequestDataBuilder()
mediaLoadRequestDataBuilder.queueData = queueDataBuilder.build()
let request = sessionManager.currentCastSession?.remoteMediaClient?.loadMedia(with: mediaLoadRequestDataBuilder.build())
request?.delegate = self
}
_localPlayerView.stop()
_localPlayerView.showSplashScreen()
setQueueButtonVisible(true)
sessionManager.currentCastSession?.remoteMediaClient?.add(self)
playbackMode = .remote
}
/* Play has been pressed in the LocalPlayerView. */
func continueAfterPlayButtonClicked() -> Bool {
let hasConnectedCastSession = sessionManager.hasConnectedCastSession
if mediaInfo != nil, hasConnectedCastSession() {
// Display an alert box to allow the user to add to queue or play
// immediately.
if actionSheet == nil {
actionSheet = ActionSheet(title: "Play Item", message: "Select an action", cancelButtonText: "Cancel")
actionSheet?.addAction(withTitle: "Play Now", target: self,
selector: #selector(playSelectedItemRemotely))
}
actionSheet?.present(in: self, sourceView: _localPlayerView)
return false
}
return true
}
Bây giờ, hãy chạy ứng dụng trên thiết bị di động. Kết nối với Thiết bị truyền của bạn và bắt đầu phát video. Bạn sẽ thấy video phát trên thiết bị nhận.
7. Tay điều khiển nhỏ
Danh sách kiểm tra thiết kế Cast yêu cầu tất cả các ứng dụng Truyền đều cung cấp bộ điều khiển nhỏ để xuất hiện khi người dùng di chuyển khỏi trang nội dung hiện tại. Bộ điều khiển mini cho phép truy cập tức thì và hiển thị lời nhắc cho phiên Truyền hiện tại.
SDK Truyền cung cấp một thanh điều khiển (GCKUIMiniMediaControlsViewController
) có thể được thêm vào các cảnh mà bạn muốn hiện các nút điều khiển liên tục.
Đối với ứng dụng mẫu, chúng ta sẽ sử dụng GCKUICastContainerViewController
để gói một trình điều khiển chế độ xem khác và thêm GCKUIMiniMediaControlsViewController
ở dưới cùng.
Sửa đổi tệp AppDelegate.swift
và thêm mã sau đây cho điều kiện if useCastContainerViewController
trong phương thức sau:
func application(_: UIApplication,
didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
...
let appStoryboard = UIStoryboard(name: "Main", bundle: nil)
guard let navigationController = appStoryboard.instantiateViewController(withIdentifier: "MainNavigation")
as? UINavigationController else { return false }
let castContainerVC = GCKCastContext.sharedInstance().createCastContainerController(for: navigationController)
as GCKUICastContainerViewController
castContainerVC.miniMediaControlsItemEnabled = true
window = UIWindow(frame: UIScreen.main.bounds)
window?.rootViewController = castContainerVC
window?.makeKeyAndVisible()
...
}
Thêm thuộc tính này và phương thức setter/getter để kiểm soát chế độ hiển thị của trình điều khiển thu nhỏ (chúng ta sẽ sử dụng các thành phần này trong phần sau):
var isCastControlBarsEnabled: Bool {
get {
if useCastContainerViewController {
let castContainerVC = (window?.rootViewController as? GCKUICastContainerViewController)
return castContainerVC!.miniMediaControlsItemEnabled
} else {
let rootContainerVC = (window?.rootViewController as? RootContainerViewController)
return rootContainerVC!.miniMediaControlsViewEnabled
}
}
set(notificationsEnabled) {
if useCastContainerViewController {
var castContainerVC: GCKUICastContainerViewController?
castContainerVC = (window?.rootViewController as? GCKUICastContainerViewController)
castContainerVC?.miniMediaControlsItemEnabled = notificationsEnabled
} else {
var rootContainerVC: RootContainerViewController?
rootContainerVC = (window?.rootViewController as? RootContainerViewController)
rootContainerVC?.miniMediaControlsViewEnabled = notificationsEnabled
}
}
}
Chạy ứng dụng và truyền video. Khi quá trình phát bắt đầu trên bộ thu, bạn sẽ thấy tay điều khiển thu nhỏ xuất hiện ở cuối mỗi cảnh. Bạn có thể điều khiển chế độ phát từ xa bằng tay điều khiển thu nhỏ. Nếu bạn di chuyển giữa hoạt động duyệt web và hoạt động trên trình phát trên máy, thì trạng thái của tay điều khiển thu nhỏ phải luôn đồng bộ với trạng thái phát nội dung nghe nhìn của bộ nhận.
8. Lớp phủ giới thiệu
Danh sách kiểm tra thiết kế của Google Cast yêu cầu một ứng dụng dành cho người gửi để giới thiệu nút Truyền cho người dùng hiện tại để cho họ biết rằng ứng dụng gửi hiện hỗ trợ tính năng Truyền và cũng giúp người dùng mới làm quen với Google Cast.
Lớp GCKCastContext
có một phương thức, presentCastInstructionsViewControllerOnce
, có thể được dùng để làm nổi bật nút Truyền khi nút này xuất hiện lần đầu tiên cho người dùng. Thêm mã sau vào MediaViewController.swift
và MediaTableViewController.swift
:
override func viewDidLoad() {
...
NotificationCenter.default.addObserver(self, selector: #selector(castDeviceDidChange),
name: NSNotification.Name.gckCastStateDidChange,
object: GCKCastContext.sharedInstance())
}
@objc func castDeviceDidChange(_: Notification) {
if GCKCastContext.sharedInstance().castState != .noDevicesAvailable {
// You can present the instructions on how to use Google Cast on
// the first time the user uses you app
GCKCastContext.sharedInstance().presentCastInstructionsViewControllerOnce(with: castButton)
}
}
Chạy ứng dụng trên thiết bị di động và bạn sẽ thấy lớp phủ giới thiệu.
9. Đã mở rộng bộ điều khiển
Danh sách kiểm tra thiết kế Google Cast yêu cầu ứng dụng gửi phải cung cấp trình điều khiển mở rộng cho nội dung đa phương tiện đang truyền. Bộ điều khiển mở rộng là phiên bản toàn màn hình của tay điều khiển mini.
Trình điều khiển mở rộng là một chế độ xem toàn màn hình, cung cấp toàn quyền kiểm soát việc phát nội dung nghe nhìn từ xa. Chế độ xem này cho phép ứng dụng truyền phát quản lý mọi khía cạnh có thể quản lý của một phiên truyền phát, ngoại trừ chế độ điều khiển âm lượng của thiết bị nhận và vòng đời của phiên (kết nối/dừng truyền). Tệp này cũng cung cấp tất cả thông tin trạng thái về phiên phát nội dung đa phương tiện (hình minh hoạ, tiêu đề, phụ đề, v.v.).
Chức năng của thành phần hiển thị này được triển khai bằng lớp GCKUIExpandedMediaControlsViewController
.
Việc đầu tiên bạn cần làm là bật bộ điều khiển mở rộng mặc định trong ngữ cảnh truyền. Sửa đổi AppDelegate.swift
để bật bộ điều khiển mở rộng mặc định:
import GoogleCast
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
...
func application(_: UIApplication,
didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
...
// Add after the setShareInstanceWith(options) is set.
GCKCastContext.sharedInstance().useDefaultExpandedMediaControls = true
...
}
...
}
Thêm mã sau vào MediaViewController.swift
để tải tay điều khiển mở rộng khi người dùng bắt đầu truyền video:
@objc func playSelectedItemRemotely() {
...
appDelegate?.isCastControlBarsEnabled = false
GCKCastContext.sharedInstance().presentDefaultExpandedMediaControls()
}
Bộ điều khiển mở rộng cũng sẽ tự động chạy khi người dùng nhấn vào tay điều khiển thu nhỏ.
Chạy ứng dụng và truyền một video. Bạn sẽ thấy bộ điều khiển mở rộng. Quay lại danh sách video và khi bạn nhấp vào bộ điều khiển thu nhỏ, bộ điều khiển mở rộng sẽ tải lại.
10. Thêm tính năng hỗ trợ Cast Connect
Thư viện Cast Connect cho phép các ứng dụng gửi hiện có giao tiếp với các ứng dụng Android TV thông qua giao thức Cast. Cast Connect được xây dựng dựa trên cơ sở hạ tầng Cast, trong đó ứng dụng Android TV đóng vai trò là trình thu.
Phần phụ thuộc
Trong Podfile
, hãy đảm bảo google-cast-sdk
trỏ đến 4.4.8
hoặc cao hơn như liệt kê dưới đây. Nếu bạn đã sửa đổi tệp, hãy chạy pod update
trên bảng điều khiển để đồng bộ hoá nội dung thay đổi với dự án.
pod 'google-cast-sdk', '>=4.4.8'
GCKLaunchOptions
Để chạy ứng dụng Android TV, còn được gọi là Android receiver, chúng ta cần đặt cờ androidReceiverCompatible
thành true trong đối tượng GCKLaunchOptions
. Đối tượng GCKLaunchOptions
này cho biết cách chạy trình thu nhận và truyền đến GCKCastOptions
được đặt trong thực thể dùng chung bằng GCKCastContext.setSharedInstanceWith
.
Thêm các dòng sau vào AppDelegate.swift
:
let options = GCKCastOptions(discoveryCriteria:
GCKDiscoveryCriteria(applicationID: kReceiverAppID))
...
/** Following code enables CastConnect */
let launchOptions = GCKLaunchOptions()
launchOptions.androidReceiverCompatible = true
options.launchOptions = launchOptions
GCKCastContext.setSharedInstanceWith(options)
Đặt thông tin xác thực chạy
Ở phía người gửi, bạn có thể chỉ định GCKCredentialsData
để đại diện cho người tham gia phiên. credentials
là một chuỗi có thể do người dùng xác định, miễn là ứng dụng ATV của bạn có thể hiểu được chuỗi đó. GCKCredentialsData
chỉ được truyền đến ứng dụng Android TV của bạn trong thời gian khởi chạy hoặc tham gia. Nếu bạn đặt lại giá trị này trong khi đang kết nối, thì giá trị này sẽ không được chuyển đến ứng dụng Android TV.
Để đặt Thông tin xác thực khi khởi chạy, bạn cần xác định GCKCredentialsData
bất cứ lúc nào sau khi đặt GCKLaunchOptions
. Để chứng minh điều này, hãy thêm logic cho nút Creds (Thành phần) để đặt thông tin đăng nhập sẽ được truyền khi phiên được thiết lập. Thêm mã sau vào MediaTableViewController.swift
:
class MediaTableViewController: UITableViewController, GCKSessionManagerListener, MediaListModelDelegate, GCKRequestDelegate {
...
private var credentials: String? = nil
...
override func viewDidLoad() {
...
navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Creds", style: .plain,
target: self, action: #selector(toggleLaunchCreds))
...
setLaunchCreds()
}
...
@objc func toggleLaunchCreds(_: Any){
if (credentials == nil) {
credentials = "{\"userId\":\"id123\"}"
} else {
credentials = nil
}
Toast.displayMessage("Launch Credentials: "+(credentials ?? "Null"), for: 3, in: appDelegate?.window)
print("Credentials set: "+(credentials ?? "Null"))
setLaunchCreds()
}
...
func setLaunchCreds() {
GCKCastContext.sharedInstance()
.setLaunch(GCKCredentialsData(credentials: credentials))
}
}
Đặt thông tin xác thực trên yêu cầu tải
Để xử lý credentials
trên cả ứng dụng Web và ứng dụng Bộ thu Android TV, hãy thêm mã sau vào lớp MediaTableViewController.swift
trong hàm loadSelectedItem
:
let mediaLoadRequestDataBuilder = GCKMediaLoadRequestDataBuilder()
...
mediaLoadRequestDataBuilder.credentials = credentials
...
Tuỳ thuộc vào ứng dụng nhận mà người gửi đang truyền tới, SDK sẽ tự động áp dụng thông tin xác thực ở trên cho phiên đang diễn ra.
Kiểm thử Cast Connect
Các bước cài đặt tệp APK Android TV trên Chromecast có Google TV
- Tìm Địa chỉ IP của thiết bị Android TV. Thông thường, bạn có thể tìm thấy phần này trong phần Cài đặt > Mạng và Internet > (Tên mạng mà thiết bị của bạn đang kết nối). Ở bên phải, bạn sẽ thấy thông tin chi tiết và địa chỉ IP của thiết bị trên mạng.
- Sử dụng địa chỉ IP của thiết bị để kết nối với thiết bị đó qua ADB bằng dòng lệnh:
$ adb connect <device_ip_address>:5555
- Từ cửa sổ dòng lệnh, hãy chuyển đến thư mục cấp cao nhất của các mẫu trong lớp học lập trình mà bạn đã tải xuống ở đầu lớp học lập trình này. Ví dụ:
$ cd Desktop/ios_codelab_src
- Cài đặt tệp .apk trong thư mục này vào Android TV bằng cách chạy:
$ adb -s <device_ip_address>:5555 install android-tv-app.apk
- Giờ đây, bạn có thể thấy một ứng dụng có tên là Cast Videos (Truyền video) trong trình đơn Your Apps (Ứng dụng của bạn) trên thiết bị Android TV.
- Sau khi hoàn tất, hãy tạo và chạy ứng dụng trên trình mô phỏng hoặc thiết bị di động. Khi thiết lập một phiên truyền bằng thiết bị Android TV, giờ đây, thiết bị này sẽ khởi chạy ứng dụng Bộ thu Android trên Android TV của bạn. Khi phát video từ trình gửi trên thiết bị di động iOS, video sẽ chạy trong Bộ thu Android và cho phép bạn điều khiển chế độ phát bằng điều khiển từ xa cho thiết bị Android TV.
11. Tuỳ chỉnh tiện ích Truyền
Khởi chạy
Bắt đầu với thư mục App-Done (Xong). Thêm nội dung sau vào phương thức applicationDidFinishLaunchingWithOptions
trong tệp AppDelegate.swift
.
func application(_: UIApplication,
didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
...
let styler = GCKUIStyle.sharedInstance()
...
}
Sau khi bạn áp dụng xong một hoặc nhiều chế độ tuỳ chỉnh như đã đề cập trong phần còn lại của lớp học lập trình này, hãy xác nhận các kiểu tuỳ chỉnh bằng cách gọi đoạn mã dưới đây
styler.apply()
Tuỳ chỉnh chế độ xem Truyền
Bạn có thể tuỳ chỉnh tất cả các khung hiển thị mà Khung ứng dụng truyền quản lý bằng cách đặt nguyên tắc định kiểu mặc định trên các khung hiển thị. Ví dụ: hãy thay đổi màu phủ của biểu tượng.
styler.castViews.iconTintColor = .lightGray
Bạn có thể ghi đè giá trị mặc định cho từng màn hình nếu cần. Ví dụ: để ghi đè lightGrayColor cho màu phủ biểu tượng chỉ dành cho trình điều khiển nội dung nghe nhìn mở rộng.
styler.castViews.mediaControl.expandedController.iconTintColor = .green
Thay đổi màu sắc
Bạn có thể tuỳ chỉnh màu nền cho tất cả chế độ xem (hoặc tuỳ chỉnh riêng cho từng chế độ xem). Mã sau đây đặt màu nền thành màu xanh dương cho tất cả thành phần hiển thị do Khung ứng dụng truyền phát cung cấp.
styler.castViews.backgroundColor = .blue
styler.castViews.mediaControl.miniController.backgroundColor = .yellow
Thay đổi phông chữ
Bạn có thể tuỳ chỉnh phông chữ cho các nhãn khác nhau trong chế độ xem truyền. Hãy đặt tất cả phông chữ thành "Courier-Oblique" để minh hoạ.
styler.castViews.headingTextFont = UIFont.init(name: "Courier-Oblique", size: 16) ?? UIFont.systemFont(ofSize: 16)
styler.castViews.mediaControl.headingTextFont = UIFont.init(name: "Courier-Oblique", size: 6) ?? UIFont.systemFont(ofSize: 6)
Thay đổi hình ảnh nút mặc định
Thêm hình ảnh tuỳ chỉnh của riêng bạn vào dự án và chỉ định hình ảnh cho các nút để tạo kiểu cho các nút đó.
let muteOnImage = UIImage.init(named: "yourImage.png")
if let muteOnImage = muteOnImage {
styler.castViews.muteOnImage = muteOnImage
}
Thay đổi chủ đề của nút Truyền
Bạn cũng có thể tạo giao diện cho các tiện ích Cast bằng Giao thức giao diện người dùng. Các chủ đề mã sau đây của GCKUICastButton trên tất cả các khung hiển thị mà nó xuất hiện:
GCKUICastButton.appearance().tintColor = UIColor.gray
12. Xin chúc mừng
Giờ đây, bạn đã biết cách bật tính năng Truyền cho một ứng dụng video bằng tiện ích SDK Truyền trên iOS.
Để biết thêm chi tiết, hãy xem hướng dẫn dành cho nhà phát triển Trình gửi iOS.