Hướng dẫn dành cho nhà phát triển này mô tả cách thêm tính năng hỗ trợ Google Cast vào iOS của bạn bằng cách sử dụng iOS Sender SDK.
Thiết bị di động hoặc máy tính xách tay là người gửi điều khiển quá trình phát và Thiết bị Google Cast là bộ thu hiển thị nội dung trên TV.
Khung trình gửi đề cập đến tệp nhị phân của thư viện lớp Cast và tệp liên kết có trong thời gian chạy trên trình gửi. Ứng dụng người gửi hoặc Ứng dụng truyền đề cập đến một ứng dụng cũng chạy trên trình gửi. Ứng dụng Trình nhận web đề cập đến ứng dụng HTML chạy trên Web receiver.
Khung người gửi sử dụng thiết kế lệnh gọi lại không đồng bộ để thông báo cho người gửi ứng dụng của các sự kiện và để chuyển đổi giữa các trạng thái khác nhau của thời gian hoạt động của ứng dụng Truyền chu kỳ.
Luồng ứng dụng
Các bước sau đây mô tả quy trình thực thi cấp cao điển hình cho một người gửi Ứng dụng iOS:
- Khung Truyền bắt đầu
GCKDiscoveryManager
dựa trên các cơ sở lưu trú được cung cấp tạiGCKCastOptions
đến bắt đầu quét tìm thiết bị. - Khi người dùng nhấp vào nút Truyền, khung sẽ trình bày giao diện Truyền hộp thoại với danh sách các Thiết bị truyền được phát hiện.
- Khi người dùng chọn một Thiết bị truyền, khung sẽ cố khởi chạy Ứng dụng Trình nhận web trên Thiết bị truyền.
- Khung này sẽ gọi các lệnh gọi lại trong ứng dụng gửi để xác nhận rằng Phát hành ứng dụng Trình nhận web.
- Khung này tạo ra một kênh liên lạc giữa người gửi và Các ứng dụng Web nhận.
- Khung này sử dụng kênh liên lạc để tải và điều khiển nội dung nghe nhìn phát trên Web receiver.
- Khung này sẽ đồng bộ hoá trạng thái phát nội dung nghe nhìn giữa người gửi và Web receiver: khi người dùng thực hiện thao tác trên giao diện người dùng của người gửi, khung này sẽ chuyển các yêu cầu điều khiển nội dung nghe nhìn đó đến Web receiver cũng như khi Web receiver gửi thông tin cập nhật trạng thái nội dung nghe nhìn, khung sẽ cập nhật trạng thái của giao diện người dùng gửi.
- Khi người dùng nhấp vào nút Truyền để ngắt kết nối khỏi Thiết bị truyền, khung này sẽ ngắt kết nối ứng dụng của người gửi khỏi Web receiver.
Để khắc phục sự cố người gửi, bạn cần bật tính năng ghi nhật ký.
Để xem danh sách đầy đủ tất cả các lớp, phương thức và sự kiện trong Google Cast khung iOS, hãy xem API Google Cast iOS Tệp đối chiếu. Các phần sau đây trình bày các bước để tích hợp tính năng Truyền vào ứng dụng iOS.
Phương thức gọi từ luồng chính
Khởi chạy ngữ cảnh Truyền
Khung Cast có một đối tượng singleton toàn cầu,
GCKCastContext
là
điều phối tất cả hoạt động của khung này. Bạn phải khởi động đối tượng này
ở giai đoạn đầu trong vòng đời của ứng dụng, thường là trong
-[application:didFinishLaunchingWithOptions:]
của ứng dụng uỷ quyền, vì vậy
việc tự động tiếp tục phiên khi khởi động lại ứng dụng của người gửi có thể kích hoạt đúng cách.
GCKCastOptions
bạn phải cung cấp đối tượng 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. Nhiều nhất
quan trọng trong số này là ID ứng dụng Trình nhận web, được dùng để lọc
kết quả khám phá và khởi chạy ứng dụng Web receiver khi một phiên Truyền
đầu.
Phương thức -[application:didFinishLaunchingWithOptions:]
cũng là một phương thức hay
để thiết lập uỷ quyền ghi nhật ký để nhận thông báo ghi nhật ký từ khung.
Những thông tin này có thể hữu ích cho việc gỡ lỗi và khắc phục sự cố.
@UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate, GCKLoggerDelegate { let kReceiverAppID = kGCKDefaultMediaReceiverApplicationID let kDebugLoggingEnabled = true var window: UIWindow? func applicationDidFinishLaunching(_ application: UIApplication) { let criteria = GCKDiscoveryCriteria(applicationID: kReceiverAppID) let options = GCKCastOptions(discoveryCriteria: criteria) GCKCastContext.setSharedInstanceWith(options) // Enable logger. GCKLogger.sharedInstance().delegate = self ... } // MARK: - GCKLoggerDelegate func logMessage(_ message: String, at level: GCKLoggerLevel, fromFunction function: String, location: String) { if (kDebugLoggingEnabled) { print(function + " - " + message) } } }
AppDelegate.h
@interface AppDelegate () <GCKLoggerDelegate> @end
AppDelegate.m
@implementation AppDelegate static NSString *const kReceiverAppID = @"AABBCCDD"; static const BOOL kDebugLoggingEnabled = YES; - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { GCKDiscoveryCriteria *criteria = [[GCKDiscoveryCriteria alloc] initWithApplicationID:kReceiverAppID]; GCKCastOptions *options = [[GCKCastOptions alloc] initWithDiscoveryCriteria:criteria]; [GCKCastContext setSharedInstanceWithOptions:options]; // Enable logger. [GCKLogger sharedInstance].delegate = self; ... return YES; } ... #pragma mark - GCKLoggerDelegate - (void)logMessage:(NSString *)message atLevel:(GCKLoggerLevel)level fromFunction:(NSString *)function location:(NSString *)location { if (kDebugLoggingEnabled) { NSLog(@"%@ - %@, %@", function, message, location); } } @end
Tiện ích Trải nghiệm người dùng của Cast
SDK Truyền dành cho iOS cung cấp các tiện ích này tuân thủ Thiết kế truyền Danh sách kiểm tra:
Lớp phủ giới thiệu: Lớp
GCKCastContext
có một phương thứcpresentCastInstructionsViewControllerOnceWithCastButton
, có thể dùng để làm nổi bật nút Truyền vào lần đầu tiên Web nhận có sẵn. Ứng dụng dành cho người gửi có thể tuỳ chỉnh văn bản, vị trí của tiêu đề và nút Đóng.Nút truyền: Kể từ SDK gửi cho iOS phiên bản 4.6.0, nút truyền sẽ luôn hiển thị khi thiết bị của người gửi được kết nối với Wi-Fi. Lần đầu tiên người dùng nhấn trên nút Truyền sau khi khởi động ứng dụng ban đầu, một hộp thoại quyền sẽ xuất hiện để người dùng có thể cấp cho ứng dụng quyền truy cập mạng cục bộ vào thiết bị trên mạng. Sau đó, khi người dùng nhấn vào nút truyền, màn hình sẽ truyền hộp thoại được hiển thị liệt kê các thiết bị được phát hiện. Khi người dùng nhấn trên nút truyền trong khi thiết bị được kết nối, nút này hiển thị siêu dữ liệu đa phương tiện (chẳng hạn như tiêu đề, tên phòng thu và hình thu nhỏ hình ảnh) hoặc cho phép người dùng ngắt kết nối khỏi thiết bị truyền. Khi người dùng nhấn vào nút truyền khi không có thiết bị, một màn hình sẽ hiển thị và cung cấp cho người dùng thông tin về lý do không tìm thấy thiết bị và cách khắc phục sự cố.
Tay điều khiển thu nhỏ: Khi người dùng đang truyền nội dung và đã rời khỏi trang hiện tại trang nội dung hoặc bộ điều khiển mở rộng sang một màn hình khác trong ứng dụng dành cho người gửi, bộ điều khiển mini hiển thị ở cuối màn hình để cho phép người dùng xem siêu dữ liệu nội dung nghe nhìn đang truyền và điều khiển việc phát.
Bộ điều khiển mở rộng: Khi người dùng đang truyền nội dung, nếu họ nhấp vào thông báo về nội dung nghe nhìn hoặc thu nhỏ, tay điều khiển mở rộng khởi chạy, hiển thị hiện đang phát siêu dữ liệu phương tiện và cung cấp một số nút để điều khiển phát nội dung nghe nhìn.
Thêm nút Truyền
Khung này cung cấp một thành phần nút Truyền dưới dạng một lớp con UIButton
. Chiến dịch này có thể
được thêm vào thanh tiêu đề của ứng dụng bằng cách gói ứng dụng đó trong một UIBarButtonItem
. Một giá trị điển hình
Lớp con UIViewController
có thể cài đặt nút Truyền như sau:
let castButton = GCKUICastButton(frame: CGRect(x: 0, y: 0, width: 24, height: 24)) castButton.tintColor = UIColor.gray navigationItem.rightBarButtonItem = UIBarButtonItem(customView: castButton)
GCKUICastButton *castButton = [[GCKUICastButton alloc] initWithFrame:CGRectMake(0, 0, 24, 24)]; castButton.tintColor = [UIColor grayColor]; self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:castButton];
Theo mặc định, nhấn vào nút này sẽ mở hộp thoại Truyền được cung cấp bởi khung.
GCKUICastButton
cũng có thể được thêm trực tiếp vào bảng phân cảnh.
Định cấu hình chế độ khám phá thiết bị
Trong khung này, quá trình khám phá thiết bị sẽ diễn ra tự động. Không cần bắt đầu hoặc dừng quá trình khám phá một cách rõ ràng trừ phi bạn triển khai giao diện người dùng tuỳ chỉnh.
Chế độ Khám phá trong khung do lớp quản lý
GCKDiscoveryManager
!
Đây là một thuộc tính của
GCKCastContext
. Chiến lược phát hành đĩa đơn
khung cung cấp thành phần hộp thoại Truyền mặc định để lựa chọn thiết bị và
kiểm soát. Danh sách thiết bị được sắp xếp từ vựng theo tên thân thiện với thiết bị.
Cách hoạt động của tính năng quản lý phiên
SDK truyền giới thiệu khái niệm về phiên Truyền, việc thiết lập kết hợp các bước kết nối với một thiết bị, khởi chạy (hoặc tham gia) một Web ứng dụng receiver, kết nối với ứng dụng đó và khởi tạo một kênh điều khiển nội dung nghe nhìn. Xem Trình nhận web Hướng dẫn về vòng đời của ứng dụng để biết thêm thông tin về các phiên Truyền và vòng đời của Trình thu phát web.
Các phiên hoạt động do lớp học quản lý
GCKSessionManager
!
Đây là một thuộc tính của
GCKCastContext
.
Các phiên riêng lẻ được biểu thị bằng các lớp con của lớp
GCKSession
: chẳng hạn như
GCKCastSession
biểu thị các phiên có Thiết bị truyền. Bạn có thể truy cập vào Cast đang hoạt động
phiên (nếu có), dưới dạng thuộc tính currentCastSession
của GCKSessionManager
.
Chiến lược phát hành đĩa đơn
GCKSessionManagerListener
có thể dùng để theo dõi các sự kiện trong phiên, chẳng hạn như tạo phiên,
tạm ngưng, tiếp tục và chấm dứt. Khung này sẽ tự động tạm ngưng
các phiên hoạt động khi ứng dụng của người gửi chuyển sang chạy ở chế độ nền và cố gắng tiếp tục
chúng khi ứng dụng trở về nền trước (hoặc được chạy lại sau khi
chấm dứt ứng dụng bất thường/đột ngột trong khi một phiên đang hoạt động).
Nếu hộp thoại Truyền đang được sử dụng thì các phiên sẽ được tạo và thu nhỏ
tự động để phản hồi cử chỉ của người dùng. Nếu không, ứng dụng có thể bắt đầu và kết thúc
một cách rõ ràng thông qua các phương thức trên
GCKSessionManager
.
Nếu ứng dụng cần thực hiện quy trình xử lý đặc biệt để phản hồi vòng đời phiên
các sự kiện này, mã này có thể đăng ký một hoặc nhiều thực thể GCKSessionManagerListener
bằng
GCKSessionManager
. GCKSessionManagerListener
là một giao thức xác định
lệnh gọi lại cho các sự kiện như bắt đầu phiên, kết thúc phiên, v.v.
Chuyển sự kiện phát trực tiếp
Việc bảo toàn trạng thái phiên là cơ sở của quá trình chuyển luồng, trong đó người dùng có thể di chuyển luồng âm thanh và video hiện có giữa các thiết bị bằng lệnh thoại, Google Home Ứng dụng hoặc màn hình thông minh. Phương tiện ngừng phát trên một thiết bị (nguồn) và tiếp tục phát trên một thiết bị khác (nguồn) đích). Bất kỳ thiết bị Truyền nào có chương trình cơ sở mới nhất đều có thể đóng vai trò là nguồn hoặc đích trong một truyền trực tuyến.
Để có được thiết bị đích mới trong quá trình truyền, hãy sử dụng
GCKCastSession#device
trong khoảng thời gian
[sessionManager:didResumeCastSession:]
.
Xem Chuyển sự kiện phát trực tiếp trên Web receiver để biết thêm thông tin.
Tự động kết nối lại
Khung Cast bổ sung logic kết nối lại để tự động xử lý việc kết nối lại trong nhiều trường hợp khó thấy, chẳng hạn như:
- Khôi phục sau khi mất Wi-Fi tạm thời
- Khôi phục từ chế độ ngủ của thiết bị
- Khôi phục sau khi chạy ứng dụng ở chế độ nền
- Khôi phục nếu ứng dụng gặp sự cố
Cách hoạt động của tính năng điều khiển nội dung nghe nhìn
Nếu phiên Truyền được thiết lập bằng ứng dụng Bộ thu trên web có hỗ trợ nội dung nghe nhìn
không gian tên, một bản sao của
GCKRemoteMediaClient
sẽ do khung này tạo tự động; có thể truy cập dưới dạng
thuộc tính remoteMediaClient
của
GCKCastSession
thực thể.
Tất cả các phương thức trên GCKRemoteMediaClient
gửi yêu cầu đến Trình nhận web
sẽ trả về a
GCKRequest
đối tượng
có thể được sử dụng để theo dõi yêu cầu đó. Đáp
GCKRequestDelegate
có thể được chỉ định cho đối tượng này để nhận thông báo về
kết quả của hoạt động.
Dự kiến thực thể của GCKRemoteMediaClient
có thể được chia sẻ giữa nhiều phần của ứng dụng và thực sự là một số thành phần nội bộ
của khung này, chẳng hạn như hộp thoại Truyền và các nút điều khiển nội dung nghe nhìn nhỏ sẽ chia sẻ
thực thể. Để đạt được mục tiêu đó, GCKRemoteMediaClient
hỗ trợ đăng ký nhiều
GCKRemoteMediaClientListener
.
Thiết lập siêu dữ liệu đa phương tiện
Chiến lược phát hành đĩa đơn
GCKMediaMetadata
biểu thị thông tin về một mục nội dung đa phương tiện bạn muốn truyền. Nội dung sau đây
Ví dụ sẽ tạo một phiên bản GCKMediaMetadata
mới của một bộ phim và đặt tiêu đề,
phụ đề, tên phòng thu và hai hình ảnh.
let metadata = GCKMediaMetadata() metadata.setString("Big Buck Bunny (2008)", forKey: kGCKMetadataKeyTitle) metadata.setString("Big Buck Bunny tells the story of a giant rabbit with a heart bigger than " + "himself. When one sunny day three rodents rudely harass him, something " + "snaps... and the rabbit ain't no bunny anymore! In the typical cartoon " + "tradition he prepares the nasty rodents a comical revenge.", forKey: kGCKMetadataKeySubtitle) metadata.addImage(GCKImage(url: URL(string: "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/images/BigBuckBunny.jpg")!, width: 480, height: 360))
GCKMediaMetadata *metadata = [[GCKMediaMetadata alloc] initWithMetadataType:GCKMediaMetadataTypeMovie]; [metadata setString:@"Big Buck Bunny (2008)" forKey:kGCKMetadataKeyTitle]; [metadata setString:@"Big Buck Bunny tells the story of a giant rabbit with a heart bigger than " "himself. When one sunny day three rodents rudely harass him, something " "snaps... and the rabbit ain't no bunny anymore! In the typical cartoon " "tradition he prepares the nasty rodents a comical revenge." forKey:kGCKMetadataKeySubtitle]; [metadata addImage:[[GCKImage alloc] initWithURL:[[NSURL alloc] initWithString:@"https://commondatastorage.googleapis.com/" "gtv-videos-bucket/sample/images/BigBuckBunny.jpg"] width:480 height:360]];
Hãy xem phần Lựa chọn hình ảnh và Lưu vào bộ nhớ đệm về việc sử dụng hình ảnh cùng với siêu dữ liệu phương tiện.
Tải nội dung nghe nhìn
Để tải một mục nội dung nghe nhìn, hãy tạo một
GCKMediaInformation
bằng siêu dữ liệu của phương tiện. Sau đó, lấy giá trị hiện tại
GCKCastSession
và
sử dụng
GCKRemoteMediaClient
để tải nội dung đa phương tiện trên ứng dụng nhận. Sau đó, bạn có thể sử dụng GCKRemoteMediaClient
để điều khiển ứng dụng trình phát nội dung đa phương tiện chạy trên bộ thu, chẳng hạn như để phát,
tạm dừng rồi dừng lại.
let url = URL.init(string: "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4") guard let mediaURL = url else { print("invalid mediaURL") return } let mediaInfoBuilder = GCKMediaInformationBuilder.init(contentURL: mediaURL) mediaInfoBuilder.streamType = GCKMediaStreamType.none; mediaInfoBuilder.contentType = "video/mp4" mediaInfoBuilder.metadata = metadata; mediaInformation = mediaInfoBuilder.build() guard let mediaInfo = mediaInformation else { print("invalid mediaInformation") return } if let request = sessionManager.currentSession?.remoteMediaClient?.loadMedia(mediaInfo) { request.delegate = self }
GCKMediaInformationBuilder *mediaInfoBuilder = [[GCKMediaInformationBuilder alloc] initWithContentURL: [NSURL URLWithString:@"https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4"]]; mediaInfoBuilder.streamType = GCKMediaStreamTypeNone; mediaInfoBuilder.contentType = @"video/mp4"; mediaInfoBuilder.metadata = metadata; self.mediaInformation = [mediaInfoBuilder build]; GCKRequest *request = [self.sessionManager.currentSession.remoteMediaClient loadMedia:self.mediaInformation]; if (request != nil) { request.delegate = self; }
Ngoài ra, hãy xem phần này trên bằng các bản nhạc nội dung nghe nhìn.
Định dạng video 4K
Để xác định định dạng video cho nội dung nghe nhìn của bạn, hãy sử dụng thuộc tính videoInfo
của
GCKMediaStatus
để lấy thực thể hiện tại của
GCKVideoInfo
.
Phiên bản này chứa loại định dạng TV HDR cùng với chiều cao và chiều rộng trong
điểm ảnh. Biến thể của định dạng 4K được biểu thị trong thuộc tính hdrType
bằng enum
giá trị GCKVideoInfoHDRType
.
Thêm tay điều khiển mini
Theo Cast Design Danh sách kiểm tra, ứng dụng của người gửi sẽ cung cấp chế độ kiểm soát liên tục được gọi là cơ chế tay điều khiển sẽ xuất hiện khi người dùng điều hướng 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 người dùng phiên Truyền hiện tại.
Khung Truyền cung cấp một thanh điều khiển,
GCKUIMiniMediaControlsViewController
!
Bạn có thể thêm nút này vào cảnh bạn muốn trình điều khiển thu nhỏ xuất hiện.
Khi ứng dụng của người gửi đang phát video hoặc âm thanh trực tiếp, SDK tự động hiển thị nút phát/dừng ở vị trí cho nút phát/tạm dừng trên trình điều khiển mini.
Xem Tuỳ chỉnh giao diện người gửi trên iOS để biết cách ứng dụng gửi có thể định cấu hình giao diện của tiện ích Truyền.
Có hai cách để thêm bộ điều khiển mini vào ứng dụng của người gửi:
- Cho phép khung Truyền quản lý bố cục của trình điều khiển nhỏ bằng cách gói bộ điều khiển chế độ xem hiện tại của bạn với bộ điều khiển chế độ xem riêng.
- Tự quản lý bố cục của tiện ích tay điều khiển nhỏ bằng cách thêm tiện ích đó vào hiện có bộ điều khiển khung hiển thị bằng cách cung cấp một khung hiển thị phụ trong bảng phân cảnh.
Gói bằng GCKUICastContainerViewController
Cách đầu tiên là sử dụng
GCKUICastContainerViewController
bao bọc một bộ điều khiển chế độ xem khác và thêm
GCKUIMiniMediaControlsViewController
ở dưới cùng. Phương pháp này bị hạn chế ở chỗ bạn không thể tuỳ chỉnh
ảnh động và không thể định cấu hình hành vi của bộ điều khiển chế độ xem vùng chứa.
Cách này đầu tiên thường được thực hiện trong
Phương thức -[application:didFinishLaunchingWithOptions:]
của ứng dụng uỷ quyền:
func applicationDidFinishLaunching(_ application: UIApplication) { ... // Wrap main view in the GCKUICastContainerViewController and display the mini controller. let appStoryboard = UIStoryboard(name: "Main", bundle: nil) let navigationController = appStoryboard.instantiateViewController(withIdentifier: "MainNavigation") let castContainerVC = GCKCastContext.sharedInstance().createCastContainerController(for: navigationController) castContainerVC.miniMediaControlsItemEnabled = true window = UIWindow(frame: UIScreen.main.bounds) window!.rootViewController = castContainerVC window!.makeKeyAndVisible() ... }
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { ... // Wrap main view in the GCKUICastContainerViewController and display the mini controller. UIStoryboard *appStoryboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil]; UINavigationController *navigationController = [appStoryboard instantiateViewControllerWithIdentifier:@"MainNavigation"]; GCKUICastContainerViewController *castContainerVC = [[GCKCastContext sharedInstance] createCastContainerControllerForViewController:navigationController]; castContainerVC.miniMediaControlsItemEnabled = YES; self.window = [[UIWindow alloc] initWithFrame:UIScreen.mainScreen.bounds]; self.window.rootViewController = castContainerVC; [self.window makeKeyAndVisible]; ... }
var castControlBarsEnabled: Bool { set(enabled) { if let castContainerVC = self.window?.rootViewController as? GCKUICastContainerViewController { castContainerVC.miniMediaControlsItemEnabled = enabled } else { print("GCKUICastContainerViewController is not correctly configured") } } get { if let castContainerVC = self.window?.rootViewController as? GCKUICastContainerViewController { return castContainerVC.miniMediaControlsItemEnabled } else { print("GCKUICastContainerViewController is not correctly configured") return false } } }
AppDelegate.h
@interface AppDelegate : UIResponder <UIApplicationDelegate> @property (nonatomic, strong) UIWindow *window; @property (nonatomic, assign) BOOL castControlBarsEnabled; @end
AppDelegate.m
@implementation AppDelegate ... - (void)setCastControlBarsEnabled:(BOOL)notificationsEnabled { GCKUICastContainerViewController *castContainerVC; castContainerVC = (GCKUICastContainerViewController *)self.window.rootViewController; castContainerVC.miniMediaControlsItemEnabled = notificationsEnabled; } - (BOOL)castControlBarsEnabled { GCKUICastContainerViewController *castContainerVC; castContainerVC = (GCKUICastContainerViewController *)self.window.rootViewController; return castContainerVC.miniMediaControlsItemEnabled; } ... @end
Nhúng vào bộ điều khiển chế độ xem hiện có
Cách thứ hai là thêm trực tiếp bộ điều khiển thu nhỏ vào chế độ xem hiện có
bằng cách sử dụng
createMiniMediaControlsViewController
để tạo một
GCKUIMiniMediaControlsViewController
rồi thêm thực thể đó vào trình kiểm soát chế độ xem vùng chứa dưới dạng chế độ xem phụ.
Thiết lập bộ điều khiển chế độ xem trong tính năng uỷ quyền ứng dụng:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { ... GCKCastContext.sharedInstance().useDefaultExpandedMediaControls = true window?.clipsToBounds = true let rootContainerVC = (window?.rootViewController as? RootContainerViewController) rootContainerVC?.miniMediaControlsViewEnabled = true ... return true }
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { ... [GCKCastContext sharedInstance].useDefaultExpandedMediaControls = YES; self.window.clipsToBounds = YES; RootContainerViewController *rootContainerVC; rootContainerVC = (RootContainerViewController *)self.window.rootViewController; rootContainerVC.miniMediaControlsViewEnabled = YES; ... return YES; }
Trong bộ điều khiển chế độ xem gốc, hãy tạo một GCKUIMiniMediaControlsViewController
và thêm thực thể đó vào trình kiểm soát chế độ xem vùng chứa dưới dạng chế độ xem phụ:
let kCastControlBarsAnimationDuration: TimeInterval = 0.20 @objc(RootContainerViewController) class RootContainerViewController: UIViewController, GCKUIMiniMediaControlsViewControllerDelegate { @IBOutlet weak private var _miniMediaControlsContainerView: UIView! @IBOutlet weak private var _miniMediaControlsHeightConstraint: NSLayoutConstraint! private var miniMediaControlsViewController: GCKUIMiniMediaControlsViewController! var miniMediaControlsViewEnabled = false { didSet { if self.isViewLoaded { self.updateControlBarsVisibility() } } } var overriddenNavigationController: UINavigationController? override var navigationController: UINavigationController? { get { return overriddenNavigationController } set { overriddenNavigationController = newValue } } var miniMediaControlsItemEnabled = false override func viewDidLoad() { super.viewDidLoad() let castContext = GCKCastContext.sharedInstance() self.miniMediaControlsViewController = castContext.createMiniMediaControlsViewController() self.miniMediaControlsViewController.delegate = self self.updateControlBarsVisibility() self.installViewController(self.miniMediaControlsViewController, inContainerView: self._miniMediaControlsContainerView) } func updateControlBarsVisibility() { if self.miniMediaControlsViewEnabled && self.miniMediaControlsViewController.active { self._miniMediaControlsHeightConstraint.constant = self.miniMediaControlsViewController.minHeight self.view.bringSubview(toFront: self._miniMediaControlsContainerView) } else { self._miniMediaControlsHeightConstraint.constant = 0 } UIView.animate(withDuration: kCastControlBarsAnimationDuration, animations: {() -> Void in self.view.layoutIfNeeded() }) self.view.setNeedsLayout() } func installViewController(_ viewController: UIViewController?, inContainerView containerView: UIView) { if let viewController = viewController { self.addChildViewController(viewController) viewController.view.frame = containerView.bounds containerView.addSubview(viewController.view) viewController.didMove(toParentViewController: self) } } func uninstallViewController(_ viewController: UIViewController) { viewController.willMove(toParentViewController: nil) viewController.view.removeFromSuperview() viewController.removeFromParentViewController() } override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if segue.identifier == "NavigationVCEmbedSegue" { self.navigationController = (segue.destination as? UINavigationController) } } ...
RootContainerViewController.h
static const NSTimeInterval kCastControlBarsAnimationDuration = 0.20; @interface RootContainerViewController () <GCKUIMiniMediaControlsViewControllerDelegate> { __weak IBOutlet UIView *_miniMediaControlsContainerView; __weak IBOutlet NSLayoutConstraint *_miniMediaControlsHeightConstraint; GCKUIMiniMediaControlsViewController *_miniMediaControlsViewController; } @property(nonatomic, weak, readwrite) UINavigationController *navigationController; @property(nonatomic, assign, readwrite) BOOL miniMediaControlsViewEnabled; @property(nonatomic, assign, readwrite) BOOL miniMediaControlsItemEnabled; @end
RootContainerViewController.m
@implementation RootContainerViewController - (void)viewDidLoad { [super viewDidLoad]; GCKCastContext *castContext = [GCKCastContext sharedInstance]; _miniMediaControlsViewController = [castContext createMiniMediaControlsViewController]; _miniMediaControlsViewController.delegate = self; [self updateControlBarsVisibility]; [self installViewController:_miniMediaControlsViewController inContainerView:_miniMediaControlsContainerView]; } - (void)setMiniMediaControlsViewEnabled:(BOOL)miniMediaControlsViewEnabled { _miniMediaControlsViewEnabled = miniMediaControlsViewEnabled; if (self.isViewLoaded) { [self updateControlBarsVisibility]; } } - (void)updateControlBarsVisibility { if (self.miniMediaControlsViewEnabled && _miniMediaControlsViewController.active) { _miniMediaControlsHeightConstraint.constant = _miniMediaControlsViewController.minHeight; [self.view bringSubviewToFront:_miniMediaControlsContainerView]; } else { _miniMediaControlsHeightConstraint.constant = 0; } [UIView animateWithDuration:kCastControlBarsAnimationDuration animations:^{ [self.view layoutIfNeeded]; }]; [self.view setNeedsLayout]; } - (void)installViewController:(UIViewController *)viewController inContainerView:(UIView *)containerView { if (viewController) { [self addChildViewController:viewController]; viewController.view.frame = containerView.bounds; [containerView addSubview:viewController.view]; [viewController didMoveToParentViewController:self]; } } - (void)uninstallViewController:(UIViewController *)viewController { [viewController willMoveToParentViewController:nil]; [viewController.view removeFromSuperview]; [viewController removeFromParentViewController]; } - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { if ([segue.identifier isEqualToString:@"NavigationVCEmbedSegue"]) { self.navigationController = (UINavigationController *)segue.destinationViewController; } } ... @end
Chiến lược phát hành đĩa đơn
GCKUIMiniMediaControlsViewControllerDelegate
cho trình điều khiển chế độ xem của máy chủ biết khi nào nên hiển thị tay điều khiển nhỏ:
func miniMediaControlsViewController(_: GCKUIMiniMediaControlsViewController, shouldAppear _: Bool) { updateControlBarsVisibility() }
- (void)miniMediaControlsViewController: (GCKUIMiniMediaControlsViewController *)miniMediaControlsViewController shouldAppear:(BOOL)shouldAppear { [self updateControlBarsVisibility]; }
Thêm bộ điều khiển mở rộng
Danh sách kiểm tra thiết kế của Google Cast yêu cầu ứng dụng gửi phải cung cấp bản mở rộng tay điều khiển cho nội dung nghe nhìn đang được truyền. Bộ điều khiển mở rộng là phiên bản toàn màn hình của trình điều khiển mini.
Bộ điều khiển mở rộng là chế độ xem toàn màn hình, cho phép toàn quyền kiểm soát phát nội dung nghe nhìn từ xa. Chế độ xem này sẽ cho phép ứng dụng truyền quản lý mọi khung hình dễ quản lý của phiên truyền, ngoại trừ âm lượng của Bộ thu trên web vòng đời điều khiển và phiên (kết nối/dừng truyền). Nền tảng 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 chế độ xem này được triển khai bởi
GCKUIExpandedMediaControlsViewController
.
Việc đầu tiên bạn phải làm là bật bộ điều khiển mở rộng mặc định trong truyền bối cảnh. Sửa đổi tính năng uỷ quyền ứng dụng để bật bộ điều khiển mở rộng mặc định:
func applicationDidFinishLaunching(_ application: UIApplication) { .. GCKCastContext.sharedInstance().useDefaultExpandedMediaControls = true ... }
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { ... [GCKCastContext sharedInstance].useDefaultExpandedMediaControls = YES; .. }
Thêm mã sau vào bộ điều khiển chế độ xem để tải bộ điều khiển mở rộng khi người dùng bắt đầu truyền video:
func playSelectedItemRemotely() { GCKCastContext.sharedInstance().presentDefaultExpandedMediaControls() ... // Load your media sessionManager.currentSession?.remoteMediaClient?.loadMedia(mediaInformation) }
- (void)playSelectedItemRemotely { [[GCKCastContext sharedInstance] presentDefaultExpandedMediaControls]; ... // Load your media [self.sessionManager.currentSession.remoteMediaClient loadMedia:mediaInformation]; }
Bộ điều khiển mở rộng cũng sẽ tự động chạy khi người dùng nhấn vào trình điều khiển mini.
Khi ứng dụng của người gửi đang phát video hoặc âm thanh trực tiếp, SDK tự động hiển thị nút phát/dừng ở vị trí cho nút phát/tạm dừng trong bộ điều khiển mở rộng.
Xem Áp dụng kiểu tuỳ chỉnh cho iOS của bạn Ứng dụng để biết cách ứng dụng gửi của bạn có thể định cấu hình giao diện của tiện ích Truyền.
Điều chỉnh âm lượng
Khung Cast tự động quản lý âm lượng cho ứng dụng gửi. Chiến lược phát hành đĩa đơn
khung này tự động đồng bộ hoá với âm lượng Web receiver cho
các tiện ích giao diện người dùng đã cung cấp. Để đồng bộ hoá thanh trượt do ứng dụng cung cấp, hãy sử dụng
GCKUIDeviceVolumeController
.
Kiểm soát âm lượng bằng nút vật lý
Bạn có thể sử dụng các nút âm lượng vật lý trên thiết bị gửi để thay đổi
âm lượng của phiên Truyền trên Web receiver bằng cách sử dụng
Cờ physicalVolumeButtonsWillControlDeviceVolume
trên
GCKCastOptions
,
được đặt trên
GCKCastContext
.
let criteria = GCKDiscoveryCriteria(applicationID: kReceiverAppID) let options = GCKCastOptions(discoveryCriteria: criteria) options.physicalVolumeButtonsWillControlDeviceVolume = true GCKCastContext.setSharedInstanceWith(options)
GCKDiscoveryCriteria *criteria = [[GCKDiscoveryCriteria alloc] initWithApplicationID:kReceiverAppID]; GCKCastOptions *options = [[GCKCastOptions alloc] initWithDiscoveryCriteria :criteria]; options.physicalVolumeButtonsWillControlDeviceVolume = YES; [GCKCastContext setSharedInstanceWithOptions:options];
Xử lý lỗi
Điều quan trọng là ứng dụng của người gửi phải xử lý tất cả các lệnh gọi lại báo lỗi và quyết định phản hồi tốt nhất cho từng giai đoạn trong vòng đời của tính năng Truyền. Ứng dụng có thể hiển thị hộp thoại lỗi cho người dùng hoặc có thể quyết định kết thúc phiên Truyền.
Ghi nhật ký
GCKLogger
là một singleton dùng để ghi nhật ký theo khung. Sử dụng
GCKLoggerDelegate
để tuỳ chỉnh cách bạn xử lý thông điệp nhật ký.
Khi sử dụng GCKLogger
, SDK sẽ tạo ra kết quả ghi nhật ký ở dạng gỡ lỗi
thông báo, lỗi và cảnh báo. Những thông điệp nhật ký này hỗ trợ việc gỡ lỗi và hữu ích
để khắc phục sự cố và xác định sự cố. Theo mặc định, đầu ra nhật ký là
bị chặn, nhưng bằng cách chỉ định GCKLoggerDelegate
, ứng dụng của người gửi có thể nhận
những thông báo này từ SDK rồi ghi vào bảng điều khiển hệ thống.
@UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate, GCKLoggerDelegate { let kReceiverAppID = kGCKDefaultMediaReceiverApplicationID let kDebugLoggingEnabled = true var window: UIWindow? func applicationDidFinishLaunching(_ application: UIApplication) { ... // Enable logger. GCKLogger.sharedInstance().delegate = self ... } // MARK: - GCKLoggerDelegate func logMessage(_ message: String, at level: GCKLoggerLevel, fromFunction function: String, location: String) { if (kDebugLoggingEnabled) { print(function + " - " + message) } } }
AppDelegate.h
@interface AppDelegate () <GCKLoggerDelegate> @end
AppDelegate.m
@implementation AppDelegate static NSString *const kReceiverAppID = @"AABBCCDD"; static const BOOL kDebugLoggingEnabled = YES; - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { ... // Enable logger. [GCKLogger sharedInstance].delegate = self; ... return YES; } ... #pragma mark - GCKLoggerDelegate - (void)logMessage:(NSString *)message atLevel:(GCKLoggerLevel)level fromFunction:(NSString *)function location:(NSString *)location { if (kDebugLoggingEnabled) { NSLog(@"%@ - %@, %@", function, message, location); } } @end
Để bật các thông báo gỡ lỗi và thông báo chi tiết, hãy thêm dòng này vào đoạn mã sau thiết lập đại biểu (hiển thị trước đó):
let filter = GCKLoggerFilter.init() filter.minimumLevel = GCKLoggerLevel.verbose GCKLogger.sharedInstance().filter = filter
GCKLoggerFilter *filter = [[GCKLoggerFilter alloc] init]; [filter setMinimumLevel:GCKLoggerLevelVerbose]; [GCKLogger sharedInstance].filter = filter;
Bạn cũng có thể lọc thông điệp nhật ký do
GCKLogger
.
Đặt cấp độ ghi nhật ký tối thiểu cho mỗi lớp, ví dụ:
let filter = GCKLoggerFilter.init() filter.setLoggingLevel(GCKLoggerLevel.verbose, forClasses: ["GCKUICastButton", "GCKUIImageCache", "NSMutableDictionary"]) GCKLogger.sharedInstance().filter = filter
GCKLoggerFilter *filter = [[GCKLoggerFilter alloc] init]; [filter setLoggingLevel:GCKLoggerLevelVerbose forClasses:@[@"GCKUICastButton", @"GCKUIImageCache", @"NSMutableDictionary" ]]; [GCKLogger sharedInstance].filter = filter;
Tên lớp có thể là tên cố định hoặc mẫu hình cầu, ví dụ:
GCKUI\*
và GCK\*Session
.