diff --git a/example/ios/Flutter/AppFrameworkInfo.plist b/example/ios/Flutter/AppFrameworkInfo.plist index 6b4c0f7..25fb7fb 100644 --- a/example/ios/Flutter/AppFrameworkInfo.plist +++ b/example/ios/Flutter/AppFrameworkInfo.plist @@ -2,25 +2,25 @@ - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - App - CFBundleIdentifier - io.flutter.flutter.app - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - App - CFBundlePackageType - FMWK - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - 1.0 - MinimumOSVersion - 8.0 + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 9.0 diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index fcb0f94..7894ba8 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -2,11 +2,23 @@ PODS: - Flutter (1.0.0) - flutter_cast_framework (0.0.1): - Flutter + - google-cast-sdk-no-bluetooth (~> 4.4.4) + - google-cast-sdk-no-bluetooth (4.4.4): + - google-cast-sdk-no-bluetooth/Core (= 4.4.4) + - Protobuf (~> 3.0) + - google-cast-sdk-no-bluetooth/Core (4.4.4): + - Protobuf (~> 3.0) + - Protobuf (3.9.0) DEPENDENCIES: - Flutter (from `.symlinks/flutter/ios`) - flutter_cast_framework (from `.symlinks/plugins/flutter_cast_framework/ios`) +SPEC REPOS: + https://github.com/cocoapods/specs.git: + - google-cast-sdk-no-bluetooth + - Protobuf + EXTERNAL SOURCES: Flutter: :path: ".symlinks/flutter/ios" @@ -15,7 +27,9 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: Flutter: 0e3d915762c693b495b44d77113d4970485de6ec - flutter_cast_framework: 949a52df62065109b8e46f32c14230e095963af1 + flutter_cast_framework: 2728e840a40f44fb3cbcedbcd2c8d3f4efd53839 + google-cast-sdk-no-bluetooth: e0af19280673fba052f7fc3ddde6116c733ce505 + Protobuf: 1097ca58584c8d9be81bfbf2c5ff5975648dd87a PODFILE CHECKSUM: b6a0a141693093b304368d08511b46cf3d1d0ac5 diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj index 952a3a9..6dc1901 100644 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -19,6 +19,7 @@ 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; + 9B17E22623782F2C00BEFC07 /* ExternalAccessory.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9B17E22523782F2C00BEFC07 /* ExternalAccessory.framework */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -54,6 +55,8 @@ 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 9B17E22423782F2C00BEFC07 /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = ""; }; + 9B17E22523782F2C00BEFC07 /* ExternalAccessory.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ExternalAccessory.framework; path = System/Library/Frameworks/ExternalAccessory.framework; sourceTree = SDKROOT; }; 9DB98B1012103C7DDE22DE7D /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; DD9A724C61B1334DC791A10B /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ @@ -65,6 +68,7 @@ files = ( 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */, 3B80C3941E831B6300D905FE /* App.framework in Frameworks */, + 9B17E22623782F2C00BEFC07 /* ExternalAccessory.framework in Frameworks */, 67C5DD8CFC4D28C033AC72C9 /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -85,6 +89,7 @@ 691BB78022BE574F32D5AC40 /* Frameworks */ = { isa = PBXGroup; children = ( + 9B17E22523782F2C00BEFC07 /* ExternalAccessory.framework */, 9DB98B1012103C7DDE22DE7D /* Pods_Runner.framework */, ); name = Frameworks; @@ -125,6 +130,7 @@ 97C146F01CF9000F007C117D /* Runner */ = { isa = PBXGroup; children = ( + 9B17E22423782F2C00BEFC07 /* Runner.entitlements */, 97C146FA1CF9000F007C117D /* Main.storyboard */, 97C146FD1CF9000F007C117D /* Assets.xcassets */, 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, @@ -160,6 +166,7 @@ 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, D442A0785939ED7C311A5340 /* [CP] Embed Pods Frameworks */, + F8453FE49677B54947F70C12 /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -285,6 +292,21 @@ shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; + F8453FE49677B54947F70C12 /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Copy Pods Resources"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -374,6 +396,7 @@ baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = D9PN69G5DB; ENABLE_BITCODE = NO; @@ -382,12 +405,13 @@ "$(PROJECT_DIR)/Flutter", ); INFOPLIST_FILE = Runner/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LIBRARY_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Flutter", ); - PRODUCT_BUNDLE_IDENTIFIER = com.gianlucaparadise.flutterCastFrameworkEx; + PRODUCT_BUNDLE_IDENTIFIER = com.gianlucaparadise.FlutterCastFrameworkExam; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 4.0; @@ -508,6 +532,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = D9PN69G5DB; ENABLE_BITCODE = NO; @@ -516,12 +541,13 @@ "$(PROJECT_DIR)/Flutter", ); INFOPLIST_FILE = Runner/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LIBRARY_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Flutter", ); - PRODUCT_BUNDLE_IDENTIFIER = com.gianlucaparadise.flutterCastFrameworkEx; + PRODUCT_BUNDLE_IDENTIFIER = com.gianlucaparadise.FlutterCastFrameworkExam; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; @@ -537,6 +563,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = D9PN69G5DB; ENABLE_BITCODE = NO; @@ -545,12 +572,13 @@ "$(PROJECT_DIR)/Flutter", ); INFOPLIST_FILE = Runner/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LIBRARY_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Flutter", ); - PRODUCT_BUNDLE_IDENTIFIER = com.gianlucaparadise.flutterCastFrameworkEx; + PRODUCT_BUNDLE_IDENTIFIER = com.gianlucaparadise.FlutterCastFrameworkExam; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_SWIFT3_OBJC_INFERENCE = On; diff --git a/example/ios/Runner/AppDelegate.swift b/example/ios/Runner/AppDelegate.swift index 71cc41e..11e78fb 100644 --- a/example/ios/Runner/AppDelegate.swift +++ b/example/ios/Runner/AppDelegate.swift @@ -1,13 +1,35 @@ import UIKit import Flutter +import GoogleCast @UIApplicationMain -@objc class AppDelegate: FlutterAppDelegate { - override func application( - _ application: UIApplication, - didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]? - ) -> Bool { - GeneratedPluginRegistrant.register(with: self) - return super.application(application, didFinishLaunchingWithOptions: launchOptions) - } +@objc class AppDelegate: FlutterAppDelegate, GCKLoggerDelegate { + let kReceiverAppID = kGCKDefaultMediaReceiverApplicationID + let kDebugLoggingEnabled = true + + override func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]? + ) -> Bool { + let criteria = GCKDiscoveryCriteria(applicationID: kReceiverAppID) + let options = GCKCastOptions(discoveryCriteria: criteria) + GCKCastContext.setSharedInstanceWith(options) + + // Enable logger. + GCKLogger.sharedInstance().delegate = self + + GeneratedPluginRegistrant.register(with: self) + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } + + // MARK: - GCKLoggerDelegate + + func logMessage(_ message: String, + at level: GCKLoggerLevel, + fromFunction function: String, + location: String) { + if (kDebugLoggingEnabled) { + print(function + " - " + message) + } + } } diff --git a/example/ios/Runner/Runner.entitlements b/example/ios/Runner/Runner.entitlements new file mode 100644 index 0000000..0c67376 --- /dev/null +++ b/example/ios/Runner/Runner.entitlements @@ -0,0 +1,5 @@ + + + + + diff --git a/flutter_cast_framework.iml b/flutter_cast_framework.iml index 73e7ebd..b93b778 100644 --- a/flutter_cast_framework.iml +++ b/flutter_cast_framework.iml @@ -11,6 +11,9 @@ + + + diff --git a/ios/Classes/MethodNames.swift b/ios/Classes/MethodNames.swift new file mode 100644 index 0000000..7602140 --- /dev/null +++ b/ios/Classes/MethodNames.swift @@ -0,0 +1,13 @@ +// +// MethodNames.swift +// flutter_cast_framework +// +// Created by Gianluca Paradiso on 09/11/2019. +// + +import Foundation + +enum MethodNames : String { + case onCastStateChanged = "CastContext.onCastStateChanged" + case showCastDialog = "showCastDialog" +} diff --git a/ios/Classes/SwiftFlutterCastFrameworkPlugin.swift b/ios/Classes/SwiftFlutterCastFrameworkPlugin.swift index fc0835f..f1aa4fb 100644 --- a/ios/Classes/SwiftFlutterCastFrameworkPlugin.swift +++ b/ios/Classes/SwiftFlutterCastFrameworkPlugin.swift @@ -1,14 +1,42 @@ import Flutter import UIKit +import GoogleCast public class SwiftFlutterCastFrameworkPlugin: NSObject, FlutterPlugin { - public static func register(with registrar: FlutterPluginRegistrar) { - let channel = FlutterMethodChannel(name: "flutter_cast_framework", binaryMessenger: registrar.messenger()) - let instance = SwiftFlutterCastFrameworkPlugin() - registrar.addMethodCallDelegate(instance, channel: channel) - } - - public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { - result("iOS " + UIDevice.current.systemVersion) - } + public static func register(with registrar: FlutterPluginRegistrar) { + let channel = FlutterMethodChannel(name: "flutter_cast_framework", binaryMessenger: registrar.messenger()) + let instance = SwiftFlutterCastFrameworkPlugin(channel: channel) + registrar.addMethodCallDelegate(instance, channel: channel) + } + + let castContext: GCKCastContext + var stateObserver: NSKeyValueObservation? + var channel: FlutterMethodChannel + + init(channel: FlutterMethodChannel) { + self.channel = channel + self.castContext = GCKCastContext.sharedInstance() + self.stateObserver = GCKCastContext.sharedInstance().observe(\.castState, options: [.new, .old, .initial]){ (state, change) in + let castStateRaw = GCKCastContext.sharedInstance().castState.rawValue + // Android CastStates are 1-to-4, while iOS CastStates are 0-to-3. I align iOS to Android by adding 1 + let castStateRawAdjusted = castStateRaw + 1 + print("cast state change to: \(castStateRawAdjusted)") + channel.invokeMethod(MethodNames.onCastStateChanged.rawValue, arguments: castStateRawAdjusted) + } + super.init() + } + + public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { + switch call.method { + case MethodNames.showCastDialog.rawValue: + castContext.presentCastDialog() + default: + print("Method [\(call.method)] is not implemented.") + } + } + + deinit { + stateObserver?.invalidate() + stateObserver = nil + } } diff --git a/ios/flutter_cast_framework.podspec b/ios/flutter_cast_framework.podspec index 6ace8da..4c162f5 100644 --- a/ios/flutter_cast_framework.podspec +++ b/ios/flutter_cast_framework.podspec @@ -14,8 +14,11 @@ A new flutter plugin project. s.source = { :path => '.' } s.source_files = 'Classes/**/*' s.public_header_files = 'Classes/**/*.h' - s.dependency 'Flutter' + s.static_framework = true - s.ios.deployment_target = '8.0' + s.dependency 'Flutter' + s.dependency 'google-cast-sdk-no-bluetooth', '~> 4.4.4' + + s.ios.deployment_target = '9.0' end