diff --git a/.jazzy.yaml b/.jazzy.yaml index bf8b32fe..b77ba069 100644 --- a/.jazzy.yaml +++ b/.jazzy.yaml @@ -4,11 +4,11 @@ source_directory: XCDYouTubeKit framework_root: . umbrella_header: XCDYouTubeKit/XCDYouTubeKit.h module: XCDYouTubeKit -module_version: 2.8.1 +module_version: 2.8.2 author: Cédric Luthi author_url: https://twitter.com/0xced readme: README.md github_url: https://github.com/0xced/XCDYouTubeKit -github_file_prefix: https://github.com/0xced/XCDYouTubeKit/tree/2.8.1/XCDYouTubeKit +github_file_prefix: https://github.com/0xced/XCDYouTubeKit/tree/2.8.2/XCDYouTubeKit diff --git a/.swiftpm/xcode/xcuserdata/soneejohn.xcuserdatad/xcschemes/xcschememanagement.plist b/.swiftpm/xcode/xcuserdata/soneejohn.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 00000000..d1054dc4 --- /dev/null +++ b/.swiftpm/xcode/xcuserdata/soneejohn.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,22 @@ + + + + + SchemeUserState + + XCDYouTubeKit.xcscheme_^#shared#^_ + + orderHint + 0 + + + SuppressBuildableAutocreation + + XCDYouTubeKit + + primary + + + + + diff --git a/CHANGELOG.md b/CHANGELOG.md index 866cf696..ab2fccfe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +#### Version 2.8.2 + +* Add new `streamURL` property on `XCDYouTubeVideo` +* Fixed Swift Package Manager (#441) +* Support iOS 13 in Demo Projects + * Support background playback (#427, #442) + #### Version 2.8.1 * Adaptation to YouTube API change. (#447, #448, #449) diff --git a/Package.swift b/Package.swift index c3a522fa..6cd408e1 100644 --- a/Package.swift +++ b/Package.swift @@ -1,16 +1,22 @@ -// swift-tools-version:4.2 +// swift-tools-version:5.1 import PackageDescription let package = Package( name: "XCDYouTubeKit", - // platforms: [.iOS("8.0"), .macOS("10.10"), tvOS("9.0")], + platforms: [ + .iOS(.v8), + .tvOS(.v9), + .macOS(.v10_10) + ], products: [ - .library(name: "XCDYouTubeKit", targets: ["XCDYouTubeKit"]) + .library(name: "XCDYouTubeKit" , targets: ["XCDYouTubeKit"]) ], targets: [ .target( name: "XCDYouTubeKit", - path: "XCDYouTubeKit" + path: ".", + sources: ["XCDYouTubeKit"], + publicHeadersPath: "XCDYouTubeKit" ) ] ) diff --git a/README.md b/README.md index dafe05cc..5934df22 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ [![Platform](https://img.shields.io/cocoapods/p/XCDYouTubeKit.svg?style=flat)](http://cocoadocs.org/docsets/XCDYouTubeKit/) [![Pod Version](https://img.shields.io/cocoapods/v/XCDYouTubeKit.svg?style=flat)](https://cocoapods.org/pods/XCDYouTubeKit) [![Carthage Compatibility](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage/) -[![Accio supported](https://img.shields.io/badge/Accio-supported-0A7CF5.svg?style=flat)](https://github.com/JamitLabs/Accio) +[![Swift Package Manager Compatibility](https://img.shields.io/badge/Swift%20Package%20Manager-compatible-brightgreen)](ttps://swift.org/package-manager/) [![License](https://img.shields.io/cocoapods/l/XCDYouTubeKit.svg?style=flat)](LICENSE) **XCDYouTubeKit** is a YouTube video player for iOS, tvOS and macOS. @@ -28,7 +28,7 @@ XCDYouTubeKit is against the YouTube [Terms of Service](https://www.youtube.com/ ## Installation -XCDYouTubeKit is available through [CocoaPods](https://cocoapods.org/), [Carthage](https://github.com/Carthage/Carthage) and [Accio](https://github.com/JamitLabs/Accio). +XCDYouTubeKit is available through [CocoaPods](https://cocoapods.org/), [Carthage](https://github.com/Carthage/Carthage) and [Swift Package Manager](https://swift.org/package-manager/). CocoaPods: @@ -42,10 +42,14 @@ Carthage: github "0xced/XCDYouTubeKit" ~> 2.8 ``` -Accio: +Swift Package Manager: + +Add `XCDYouTubeKit` to the dependencies value of your `Package.swift` ```swift -.package(url: "https://github.com/0xced/XCDYouTubeKit.git", .upToNextMajor(from: "2.7.3")), +dependencies: [ + .package(url: "https://github.com/0xced/XCDYouTubeKit.git", from: "2.8.0") +] ``` Alternatively, you can manually use the provided static library or dynamic framework. In order to use the static library, you must: diff --git a/XCDYouTubeKit Demo/XCDYouTubeKit Demo.xcodeproj/project.pbxproj b/XCDYouTubeKit Demo/XCDYouTubeKit Demo.xcodeproj/project.pbxproj index ea93b3e9..7d386775 100644 --- a/XCDYouTubeKit Demo/XCDYouTubeKit Demo.xcodeproj/project.pbxproj +++ b/XCDYouTubeKit Demo/XCDYouTubeKit Demo.xcodeproj/project.pbxproj @@ -7,6 +7,9 @@ objects = { /* Begin PBXBuildFile section */ + 019AFA1E2361E9CD00B03F57 /* DemoFullScreenViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 019AFA1D2361E9CC00B03F57 /* DemoFullScreenViewController.swift */; }; + 019AFA202361F10D00B03F57 /* Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = 019AFA1F2361F10D00B03F57 /* Utilities.swift */; }; + 01E88BD523690B75002523D1 /* AVPlayerViewControllerManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01E88BD423690B75002523D1 /* AVPlayerViewControllerManager.swift */; }; 0ADD88CC5EC5E9D286D8A8E0 /* libPods-XCDYouTubeKit iOS Demo.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B3DDE49D0638521AD03AA01 /* libPods-XCDYouTubeKit iOS Demo.a */; }; 6941B80FC7AE87BA698FDD61 /* libPods-XCDYouTubeKit OS X Demo.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CF61ADAFAE5A8C5F8C082438 /* libPods-XCDYouTubeKit OS X Demo.a */; }; C232DA831C00BCEB00E26E3A /* GradientMaskView.m in Sources */ = {isa = PBXBuildFile; fileRef = C232DA821C00BCEB00E26E3A /* GradientMaskView.m */; }; @@ -17,7 +20,6 @@ C2428AEA191C3C1400065504 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C2428AE9191C3C1400065504 /* Images.xcassets */; }; C2428B07191C3DE400065504 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = C2428B04191C3DE400065504 /* main.m */; }; C2428B0C191C415300065504 /* AVKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C2428B0B191C415300065504 /* AVKit.framework */; }; - C2570B861A02415F00127127 /* NowPlayingInfoCenterProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = C2570B851A02415F00127127 /* NowPlayingInfoCenterProvider.m */; }; C2597EA21B0CB90C0030E9F2 /* JavaScriptCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C2FB52DF1918F89A00B2CBE6 /* JavaScriptCore.framework */; }; C25A0CA51C06884000C644E0 /* XCDYouTubeKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C2A1E7461BD1AE0F001EAC91 /* XCDYouTubeKit.framework */; }; C25A0CA61C06884100C644E0 /* XCDYouTubeKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C2A1E7461BD1AE0F001EAC91 /* XCDYouTubeKit.framework */; }; @@ -29,7 +31,6 @@ C27415A617F491230026834B /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C27415A517F491230026834B /* CoreGraphics.framework */; }; C27415D217F4CDD80026834B /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = C27415C017F4CDD80026834B /* AppDelegate.m */; }; C27415D317F4CDD80026834B /* DemoAsynchronousViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C27415C217F4CDD80026834B /* DemoAsynchronousViewController.m */; }; - C27415D417F4CDD80026834B /* DemoFullScreenViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C27415C417F4CDD80026834B /* DemoFullScreenViewController.m */; }; C27415D517F4CDD80026834B /* DemoInlineViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C27415C617F4CDD80026834B /* DemoInlineViewController.m */; }; C27415D617F4CDD80026834B /* DemoThumbnailViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C27415C817F4CDD80026834B /* DemoThumbnailViewController.m */; }; C27415D717F4CDD80026834B /* MainStoryboard.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C27415C917F4CDD80026834B /* MainStoryboard.storyboard */; }; @@ -39,7 +40,6 @@ C27AD2A11A0791F000866050 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C27AD2A01A0791F000866050 /* Images.xcassets */; }; C2A1E7471BD1AE0F001EAC91 /* XCDYouTubeKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C2A1E7461BD1AE0F001EAC91 /* XCDYouTubeKit.framework */; }; C2ADD72D1BE6AC3100B182ED /* VideoCell.m in Sources */ = {isa = PBXBuildFile; fileRef = C2ADD72C1BE6AC3100B182ED /* VideoCell.m */; }; - C2BA376D192AB32200B27FAD /* MPMoviePlayerController+BackgroundPlayback.m in Sources */ = {isa = PBXBuildFile; fileRef = C2BA376C192AB32200B27FAD /* MPMoviePlayerController+BackgroundPlayback.m */; }; C2C5D2981A6E5AB900F2B3F8 /* VideoPickerController.m in Sources */ = {isa = PBXBuildFile; fileRef = C2C5D2971A6E5AB900F2B3F8 /* VideoPickerController.m */; }; C2CF7CEE1B17737400C356EA /* ContextLogFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = C2CF7CED1B17737400C356EA /* ContextLogFormatter.m */; }; C2D627601BE3C648005367FF /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = C2D6275F1BE3C648005367FF /* AppDelegate.m */; }; @@ -90,6 +90,10 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 019AFA1C2361E9CC00B03F57 /* XCDYouTubeKit iOS Demo-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "XCDYouTubeKit iOS Demo-Bridging-Header.h"; sourceTree = ""; }; + 019AFA1D2361E9CC00B03F57 /* DemoFullScreenViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DemoFullScreenViewController.swift; sourceTree = ""; }; + 019AFA1F2361F10D00B03F57 /* Utilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Utilities.swift; sourceTree = ""; }; + 01E88BD423690B75002523D1 /* AVPlayerViewControllerManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AVPlayerViewControllerManager.swift; sourceTree = ""; }; 044E71F373F947A64C774319 /* Pods-XCDYouTubeKit iOS Demo.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-XCDYouTubeKit iOS Demo.debug.xcconfig"; path = "Pods/Target Support Files/Pods-XCDYouTubeKit iOS Demo/Pods-XCDYouTubeKit iOS Demo.debug.xcconfig"; sourceTree = ""; }; 4805F31947DAD8E88035A44A /* Pods-XCDYouTubeKit OS X Demo.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-XCDYouTubeKit OS X Demo.release.xcconfig"; path = "Pods/Target Support Files/Pods-XCDYouTubeKit OS X Demo/Pods-XCDYouTubeKit OS X Demo.release.xcconfig"; sourceTree = ""; }; 5B3DDE49D0638521AD03AA01 /* libPods-XCDYouTubeKit iOS Demo.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-XCDYouTubeKit iOS Demo.a"; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -106,8 +110,6 @@ C2428B04191C3DE400065504 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; C2428B05191C3DE400065504 /* XCDYouTubeKit OS X Demo-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "XCDYouTubeKit OS X Demo-Info.plist"; sourceTree = ""; }; C2428B0B191C415300065504 /* AVKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVKit.framework; path = System/Library/Frameworks/AVKit.framework; sourceTree = SDKROOT; }; - C2570B841A02415F00127127 /* NowPlayingInfoCenterProvider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NowPlayingInfoCenterProvider.h; sourceTree = ""; }; - C2570B851A02415F00127127 /* NowPlayingInfoCenterProvider.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NowPlayingInfoCenterProvider.m; sourceTree = ""; }; C2630D3D1935C449000D3917 /* PlayerEventLogger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PlayerEventLogger.h; sourceTree = ""; }; C2630D3E1935C449000D3917 /* PlayerEventLogger.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PlayerEventLogger.m; sourceTree = ""; }; C274159E17F491230026834B /* XCDYouTubeKit iOS Demo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "XCDYouTubeKit iOS Demo.app"; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -118,8 +120,6 @@ C27415C017F4CDD80026834B /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; C27415C117F4CDD80026834B /* DemoAsynchronousViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DemoAsynchronousViewController.h; sourceTree = ""; }; C27415C217F4CDD80026834B /* DemoAsynchronousViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DemoAsynchronousViewController.m; sourceTree = ""; }; - C27415C317F4CDD80026834B /* DemoFullScreenViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DemoFullScreenViewController.h; sourceTree = ""; }; - C27415C417F4CDD80026834B /* DemoFullScreenViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DemoFullScreenViewController.m; sourceTree = ""; }; C27415C517F4CDD80026834B /* DemoInlineViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DemoInlineViewController.h; sourceTree = ""; }; C27415C617F4CDD80026834B /* DemoInlineViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DemoInlineViewController.m; sourceTree = ""; }; C27415C717F4CDD80026834B /* DemoThumbnailViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DemoThumbnailViewController.h; sourceTree = ""; }; @@ -133,8 +133,6 @@ C2A1E7461BD1AE0F001EAC91 /* XCDYouTubeKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = XCDYouTubeKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; C2ADD72B1BE6AC3100B182ED /* VideoCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VideoCell.h; sourceTree = ""; }; C2ADD72C1BE6AC3100B182ED /* VideoCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VideoCell.m; sourceTree = ""; }; - C2BA376B192AB32200B27FAD /* MPMoviePlayerController+BackgroundPlayback.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MPMoviePlayerController+BackgroundPlayback.h"; sourceTree = ""; }; - C2BA376C192AB32200B27FAD /* MPMoviePlayerController+BackgroundPlayback.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MPMoviePlayerController+BackgroundPlayback.m"; sourceTree = ""; }; C2C5D2961A6E5AB900F2B3F8 /* VideoPickerController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VideoPickerController.h; sourceTree = ""; }; C2C5D2971A6E5AB900F2B3F8 /* VideoPickerController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VideoPickerController.m; sourceTree = ""; }; C2CEABA61C0EFBE80077C5CA /* Playground.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = Playground.playground; sourceTree = ""; }; @@ -272,12 +270,11 @@ C2CF7CED1B17737400C356EA /* ContextLogFormatter.m */, C2630D3D1935C449000D3917 /* PlayerEventLogger.h */, C2630D3E1935C449000D3917 /* PlayerEventLogger.m */, - C2570B841A02415F00127127 /* NowPlayingInfoCenterProvider.h */, - C2570B851A02415F00127127 /* NowPlayingInfoCenterProvider.m */, - C27415C317F4CDD80026834B /* DemoFullScreenViewController.h */, - C27415C417F4CDD80026834B /* DemoFullScreenViewController.m */, C2C5D2961A6E5AB900F2B3F8 /* VideoPickerController.h */, C2C5D2971A6E5AB900F2B3F8 /* VideoPickerController.m */, + 019AFA1F2361F10D00B03F57 /* Utilities.swift */, + 01E88BD423690B75002523D1 /* AVPlayerViewControllerManager.swift */, + 019AFA1D2361E9CC00B03F57 /* DemoFullScreenViewController.swift */, C27415C517F4CDD80026834B /* DemoInlineViewController.h */, C27415C617F4CDD80026834B /* DemoInlineViewController.m */, C27415C717F4CDD80026834B /* DemoThumbnailViewController.h */, @@ -286,10 +283,9 @@ C27415C217F4CDD80026834B /* DemoAsynchronousViewController.m */, C2EFB48518730A2B0046B1FE /* SettingsViewController.h */, C2EFB48618730A2B0046B1FE /* SettingsViewController.m */, - C2BA376B192AB32200B27FAD /* MPMoviePlayerController+BackgroundPlayback.h */, - C2BA376C192AB32200B27FAD /* MPMoviePlayerController+BackgroundPlayback.m */, C27415C917F4CDD80026834B /* MainStoryboard.storyboard */, C27415CB17F4CDD80026834B /* Supporting Files */, + 019AFA1C2361E9CC00B03F57 /* XCDYouTubeKit iOS Demo-Bridging-Header.h */, ); path = "iOS Demo"; sourceTree = ""; @@ -422,6 +418,9 @@ LastUpgradeCheck = 0700; ORGANIZATIONNAME = "Cédric Luthi"; TargetAttributes = { + C274159D17F491230026834B = { + LastSwiftMigration = 1110; + }; C2D627581BE3C648005367FF = { CreatedOnToolsVersion = 7.1; }; @@ -432,6 +431,7 @@ developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( + English, en, Base, ); @@ -632,18 +632,18 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 01E88BD523690B75002523D1 /* AVPlayerViewControllerManager.swift in Sources */, C27415D217F4CDD80026834B /* AppDelegate.m in Sources */, - C2570B861A02415F00127127 /* NowPlayingInfoCenterProvider.m in Sources */, C27415D317F4CDD80026834B /* DemoAsynchronousViewController.m in Sources */, C2630D3F1935C449000D3917 /* PlayerEventLogger.m in Sources */, + 019AFA202361F10D00B03F57 /* Utilities.swift in Sources */, C2CF7CEE1B17737400C356EA /* ContextLogFormatter.m in Sources */, - C27415D417F4CDD80026834B /* DemoFullScreenViewController.m in Sources */, C2C5D2981A6E5AB900F2B3F8 /* VideoPickerController.m in Sources */, C27415D517F4CDD80026834B /* DemoInlineViewController.m in Sources */, C27415D617F4CDD80026834B /* DemoThumbnailViewController.m in Sources */, + 019AFA1E2361E9CD00B03F57 /* DemoFullScreenViewController.swift in Sources */, C27415DC17F4CDD80026834B /* main.m in Sources */, C2EFB48718730A2B0046B1FE /* SettingsViewController.m in Sources */, - C2BA376D192AB32200B27FAD /* MPMoviePlayerController+BackgroundPlayback.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -760,7 +760,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 2.8.1; + CURRENT_PROJECT_VERSION = 2.8.2; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; @@ -804,7 +804,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = YES; - CURRENT_PROJECT_VERSION = 2.8.1; + CURRENT_PROJECT_VERSION = 2.8.2; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; @@ -833,10 +833,14 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; + CLANG_ENABLE_MODULES = YES; INFOPLIST_FILE = "iOS Demo/Supporting Files/XCDYouTubeKit iOS Demo-Info.plist"; LD_RUNPATH_SEARCH_PATHS = "@loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = ch.pitaya.xcdyoutubekit.demo.ios; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "iOS Demo/XCDYouTubeKit iOS Demo-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; WRAPPER_EXTENSION = app; }; @@ -848,10 +852,13 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; + CLANG_ENABLE_MODULES = YES; INFOPLIST_FILE = "iOS Demo/Supporting Files/XCDYouTubeKit iOS Demo-Info.plist"; LD_RUNPATH_SEARCH_PATHS = "@loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = ch.pitaya.xcdyoutubekit.demo.ios; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "iOS Demo/XCDYouTubeKit iOS Demo-Bridging-Header.h"; + SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; WRAPPER_EXTENSION = app; }; diff --git a/XCDYouTubeKit Demo/iOS Demo/AVPlayerViewControllerManager.swift b/XCDYouTubeKit Demo/iOS Demo/AVPlayerViewControllerManager.swift new file mode 100644 index 00000000..041a24a1 --- /dev/null +++ b/XCDYouTubeKit Demo/iOS Demo/AVPlayerViewControllerManager.swift @@ -0,0 +1,214 @@ +// +// AVPlayerViewControllerManager.swift +// XCDYouTubeKit iOS Demo +// +// Created by Soneé John on 10/29/19. +// Copyright © 2019 Cédric Luthi. All rights reserved. +// + +import Foundation +import AVKit +import MediaPlayer + +extension UIViewController { + func topMostViewController() -> UIViewController { + if self.presentedViewController == nil { + return self + } + if let navigation = self.presentedViewController as? UINavigationController { + return navigation.visibleViewController!.topMostViewController() + } + if let tab = self.presentedViewController as? UITabBarController { + if let selectedTab = tab.selectedViewController { + return selectedTab.topMostViewController() + } + return tab.topMostViewController() + } + return self.presentedViewController!.topMostViewController() + } +} + +extension UIView { + var parentViewController: UIViewController? { + var parentResponder: UIResponder? = self + while parentResponder != nil { + parentResponder = parentResponder!.next + if let viewController = parentResponder as? UIViewController { + return viewController + } + } + return nil + } +} + +@objcMembers class AVPlayerViewControllerManager: NSObject { + //MARK: - Public + public static let shared = AVPlayerViewControllerManager() + public var lowQualityMode = false + public dynamic var duration: Float = 0 + + public var video: XCDYouTubeVideo? { + didSet { + guard let video = video else { return } + guard lowQualityMode == false else { + guard let streamURL = video.streamURLs[XCDYouTubeVideoQualityHTTPLiveStreaming] ?? video.streamURLs[XCDYouTubeVideoQuality.medium360.rawValue] ?? video.streamURLs[XCDYouTubeVideoQuality.small240.rawValue] else { fatalError("No stream URL") } + + self.player = AVPlayer(url: streamURL) + self.controller.player = self.player + return + } + self.player = AVPlayer(url: video.streamURL) + self.controller.player = self.player + } + } + + public var player: AVPlayer? { + didSet { + if let playerRateObserverToken = playerRateObserverToken { + playerRateObserverToken.invalidate() + self.playerRateObserverToken = nil + } + + self.playerRateObserverToken = player?.observe(\.rate, changeHandler: { (item, value) in + self.updatePlaybackRateMetadata() + }) + + guard let video = self.video else { return } + if let token = timeObserverToken { + oldValue?.removeTimeObserver(token) + timeObserverToken = nil + } + self.setupRemoteTransportControls() + self.updateGeneralMetadata(video: video) + self.updatePlaybackDuration() + } + } + + public lazy var controller: AVPlayerViewController = { + let controller = AVPlayerViewController() + if #available(iOS 10.0, *) { + controller.updatesNowPlayingInfoCenter = false + } + return controller + }() + + override init() { + super.init() + + NotificationCenter.default.addObserver(forName: AVAudioSession.interruptionNotification, object: AVAudioSession.sharedInstance(), queue: .main) { (notification) in + + guard let userInfo = notification.userInfo, + let typeValue = userInfo[AVAudioSessionInterruptionTypeKey] as? UInt, + let type = AVAudioSession.InterruptionType(rawValue: typeValue) else { + return + } + + if type == .began { + self.player?.pause() + } else if type == .ended { + guard ((try? AVAudioSession.sharedInstance().setActive(true)) != nil) else { return } + guard let optionsValue = userInfo[AVAudioSessionInterruptionOptionKey] as? UInt else { return } + let options = AVAudioSession.InterruptionOptions(rawValue: optionsValue) + guard options.contains(.shouldResume) else { return } + self.player?.play() + } + } + } + + public func disconnectPlayer() { + self.controller.player = nil + } + + public func reconnectPlayer(rootViewController: UIViewController) { + let viewController = rootViewController.topMostViewController() + guard let playerViewController = viewController as? AVPlayerViewController else { + if rootViewController is UINavigationController { + guard let vc = (rootViewController as! UINavigationController).visibleViewController else { return } + for childVC in vc.children { + guard let playerViewController = childVC as? AVPlayerViewController else { continue } + playerViewController.player = self.player + break + } + } + return + } + playerViewController.player = self.player + } + + //MARK: Private + + fileprivate var playerRateObserverToken: NSKeyValueObservation? + fileprivate var timeObserverToken: Any? + fileprivate let nowPlayingInfoCenter = MPNowPlayingInfoCenter.default() + + fileprivate func setupRemoteTransportControls() { + let commandCenter = MPRemoteCommandCenter.shared() + commandCenter.playCommand.addTarget { [unowned self] event in + if self.player?.rate == 0.0 { + self.player?.play() + return .success + } + return .commandFailed + } + + commandCenter.pauseCommand.addTarget { event in + if self.player?.rate == 1.0 { + self.player?.pause() + return .success + } + return .commandFailed + } + } + + fileprivate func updateGeneralMetadata(video: XCDYouTubeVideo) { + guard player?.currentItem != nil else { + nowPlayingInfoCenter.nowPlayingInfo = nil + return + } + + var nowPlayingInfo = nowPlayingInfoCenter.nowPlayingInfo ?? [String: Any]() + let title = video.title + + if let thumbnailURL = video.thumbnailURL { + URLSession.shared.dataTask(with: thumbnailURL) { (data, _, error) in + guard error == nil else { return } + guard data != nil else { return } + guard let image = UIImage(data: data!) else { return } + + let artwork = MPMediaItemArtwork(image: image) + nowPlayingInfo[MPMediaItemPropertyArtwork] = artwork + self.nowPlayingInfoCenter.nowPlayingInfo = nowPlayingInfo + }.resume() + } + + nowPlayingInfo[MPMediaItemPropertyTitle] = title + nowPlayingInfoCenter.nowPlayingInfo = nowPlayingInfo + } + + fileprivate func updatePlaybackDuration() { + let interval = CMTime(seconds: 1.0, preferredTimescale: CMTimeScale(NSEC_PER_SEC)) + + timeObserverToken = self.player?.addPeriodicTimeObserver(forInterval: interval, queue: .main, using: { [weak self] (time) in + guard let player = self?.player else { return } + guard player.currentItem != nil else { return } + + var nowPlayingInfo = self!.nowPlayingInfoCenter.nowPlayingInfo ?? [String: Any]() + self!.duration = Float(CMTimeGetSeconds(player.currentItem!.duration)) + nowPlayingInfo[MPMediaItemPropertyPlaybackDuration] = self!.duration + nowPlayingInfo[MPNowPlayingInfoPropertyElapsedPlaybackTime] = CMTimeGetSeconds(player.currentItem!.currentTime()) + self!.nowPlayingInfoCenter.nowPlayingInfo = nowPlayingInfo + }) + } + + fileprivate func updatePlaybackRateMetadata() { + guard player?.currentItem != nil else { + duration = 0 + nowPlayingInfoCenter.nowPlayingInfo = nil + return + } + + var nowPlayingInfo = nowPlayingInfoCenter.nowPlayingInfo ?? [String: Any]() + nowPlayingInfo[MPNowPlayingInfoPropertyPlaybackRate] = player!.rate + nowPlayingInfo[MPNowPlayingInfoPropertyDefaultPlaybackRate] = player!.rate + } +} diff --git a/XCDYouTubeKit Demo/iOS Demo/AppDelegate.m b/XCDYouTubeKit Demo/iOS Demo/AppDelegate.m index 4451e322..b6620944 100644 --- a/XCDYouTubeKit Demo/iOS Demo/AppDelegate.m +++ b/XCDYouTubeKit Demo/iOS Demo/AppDelegate.m @@ -9,6 +9,7 @@ #import #import "ContextLogFormatter.h" +#import "XCDYouTubeKit_iOS_Demo-Swift.h" @implementation AppDelegate @@ -19,9 +20,6 @@ - (instancetype) init if (!(self = [super init])) return nil; - _playerEventLogger = [PlayerEventLogger new]; - _nowPlayingInfoCenterProvider = [NowPlayingInfoCenterProvider new]; - return self; } @@ -80,4 +78,13 @@ - (BOOL) application:(UIApplication *)application didFinishLaunchingWithOptions: return YES; } + +- (void)applicationDidEnterBackground:(UIApplication *)application { + [[AVPlayerViewControllerManager shared]disconnectPlayer]; +} + +- (void)applicationWillEnterForeground:(UIApplication *)application { + [[AVPlayerViewControllerManager shared]reconnectPlayerWithRootViewController:self.window.rootViewController]; +} + @end diff --git a/XCDYouTubeKit Demo/iOS Demo/DemoAsynchronousViewController.m b/XCDYouTubeKit Demo/iOS Demo/DemoAsynchronousViewController.m index 33f2989f..405b0f06 100644 --- a/XCDYouTubeKit Demo/iOS Demo/DemoAsynchronousViewController.m +++ b/XCDYouTubeKit Demo/iOS Demo/DemoAsynchronousViewController.m @@ -6,7 +6,9 @@ #import -#import "MPMoviePlayerController+BackgroundPlayback.h" +#import + +#import "XCDYouTubeKit_iOS_Demo-Swift.h" @implementation DemoAsynchronousViewController @@ -21,18 +23,38 @@ - (IBAction) play:(id)sender { NSString *apiKey = self.apiKeyTextField.text; [[NSUserDefaults standardUserDefaults] setObject:apiKey forKey:@"YouTubeAPIKey"]; - - XCDYouTubeVideoPlayerViewController *videoPlayerViewController = [XCDYouTubeVideoPlayerViewController new]; - videoPlayerViewController.moviePlayer.backgroundPlaybackEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:@"PlayVideoInBackground"]; - [self presentMoviePlayerViewControllerAnimated:videoPlayerViewController]; - + // https://developers.google.com/youtube/v3/docs/videos/list NSURL *mostPopularURL = [NSURL URLWithString:[NSString stringWithFormat:@"https://www.googleapis.com/youtube/v3/videos?key=%@&chart=mostPopular&part=id", apiKey]]; - [NSURLConnection sendAsynchronousRequest:[NSURLRequest requestWithURL:mostPopularURL] queue:[NSOperationQueue new] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) - { + + [[[NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration ephemeralSessionConfiguration]]dataTaskWithURL:mostPopularURL completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) + { + if (error) { + [[Utilities shared]displayError:error originViewController:self]; + return; + } + id json = [NSJSONSerialization JSONObjectWithData:data ?: [NSData new] options:0 error:NULL]; NSString *videoIdentifier = [[[json valueForKeyPath:@"items.id"] firstObject] description]; - videoPlayerViewController.videoIdentifier = videoIdentifier; + [self displayVideoIdentifier:videoIdentifier]; + }] resume]; +} + +- (void) displayVideoIdentifier:(NSString *)videoIdentifier +{ + + [[XCDYouTubeClient defaultClient]getVideoWithIdentifier:videoIdentifier completionHandler:^(XCDYouTubeVideo * _Nullable video, NSError * _Nullable error) + { + if (error) { + [[Utilities shared]displayError:error originViewController:self]; + return; + } + + [AVPlayerViewControllerManager shared].video = video; + AVPlayerViewController *playerViewController = [AVPlayerViewControllerManager shared].controller; + [self presentViewController:playerViewController animated:YES completion:nil]; + [playerViewController.player play]; + }]; } diff --git a/XCDYouTubeKit Demo/iOS Demo/DemoFullScreenViewController.h b/XCDYouTubeKit Demo/iOS Demo/DemoFullScreenViewController.h deleted file mode 100644 index 2085880d..00000000 --- a/XCDYouTubeKit Demo/iOS Demo/DemoFullScreenViewController.h +++ /dev/null @@ -1,16 +0,0 @@ -// -// Copyright (c) 2013-2016 Cédric Luthi. All rights reserved. -// - -@import UIKit; - -#import "VideoPickerController.h" - -@interface DemoFullScreenViewController : UIViewController - -@property (nonatomic, weak) IBOutlet UITextField *videoIdentifierTextField; -@property (nonatomic, weak) IBOutlet UISwitch *lowQualitySwitch; - -- (IBAction) play:(id)sender; - -@end diff --git a/XCDYouTubeKit Demo/iOS Demo/DemoFullScreenViewController.m b/XCDYouTubeKit Demo/iOS Demo/DemoFullScreenViewController.m deleted file mode 100644 index 92438df4..00000000 --- a/XCDYouTubeKit Demo/iOS Demo/DemoFullScreenViewController.m +++ /dev/null @@ -1,83 +0,0 @@ -// -// Copyright (c) 2013-2016 Cédric Luthi. All rights reserved. -// - -#import "DemoFullScreenViewController.h" - -#import - -#import "MPMoviePlayerController+BackgroundPlayback.h" - -@implementation DemoFullScreenViewController - -- (void) viewDidLoad -{ - [super viewDidLoad]; - - [self restoreVideoIdentifier]; -} - -- (void) saveVideoIdentifier -{ - [[NSUserDefaults standardUserDefaults] setObject:self.videoIdentifierTextField.text forKey:@"VideoIdentifier"]; -} - -- (void) restoreVideoIdentifier -{ - self.videoIdentifierTextField.text = [[NSUserDefaults standardUserDefaults] objectForKey:@"VideoIdentifier"]; -} - -- (IBAction) endEditing:(id)sender -{ - [self.view endEditing:YES]; -} - -- (IBAction) play:(id)sender -{ - XCDYouTubeVideoPlayerViewController *videoPlayerViewController = [[XCDYouTubeVideoPlayerViewController alloc] initWithVideoIdentifier:self.videoIdentifierTextField.text]; - videoPlayerViewController.moviePlayer.backgroundPlaybackEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:@"PlayVideoInBackground"]; - videoPlayerViewController.preferredVideoQualities = self.lowQualitySwitch.on ? @[ @(XCDYouTubeVideoQualitySmall240), @(XCDYouTubeVideoQualityMedium360) ] : nil; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(moviePlayerPlaybackDidFinish:) name:MPMoviePlayerPlaybackDidFinishNotification object:videoPlayerViewController.moviePlayer]; - [self presentMoviePlayerViewControllerAnimated:videoPlayerViewController]; -} - -#pragma mark - Notifications - -- (void) moviePlayerPlaybackDidFinish:(NSNotification *)notification -{ - [[NSNotificationCenter defaultCenter] removeObserver:self name:MPMoviePlayerPlaybackDidFinishNotification object:notification.object]; - MPMovieFinishReason finishReason = [notification.userInfo[MPMoviePlayerPlaybackDidFinishReasonUserInfoKey] integerValue]; - if (finishReason == MPMovieFinishReasonPlaybackError) - { - NSString *title = NSLocalizedString(@"Video Playback Error", @"Full screen video error alert - title"); - NSError *error = notification.userInfo[XCDMoviePlayerPlaybackDidFinishErrorUserInfoKey]; - NSString *message = [NSString stringWithFormat:@"%@\n%@ (%@)", error.localizedDescription, error.domain, @(error.code)]; - NSString *cancelButtonTitle = NSLocalizedString(@"OK", @"Full screen video error alert - cancel button"); - UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:title message:message delegate:nil cancelButtonTitle:cancelButtonTitle otherButtonTitles:nil]; - [alertView show]; - } -} - - -#pragma mark - UITextFieldDelegate - -- (BOOL) textFieldShouldReturn:(UITextField *)textField -{ - [self play:textField]; - return YES; -} - -- (void) textFieldDidEndEditing:(UITextField *)textField -{ - [self saveVideoIdentifier]; -} - -#pragma mark - VideoPickerControllerDelegate - -- (void) videoPickerController:(VideoPickerController *)videoPickerController didSelectVideoWithIdentifier:(NSString *)videoIdentifier -{ - self.videoIdentifierTextField.text = videoIdentifier; - [self saveVideoIdentifier]; -} - -@end diff --git a/XCDYouTubeKit Demo/iOS Demo/DemoFullScreenViewController.swift b/XCDYouTubeKit Demo/iOS Demo/DemoFullScreenViewController.swift new file mode 100644 index 00000000..0a42b55b --- /dev/null +++ b/XCDYouTubeKit Demo/iOS Demo/DemoFullScreenViewController.swift @@ -0,0 +1,60 @@ +// +// DemoFullScreenViewController.swift +// XCDYouTubeKit iOS Demo +// +// Created by Soneé John on 10/17/19. +// Copyright © 2019 Cédric Luthi. All rights reserved. +// + +import UIKit +import AVKit +import XCDYouTubeKit + +extension DemoFullScreenViewController: VideoPickerControllerDelegate { + func videoPickerController(_ videoPickerController: VideoPickerController!, didSelectVideoWithIdentifier videoIdentifier: String!) { + self.videoIdentifierTextField.text = videoIdentifier + UserDefaults.standard.set(videoIdentifier, forKey: "VideoIdentifier") + } +} + +extension DemoFullScreenViewController: UITextFieldDelegate { + func textFieldShouldReturn(_ textField: UITextField) -> Bool { + self.play(textField) + return true + } + + func textFieldDidEndEditing(_ textField: UITextField) { + UserDefaults.standard.set(self.videoIdentifierTextField.text, forKey: "VideoIdentifier") + } +} + +class DemoFullScreenViewController: UIViewController { + + @IBOutlet weak open var lowQualitySwitch: UISwitch! + @IBOutlet weak open var videoIdentifierTextField: UITextField! + var ob: NSKeyValueObservation? + private var timeObserverToken: Any? + + override func viewDidLoad() { + super.viewDidLoad() + self.videoIdentifierTextField.text = UserDefaults.standard.string(forKey: "VideoIdentifier") + } + + @IBAction open func endEditing(_ sender: Any!) { + self.view.endEditing(true) + } + + @IBAction open func play(_ sender: Any!) { + XCDYouTubeClient.default().getVideoWithIdentifier(self.videoIdentifierTextField.text) { (video, error) in + guard error == nil else { + Utilities.shared.displayError(error! as NSError, originViewController: self) + return + } + AVPlayerViewControllerManager.shared.lowQualityMode = self.lowQualitySwitch.isOn + AVPlayerViewControllerManager.shared.video = video + self.present(AVPlayerViewControllerManager.shared.controller, animated: true) { + AVPlayerViewControllerManager.shared.controller.player?.play() + } + } + } +} diff --git a/XCDYouTubeKit Demo/iOS Demo/DemoInlineViewController.h b/XCDYouTubeKit Demo/iOS Demo/DemoInlineViewController.h index cc4596bc..3531a67b 100644 --- a/XCDYouTubeKit Demo/iOS Demo/DemoInlineViewController.h +++ b/XCDYouTubeKit Demo/iOS Demo/DemoInlineViewController.h @@ -7,10 +7,8 @@ @interface DemoInlineViewController : UIViewController @property (nonatomic, weak) IBOutlet UIView *videoContainerView; -@property (nonatomic, weak) IBOutlet UISwitch *prepareToPlaySwitch; @property (nonatomic, weak) IBOutlet UISwitch *shouldAutoplaySwitch; - (IBAction) load:(id)sender; -- (IBAction) prepareToPlay:(UISwitch *)sender; @end diff --git a/XCDYouTubeKit Demo/iOS Demo/DemoInlineViewController.m b/XCDYouTubeKit Demo/iOS Demo/DemoInlineViewController.m index 6c2d7e03..df910489 100644 --- a/XCDYouTubeKit Demo/iOS Demo/DemoInlineViewController.m +++ b/XCDYouTubeKit Demo/iOS Demo/DemoInlineViewController.m @@ -6,44 +6,40 @@ #import -#import "MPMoviePlayerController+BackgroundPlayback.h" +#import -@interface DemoInlineViewController () - -@property (nonatomic, strong) XCDYouTubeVideoPlayerViewController *videoPlayerViewController; - -@end +#import "XCDYouTubeKit_iOS_Demo-Swift.h" @implementation DemoInlineViewController -- (void) viewWillDisappear:(BOOL)animated -{ + +- (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; - // Beware, viewWillDisappear: is called when the player view enters full screen on iOS 6+ - if ([self isMovingFromParentViewController]) - [self.videoPlayerViewController.moviePlayer stop]; + [[AVPlayerViewControllerManager shared].controller.player pause]; } - - (IBAction) load:(id)sender { - [self.videoContainerView.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)]; - NSString *videoIdentifier = [[NSUserDefaults standardUserDefaults] objectForKey:@"VideoIdentifier"]; - self.videoPlayerViewController = [[XCDYouTubeVideoPlayerViewController alloc] initWithVideoIdentifier:videoIdentifier]; - self.videoPlayerViewController.moviePlayer.backgroundPlaybackEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:@"PlayVideoInBackground"]; - [self.videoPlayerViewController presentInView:self.videoContainerView]; - - if (self.prepareToPlaySwitch.on) - [self.videoPlayerViewController.moviePlayer prepareToPlay]; - - self.videoPlayerViewController.moviePlayer.shouldAutoplay = self.shouldAutoplaySwitch.on; -} -- (IBAction) prepareToPlay:(UISwitch *)sender -{ - if (sender.on) - [self.videoPlayerViewController.moviePlayer prepareToPlay]; + [[XCDYouTubeClient defaultClient] getVideoWithIdentifier:videoIdentifier completionHandler:^(XCDYouTubeVideo * _Nullable video, NSError * _Nullable error) { + if (video) + { + [AVPlayerViewControllerManager shared].video = video; + AVPlayerViewController *playerViewController = [AVPlayerViewControllerManager shared].controller; + playerViewController.view.frame = self.videoContainerView.bounds; + [self addChildViewController:playerViewController]; + [self.videoContainerView addSubview:playerViewController.view]; + [playerViewController didMoveToParentViewController:self]; + + if (self.shouldAutoplaySwitch.on) + [playerViewController.player play]; + } + else + { + [[Utilities shared]displayError:error originViewController:self]; + } + }]; } @end diff --git a/XCDYouTubeKit Demo/iOS Demo/DemoThumbnailViewController.m b/XCDYouTubeKit Demo/iOS Demo/DemoThumbnailViewController.m index 588d19d9..de66659e 100644 --- a/XCDYouTubeKit Demo/iOS Demo/DemoThumbnailViewController.m +++ b/XCDYouTubeKit Demo/iOS Demo/DemoThumbnailViewController.m @@ -6,11 +6,13 @@ #import -#import "MPMoviePlayerController+BackgroundPlayback.h" +#import + +#import "XCDYouTubeKit_iOS_Demo-Swift.h" @interface DemoThumbnailViewController () -@property (nonatomic, strong) XCDYouTubeVideoPlayerViewController *videoPlayerViewController; +@property (nonatomic, strong) XCDYouTubeVideo *video; @end @@ -19,46 +21,48 @@ @implementation DemoThumbnailViewController - (IBAction) loadThumbnail:(id)sender { NSString *videoIdentifier = [[NSUserDefaults standardUserDefaults] objectForKey:@"VideoIdentifier"]; - self.videoPlayerViewController = [[XCDYouTubeVideoPlayerViewController alloc] initWithVideoIdentifier:videoIdentifier]; - self.videoPlayerViewController.moviePlayer.backgroundPlaybackEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:@"PlayVideoInBackground"]; - NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter]; - [defaultCenter addObserver:self selector:@selector(videoPlayerViewControllerDidReceiveVideo:) name:XCDYouTubeVideoPlayerViewControllerDidReceiveVideoNotification object:self.videoPlayerViewController]; - [defaultCenter addObserver:self selector:@selector(moviePlayerPlaybackDidFinish:) name:MPMoviePlayerPlaybackDidFinishNotification object:self.videoPlayerViewController.moviePlayer]; + [[XCDYouTubeClient defaultClient]getVideoWithIdentifier:videoIdentifier completionHandler:^(XCDYouTubeVideo * _Nullable video, NSError * _Nullable error) + { + if (error) { + [[Utilities shared]displayError:error originViewController:self]; + return; + } + + [self displayThumbnailWithVideo:video]; + + }]; } - (IBAction) play:(id)sender { - [self.videoPlayerViewController presentInView:self.videoContainerView]; - [self.videoPlayerViewController.moviePlayer play]; + [AVPlayerViewControllerManager shared].video = self.video; + AVPlayerViewController *playerViewController = [AVPlayerViewControllerManager shared].controller; + [self presentViewController:playerViewController animated:YES completion:nil]; + [playerViewController.player play]; } -#pragma mark - Notifications - -- (void) videoPlayerViewControllerDidReceiveVideo:(NSNotification *)notification +- (void) displayThumbnailWithVideo:(XCDYouTubeVideo *)video { - XCDYouTubeVideo *video = notification.userInfo[XCDYouTubeVideoUserInfoKey]; + self.video = video; self.titleLabel.text = video.title; - - NSURL *thumbnailURL = video.mediumThumbnailURL ?: video.smallThumbnailURL; - [NSURLConnection sendAsynchronousRequest:[NSURLRequest requestWithURL:thumbnailURL] queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) - { - self.thumbnailImageView.image = [UIImage imageWithData:data]; - - [self.actionButton setTitle:NSLocalizedString(@"Play Video", nil) forState:UIControlStateNormal]; - [self.actionButton removeTarget:self action:NULL forControlEvents:UIControlEventAllEvents]; - [self.actionButton addTarget:self action:@selector(play:) forControlEvents:UIControlEventTouchUpInside]; - }]; -} + NSURL *thumbnailURL = video.thumbnailURL; -- (void) moviePlayerPlaybackDidFinish:(NSNotification *)notification -{ - NSError *error = notification.userInfo[XCDMoviePlayerPlaybackDidFinishErrorUserInfoKey]; - if (error) - { - UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Error", nil) message:error.localizedDescription delegate:nil cancelButtonTitle:NSLocalizedString(@"OK", nil) otherButtonTitles:nil]; - [alertView show]; - } + [[[NSURLSession sharedSession]dataTaskWithURL:thumbnailURL completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) + { + if (error) { + [[Utilities shared]displayError:error originViewController:self]; + return; + } + + [[NSOperationQueue mainQueue]addOperationWithBlock:^{ + self.thumbnailImageView.image = [UIImage imageWithData:data]; + [self.actionButton setTitle:NSLocalizedString(@"Play Video", nil) forState:UIControlStateNormal]; + [self.actionButton removeTarget:self action:NULL forControlEvents:UIControlEventAllEvents]; + [self.actionButton addTarget:self action:@selector(play:) forControlEvents:UIControlEventTouchUpInside]; + }]; + + }] resume]; } @end diff --git a/XCDYouTubeKit Demo/iOS Demo/MPMoviePlayerController+BackgroundPlayback.h b/XCDYouTubeKit Demo/iOS Demo/MPMoviePlayerController+BackgroundPlayback.h deleted file mode 100644 index 30c6b242..00000000 --- a/XCDYouTubeKit Demo/iOS Demo/MPMoviePlayerController+BackgroundPlayback.h +++ /dev/null @@ -1,18 +0,0 @@ -// -// Copyright (c) 2013-2016 Cédric Luthi. All rights reserved. -// - -@import MediaPlayer; - -@interface MPMoviePlayerController (BackgroundPlayback) - -/** - * When enabling background playback: - * - The `UIBackgroundModes` array (Required background modes) in the application Info.plist file must contain the `audio` element (App plays audio or streams audio/video using AirPlay). - * - The audio session category must be set to `AVAudioSessionCategoryPlayback`. - * - * @discussion On iOS < 7, the `backgroundPlaybackEnabled` property does nothing. Instead, you must set the `PlayVideoInBackground` boolean user default used by the MediaPlayer framework. The `PlayVideoInBackground` user default must be set before a `MPMoviePlayerController` object is created. - */ -@property (nonatomic, assign, getter = isBackgroundPlaybackEnabled) BOOL backgroundPlaybackEnabled; - -@end diff --git a/XCDYouTubeKit Demo/iOS Demo/MPMoviePlayerController+BackgroundPlayback.m b/XCDYouTubeKit Demo/iOS Demo/MPMoviePlayerController+BackgroundPlayback.m deleted file mode 100644 index 510d0fa3..00000000 --- a/XCDYouTubeKit Demo/iOS Demo/MPMoviePlayerController+BackgroundPlayback.m +++ /dev/null @@ -1,119 +0,0 @@ -// -// Copyright (c) 2013-2016 Cédric Luthi. All rights reserved. -// - -#import "MPMoviePlayerController+BackgroundPlayback.h" - -@import AVFoundation; -@import ObjectiveC; - -#ifndef NSFoundationVersionNumber_iOS_7_0 -#define NSFoundationVersionNumber_iOS_7_0 1047.2 -#endif - -@implementation MPMoviePlayerController (BackgroundPlayback) - -+ (void) load -{ - // On iOS 7, working with playerLayer.player as documented in Technical Q&A QA1668 works fine. - // On iOS 5 and 6, setting playerLayer.player to nil is not enough for background playback when locking the device, the `PlayVideoInBackground` user default must be used instead. - if (NSFoundationVersionNumber < NSFoundationVersionNumber_iOS_7_0) - return; - - dispatch_async(dispatch_get_main_queue(), ^{ - // Register for these notifications as early as possible in order to be called before -[MPAVController _applicationWillResignActive:] which calls `_pausePlaybackIfNecessary`. - NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter]; - [defaultCenter addObserver:self selector:@selector(backgroundPlayback_moviePlayerNowPlayingMovieDidChange:) name:MPMoviePlayerNowPlayingMovieDidChangeNotification object:nil]; - [defaultCenter addObserver:self selector:@selector(backgroundPlayback_moviePlayerPlaybackDidFinish:) name:MPMoviePlayerPlaybackDidFinishNotification object:nil]; - [defaultCenter addObserver:self selector:@selector(backgroundPlayback_applicationWillResignActive:) name:UIApplicationWillResignActiveNotification object:nil]; - [defaultCenter addObserver:self selector:@selector(backgroundPlayback_applicationDidBecomeActive:) name:UIApplicationDidBecomeActiveNotification object:nil]; - }); -} - -static const void * const BackgroundPlaybackEnabledKey = &BackgroundPlaybackEnabledKey; - -- (BOOL) isBackgroundPlaybackEnabled -{ - return [objc_getAssociatedObject(self, BackgroundPlaybackEnabledKey) boolValue]; -} - -- (void) setBackgroundPlaybackEnabled:(BOOL)backgroundPlaybackEnabled -{ - if (backgroundPlaybackEnabled) - { - NSArray *backgroundModes = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"UIBackgroundModes"]; - if (!backgroundModes || ([backgroundModes isKindOfClass:[NSArray class]] && ![backgroundModes containsObject:@"audio"])) - NSLog(@"ERROR: The `UIBackgroundModes` array in the application Info.plist file must contain the `audio` element for background playback."); - } - - objc_setAssociatedObject(self, BackgroundPlaybackEnabledKey, @(backgroundPlaybackEnabled), OBJC_ASSOCIATION_RETAIN_NONATOMIC); -} - -static __weak MPMoviePlayerController *currentMoviePlayerController; - -+ (void) backgroundPlayback_moviePlayerNowPlayingMovieDidChange:(NSNotification *)notification -{ - currentMoviePlayerController = notification.object; -} - -+ (void) backgroundPlayback_moviePlayerPlaybackDidFinish:(NSNotification *)notification -{ - currentMoviePlayerController = nil; -} - -__attribute__((overloadable)) -static AVPlayerLayer * PlayerLayer(void) -{ - // When an inline movie player controller goes fullscreen, its view is somehow transferred to the key window. - return PlayerLayer(currentMoviePlayerController.view) ?: PlayerLayer([[UIApplication sharedApplication] keyWindow]); -} - -// Since MPMoviePlayerController doesn't expose its AVFoundation internals, traversing its subviews is the least worst solution to access its AVPlayerLayer. -// See Technical Q&A QA1668 - Playing media while in the background using AV Foundation on iOS https://developer.apple.com/library/ios/qa/qa1668/_index.html -__attribute__((overloadable)) -static AVPlayerLayer * PlayerLayer(UIView *view) -{ - AVPlayerLayer *playerLayer = nil; - if ([view.layer isKindOfClass:[AVPlayerLayer class]]) - { - playerLayer = (AVPlayerLayer *)view.layer; - } - else - { - for (UIView *subview in view.subviews) - { - playerLayer = PlayerLayer(subview); - if (playerLayer) - break; - } - } - return playerLayer; -} - -static const void * const PlayerKey = &PlayerKey; - -+ (void) backgroundPlayback_applicationWillResignActive:(NSNotification *)notification -{ - if (!currentMoviePlayerController) - return; - - AVPlayerLayer *playerLayer = PlayerLayer(); - objc_setAssociatedObject(currentMoviePlayerController, PlayerKey, playerLayer.player, OBJC_ASSOCIATION_RETAIN_NONATOMIC); - if (currentMoviePlayerController.isBackgroundPlaybackEnabled) - { - if (![[[AVAudioSession sharedInstance] category] isEqualToString:AVAudioSessionCategoryPlayback]) - NSLog(@"ERROR: The audio session category must be `AVAudioSessionCategoryPlayback` when background playback is enabled."); - - playerLayer.player = nil; - } -} - -+ (void) backgroundPlayback_applicationDidBecomeActive:(NSNotification *)notification -{ - AVPlayerLayer *playerLayer = PlayerLayer(); - AVPlayer *player = objc_getAssociatedObject(currentMoviePlayerController, PlayerKey); - if (player) - playerLayer.player = player; -} - -@end diff --git a/XCDYouTubeKit Demo/iOS Demo/SettingsViewController.m b/XCDYouTubeKit Demo/iOS Demo/SettingsViewController.m index a0234fe2..a63f2d58 100644 --- a/XCDYouTubeKit Demo/iOS Demo/SettingsViewController.m +++ b/XCDYouTubeKit Demo/iOS Demo/SettingsViewController.m @@ -8,7 +8,6 @@ @interface SettingsViewController () -@property (nonatomic, weak) IBOutlet UISwitch *playVideoInBackgroundSwitch; @property (nonatomic, weak) IBOutlet UILabel *audioSessionCategoryLabel; @property (nonatomic, weak) IBOutlet UILabel *versionLabel; @@ -20,29 +19,17 @@ - (void) viewDidLoad { [super viewDidLoad]; - self.playVideoInBackgroundSwitch.on = [[NSUserDefaults standardUserDefaults] boolForKey:@"PlayVideoInBackground"]; - self.audioSessionCategoryLabel.text = [[AVAudioSession sharedInstance] category]; + if (@available(iOS 13.0, *)) { + self.overrideUserInterfaceStyle = UIUserInterfaceStyleLight; + } + self.audioSessionCategoryLabel.text = [[AVAudioSession sharedInstance] category]; NSBundle *bundle = [NSBundle bundleWithIdentifier:@"ch.pitaya.xcdyoutubekit"]; self.versionLabel.text = [NSString stringWithFormat:@"Version %@ (%@)", [bundle objectForInfoDictionaryKey:@"CFBundleShortVersionString"], [bundle objectForInfoDictionaryKey:@"CFBundleVersion"]]; } #pragma mark - Actions -- (IBAction) togglePlayVideoInBackground:(UISwitch *)sender -{ - /** - * `PlayVideoInBackground` is a user default used by the MediaPlayer framework which controls whether a `MPMoviePlayerController` continues playing videos while in the background. - * - * In addition to the `PlayVideoInBackground` user default, background playback requires: - * - The `UIBackgroundModes` array (Required background modes) in the application Info.plist file must contain the `audio` element (App plays audio or streams audio/video using AirPlay). - * - The audio session category must be set to `AVAudioSessionCategoryPlayback`. - * - * On iOS 7, changing the `PlayVideoInBackground` user default has no effect. See MPMoviePlayerController+BackgroundPlayback for a solution. - */ - [[NSUserDefaults standardUserDefaults] setBool:self.playVideoInBackgroundSwitch.on forKey:@"PlayVideoInBackground"]; -} - - (IBAction) selectAudioSessionCategory:(UIButton *)sender { UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:NSLocalizedString(@"Audio Session Category", nil) delegate:self cancelButtonTitle:NSLocalizedString(@"Cancel", nil) destructiveButtonTitle:nil otherButtonTitles:NSLocalizedString(@"Solo Ambient", nil), NSLocalizedString(@"Playback", nil), nil]; diff --git a/XCDYouTubeKit Demo/iOS Demo/Utilities.swift b/XCDYouTubeKit Demo/iOS Demo/Utilities.swift new file mode 100644 index 00000000..a4393929 --- /dev/null +++ b/XCDYouTubeKit Demo/iOS Demo/Utilities.swift @@ -0,0 +1,23 @@ +// +// Utilities.swift +// XCDYouTubeKit iOS Demo +// +// Created by Soneé John on 10/24/19. +// Copyright © 2019 Cédric Luthi. All rights reserved. +// + +import UIKit + +@objcMembers class Utilities: NSObject { + static let shared = Utilities() + + func displayError(_ error: NSError, originViewController: UIViewController) { + OperationQueue.main.addOperation { + originViewController.dismiss(animated: true) { + let alert = UIAlertController(title: NSLocalizedString("Error", comment: ""), message: error.localizedDescription, preferredStyle: .alert) + alert.addAction(UIAlertAction(title: NSLocalizedString("OK", comment: ""), style: .default, handler: nil)) + originViewController.present(alert, animated: true, completion: nil) + } + } + } +} diff --git a/XCDYouTubeKit Demo/iOS Demo/XCDYouTubeKit iOS Demo-Bridging-Header.h b/XCDYouTubeKit Demo/iOS Demo/XCDYouTubeKit iOS Demo-Bridging-Header.h new file mode 100644 index 00000000..76d1cafe --- /dev/null +++ b/XCDYouTubeKit Demo/iOS Demo/XCDYouTubeKit iOS Demo-Bridging-Header.h @@ -0,0 +1,6 @@ +// +// Use this file to import your target's public headers that you would like to expose to Swift. +// + +#import "VideoPickerController.h" +#import diff --git a/XCDYouTubeKit Demo/iOS Demo/en.lproj/MainStoryboard.storyboard b/XCDYouTubeKit Demo/iOS Demo/en.lproj/MainStoryboard.storyboard index bdae45be..c31579cd 100644 --- a/XCDYouTubeKit Demo/iOS Demo/en.lproj/MainStoryboard.storyboard +++ b/XCDYouTubeKit Demo/iOS Demo/en.lproj/MainStoryboard.storyboard @@ -1,8 +1,10 @@ - - + + + - + + @@ -11,8 +13,8 @@ + - @@ -20,86 +22,60 @@ - + + + + + - + - - + + - - - - - - - - - - - - - - - - - - - - - + - - + + - - - + - - + @@ -110,114 +86,104 @@ - - + - + - - + - + - + - - + - + - + - - + - + - + - - + - + - + - - + @@ -236,59 +202,57 @@ - + + + + + - + - - + + - - + - + - - - + - - - + - - + @@ -300,45 +264,45 @@ - + + + + + - + - - - + @@ -347,78 +311,73 @@ - + - + + + + + - + - - + + - - - - - + + - - - + @@ -449,91 +408,73 @@ - + + + + + - + - - + + - - + - - + - - - + - - + - - + + - @@ -541,7 +482,7 @@ - + diff --git a/XCDYouTubeKit.podspec b/XCDYouTubeKit.podspec index fc0c8c64..3636cc32 100644 --- a/XCDYouTubeKit.podspec +++ b/XCDYouTubeKit.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "XCDYouTubeKit" - s.version = "2.8.1" + s.version = "2.8.2" s.summary = "YouTube video player for iOS and OS X." s.homepage = "https://github.com/0xced/XCDYouTubeKit" s.screenshot = "https://raw.github.com/0xced/XCDYouTubeKit/#{s.version}/Screenshots/XCDYouTubeVideoPlayerViewController.png" diff --git a/XCDYouTubeKit.xcodeproj/project.pbxproj b/XCDYouTubeKit.xcodeproj/project.pbxproj index 9412e4d1..9e5a0946 100644 --- a/XCDYouTubeKit.xcodeproj/project.pbxproj +++ b/XCDYouTubeKit.xcodeproj/project.pbxproj @@ -613,10 +613,10 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COMBINE_HIDPI_IMAGES = YES; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 40; + CURRENT_PROJECT_VERSION = 41; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 2.0.0; - DYLIB_CURRENT_VERSION = 2.8.1; + DYLIB_CURRENT_VERSION = 2.8.2; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; @@ -691,10 +691,10 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COMBINE_HIDPI_IMAGES = YES; COPY_PHASE_STRIP = YES; - CURRENT_PROJECT_VERSION = 40; + CURRENT_PROJECT_VERSION = 41; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 2.0.0; - DYLIB_CURRENT_VERSION = 2.8.1; + DYLIB_CURRENT_VERSION = 2.8.2; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; diff --git a/XCDYouTubeKit/XCDYouTubeClient.h b/XCDYouTubeKit/XCDYouTubeClient.h index 2b89201c..e9a2778a 100644 --- a/XCDYouTubeKit/XCDYouTubeClient.h +++ b/XCDYouTubeKit/XCDYouTubeClient.h @@ -11,9 +11,9 @@ #import -#import -#import -#import +#import "XCDYouTubeOperation.h" +#import "XCDYouTubeVideo.h" +#import "XCDYouTubeError.h" NS_ASSUME_NONNULL_BEGIN diff --git a/XCDYouTubeKit/XCDYouTubeKit.h b/XCDYouTubeKit/XCDYouTubeKit.h index 250ef88f..bff607ef 100644 --- a/XCDYouTubeKit/XCDYouTubeKit.h +++ b/XCDYouTubeKit/XCDYouTubeKit.h @@ -4,13 +4,14 @@ #import -#import -#import -#import -#import -#import -#import +#import "XCDYouTubeClient.h" +#import "XCDYouTubeError.h" +#import "XCDYouTubeLogger.h" +#import "XCDYouTubeOperation.h" +#import "XCDYouTubeVideo.h" +#import "XCDYouTubeVideoOperation.h" + #if TARGET_OS_IOS || (!defined(TARGET_OS_IOS) && TARGET_OS_IPHONE) -#import +#import "XCDYouTubeVideoPlayerViewController.h" #endif diff --git a/XCDYouTubeKit/XCDYouTubeVideo+Private.h b/XCDYouTubeKit/XCDYouTubeVideo+Private.h index 3f1c196c..54c0c3cd 100644 --- a/XCDYouTubeKit/XCDYouTubeVideo+Private.h +++ b/XCDYouTubeKit/XCDYouTubeVideo+Private.h @@ -2,7 +2,7 @@ // Copyright (c) 2013-2016 Cédric Luthi. All rights reserved. // -#import +#import "XCDYouTubeVideo.h" #import "XCDYouTubePlayerScript.h" diff --git a/XCDYouTubeKit/XCDYouTubeVideo.h b/XCDYouTubeKit/XCDYouTubeVideo.h index 7668a930..4cd09143 100644 --- a/XCDYouTubeKit/XCDYouTubeVideo.h +++ b/XCDYouTubeKit/XCDYouTubeVideo.h @@ -106,6 +106,13 @@ extern NSString *const XCDYouTubeVideoQualityHTTPLiveStreaming; @property (nonatomic, readonly) NSDictionary *streamURLs; #endif +/** + +* A streamURL that is compatible on Apple devices. +* The `streamURLs` may contain both video and audio streams, some video streams do not contain any audio. This property will return a video stream that contains both audio and video with a maximum video quality of 720p in the case of videos that aren't live. Also, this properly will return the URL to a live stream in the case of live videos. +*/ +@property (nonatomic, readonly) NSURL *streamURL; + /** * A dictionary of caption URLs (XML). diff --git a/XCDYouTubeKit/XCDYouTubeVideo.m b/XCDYouTubeKit/XCDYouTubeVideo.m index 02cd7f33..8769b753 100644 --- a/XCDYouTubeKit/XCDYouTubeVideo.m +++ b/XCDYouTubeKit/XCDYouTubeVideo.m @@ -280,6 +280,8 @@ - (instancetype) initWithIdentifier:(NSString *)identifier info:(NSDictionary *) } } + _streamURL = _streamURLs[XCDYouTubeVideoQualityHTTPLiveStreaming] ?: _streamURLs[@(XCDYouTubeVideoQualityHD720)] ?: _streamURLs[@(XCDYouTubeVideoQualityMedium360)] ?: _streamURLs[@(XCDYouTubeVideoQualitySmall240)]; + return self; } else diff --git a/XCDYouTubeKit/XCDYouTubeVideoOperation.h b/XCDYouTubeKit/XCDYouTubeVideoOperation.h index 4ee8b7b0..644aa4ef 100644 --- a/XCDYouTubeKit/XCDYouTubeVideoOperation.h +++ b/XCDYouTubeKit/XCDYouTubeVideoOperation.h @@ -10,8 +10,8 @@ #import -#import -#import +#import "XCDYouTubeOperation.h" +#import "XCDYouTubeVideo.h" NS_ASSUME_NONNULL_BEGIN diff --git a/XCDYouTubeKit/XCDYouTubeVideoPlayerViewController.h b/XCDYouTubeKit/XCDYouTubeVideoPlayerViewController.h index 812ee9c1..c4c3a4f6 100644 --- a/XCDYouTubeKit/XCDYouTubeVideoPlayerViewController.h +++ b/XCDYouTubeKit/XCDYouTubeVideoPlayerViewController.h @@ -9,6 +9,10 @@ #define null_resettable #endif +#import + +#if TARGET_OS_IOS + #import NS_ASSUME_NONNULL_BEGIN @@ -124,3 +128,5 @@ MP_EXTERN NSString *const XCDMetadataKeyMediumThumbnailURL DEPRECATED_MSG_ATTRIB MP_EXTERN NSString *const XCDMetadataKeyLargeThumbnailURL DEPRECATED_MSG_ATTRIBUTE("Use XCDYouTubeVideoUserInfoKey instead."); NS_ASSUME_NONNULL_END + +#endif diff --git a/XCDYouTubeKit/XCDYouTubeVideoPlayerViewController.m b/XCDYouTubeKit/XCDYouTubeVideoPlayerViewController.m index ebec6c3c..54a77fe8 100644 --- a/XCDYouTubeKit/XCDYouTubeVideoPlayerViewController.m +++ b/XCDYouTubeKit/XCDYouTubeVideoPlayerViewController.m @@ -8,6 +8,8 @@ #import +#if TARGET_OS_IOS + #pragma clang diagnostic ignored "-Wdeprecated-declarations" NSString *const XCDMoviePlayerPlaybackDidFinishErrorUserInfoKey = @"error"; // documented in -[MPMoviePlayerController initWithContentURL:] @@ -207,3 +209,4 @@ - (void) viewWillDisappear:(BOOL)animated } @end +#endif