diff --git a/README.md b/README.md index 157dfd57..df1cb1be 100755 --- a/README.md +++ b/README.md @@ -5,6 +5,19 @@ A VLC-powered alternative to Flutter's video_player that supports iOS and Androi ## Installation +### Version 3.0 Upgrade For Existing Apps +For migration to version 3, the project is based in swift. Your existing project will need to migratate + + Delete existing ios folder from root of flutter project. + Run this command flutter create -i swift . + +This command will create only ios directory with swift support. See https://stackoverflow.com/questions/52244346/how-to-enable-swift-support-for-existing-project-in-flutter + +Change your project to use 9.0 +# Uncomment this line to define a global platform for your project + platform :ios, '9.0' + + ### iOS For iOS, you need to opt into the Flutter embedded views preview. This is done by adding the following to your project's `/ios/Runner/Info.plist` file (see example for details): diff --git a/example/ios/.gitignore b/example/ios/.gitignore new file mode 100755 index 00000000..e96ef602 --- /dev/null +++ b/example/ios/.gitignore @@ -0,0 +1,32 @@ +*.mode1v3 +*.mode2v3 +*.moved-aside +*.pbxuser +*.perspectivev3 +**/*sync/ +.sconsign.dblite +.tags* +**/.vagrant/ +**/DerivedData/ +Icon? +**/Pods/ +**/.symlinks/ +profile +xcuserdata +**/.generated/ +Flutter/App.framework +Flutter/Flutter.framework +Flutter/Flutter.podspec +Flutter/Generated.xcconfig +Flutter/app.flx +Flutter/app.zip +Flutter/flutter_assets/ +Flutter/flutter_export_environment.sh +ServiceDefinitions.json +Runner/GeneratedPluginRegistrant.* + +# Exceptions to above rules. +!default.mode1v3 +!default.mode2v3 +!default.pbxuser +!default.perspectivev3 diff --git a/example/ios/Flutter/.last_build_id b/example/ios/Flutter/.last_build_id new file mode 100755 index 00000000..69faea91 --- /dev/null +++ b/example/ios/Flutter/.last_build_id @@ -0,0 +1 @@ +9a6723ad18e3f950fccdc81adda11616 \ No newline at end of file diff --git a/example/ios/Flutter/AppFrameworkInfo.plist b/example/ios/Flutter/AppFrameworkInfo.plist index 9367d483..6b4c0f78 100755 --- a/example/ios/Flutter/AppFrameworkInfo.plist +++ b/example/ios/Flutter/AppFrameworkInfo.plist @@ -3,7 +3,7 @@ CFBundleDevelopmentRegion - en + $(DEVELOPMENT_LANGUAGE) CFBundleExecutable App CFBundleIdentifier diff --git a/example/ios/Podfile b/example/ios/Podfile index 60671892..d5a6946a 100755 --- a/example/ios/Podfile +++ b/example/ios/Podfile @@ -33,6 +33,9 @@ def parse_KV_file(file, separator='=') end target 'Runner' do + use_frameworks! + use_modular_headers! + # Flutter Pod copied_flutter_dir = File.join(__dir__, 'Flutter') @@ -75,9 +78,6 @@ target 'Runner' do end end -# Prevent Cocoapods from embedding a second Flutter framework and causing an error with the new Xcode build system. -install! 'cocoapods', :disable_input_output_paths => true - post_install do |installer| installer.pods_project.targets.each do |target| target.build_configurations.each do |config| diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj index bfd80962..9fcbe26b 100755 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -3,19 +3,17 @@ archiveVersion = 1; classes = { }; - objectVersion = 46; + objectVersion = 50; objects = { /* Begin PBXBuildFile section */ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; - 26DF11FAA5F98736591E80F5 /* libPods-Runner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = AF4F429098B10D1DBF010B1F /* libPods-Runner.a */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; - 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB21CF90195004384FC /* Debug.xcconfig */; }; - 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; }; - 97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; }; + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; 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 */; }; + A9D86FB4F06E287FB4AE25E0 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 94D12D7C13D4A2D32D6FA4C6 /* Pods_Runner.framework */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -32,24 +30,23 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - 042307F67E34FF5CF33CC5CB /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 1F4C2009653F3AEF1D8DAB60 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; - 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; - 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; + 94D12D7C13D4A2D32D6FA4C6 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 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 = ""; }; - 99D00B394711D92C026EF5DA /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; - AF4F429098B10D1DBF010B1F /* libPods-Runner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Runner.a"; sourceTree = BUILT_PRODUCTS_DIR; }; - B8ECB9264574DFB838FC003F /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; + C68CB3143740C2FFA027C642 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + F18E8FBD8B753ECD2497A53F /* 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 */ /* Begin PBXFrameworksBuildPhase section */ @@ -57,29 +54,29 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 26DF11FAA5F98736591E80F5 /* libPods-Runner.a in Frameworks */, + A9D86FB4F06E287FB4AE25E0 /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 501AA65262973F1C41FAA211 /* Frameworks */ = { + 1A1059993B77FC304540F3D1 /* Pods */ = { isa = PBXGroup; children = ( - AF4F429098B10D1DBF010B1F /* libPods-Runner.a */, + 1F4C2009653F3AEF1D8DAB60 /* Pods-Runner.debug.xcconfig */, + C68CB3143740C2FFA027C642 /* Pods-Runner.release.xcconfig */, + F18E8FBD8B753ECD2497A53F /* Pods-Runner.profile.xcconfig */, ); - name = Frameworks; + path = Pods; sourceTree = ""; }; - 963DC04707CD559927B17E72 /* Pods */ = { + 68EAB08213E9FF633B32D632 /* Frameworks */ = { isa = PBXGroup; children = ( - 99D00B394711D92C026EF5DA /* Pods-Runner.debug.xcconfig */, - 042307F67E34FF5CF33CC5CB /* Pods-Runner.release.xcconfig */, - B8ECB9264574DFB838FC003F /* Pods-Runner.profile.xcconfig */, + 94D12D7C13D4A2D32D6FA4C6 /* Pods_Runner.framework */, ); - name = Pods; + name = Frameworks; sourceTree = ""; }; 9740EEB11CF90186004384FC /* Flutter */ = { @@ -99,8 +96,8 @@ 9740EEB11CF90186004384FC /* Flutter */, 97C146F01CF9000F007C117D /* Runner */, 97C146EF1CF9000F007C117D /* Products */, - 963DC04707CD559927B17E72 /* Pods */, - 501AA65262973F1C41FAA211 /* Frameworks */, + 1A1059993B77FC304540F3D1 /* Pods */, + 68EAB08213E9FF633B32D632 /* Frameworks */, ); sourceTree = ""; }; @@ -115,8 +112,6 @@ 97C146F01CF9000F007C117D /* Runner */ = { isa = PBXGroup; children = ( - 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */, - 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */, 97C146FA1CF9000F007C117D /* Main.storyboard */, 97C146FD1CF9000F007C117D /* Assets.xcassets */, 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, @@ -124,6 +119,8 @@ 97C146F11CF9000F007C117D /* Supporting Files */, 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, ); path = Runner; sourceTree = ""; @@ -131,7 +128,6 @@ 97C146F11CF9000F007C117D /* Supporting Files */ = { isa = PBXGroup; children = ( - 97C146F21CF9000F007C117D /* main.m */, ); name = "Supporting Files"; sourceTree = ""; @@ -143,14 +139,14 @@ isa = PBXNativeTarget; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( - A962281F56E29E81F7ADEA7F /* [CP] Check Pods Manifest.lock */, + C38A7EC27FA01A9FA4D4D0C2 /* [CP] Check Pods Manifest.lock */, 9740EEB61CF901F6004384FC /* Run Script */, 97C146EA1CF9000F007C117D /* Sources */, 97C146EB1CF9000F007C117D /* Frameworks */, 97C146EC1CF9000F007C117D /* Resources */, 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, - 01A7FC6AAF62780F10F207C4 /* [CP] Embed Pods Frameworks */, + 6C16DDC0666AA59926B93E59 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -167,22 +163,20 @@ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0910; - ORGANIZATIONNAME = "The Chromium Authors"; + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; TargetAttributes = { 97C146ED1CF9000F007C117D = { CreatedOnToolsVersion = 7.3.1; - DevelopmentTeam = 876SUF433Q; - ProvisioningStyle = Automatic; + LastSwiftMigration = 1100; }; }; }; buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( - English, en, Base, ); @@ -203,7 +197,6 @@ files = ( 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, - 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */, 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, ); @@ -212,34 +205,36 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ - 01A7FC6AAF62780F10F207C4 /* [CP] Embed Pods Frameworks */ = { + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); - name = "[CP] Embed Pods Frameworks"; + name = "Thin Binary"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; - showEnvVarsInLog = 0; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; }; - 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + 6C16DDC0666AA59926B93E59 /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); - inputPaths = ( + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); - name = "Thin Binary"; - outputPaths = ( + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed\n/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin\n"; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; }; 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; @@ -255,7 +250,7 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; }; - A962281F56E29E81F7ADEA7F /* [CP] Check Pods Manifest.lock */ = { + C38A7EC27FA01A9FA4D4D0C2 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -284,8 +279,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */, - 97C146F31CF9000F007C117D /* main.m in Sources */, + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -314,7 +308,6 @@ /* Begin XCBuildConfiguration section */ 249021D3217E4FDB00AE95B9 /* Profile */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; @@ -326,12 +319,14 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; @@ -352,9 +347,10 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; @@ -365,67 +361,33 @@ baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Automatic; + CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - DEVELOPMENT_TEAM = 876SUF433Q; + DEVELOPMENT_TEAM = FVU6RGL532; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Flutter", ); INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( + LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)/Flutter", + "@executable_path/Frameworks", ); - OTHER_LDFLAGS = ( + LIBRARY_SEARCH_PATHS = ( "$(inherited)", - "-ObjC", - "-l\"bz2\"", - "-l\"c++\"", - "-l\"flutter_vlc_player\"", - "-l\"iconv\"", - "-l\"xml2\"", - "-l\"z\"", - "-framework", - "\"AVFoundation\"", - "-framework", - "\"AudioToolbox\"", - "-framework", - "\"CFNetwork\"", - "-framework", - "\"CoreGraphics\"", - "-framework", - "\"CoreMedia\"", - "-framework", - "\"CoreText\"", - "-framework", - "\"Flutter\"", - "-framework", - "\"MobileVLCKit\"", - "-framework", - "\"OpenGLES\"", - "-framework", - "\"QuartzCore\"", - "-framework", - "\"Security\"", - "-framework", - "\"VideoToolbox\"", - "-framework", - Flutter, + "$(PROJECT_DIR)/Flutter", ); PRODUCT_BUNDLE_IDENTIFIER = com.flutterVlcPlayer.flutterVlcPlayerExample; PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; }; name = Profile; }; 97C147031CF9000F007C117D /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; @@ -437,12 +399,14 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; @@ -469,7 +433,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -479,7 +443,6 @@ }; 97C147041CF9000F007C117D /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; @@ -491,12 +454,14 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; @@ -517,9 +482,12 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; @@ -530,94 +498,28 @@ baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Automatic; + CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - DEVELOPMENT_TEAM = 876SUF433Q; + DEVELOPMENT_TEAM = FVU6RGL532; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Flutter", ); INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - OTHER_LDFLAGS = ( + LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", - "-ObjC", - "-l\"bz2\"", - "-l\"c++\"", - "-l\"flutter_vlc_player\"", - "-l\"iconv\"", - "-l\"xml2\"", - "-l\"z\"", - "-framework", - "\"AVFoundation\"", - "-framework", - "\"AudioToolbox\"", - "-framework", - "\"CFNetwork\"", - "-framework", - "\"CoreGraphics\"", - "-framework", - "\"CoreMedia\"", - "-framework", - "\"CoreText\"", - "-framework", - "\"Flutter\"", - "-framework", - "\"MobileVLCKit\"", - "-framework", - "\"OpenGLES\"", - "-framework", - "\"QuartzCore\"", - "-framework", - "\"Security\"", - "-framework", - "\"VideoToolbox\"", - "-framework", - Flutter, + "@executable_path/Frameworks", ); - "OTHER_LDFLAGS[arch=*]" = ( + LIBRARY_SEARCH_PATHS = ( "$(inherited)", - "-ObjC", - "-l\"bz2\"", - "-l\"c++\"", - "-l\"flutter_vlc_player\"", - "-l\"iconv\"", - "-l\"xml2\"", - "-l\"z\"", - "-framework", - "\"AVFoundation\"", - "-framework", - "\"AudioToolbox\"", - "-framework", - "\"CFNetwork\"", - "-framework", - "\"CoreGraphics\"", - "-framework", - "\"CoreMedia\"", - "-framework", - "\"CoreText\"", - "-framework", - "\"Flutter\"", - "-framework", - "\"MobileVLCKit\"", - "-framework", - "\"OpenGLES\"", - "-framework", - "\"QuartzCore\"", - "-framework", - "\"Security\"", - "-framework", - "\"VideoToolbox\"", + "$(PROJECT_DIR)/Flutter", ); PRODUCT_BUNDLE_IDENTIFIER = com.flutterVlcPlayer.flutterVlcPlayerExample; PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; }; name = Debug; @@ -627,60 +529,27 @@ baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Automatic; + CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - DEVELOPMENT_TEAM = 876SUF433Q; + DEVELOPMENT_TEAM = FVU6RGL532; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Flutter", ); INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( + LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)/Flutter", + "@executable_path/Frameworks", ); - OTHER_LDFLAGS = ( + LIBRARY_SEARCH_PATHS = ( "$(inherited)", - "-ObjC", - "-l\"bz2\"", - "-l\"c++\"", - "-l\"flutter_vlc_player\"", - "-l\"iconv\"", - "-l\"xml2\"", - "-l\"z\"", - "-framework", - "\"AVFoundation\"", - "-framework", - "\"AudioToolbox\"", - "-framework", - "\"CFNetwork\"", - "-framework", - "\"CoreGraphics\"", - "-framework", - "\"CoreMedia\"", - "-framework", - "\"CoreText\"", - "-framework", - "\"Flutter\"", - "-framework", - "\"MobileVLCKit\"", - "-framework", - "\"OpenGLES\"", - "-framework", - "\"QuartzCore\"", - "-framework", - "\"Security\"", - "-framework", - "\"VideoToolbox\"", - "-framework", - Flutter, + "$(PROJECT_DIR)/Flutter", ); PRODUCT_BUNDLE_IDENTIFIER = com.flutterVlcPlayer.flutterVlcPlayerExample; PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; }; name = Release; diff --git a/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100755 index 00000000..f9b0d7c5 --- /dev/null +++ b/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index ad6250a1..a28140cf 100755 --- a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ + + - - + + + + - BuildSystemType - Latest PreviewsEnabled diff --git a/example/ios/Runner/AppDelegate.h b/example/ios/Runner/AppDelegate.h deleted file mode 100755 index 36e21bbf..00000000 --- a/example/ios/Runner/AppDelegate.h +++ /dev/null @@ -1,6 +0,0 @@ -#import -#import - -@interface AppDelegate : FlutterAppDelegate - -@end diff --git a/example/ios/Runner/AppDelegate.m b/example/ios/Runner/AppDelegate.m deleted file mode 100755 index 59a72e90..00000000 --- a/example/ios/Runner/AppDelegate.m +++ /dev/null @@ -1,13 +0,0 @@ -#include "AppDelegate.h" -#include "GeneratedPluginRegistrant.h" - -@implementation AppDelegate - -- (BOOL)application:(UIApplication *)application - didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { - [GeneratedPluginRegistrant registerWithRegistry:self]; - // Override point for customization after application launch. - return [super application:application didFinishLaunchingWithOptions:launchOptions]; -} - -@end diff --git a/example/ios/Runner/AppDelegate.swift b/example/ios/Runner/AppDelegate.swift new file mode 100755 index 00000000..70693e4a --- /dev/null +++ b/example/ios/Runner/AppDelegate.swift @@ -0,0 +1,13 @@ +import UIKit +import Flutter + +@UIApplicationMain +@objc class AppDelegate: FlutterAppDelegate { + override func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) -> Bool { + GeneratedPluginRegistrant.register(with: self) + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } +} diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png index 3d43d11e..dc9ada47 100755 Binary files a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png and b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png differ diff --git a/example/ios/Runner/Info.plist b/example/ios/Runner/Info.plist index 3a038b1c..53b9930a 100755 --- a/example/ios/Runner/Info.plist +++ b/example/ios/Runner/Info.plist @@ -3,7 +3,7 @@ CFBundleDevelopmentRegion - en + $(DEVELOPMENT_LANGUAGE) CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier @@ -26,6 +26,13 @@ LaunchScreen UIMainStoryboardFile Main + io.flutter.embedded_views_preview + + NSAppTransportSecurity + + NSAllowsArbitraryLoads + + UISupportedInterfaceOrientations UIInterfaceOrientationPortrait @@ -41,7 +48,5 @@ UIViewControllerBasedStatusBarAppearance - io.flutter.embedded_views_preview - diff --git a/example/ios/Runner/Runner-Bridging-Header.h b/example/ios/Runner/Runner-Bridging-Header.h new file mode 100755 index 00000000..308a2a56 --- /dev/null +++ b/example/ios/Runner/Runner-Bridging-Header.h @@ -0,0 +1 @@ +#import "GeneratedPluginRegistrant.h" diff --git a/example/ios/Runner/main.m b/example/ios/Runner/main.m deleted file mode 100755 index dff6597e..00000000 --- a/example/ios/Runner/main.m +++ /dev/null @@ -1,9 +0,0 @@ -#import -#import -#import "AppDelegate.h" - -int main(int argc, char* argv[]) { - @autoreleasepool { - return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); - } -} diff --git a/example/lib/main.dart b/example/lib/main.dart index e118ee6a..208f588c 100755 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -27,6 +27,7 @@ class MyAppScaffoldState extends State { VlcPlayerController _videoViewController; VlcPlayerController _videoViewController2; + bool isPlaying = true; @override void initState() { @@ -93,6 +94,12 @@ class MyAppScaffoldState extends State { ), ), ), + FlatButton( + child: isPlaying ? Icon(Icons.pause) : Icon(Icons.play_arrow) , + onPressed: () => { + playOrPauseVideo() + } + ), FlatButton( child: Text("Change URL"), onPressed: () => _videoViewController.setStreamUrl( @@ -126,6 +133,23 @@ class MyAppScaffoldState extends State { ); } + void playOrPauseVideo() { + String state = _videoViewController.playingState.toString(); + + if ( state == "PlayingState.PLAYING" ){ + _videoViewController.pause(); + setState(() { + isPlaying = false; + }); + } else { + _videoViewController.play(); + setState(() { + isPlaying = true; + }); + } + + } + void _createCameraImage() async { Uint8List file = await _videoViewController.takeSnapshot(); setState(() { diff --git a/example/test/widget_test.dart b/example/test/widget_test.dart new file mode 100755 index 00000000..38179b65 --- /dev/null +++ b/example/test/widget_test.dart @@ -0,0 +1,27 @@ +// This is a basic Flutter widget test. +// +// To perform an interaction with a widget in your test, use the WidgetTester +// utility that Flutter provides. For example, you can send tap and scroll +// gestures. You can also use WidgetTester to find child widgets in the widget +// tree, read text, and verify that the values of widget properties are correct. + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'package:flutter_vlc_player_example/main.dart'; + +void main() { + testWidgets('Verify Platform version', (WidgetTester tester) async { + // Build our app and trigger a frame. + await tester.pumpWidget(MyApp()); + + // Verify that platform version is retrieved. + expect( + find.byWidgetPredicate( + (Widget widget) => widget is Text && + widget.data.startsWith('Running on:'), + ), + findsOneWidget, + ); + }); +} diff --git a/ios/.gitignore b/ios/.gitignore index 710ec6cf..aa479fd3 100755 --- a/ios/.gitignore +++ b/ios/.gitignore @@ -34,3 +34,4 @@ Icon? .tags* /Flutter/Generated.xcconfig +/Flutter/flutter_export_environment.sh \ No newline at end of file diff --git a/ios/Classes/FlutterVlcPlayerPlugin.h b/ios/Classes/FlutterVlcPlayerPlugin.h index 04381f02..78d798df 100755 --- a/ios/Classes/FlutterVlcPlayerPlugin.h +++ b/ios/Classes/FlutterVlcPlayerPlugin.h @@ -1,34 +1,4 @@ #import -#import @interface FlutterVlcPlayerPlugin : NSObject @end - -@interface FLTPlayerView : NSObject - -/// View to show video over -@property (nonatomic, strong) UIView *hostedView; -/// Player showing video -@property (nonatomic, strong) VLCMediaPlayer *player; -/// result to comunicate back to Flutter -@property (nonatomic) FlutterResult result; -/// Set to indicate that aspect has been set which is only needed once. -@property (nonatomic, assign) BOOL aspectSet; - - -/// Initialize a new instance with the channel -/// @param methodChannel Method channel for communication from flutter -/// @param eventChannel Event channel for communication back to flutter -+ (instancetype)initWithChannels: (FlutterMethodChannel*) methodChannel andEventChannel:(FlutterEventChannel*) eventChannel; - -@end - -@interface FLTPlayerViewFactory : NSObject -+ (instancetype)initWithRegistrar : (NSObject*)registrar; -@end - -@interface FLTPlayerEventStreamHandler : NSObject - -@property (nonatomic) FlutterEventSink eventSink; - -@end \ No newline at end of file diff --git a/ios/Classes/FlutterVlcPlayerPlugin.m b/ios/Classes/FlutterVlcPlayerPlugin.m index 7d120c32..63ec0a27 100755 --- a/ios/Classes/FlutterVlcPlayerPlugin.m +++ b/ios/Classes/FlutterVlcPlayerPlugin.m @@ -1,292 +1,15 @@ -// -// FlutterVlcPlayerPlugin.m -// flutter_vlc_player -// - #import "FlutterVlcPlayerPlugin.h" -#import "VLCMediaPlayer.h" - -@implementation FLTPlayerView - -NSObject *_messenger; - -+ (instancetype)initWithChannels: (FlutterMethodChannel*) methodChannel andEventChannel:(FlutterEventChannel*) eventChannel { - - // Initialize hostedView and set relevant parameters. - FLTPlayerView *instance = [[super alloc] init]; - UIView *hostedView = [[UIView alloc] init]; - hostedView.contentMode = UIViewContentModeScaleAspectFit; - hostedView.backgroundColor = [UIColor blackColor]; - hostedView.clipsToBounds = YES; - hostedView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth; - instance.hostedView = hostedView; - - // Create event channel handler. - FLTPlayerEventStreamHandler* eventChannelHandler = [[FLTPlayerEventStreamHandler alloc] init]; - [eventChannel setStreamHandler:eventChannelHandler]; - - // Set method channel handler. - [methodChannel setMethodCallHandler:^(FlutterMethodCall * _Nonnull call, FlutterResult _Nonnull result) { - - instance.result = result; - - if([call.method isEqualToString:@"initialize"]) { - - NSString *url = call.arguments[@"url"]; - - VLCMediaPlayer *player = [[VLCMediaPlayer alloc] init]; - player.delegate = eventChannelHandler; - - instance.player = player; - - VLCMedia *media = [VLCMedia mediaWithURL:[NSURL URLWithString:url]]; - player.media = media; - player.position = 0.5; - player.drawable = instance.hostedView; - [player addObserver:instance forKeyPath:@"state" options:NSKeyValueObservingOptionNew context:nil]; - - result(nil); - return; - - } else if ([call.method isEqualToString:@"dispose"]) { - - [instance.player stop]; - return; - - } else if ([call.method isEqualToString:@"changeURL"]) { - - if(instance.player == nil) { - result([FlutterError errorWithCode:@"VLC_NOT_INITIALIZED" - message:@"The player has not yet been initialized." - details:nil]); - - return; - } - - [instance.player stop]; - - NSString *url = call.arguments[@"url"]; - VLCMedia *media = [VLCMedia mediaWithURL:[NSURL URLWithString:url]]; - instance.player.media = media; - - result(nil); - return; - - } else if ([call.method isEqualToString:@"getSnapshot"]) { - - UIView *drawable = instance.player.drawable; - CGSize size = drawable.frame.size; - - UIGraphicsBeginImageContextWithOptions(size, false, 0.0); - - CGRect rec = drawable.frame; - [drawable drawViewHierarchyInRect:rec afterScreenUpdates:false]; - - UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); - UIGraphicsEndImageContext(); - - NSString *byteArray = [UIImagePNGRepresentation(image) base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength]; - result(@{@"snapshot" : byteArray}); - - } else if ([call.method isEqualToString:@"setPlaybackState"]) { - - NSString *playbackState = call.arguments[@"playbackState"]; - - if([playbackState isEqualToString:@"play"]) { - [instance.player play]; - } else if ([playbackState isEqualToString:@"pause"]) { - [instance.player pause]; - } else if ([playbackState isEqualToString:@"stop"]) { - [instance.player stop]; - } - - result(nil); - return; - - } else if ([call.method isEqualToString:@"setPlaybackSpeed"]) { - - NSNumber *playbackSpeed = call.arguments[@"speed"]; - float rate = playbackSpeed.floatValue; - instance.player.rate = rate; - - result(nil); - return; - - } else if ([call.method isEqualToString:@"setTime"]) { - - VLCTime *time = [VLCTime timeWithNumber:call.arguments[@"time"]]; - instance.player.time = time; - - result(nil); - return; - - } - - }]; - - return instance; - -} - -- (nonnull UIView *)view { - return self.hostedView; -} - --(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{ - - // Player won't play if this aspect does't get set in response to the KV changing. - - if (self.aspectSet) return; - if (!self.player.isPlaying) return; - - [_player setDrawable:_hostedView]; - [_player setVideoAspectRatio:"0.7"]; - [_player setCurrentVideoTrackIndex:0]; - [_player setScaleFactor:0.0]; - NSString *aspectStr = [NSString stringWithUTF8String:[_player videoAspectRatio]]; - self.result(@{@"aspectRatio" : aspectStr}); - self.aspectSet = YES; -} - - -@end - - -@implementation FLTPlayerViewFactory -NSObject *_registrar; - -+ (instancetype)initWithRegistrar : (NSObject*)registrar { - _registrar = registrar; - return [[super alloc] init]; -} - -- (nonnull NSObject *)createWithFrame:(CGRect)frame viewIdentifier:(int64_t)viewId arguments:(NSObject *)messenger { - // Create method channel. - NSString *_methodChannelName = [NSString stringWithFormat:@"%@_%@",@"flutter_video_plugin/getVideoView", [NSString stringWithFormat:@"%lld", viewId]]; - FlutterMethodChannel* methodChannel = [FlutterMethodChannel - methodChannelWithName:_methodChannelName - binaryMessenger:[_registrar messenger]]; - - // Create event channel. - NSString *_eventChannelName = [NSString stringWithFormat:@"%@_%@",@"flutter_video_plugin/getVideoEvents", [NSString stringWithFormat:@"%lld", viewId]]; - FlutterEventChannel* eventChannel = [FlutterEventChannel - eventChannelWithName:_eventChannelName - binaryMessenger:[_registrar messenger]]; - - return [FLTPlayerView initWithChannels:methodChannel andEventChannel:eventChannel]; -} - - -@end - +#if __has_include() +#import +#else +// Support project import fallback if the generated compatibility header +// is not copied when this plugin is created as a library. +// https://forums.swift.org/t/swift-static-libraries-dont-copy-generated-objective-c-header/19816 +#import "flutter_vlc_player-Swift.h" +#endif @implementation FlutterVlcPlayerPlugin - -+ (void)registerWithRegistrar:(nonnull NSObject *)registrar { - [registrar registerViewFactory: [FLTPlayerViewFactory initWithRegistrar: registrar] withId:@"flutter_video_plugin/getVideoView"]; ++ (void)registerWithRegistrar:(NSObject*)registrar { + [SwiftFlutterVlcPlayerPlugin registerWithRegistrar:registrar]; } - -@end - -@implementation FLTPlayerEventStreamHandler - -- (FlutterError*)onListenWithArguments:(id)arguments eventSink:(FlutterEventSink)eventSink { - _eventSink = eventSink; - return nil; -} - -- (FlutterError*)onCancelWithArguments:(id)arguments { - _eventSink = nil; - return nil; -} - -- (void)mediaPlayerStateChanged:(NSNotification *)aNotification { - - VLCMediaPlayer *player = aNotification.object; - VLCMedia *media = player.media; - - NSArray* tracks = media.tracksInformation; - NSDictionary* track; - - float ratio = 0.0; - NSNumber* height = @0; - NSNumber* width = @0; - - if(player.currentVideoTrackIndex != -1){ - track = tracks[player.currentVideoTrackIndex]; - - height = [track objectForKey:@"height"]; - width = [track objectForKey:@"width"]; - - if(height != nil && width != nil && height > 0) { - ratio = width.floatValue / height.floatValue; - } - } - - switch(player.state){ - case VLCMediaPlayerStateESAdded: - case VLCMediaPlayerStateBuffering: - case VLCMediaPlayerStateOpening: - return; - - case VLCMediaPlayerStatePlaying: - _eventSink(@{ - @"name": @"buffering", - @"value": @(NO) - }); - - _eventSink(@{ - @"name": @"playing", - @"value": @(YES), - @"ratio": @(ratio), - @"height": height, - @"width": width, - @"length": media.length.value ?: @0 - }); - return; - - case VLCMediaPlayerStateEnded: - _eventSink(@{ - @"name": @"ended" - }); - - _eventSink(@{ - @"name": @"playing", - @"value": @(NO), - @"reason": @"EndReached" - }); - return; - - case VLCMediaPlayerStateError: - NSLog(@"(flutter_vlc_plugin) A VLC error occurred."); - return; - - case VLCMediaPlayerStatePaused: - case VLCMediaPlayerStateStopped: - _eventSink(@{ - @"name": @"buffering", - @"value": @(NO) - }); - - _eventSink(@{ - @"name": @"playing", - @"value": @(NO) - }); - return; - } -} - -- (void)mediaPlayerTimeChanged:(NSNotification *)aNotification { - - VLCMediaPlayer *player = aNotification.object; - - _eventSink(@{ - @"name": @"timeChanged", - @"value": player.time.value, - @"speed": @(player.rate), - }); - - return; -} - @end diff --git a/ios/Classes/SwiftFlutterVlcPlayerPlugin.swift b/ios/Classes/SwiftFlutterVlcPlayerPlugin.swift new file mode 100755 index 00000000..b2a717ba --- /dev/null +++ b/ios/Classes/SwiftFlutterVlcPlayerPlugin.swift @@ -0,0 +1,303 @@ +import Flutter +import UIKit +import MobileVLCKit + +public class SwiftFlutterVlcPlayerPlugin: NSObject, FlutterPlugin { + + private var factory: VLCViewFactory + public init(with registrar: FlutterPluginRegistrar) { + self.factory = VLCViewFactory(withRegistrar: registrar) + registrar.register(factory, withId: "flutter_video_plugin/getVideoView") + } + + public static func register(with registrar: FlutterPluginRegistrar) { + registrar.addApplicationDelegate(SwiftFlutterVlcPlayerPlugin(with: registrar)) + } + +} + + +public class VLCView: NSObject, FlutterPlatformView { + + + @IBOutlet private var hostedView: UIView! + private var vlcMediaPlayer: VLCMediaPlayer! + private var registrar: FlutterPluginRegistrar + private var channel: FlutterMethodChannel + private var eventChannel: FlutterEventChannel + private var player: VLCMediaPlayer + private var eventChannelHandler: VLCPlayerEventStreamHandler + private var aspectSet = false + + + + public init(withFrame frame: CGRect, withRegistrar registrar: FlutterPluginRegistrar, withId id: Int64){ + self.registrar = registrar + self.hostedView = UIView() + self.player = VLCMediaPlayer() + self.channel = FlutterMethodChannel(name: "flutter_video_plugin/getVideoView_\(id)", binaryMessenger: registrar.messenger()) + self.eventChannel = FlutterEventChannel(name: "flutter_video_plugin/getVideoEvents_\(id)", binaryMessenger: registrar.messenger()) + self.eventChannelHandler = VLCPlayerEventStreamHandler() + + + } + + public func view() -> UIView { + channel.setMethodCallHandler({ + [weak self] (call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in + + guard let self = self else { return } + + if let arguments = call.arguments as? Dictionary + { + switch(FlutterMethodCallOption(rawValue: call.method)){ + case .initialize: + + guard let urlString = arguments["url"] as? String, let url = URL(string: urlString) else { + + result(FlutterError(code: "500", + message: "Url is need to initialization", + details: nil) + ) + return + } + + let media = VLCMedia(url: url) + + + self.player.media = media + self.player.position = 0.5 + self.player.drawable = self.hostedView + self.player.delegate = self.eventChannelHandler + + result(nil) + return + case .setPlaybackState: + let playbackState = arguments["playbackState"] as? String + + if (playbackState == "play") { + self.player.play() + } else if (playbackState == "pause") { + self.player.pause() + } else if (playbackState == "stop") { + self.player.stop() + } + + result(nil) + return + case .dispose: + self.player.stop() + return + case .changeURL: + self.player.stop() + + guard let urlString = arguments["url"] as? String, let url = URL(string: urlString) else { + + result(FlutterError(code: "500", + message: "Url is need to initialization", + details: nil) + ) + return + } + + let media = VLCMedia(url: url) + + self.player.media = media + result(nil) + return + + case .getSnapshot: + let drawable:UIView = self.player.drawable as! UIView + let size = drawable.frame.size + + UIGraphicsBeginImageContextWithOptions(size , _: false, _: 0.0) + + let rec = drawable.frame + drawable.drawHierarchy(in: rec , afterScreenUpdates: false) + + let image = UIGraphicsGetImageFromCurrentImageContext() + UIGraphicsEndImageContext() + + let byteArray = (image ?? UIImage()).pngData() + + result([ + "snapshot": byteArray + ]) + return + + case .setPlaybackSpeed: + + let playbackSpeed = arguments["speed"] as? String + let rate = (playbackSpeed! as NSString).floatValue + self.player.rate = rate + result(nil) + return + + case .setTime: + + let time = VLCTime(number: arguments["time"] as? NSNumber) + self.player.time = time + result(nil) + return + + default: + result(FlutterMethodNotImplemented) + return + } + } + + }) + + eventChannel.setStreamHandler(eventChannelHandler) + return hostedView + + } + + + +} + +class VLCPlayerEventStreamHandler:NSObject, FlutterStreamHandler, VLCMediaPlayerDelegate { + + private var eventSink: FlutterEventSink? + + + func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) -> FlutterError? { + self.eventSink = events + return nil + } + + func onCancel(withArguments arguments: Any?) -> FlutterError? { + eventSink = nil + return nil + } + + + func mediaPlayerStateChanged(_ aNotification: Notification?) { + + guard let eventSink = self.eventSink else { return } + + let player = aNotification?.object as? VLCMediaPlayer + let media = player?.media + let tracks: [Any] = media?.tracksInformation ?? [""] //[Any] + var track:NSDictionary + + var ratio = Float(0.0) + var height = 0 + var width = 0 + + if player?.currentVideoTrackIndex != -1 { + if (player?.currentVideoTrackIndex) != nil { + track = tracks[0] as! NSDictionary + height = (track["height"] as? Int ) ?? 0 + width = (track["width"] as? Int) ?? 0 + + if height != 0 && width != 0 { + ratio = Float(width / height) + } + + } + + } + + switch player?.state { + + case .esAdded, .buffering, .opening: + return + case .playing: + eventSink([ + "name": "buffering", + "value": NSNumber(value: false) + ]) + if let value = media?.length.value { + eventSink([ + "name": "playing", + "value": NSNumber(value: true), + "ratio": NSNumber(value: ratio), + "height": height, + "width": width, + "length": value + ]) + } + return + case .ended: + eventSink([ + "name": "ended" + ]) + eventSink([ + "name": "playing", + "value": NSNumber(value: false), + "reason": "EndReached" + ]) + return + case .error: + eventSink(FlutterError(code: "500", + message: "Player State got an error", + details: nil) + ) + + return + + case .paused, .stopped: + eventSink([ + "name": "buffering", + "value": NSNumber(value: false) + ]) + eventSink([ + "name": "playing", + "value": NSNumber(value: false) + ]) + return + default: + break + } + + } + + func mediaPlayerTimeChanged(_ aNotification: Notification!) { + + let player = aNotification?.object as? VLCMediaPlayer + + if let value = player?.time.value { + eventSink?([ + "name": "timeChanged", + "value": value, + "speed": NSNumber(value: player?.rate ?? 1.0) + ]) + } + + + } +} + + +public class VLCViewFactory: NSObject, FlutterPlatformViewFactory { + + private var registrar: FlutterPluginRegistrar? + + public init(withRegistrar registrar: FlutterPluginRegistrar){ + super.init() + self.registrar = registrar + } + + public func create(withFrame frame: CGRect, viewIdentifier viewId: Int64, arguments args: Any?) -> FlutterPlatformView { + //Can pass args if necessary for intialization. For now default to empty Rect. + //let dictionary = args as! Dictionary + return VLCView(withFrame: CGRect(x: 0, y: 0, width: 0, height: 0), withRegistrar: registrar!,withId: viewId) + } + + public func createArgsCodec() -> FlutterMessageCodec & NSObjectProtocol { + return FlutterStandardMessageCodec(readerWriter: FlutterStandardReaderWriter()) + } +} + + +enum FlutterMethodCallOption :String { + case initialize = "initialize" + case setPlaybackState = "setPlaybackState" + case dispose = "dispose" + case changeURL = "changeURL" + case getSnapshot = "getSnapshot" + case setPlaybackSpeed = "setPlaybackSpeed" + case setTime = "setTime" +} diff --git a/ios/flutter_vlc_player.podspec b/ios/flutter_vlc_player.podspec index 26f3bf89..7f225b72 100755 --- a/ios/flutter_vlc_player.podspec +++ b/ios/flutter_vlc_player.podspec @@ -1,24 +1,25 @@ # -# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html +# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html. +# Run `pod lib lint flutter_vlc_player.podspec' to validate before publishing. # Pod::Spec.new do |s| s.name = 'flutter_vlc_player' - s.version = '0.0.3' - s.summary = 'A new Flutter project.' + s.version = '3.0.0' + s.summary = 'A new flutter plugin project.' s.description = <<-DESC -A new Flutter project. + A VLC-powered alternative to Flutter video_player. Supports multiple players on one screen. DESC - s.homepage = 'http://example.com' + s.homepage = 'https://github.com/solid-software/flutter_vlc_player' s.license = { :file => '../LICENSE' } s.author = { 'Your Company' => 'email@example.com' } s.source = { :path => '.' } s.source_files = 'Classes/**/*' - s.public_header_files = 'Classes/**/*.h' s.dependency 'Flutter' - - s.dependency 'MobileVLCKit', '~> 3.3.10' + s.platform = :ios, '9.0' + s.dependency 'MobileVLCKit', '~> 3.3.11' s.static_framework = true - - s.ios.deployment_target = '9.0' + + # Flutter.framework does not contain a i386 slice. Only x86_64 simulators are supported. + s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'VALID_ARCHS[sdk=iphonesimulator*]' => 'x86_64' } + s.swift_version = '5.0' end - diff --git a/pubspec.yaml b/pubspec.yaml index 581d239f..92ded1c0 100755 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_vlc_player description: A VLC-powered alternative to Flutter's video_player. Supports multiple players on one screen. -version: 2.0.0 +version: 3.0.0 homepage: https://github.com/solid-software/flutter_vlc_player environment: diff --git a/test/flutter_vlc_player_test.dart b/test/flutter_vlc_player_test.dart new file mode 100755 index 00000000..b8362627 --- /dev/null +++ b/test/flutter_vlc_player_test.dart @@ -0,0 +1,23 @@ +import 'package:flutter/services.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:flutter_vlc_player/flutter_vlc_player.dart'; + +void main() { + const MethodChannel channel = MethodChannel('flutter_vlc_player'); + + TestWidgetsFlutterBinding.ensureInitialized(); + + setUp(() { + channel.setMockMethodCallHandler((MethodCall methodCall) async { + return '42'; + }); + }); + + tearDown(() { + channel.setMockMethodCallHandler(null); + }); + + test('getPlatformVersion', () async { + expect(await FlutterVlcPlayer.platformVersion, '42'); + }); +}