diff --git a/CHANGELOG.md b/CHANGELOG.md index c7db1649..79e753bd 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## 6.0.0 + +- Added `pauseAllMediaPlayback`, `setAllMediaPlaybackSuspended`, `closeAllMediaPresentations`, `requestMediaPlaybackState` WebView controller methods +- Deprecated old classes/properties/methods to make them eventually compatible with other operating systems and WebView engines. + ## 5.4.0+2 - Fixed Android `ChromeCustomTabsActivity` not responding to the `ActionBroadcastReceiver` diff --git a/example/ios/Flutter/Flutter.podspec b/example/ios/Flutter/Flutter.podspec new file mode 100644 index 00000000..663d5b29 --- /dev/null +++ b/example/ios/Flutter/Flutter.podspec @@ -0,0 +1,18 @@ +# +# NOTE: This podspec is NOT to be published. It is only used as a local source! +# This is a generated file; do not edit or check into version control. +# + +Pod::Spec.new do |s| + s.name = 'Flutter' + s.version = '1.0.0' + s.summary = 'High-performance, high-fidelity mobile apps.' + s.homepage = 'https://flutter.io' + s.license = { :type => 'MIT' } + s.author = { 'Flutter Dev Team' => 'flutter-dev@googlegroups.com' } + s.source = { :git => 'https://github.com/flutter/engine', :tag => s.version.to_s } + s.ios.deployment_target = '9.0' + # Framework linking is handled by Flutter tooling, not CocoaPods. + # Add a placeholder to satisfy `s.dependency 'Flutter'` plugin podspecs. + s.vendored_frameworks = 'path/to/nothing' +end diff --git a/example/ios/Flutter/flutter_export_environment.sh b/example/ios/Flutter/flutter_export_environment.sh index dad54015..9e98dd5e 100755 --- a/example/ios/Flutter/flutter_export_environment.sh +++ b/example/ios/Flutter/flutter_export_environment.sh @@ -3,11 +3,12 @@ export "FLUTTER_ROOT=/Users/lorenzopichilli/fvm/versions/2.10.4" export "FLUTTER_APPLICATION_PATH=/Users/lorenzopichilli/Desktop/flutter_inappwebview/example" export "COCOAPODS_PARALLEL_CODE_SIGN=true" -export "FLUTTER_TARGET=lib/main.dart" +export "FLUTTER_TARGET=/Users/lorenzopichilli/Desktop/flutter_inappwebview/example/lib/main.dart" export "FLUTTER_BUILD_DIR=build" export "FLUTTER_BUILD_NAME=1.0.0" export "FLUTTER_BUILD_NUMBER=1" +export "DART_DEFINES=Zmx1dHRlci5pbnNwZWN0b3Iuc3RydWN0dXJlZEVycm9ycz10cnVl,RkxVVFRFUl9XRUJfQVVUT19ERVRFQ1Q9dHJ1ZQ==" export "DART_OBFUSCATION=false" -export "TRACK_WIDGET_CREATION=false" +export "TRACK_WIDGET_CREATION=true" export "TREE_SHAKE_ICONS=false" -export "PACKAGE_CONFIG=.packages" +export "PACKAGE_CONFIG=/Users/lorenzopichilli/Desktop/flutter_inappwebview/example/.dart_tool/package_config.json" diff --git a/example/lib/in_app_webiew_example.screen.dart b/example/lib/in_app_webiew_example.screen.dart index f0d48784..3bba112f 100755 --- a/example/lib/in_app_webiew_example.screen.dart +++ b/example/lib/in_app_webiew_example.screen.dart @@ -118,7 +118,7 @@ class _InAppWebViewExampleScreenState extends State { key: webViewKey, // contextMenu: contextMenu, initialUrlRequest: - URLRequest(url: Uri.parse("https://github.com/flutter")), + URLRequest(url: Uri.parse("https://www.youtube.com/watch?v=7_v6oMtz7tA")), // initialFile: "assets/index.html", initialUserScripts: UnmodifiableListView([]), initialSettings: settings, @@ -167,6 +167,8 @@ class _InAppWebViewExampleScreenState extends State { this.url = url.toString(); urlController.text = this.url; }); + await Future.delayed(Duration(seconds: 2)); + await controller.closeAllMediaPresentations(); }, onLoadError: (controller, url, code, message) { pullToRefreshController.endRefreshing(); diff --git a/ios/Classes/InAppWebViewMethodHandler.swift b/ios/Classes/InAppWebViewMethodHandler.swift index 2be84dc4..6650e8f9 100644 --- a/ios/Classes/InAppWebViewMethodHandler.swift +++ b/ios/Classes/InAppWebViewMethodHandler.swift @@ -547,6 +547,44 @@ public class InAppWebViewMethodHandler: FlutterMethodCallDelegate { result(false) } break + case "pauseAllMediaPlayback": + if let webView = webView, #available(iOS 15.0, *) { + webView.pauseAllMediaPlayback(completionHandler: { () -> Void in + result(true) + }) + } else { + result(false) + } + break + case "setAllMediaPlaybackSuspended": + if let webView = webView, #available(iOS 15.0, *) { + let suspended = arguments!["suspended"] as! Bool + webView.setAllMediaPlaybackSuspended(suspended, completionHandler: { () -> Void in + result(true) + }) + } else { + result(false) + } + break + case "closeAllMediaPresentations": + if let webView = self.webView, #available(iOS 14.5, *) { + // closeAllMediaPresentations with completionHandler v15.0 makes the app crash + // with error EXC_BAD_ACCESS, so use closeAllMediaPresentations v14.5 + webView.closeAllMediaPresentations() + result(true) + } else { + result(false) + } + break + case "requestMediaPlaybackState": + if let webView = webView, #available(iOS 15.0, *) { + webView.requestMediaPlaybackState(completionHandler: { (state) -> Void in + result(state.rawValue) + }) + } else { + result(nil) + } + break default: result(FlutterMethodNotImplemented) break diff --git a/lib/src/in_app_webview/in_app_webview_controller.dart b/lib/src/in_app_webview/in_app_webview_controller.dart index 5c32faa3..0669b6df 100644 --- a/lib/src/in_app_webview/in_app_webview_controller.dart +++ b/lib/src/in_app_webview/in_app_webview_controller.dart @@ -2793,6 +2793,56 @@ class InAppWebViewController await _channel.invokeMethod('addWebMessageListener', args); } + ///Pauses playback of all media in the web view. + /// + ///**NOTE for iOS**: available on iOS 15.0+. + /// + ///**Supported Platforms/Implementations**: + ///- iOS ([Official API - WKWebView.pauseAllMediaPlayback](https://developer.apple.com/documentation/webkit/wkwebview/3752240-pauseallmediaplayback)). + Future pauseAllMediaPlayback() async { + Map args = {}; + return await _channel.invokeMethod('pauseAllMediaPlayback', args); + } + + ///Changes whether the webpage is suspending playback of all media in the page. + ///Pass `true` to pause all media the web view is playing. Neither the user nor the webpage can resume playback until you call this method again with `false`. + /// + ///[suspended] represents a [bool] value that indicates whether the webpage should suspend media playback. + /// + ///**NOTE for iOS**: available on iOS 15.0+. + /// + ///**Supported Platforms/Implementations**: + ///- iOS ([Official API - WKWebView.setAllMediaPlaybackSuspended](https://developer.apple.com/documentation/webkit/wkwebview/3752242-setallmediaplaybacksuspended)). + Future setAllMediaPlaybackSuspended({required bool suspended}) async { + Map args = {}; + args.putIfAbsent("suspended", () => suspended); + return await _channel.invokeMethod('setAllMediaPlaybackSuspended', args); + } + + ///Closes all media the web view is presenting, including picture-in-picture video and fullscreen video. + /// + ///**NOTE for iOS**: available on iOS 14.5+. + /// + ///**Supported Platforms/Implementations**: + ///- iOS ([Official API - WKWebView.closeAllMediaPresentations](https://developer.apple.com/documentation/webkit/wkwebview/3752235-closeallmediapresentations)). + Future closeAllMediaPresentations() async { + Map args = {}; + return await _channel.invokeMethod('closeAllMediaPresentations', args); + } + + ///Requests the playback status of media in the web view. + ///Returns a [MediaPlaybackState] that indicates whether the media in the web view is playing, paused, or suspended. + ///If there’s no media in the web view to play, this method provides [MediaPlaybackState.NONE]. + /// + ///**NOTE for iOS**: available on iOS 15.0+. + /// + ///**Supported Platforms/Implementations**: + ///- iOS ([Official API - WKWebView.requestMediaPlaybackState](https://developer.apple.com/documentation/webkit/wkwebview/3752241-requestmediaplaybackstate)). + Future requestMediaPlaybackState() async { + Map args = {}; + return MediaPlaybackState.fromValue(await _channel.invokeMethod('requestMediaPlaybackState', args)); + } + ///Returns `true` if the webpage can scroll vertically, otherwise `false`. Future canScrollVertically() async { Map args = {}; diff --git a/lib/src/types.dart b/lib/src/types.dart index 9701c297..7506b029 100755 --- a/lib/src/types.dart +++ b/lib/src/types.dart @@ -10385,3 +10385,66 @@ class TrustedWebActivityScreenOrientation { @override int get hashCode => _value.hashCode; } + +///Class that describes whether an audio or video presentation is playing, paused, or suspended. +class MediaPlaybackState { + final int _value; + + const MediaPlaybackState._internal(this._value); + + static final Set values = [ + MediaPlaybackState.NONE, + MediaPlaybackState.PLAYING, + MediaPlaybackState.PAUSED, + MediaPlaybackState.SUSPENDED, + ].toSet(); + + static MediaPlaybackState? fromValue(int? value) { + if (value != null) { + try { + return MediaPlaybackState.values + .firstWhere((element) => element.toValue() == value); + } catch (e) { + return null; + } + } + return null; + } + + int toValue() => _value; + + @override + String toString() { + switch (_value) { + case 1: + return "PLAYING"; + case 2: + return "PAUSED"; + case 3: + return "SUSPENDED"; + case 0: + default: + return "NONE"; + } + } + + ///There is no media to play back. + static const NONE = const MediaPlaybackState._internal(0); + + ///The media is playing. + static const PLAYING = + const MediaPlaybackState._internal(1); + + ///The media playback is paused. + static const PAUSED = + const MediaPlaybackState._internal(2); + + ///The media is not playing, and cannot be resumed until the user revokes the suspension. + static const SUSPENDED = + const MediaPlaybackState._internal(3); + + bool operator ==(value) => value == _value; + + @override + int get hashCode => _value.hashCode; +} \ No newline at end of file diff --git a/pubspec.yaml b/pubspec.yaml index 3191400f..8678b95e 100755 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_inappwebview description: A Flutter plugin that allows you to add an inline webview, to use an headless webview, and to open an in-app browser window. -version: 5.4.0+2 +version: 6.0.0 homepage: https://github.com/pichillilorenzo/flutter_inappwebview environment: