diff --git a/example/macos/Flutter/GeneratedPluginRegistrant.swift b/example/macos/Flutter/GeneratedPluginRegistrant.swift index 154ccce1..959e5aa0 100644 --- a/example/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/example/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,7 +5,7 @@ import FlutterMacOS import Foundation -import flutter_inappwebview +import flutter_inappwebview_macos import path_provider_foundation import url_launcher_macos diff --git a/flutter_inappwebview_android/build.yaml b/flutter_inappwebview_android/build.yaml new file mode 100644 index 00000000..e2b3acf3 --- /dev/null +++ b/flutter_inappwebview_android/build.yaml @@ -0,0 +1,5 @@ +targets: + $default: + sources: + exclude: + - example/**.dart diff --git a/flutter_inappwebview_ios/build.yaml b/flutter_inappwebview_ios/build.yaml new file mode 100644 index 00000000..e2b3acf3 --- /dev/null +++ b/flutter_inappwebview_ios/build.yaml @@ -0,0 +1,5 @@ +targets: + $default: + sources: + exclude: + - example/**.dart diff --git a/flutter_inappwebview_ios/lib/src/in_app_webview/in_app_webview_controller.dart b/flutter_inappwebview_ios/lib/src/in_app_webview/in_app_webview_controller.dart index 210323b7..e3b4925f 100644 --- a/flutter_inappwebview_ios/lib/src/in_app_webview/in_app_webview_controller.dart +++ b/flutter_inappwebview_ios/lib/src/in_app_webview/in_app_webview_controller.dart @@ -1923,13 +1923,6 @@ class IOSInAppWebViewController extends PlatformInAppWebViewController args.putIfAbsent('source', () => source); args.putIfAbsent('contentWorld', () => contentWorld?.toMap()); var data = await channel?.invokeMethod('evaluateJavascript', args); - if (data != null && (Util.isAndroid || Util.isWeb)) { - try { - // try to json decode the data coming from JavaScript - // otherwise return it as it is. - data = json.decode(data); - } catch (e) {} - } return data; } @@ -2185,9 +2178,6 @@ class IOSInAppWebViewController extends PlatformInAppWebViewController {required double zoomFactor, @Deprecated('Use animated instead') bool? iosAnimated, bool animated = false}) async { - assert(!Util.isAndroid || - (Util.isAndroid && zoomFactor > 0.01 && zoomFactor <= 100.0)); - Map args = {}; args.putIfAbsent('zoomFactor', () => zoomFactor); args.putIfAbsent('animated', () => iosAnimated ?? animated); @@ -2398,7 +2388,7 @@ class IOSInAppWebViewController extends PlatformInAppWebViewController @override Future addUserScript({required UserScript userScript}) async { - assert(webviewParams?.windowId == null || (!Util.isIOS && !Util.isMacOS)); + assert(webviewParams?.windowId == null); Map args = {}; args.putIfAbsent('userScript', () => userScript.toMap()); @@ -2411,7 +2401,7 @@ class IOSInAppWebViewController extends PlatformInAppWebViewController @override Future addUserScripts({required List userScripts}) async { - assert(webviewParams?.windowId == null || (!Util.isIOS && !Util.isMacOS)); + assert(webviewParams?.windowId == null); for (var i = 0; i < userScripts.length; i++) { await addUserScript(userScript: userScripts[i]); @@ -2420,7 +2410,7 @@ class IOSInAppWebViewController extends PlatformInAppWebViewController @override Future removeUserScript({required UserScript userScript}) async { - assert(webviewParams?.windowId == null || (!Util.isIOS && !Util.isMacOS)); + assert(webviewParams?.windowId == null); var index = _userScripts[userScript.injectionTime]?.indexOf(userScript); if (index == null || index == -1) { @@ -2438,7 +2428,7 @@ class IOSInAppWebViewController extends PlatformInAppWebViewController @override Future removeUserScriptsByGroupName({required String groupName}) async { - assert(webviewParams?.windowId == null || (!Util.isIOS && !Util.isMacOS)); + assert(webviewParams?.windowId == null); final List userScriptsAtDocumentStart = List.from( _userScripts[UserScriptInjectionTime.AT_DOCUMENT_START] ?? []); @@ -2464,7 +2454,7 @@ class IOSInAppWebViewController extends PlatformInAppWebViewController @override Future removeUserScripts( {required List userScripts}) async { - assert(webviewParams?.windowId == null || (!Util.isIOS && !Util.isMacOS)); + assert(webviewParams?.windowId == null); for (final userScript in userScripts) { await removeUserScript(userScript: userScript); @@ -2473,7 +2463,7 @@ class IOSInAppWebViewController extends PlatformInAppWebViewController @override Future removeAllUserScripts() async { - assert(webviewParams?.windowId == null || (!Util.isIOS && !Util.isMacOS)); + assert(webviewParams?.windowId == null); _userScripts[UserScriptInjectionTime.AT_DOCUMENT_START]?.clear(); _userScripts[UserScriptInjectionTime.AT_DOCUMENT_END]?.clear(); @@ -2501,9 +2491,6 @@ class IOSInAppWebViewController extends PlatformInAppWebViewController if (data == null) { return null; } - if (Util.isAndroid) { - data = json.decode(data); - } return CallAsyncJavaScriptResult( value: data["value"], error: data["error"]); } @@ -2512,12 +2499,8 @@ class IOSInAppWebViewController extends PlatformInAppWebViewController Future saveWebArchive( {required String filePath, bool autoname = false}) async { if (!autoname) { - if (Util.isAndroid) { - assert(filePath.endsWith("." + WebArchiveFormat.MHT.toNativeValue())); - } else if (Util.isIOS || Util.isMacOS) { - assert(filePath - .endsWith("." + WebArchiveFormat.WEBARCHIVE.toNativeValue())); - } + assert(filePath + .endsWith("." + WebArchiveFormat.WEBARCHIVE.toNativeValue())); } Map args = {}; diff --git a/flutter_inappwebview_ios/lib/src/web_authentication_session/web_authenticate_session.dart b/flutter_inappwebview_ios/lib/src/web_authentication_session/web_authenticate_session.dart index 7946d866..9ef52c87 100755 --- a/flutter_inappwebview_ios/lib/src/web_authentication_session/web_authenticate_session.dart +++ b/flutter_inappwebview_ios/lib/src/web_authentication_session/web_authenticate_session.dart @@ -22,29 +22,7 @@ class IOSWebAuthenticationSessionCreationParams } } -///A session that an app uses to authenticate a user through a web service. -/// -///It is implemented using [ASWebAuthenticationSession](https://developer.apple.com/documentation/authenticationservices/aswebauthenticationsession) on iOS 12.0+ and MacOS 10.15+ -///and [SFAuthenticationSession](https://developer.apple.com/documentation/safariservices/sfauthenticationsession) on iOS 11.0. -/// -///Use an [IOSWebAuthenticationSession] instance to authenticate a user through a web service, including one run by a third party. -///Initialize the session with a URL that points to the authentication webpage. -///A browser loads and displays the page, from which the user can authenticate. -///In iOS, the browser is a secure, embedded web view. -///In macOS, the system opens the user’s default browser if it supports web authentication sessions, or Safari otherwise. -/// -///On completion, the service sends a callback URL to the session with an authentication token, and the session passes this URL back to the app through a completion handler. -///[IOSWebAuthenticationSession] ensures that only the calling app’s session receives the authentication callback, even when more than one app registers the same callback URL scheme. -/// -///**NOTE**: Remember to dispose it when you don't need it anymore. -/// -///**NOTE for iOS**: Available only on iOS 11.0+. -/// -///**NOTE for MacOS**: Available only on MacOS 10.15+. -/// -///**Supported Platforms/Implementations**: -///- iOS -///- MacOS +///{@macro flutter_inappwebview_platform_interface.PlatformWebAuthenticationSession} class IOSWebAuthenticationSession extends PlatformWebAuthenticationSession with ChannelController { /// Constructs a [IOSWebAuthenticationSession]. diff --git a/flutter_inappwebview_ios/pubspec.yaml b/flutter_inappwebview_ios/pubspec.yaml index 62aa3c47..8628c006 100644 --- a/flutter_inappwebview_ios/pubspec.yaml +++ b/flutter_inappwebview_ios/pubspec.yaml @@ -42,8 +42,8 @@ flutter: # This is required for using `dart:ffi`. # All these are used by the tooling to maintain consistency when # adding or updating assets for this project. - implements: flutter_inappwebview plugin: + implements: flutter_inappwebview platforms: ios: pluginClass: InAppWebViewFlutterPlugin diff --git a/flutter_inappwebview_macos/.gitignore b/flutter_inappwebview_macos/.gitignore new file mode 100644 index 00000000..96486fd9 --- /dev/null +++ b/flutter_inappwebview_macos/.gitignore @@ -0,0 +1,30 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. +/pubspec.lock +**/doc/api/ +.dart_tool/ +.packages +build/ diff --git a/flutter_inappwebview_macos/.metadata b/flutter_inappwebview_macos/.metadata new file mode 100644 index 00000000..650038ed --- /dev/null +++ b/flutter_inappwebview_macos/.metadata @@ -0,0 +1,30 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: "6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e" + channel: "stable" + +project_type: plugin + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: 6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e + base_revision: 6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e + - platform: macos + create_revision: 6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e + base_revision: 6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/flutter_inappwebview_macos/CHANGELOG.md b/flutter_inappwebview_macos/CHANGELOG.md new file mode 100644 index 00000000..41cc7d81 --- /dev/null +++ b/flutter_inappwebview_macos/CHANGELOG.md @@ -0,0 +1,3 @@ +## 0.0.1 + +* TODO: Describe initial release. diff --git a/flutter_inappwebview_macos/LICENSE b/flutter_inappwebview_macos/LICENSE new file mode 100644 index 00000000..ba75c69f --- /dev/null +++ b/flutter_inappwebview_macos/LICENSE @@ -0,0 +1 @@ +TODO: Add your license here. diff --git a/flutter_inappwebview_macos/README.md b/flutter_inappwebview_macos/README.md new file mode 100644 index 00000000..020338c4 --- /dev/null +++ b/flutter_inappwebview_macos/README.md @@ -0,0 +1,15 @@ +# flutter_inappwebview_macos + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter +[plug-in package](https://flutter.dev/developing-packages/), +a specialized package that includes platform-specific implementation code for +Android and/or iOS. + +For help getting started with Flutter development, view the +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. + diff --git a/flutter_inappwebview_macos/analysis_options.yaml b/flutter_inappwebview_macos/analysis_options.yaml new file mode 100644 index 00000000..c98f8e5d --- /dev/null +++ b/flutter_inappwebview_macos/analysis_options.yaml @@ -0,0 +1,13 @@ +include: package:flutter_lints/flutter.yaml + +linter: + rules: + constant_identifier_names: ignore + deprecated_member_use_from_same_package: ignore + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options +analyzer: + errors: + deprecated_member_use: ignore + deprecated_member_use_from_same_package: ignore diff --git a/flutter_inappwebview_macos/build.yaml b/flutter_inappwebview_macos/build.yaml new file mode 100644 index 00000000..e2b3acf3 --- /dev/null +++ b/flutter_inappwebview_macos/build.yaml @@ -0,0 +1,5 @@ +targets: + $default: + sources: + exclude: + - example/**.dart diff --git a/flutter_inappwebview_macos/example/.gitignore b/flutter_inappwebview_macos/example/.gitignore new file mode 100644 index 00000000..24476c5d --- /dev/null +++ b/flutter_inappwebview_macos/example/.gitignore @@ -0,0 +1,44 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Android Studio will place build artifacts here +/android/app/debug +/android/app/profile +/android/app/release diff --git a/flutter_inappwebview_macos/example/README.md b/flutter_inappwebview_macos/example/README.md new file mode 100644 index 00000000..1e75fecb --- /dev/null +++ b/flutter_inappwebview_macos/example/README.md @@ -0,0 +1,16 @@ +# flutter_inappwebview_macos_example + +Demonstrates how to use the flutter_inappwebview_macos plugin. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook) + +For help getting started with Flutter development, view the +[online documentation](https://docs.flutter.dev/), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/flutter_inappwebview_macos/example/analysis_options.yaml b/flutter_inappwebview_macos/example/analysis_options.yaml new file mode 100644 index 00000000..0d290213 --- /dev/null +++ b/flutter_inappwebview_macos/example/analysis_options.yaml @@ -0,0 +1,28 @@ +# This file configures the analyzer, which statically analyzes Dart code to +# check for errors, warnings, and lints. +# +# The issues identified by the analyzer are surfaced in the UI of Dart-enabled +# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be +# invoked from the command line by running `flutter analyze`. + +# The following line activates a set of recommended lints for Flutter apps, +# packages, and plugins designed to encourage good coding practices. +include: package:flutter_lints/flutter.yaml + +linter: + # The lint rules applied to this project can be customized in the + # section below to disable rules from the `package:flutter_lints/flutter.yaml` + # included above or to enable additional rules. A list of all available lints + # and their documentation is published at https://dart.dev/lints. + # + # Instead of disabling a lint rule for the entire project in the + # section below, it can also be suppressed for a single line of code + # or a specific dart file by using the `// ignore: name_of_lint` and + # `// ignore_for_file: name_of_lint` syntax on the line or in the file + # producing the lint. + rules: + # avoid_print: false # Uncomment to disable the `avoid_print` rule + # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/flutter_inappwebview_macos/example/integration_test/plugin_integration_test.dart b/flutter_inappwebview_macos/example/integration_test/plugin_integration_test.dart new file mode 100644 index 00000000..e69de29b diff --git a/flutter_inappwebview_macos/example/lib/main.dart b/flutter_inappwebview_macos/example/lib/main.dart new file mode 100644 index 00000000..e69de29b diff --git a/flutter_inappwebview_macos/example/macos/.gitignore b/flutter_inappwebview_macos/example/macos/.gitignore new file mode 100644 index 00000000..746adbb6 --- /dev/null +++ b/flutter_inappwebview_macos/example/macos/.gitignore @@ -0,0 +1,7 @@ +# Flutter-related +**/Flutter/ephemeral/ +**/Pods/ + +# Xcode-related +**/dgph +**/xcuserdata/ diff --git a/flutter_inappwebview_macos/example/macos/Flutter/Flutter-Debug.xcconfig b/flutter_inappwebview_macos/example/macos/Flutter/Flutter-Debug.xcconfig new file mode 100644 index 00000000..4b81f9b2 --- /dev/null +++ b/flutter_inappwebview_macos/example/macos/Flutter/Flutter-Debug.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/flutter_inappwebview_macos/example/macos/Flutter/Flutter-Release.xcconfig b/flutter_inappwebview_macos/example/macos/Flutter/Flutter-Release.xcconfig new file mode 100644 index 00000000..5caa9d15 --- /dev/null +++ b/flutter_inappwebview_macos/example/macos/Flutter/Flutter-Release.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/flutter_inappwebview_macos/example/macos/Flutter/GeneratedPluginRegistrant.swift b/flutter_inappwebview_macos/example/macos/Flutter/GeneratedPluginRegistrant.swift new file mode 100644 index 00000000..738fc0a4 --- /dev/null +++ b/flutter_inappwebview_macos/example/macos/Flutter/GeneratedPluginRegistrant.swift @@ -0,0 +1,12 @@ +// +// Generated file. Do not edit. +// + +import FlutterMacOS +import Foundation + +import flutter_inappwebview_macos + +func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + InAppWebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "InAppWebViewFlutterPlugin")) +} diff --git a/flutter_inappwebview_macos/example/macos/Podfile b/flutter_inappwebview_macos/example/macos/Podfile new file mode 100644 index 00000000..c795730d --- /dev/null +++ b/flutter_inappwebview_macos/example/macos/Podfile @@ -0,0 +1,43 @@ +platform :osx, '10.14' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_macos_podfile_setup + +target 'Runner' do + use_frameworks! + use_modular_headers! + + flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_macos_build_settings(target) + end +end diff --git a/flutter_inappwebview_macos/example/macos/Runner.xcodeproj/project.pbxproj b/flutter_inappwebview_macos/example/macos/Runner.xcodeproj/project.pbxproj new file mode 100644 index 00000000..6c14ab4e --- /dev/null +++ b/flutter_inappwebview_macos/example/macos/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,695 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXAggregateTarget section */ + 33CC111A2044C6BA0003C045 /* Flutter Assemble */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */; + buildPhases = ( + 33CC111E2044C6BF0003C045 /* ShellScript */, + ); + dependencies = ( + ); + name = "Flutter Assemble"; + productName = FLX; + }; +/* End PBXAggregateTarget section */ + +/* Begin PBXBuildFile section */ + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; }; + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC10EC2044A3C60003C045; + remoteInfo = Runner; + }; + 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC111A2044C6BA0003C045; + remoteInfo = FLX; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 33CC110E2044A8840003C045 /* Bundle Framework */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Bundle Framework"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; + 33CC10ED2044A3C60003C045 /* flutter_inappwebview_macos_example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "flutter_inappwebview_macos_example.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; + 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; + 33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = ""; }; + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = ""; }; + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = ""; }; + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = ""; }; + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = ""; }; + 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; + 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; + 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 331C80D2294CF70F00263BE5 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EA2044A3C60003C045 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 331C80D6294CF71000263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C80D7294CF71000263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; + 33BA886A226E78AF003329D5 /* Configs */ = { + isa = PBXGroup; + children = ( + 33E5194F232828860026EE4D /* AppInfo.xcconfig */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */, + ); + path = Configs; + sourceTree = ""; + }; + 33CC10E42044A3C60003C045 = { + isa = PBXGroup; + children = ( + 33FAB671232836740065AC1E /* Runner */, + 33CEB47122A05771004F2AC0 /* Flutter */, + 331C80D6294CF71000263BE5 /* RunnerTests */, + 33CC10EE2044A3C60003C045 /* Products */, + D73912EC22F37F3D000D13A0 /* Frameworks */, + ); + sourceTree = ""; + }; + 33CC10EE2044A3C60003C045 /* Products */ = { + isa = PBXGroup; + children = ( + 33CC10ED2044A3C60003C045 /* flutter_inappwebview_macos_example.app */, + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 33CC11242044D66E0003C045 /* Resources */ = { + isa = PBXGroup; + children = ( + 33CC10F22044A3C60003C045 /* Assets.xcassets */, + 33CC10F42044A3C60003C045 /* MainMenu.xib */, + 33CC10F72044A3C60003C045 /* Info.plist */, + ); + name = Resources; + path = ..; + sourceTree = ""; + }; + 33CEB47122A05771004F2AC0 /* Flutter */ = { + isa = PBXGroup; + children = ( + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */, + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */, + ); + path = Flutter; + sourceTree = ""; + }; + 33FAB671232836740065AC1E /* Runner */ = { + isa = PBXGroup; + children = ( + 33CC10F02044A3C60003C045 /* AppDelegate.swift */, + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */, + 33E51913231747F40026EE4D /* DebugProfile.entitlements */, + 33E51914231749380026EE4D /* Release.entitlements */, + 33CC11242044D66E0003C045 /* Resources */, + 33BA886A226E78AF003329D5 /* Configs */, + ); + path = Runner; + sourceTree = ""; + }; + D73912EC22F37F3D000D13A0 /* Frameworks */ = { + isa = PBXGroup; + children = ( + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 331C80D4294CF70F00263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + 331C80D1294CF70F00263BE5 /* Sources */, + 331C80D2294CF70F00263BE5 /* Frameworks */, + 331C80D3294CF70F00263BE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 331C80DA294CF71000263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C80D5294CF71000263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 33CC10EC2044A3C60003C045 /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 33CC10E92044A3C60003C045 /* Sources */, + 33CC10EA2044A3C60003C045 /* Frameworks */, + 33CC10EB2044A3C60003C045 /* Resources */, + 33CC110E2044A8840003C045 /* Bundle Framework */, + 3399D490228B24CF009A79C7 /* ShellScript */, + ); + buildRules = ( + ); + dependencies = ( + 33CC11202044C79F0003C045 /* PBXTargetDependency */, + ); + name = Runner; + productName = Runner; + productReference = 33CC10ED2044A3C60003C045 /* flutter_inappwebview_macos_example.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 33CC10E52044A3C60003C045 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0920; + LastUpgradeCheck = 1430; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 331C80D4294CF70F00263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 33CC10EC2044A3C60003C045; + }; + 33CC10EC2044A3C60003C045 = { + CreatedOnToolsVersion = 9.2; + LastSwiftMigration = 1100; + ProvisioningStyle = Automatic; + SystemCapabilities = { + com.apple.Sandbox = { + enabled = 1; + }; + }; + }; + 33CC111A2044C6BA0003C045 = { + CreatedOnToolsVersion = 9.2; + ProvisioningStyle = Manual; + }; + }; + }; + buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 33CC10E42044A3C60003C045; + productRefGroup = 33CC10EE2044A3C60003C045 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 33CC10EC2044A3C60003C045 /* Runner */, + 331C80D4294CF70F00263BE5 /* RunnerTests */, + 33CC111A2044C6BA0003C045 /* Flutter Assemble */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 331C80D3294CF70F00263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EB2044A3C60003C045 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */, + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3399D490228B24CF009A79C7 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; + }; + 33CC111E2044C6BF0003C045 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + Flutter/ephemeral/FlutterInputs.xcfilelist, + ); + inputPaths = ( + Flutter/ephemeral/tripwire, + ); + outputFileListPaths = ( + Flutter/ephemeral/FlutterOutputs.xcfilelist, + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 331C80D1294CF70F00263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10E92044A3C60003C045 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */, + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */, + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 331C80DA294CF71000263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC10EC2044A3C60003C045 /* Runner */; + targetProxy = 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */; + }; + 33CC11202044C79F0003C045 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */; + targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 33CC10F42044A3C60003C045 /* MainMenu.xib */ = { + isa = PBXVariantGroup; + children = ( + 33CC10F52044A3C60003C045 /* Base */, + ); + name = MainMenu.xib; + path = Runner; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 331C80DB294CF71000263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.pichillilorenzo.flutterInappwebviewMacosExample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/flutter_inappwebview_macos_example.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/flutter_inappwebview_macos_example"; + }; + name = Debug; + }; + 331C80DC294CF71000263BE5 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.pichillilorenzo.flutterInappwebviewMacosExample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/flutter_inappwebview_macos_example.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/flutter_inappwebview_macos_example"; + }; + name = Release; + }; + 331C80DD294CF71000263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.pichillilorenzo.flutterInappwebviewMacosExample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/flutter_inappwebview_macos_example.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/flutter_inappwebview_macos_example"; + }; + name = Profile; + }; + 338D0CE9231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + 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_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Profile; + }; + 338D0CEA231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Profile; + }; + 338D0CEB231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Profile; + }; + 33CC10F92044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + 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_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 33CC10FA2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + 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_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Release; + }; + 33CC10FC2044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 33CC10FD2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + 33CC111C2044C6BA0003C045 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 33CC111D2044C6BA0003C045 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C80DB294CF71000263BE5 /* Debug */, + 331C80DC294CF71000263BE5 /* Release */, + 331C80DD294CF71000263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10F92044A3C60003C045 /* Debug */, + 33CC10FA2044A3C60003C045 /* Release */, + 338D0CE9231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10FC2044A3C60003C045 /* Debug */, + 33CC10FD2044A3C60003C045 /* Release */, + 338D0CEA231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC111C2044C6BA0003C045 /* Debug */, + 33CC111D2044C6BA0003C045 /* Release */, + 338D0CEB231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 33CC10E52044A3C60003C045 /* Project object */; +} diff --git a/flutter_inappwebview_macos/example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/flutter_inappwebview_macos/example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/flutter_inappwebview_macos/example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/flutter_inappwebview_macos/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/flutter_inappwebview_macos/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 00000000..f50c0304 --- /dev/null +++ b/flutter_inappwebview_macos/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/flutter_inappwebview_macos/example/macos/Runner.xcworkspace/contents.xcworkspacedata b/flutter_inappwebview_macos/example/macos/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..1d526a16 --- /dev/null +++ b/flutter_inappwebview_macos/example/macos/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/flutter_inappwebview_macos/example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/flutter_inappwebview_macos/example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/flutter_inappwebview_macos/example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/flutter_inappwebview_macos/example/macos/Runner/AppDelegate.swift b/flutter_inappwebview_macos/example/macos/Runner/AppDelegate.swift new file mode 100644 index 00000000..d53ef643 --- /dev/null +++ b/flutter_inappwebview_macos/example/macos/Runner/AppDelegate.swift @@ -0,0 +1,9 @@ +import Cocoa +import FlutterMacOS + +@NSApplicationMain +class AppDelegate: FlutterAppDelegate { + override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { + return true + } +} diff --git a/flutter_inappwebview_macos/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/flutter_inappwebview_macos/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..a2ec33f1 --- /dev/null +++ b/flutter_inappwebview_macos/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images" : [ + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_16.png", + "scale" : "1x" + }, + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "2x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "1x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_64.png", + "scale" : "2x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_128.png", + "scale" : "1x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "2x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "1x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "2x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "1x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_1024.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/flutter_inappwebview_macos/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png b/flutter_inappwebview_macos/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png new file mode 100644 index 00000000..82b6f9d9 Binary files /dev/null and b/flutter_inappwebview_macos/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png differ diff --git a/flutter_inappwebview_macos/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png b/flutter_inappwebview_macos/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png new file mode 100644 index 00000000..13b35eba Binary files /dev/null and b/flutter_inappwebview_macos/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png differ diff --git a/flutter_inappwebview_macos/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png b/flutter_inappwebview_macos/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png new file mode 100644 index 00000000..0a3f5fa4 Binary files /dev/null and b/flutter_inappwebview_macos/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png differ diff --git a/flutter_inappwebview_macos/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png b/flutter_inappwebview_macos/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png new file mode 100644 index 00000000..bdb57226 Binary files /dev/null and b/flutter_inappwebview_macos/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png differ diff --git a/flutter_inappwebview_macos/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png b/flutter_inappwebview_macos/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png new file mode 100644 index 00000000..f083318e Binary files /dev/null and b/flutter_inappwebview_macos/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png differ diff --git a/flutter_inappwebview_macos/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png b/flutter_inappwebview_macos/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png new file mode 100644 index 00000000..326c0e72 Binary files /dev/null and b/flutter_inappwebview_macos/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png differ diff --git a/flutter_inappwebview_macos/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png b/flutter_inappwebview_macos/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png new file mode 100644 index 00000000..2f1632cf Binary files /dev/null and b/flutter_inappwebview_macos/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png differ diff --git a/flutter_inappwebview_macos/example/macos/Runner/Base.lproj/MainMenu.xib b/flutter_inappwebview_macos/example/macos/Runner/Base.lproj/MainMenu.xib new file mode 100644 index 00000000..80e867a4 --- /dev/null +++ b/flutter_inappwebview_macos/example/macos/Runner/Base.lproj/MainMenu.xib @@ -0,0 +1,343 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/flutter_inappwebview_macos/example/macos/Runner/Configs/AppInfo.xcconfig b/flutter_inappwebview_macos/example/macos/Runner/Configs/AppInfo.xcconfig new file mode 100644 index 00000000..ce19f930 --- /dev/null +++ b/flutter_inappwebview_macos/example/macos/Runner/Configs/AppInfo.xcconfig @@ -0,0 +1,14 @@ +// Application-level settings for the Runner target. +// +// This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the +// future. If not, the values below would default to using the project name when this becomes a +// 'flutter create' template. + +// The application's name. By default this is also the title of the Flutter window. +PRODUCT_NAME = flutter_inappwebview_macos_example + +// The application's bundle identifier +PRODUCT_BUNDLE_IDENTIFIER = com.pichillilorenzo.flutterInappwebviewMacosExample + +// The copyright displayed in application information +PRODUCT_COPYRIGHT = Copyright © 2023 com.pichillilorenzo. All rights reserved. diff --git a/flutter_inappwebview_macos/example/macos/Runner/Configs/Debug.xcconfig b/flutter_inappwebview_macos/example/macos/Runner/Configs/Debug.xcconfig new file mode 100644 index 00000000..36b0fd94 --- /dev/null +++ b/flutter_inappwebview_macos/example/macos/Runner/Configs/Debug.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Debug.xcconfig" +#include "Warnings.xcconfig" diff --git a/flutter_inappwebview_macos/example/macos/Runner/Configs/Release.xcconfig b/flutter_inappwebview_macos/example/macos/Runner/Configs/Release.xcconfig new file mode 100644 index 00000000..dff4f495 --- /dev/null +++ b/flutter_inappwebview_macos/example/macos/Runner/Configs/Release.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Release.xcconfig" +#include "Warnings.xcconfig" diff --git a/flutter_inappwebview_macos/example/macos/Runner/Configs/Warnings.xcconfig b/flutter_inappwebview_macos/example/macos/Runner/Configs/Warnings.xcconfig new file mode 100644 index 00000000..42bcbf47 --- /dev/null +++ b/flutter_inappwebview_macos/example/macos/Runner/Configs/Warnings.xcconfig @@ -0,0 +1,13 @@ +WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings +GCC_WARN_UNDECLARED_SELECTOR = YES +CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES +CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE +CLANG_WARN__DUPLICATE_METHOD_MATCH = YES +CLANG_WARN_PRAGMA_PACK = YES +CLANG_WARN_STRICT_PROTOTYPES = YES +CLANG_WARN_COMMA = YES +GCC_WARN_STRICT_SELECTOR_MATCH = YES +CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES +CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES +GCC_WARN_SHADOW = YES +CLANG_WARN_UNREACHABLE_CODE = YES diff --git a/flutter_inappwebview_macos/example/macos/Runner/DebugProfile.entitlements b/flutter_inappwebview_macos/example/macos/Runner/DebugProfile.entitlements new file mode 100644 index 00000000..dddb8a30 --- /dev/null +++ b/flutter_inappwebview_macos/example/macos/Runner/DebugProfile.entitlements @@ -0,0 +1,12 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.cs.allow-jit + + com.apple.security.network.server + + + diff --git a/flutter_inappwebview_macos/example/macos/Runner/Info.plist b/flutter_inappwebview_macos/example/macos/Runner/Info.plist new file mode 100644 index 00000000..4789daa6 --- /dev/null +++ b/flutter_inappwebview_macos/example/macos/Runner/Info.plist @@ -0,0 +1,32 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSHumanReadableCopyright + $(PRODUCT_COPYRIGHT) + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + + diff --git a/flutter_inappwebview_macos/example/macos/Runner/MainFlutterWindow.swift b/flutter_inappwebview_macos/example/macos/Runner/MainFlutterWindow.swift new file mode 100644 index 00000000..3cc05eb2 --- /dev/null +++ b/flutter_inappwebview_macos/example/macos/Runner/MainFlutterWindow.swift @@ -0,0 +1,15 @@ +import Cocoa +import FlutterMacOS + +class MainFlutterWindow: NSWindow { + override func awakeFromNib() { + let flutterViewController = FlutterViewController() + let windowFrame = self.frame + self.contentViewController = flutterViewController + self.setFrame(windowFrame, display: true) + + RegisterGeneratedPlugins(registry: flutterViewController) + + super.awakeFromNib() + } +} diff --git a/flutter_inappwebview_macos/example/macos/Runner/Release.entitlements b/flutter_inappwebview_macos/example/macos/Runner/Release.entitlements new file mode 100644 index 00000000..852fa1a4 --- /dev/null +++ b/flutter_inappwebview_macos/example/macos/Runner/Release.entitlements @@ -0,0 +1,8 @@ + + + + + com.apple.security.app-sandbox + + + diff --git a/flutter_inappwebview_macos/example/macos/RunnerTests/RunnerTests.swift b/flutter_inappwebview_macos/example/macos/RunnerTests/RunnerTests.swift new file mode 100644 index 00000000..fd897645 --- /dev/null +++ b/flutter_inappwebview_macos/example/macos/RunnerTests/RunnerTests.swift @@ -0,0 +1,27 @@ +import FlutterMacOS +import Cocoa +import XCTest + +@testable import flutter_inappwebview_macos + +// This demonstrates a simple unit test of the Swift portion of this plugin's implementation. +// +// See https://developer.apple.com/documentation/xctest for more information about using XCTest. + +class RunnerTests: XCTestCase { + + func testGetPlatformVersion() { + let plugin = FlutterInappwebviewMacosPlugin() + + let call = FlutterMethodCall(methodName: "getPlatformVersion", arguments: []) + + let resultExpectation = expectation(description: "result block must be called.") + plugin.handle(call) { result in + XCTAssertEqual(result as! String, + "macOS " + ProcessInfo.processInfo.operatingSystemVersionString) + resultExpectation.fulfill() + } + waitForExpectations(timeout: 1) + } + +} diff --git a/flutter_inappwebview_macos/example/pubspec.lock b/flutter_inappwebview_macos/example/pubspec.lock new file mode 100644 index 00000000..a34425ad --- /dev/null +++ b/flutter_inappwebview_macos/example/pubspec.lock @@ -0,0 +1,282 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + async: + dependency: transitive + description: + name: async + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" + url: "https://pub.dev" + source: hosted + version: "2.11.0" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + characters: + dependency: transitive + description: + name: characters + sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" + url: "https://pub.dev" + source: hosted + version: "1.3.0" + clock: + dependency: transitive + description: + name: clock + sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + url: "https://pub.dev" + source: hosted + version: "1.1.1" + collection: + dependency: transitive + description: + name: collection + sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687 + url: "https://pub.dev" + source: hosted + version: "1.17.2" + cupertino_icons: + dependency: "direct main" + description: + name: cupertino_icons + sha256: d57953e10f9f8327ce64a508a355f0b1ec902193f66288e8cb5070e7c47eeb2d + url: "https://pub.dev" + source: hosted + version: "1.0.6" + fake_async: + dependency: transitive + description: + name: fake_async + sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + url: "https://pub.dev" + source: hosted + version: "1.3.1" + file: + dependency: transitive + description: + name: file + sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d" + url: "https://pub.dev" + source: hosted + version: "6.1.4" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_driver: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + flutter_inappwebview_internal_annotations: + dependency: transitive + description: + name: flutter_inappwebview_internal_annotations + sha256: "5f80fd30e208ddded7dbbcd0d569e7995f9f63d45ea3f548d8dd4c0b473fb4c8" + url: "https://pub.dev" + source: hosted + version: "1.1.1" + flutter_inappwebview_macos: + dependency: "direct main" + description: + path: ".." + relative: true + source: path + version: "1.0.0" + flutter_inappwebview_platform_interface: + dependency: transitive + description: + path: "../../flutter_inappwebview_platform_interface" + relative: true + source: path + version: "1.0.0" + flutter_lints: + dependency: "direct dev" + description: + name: flutter_lints + sha256: a25a15ebbdfc33ab1cd26c63a6ee519df92338a9c10f122adda92938253bef04 + url: "https://pub.dev" + source: hosted + version: "2.0.3" + flutter_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + fuchsia_remote_debug_protocol: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + integration_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + lints: + dependency: transitive + description: + name: lints + sha256: "0a217c6c989d21039f1498c3ed9f3ed71b354e69873f13a8dfc3c9fe76f1b452" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + matcher: + dependency: transitive + description: + name: matcher + sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" + url: "https://pub.dev" + source: hosted + version: "0.12.16" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" + url: "https://pub.dev" + source: hosted + version: "0.5.0" + meta: + dependency: transitive + description: + name: meta + sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" + url: "https://pub.dev" + source: hosted + version: "1.9.1" + path: + dependency: transitive + description: + name: path + sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" + url: "https://pub.dev" + source: hosted + version: "1.8.3" + platform: + dependency: transitive + description: + name: platform + sha256: "4a451831508d7d6ca779f7ac6e212b4023dd5a7d08a27a63da33756410e32b76" + url: "https://pub.dev" + source: hosted + version: "3.1.0" + plugin_platform_interface: + dependency: transitive + description: + name: plugin_platform_interface + sha256: f4f88d4a900933e7267e2b353594774fc0d07fb072b47eedcd5b54e1ea3269f8 + url: "https://pub.dev" + source: hosted + version: "2.1.7" + process: + dependency: transitive + description: + name: process + sha256: "53fd8db9cec1d37b0574e12f07520d582019cb6c44abf5479a01505099a34a09" + url: "https://pub.dev" + source: hosted + version: "4.2.4" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.99" + source_span: + dependency: transitive + description: + name: source_span + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" + url: "https://pub.dev" + source: hosted + version: "1.10.0" + stack_trace: + dependency: transitive + description: + name: stack_trace + sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 + url: "https://pub.dev" + source: hosted + version: "1.11.0" + stream_channel: + dependency: transitive + description: + name: stream_channel + sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + string_scanner: + dependency: transitive + description: + name: string_scanner + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + sync_http: + dependency: transitive + description: + name: sync_http + sha256: "7f0cd72eca000d2e026bcd6f990b81d0ca06022ef4e32fb257b30d3d1014a961" + url: "https://pub.dev" + source: hosted + version: "0.3.1" + term_glyph: + dependency: transitive + description: + name: term_glyph + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" + source: hosted + version: "1.2.1" + test_api: + dependency: transitive + description: + name: test_api + sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8" + url: "https://pub.dev" + source: hosted + version: "0.6.0" + vector_math: + dependency: transitive + description: + name: vector_math + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: c620a6f783fa22436da68e42db7ebbf18b8c44b9a46ab911f666ff09ffd9153f + url: "https://pub.dev" + source: hosted + version: "11.7.1" + web: + dependency: transitive + description: + name: web + sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10 + url: "https://pub.dev" + source: hosted + version: "0.1.4-beta" + webdriver: + dependency: transitive + description: + name: webdriver + sha256: "3c923e918918feeb90c4c9fdf1fe39220fa4c0e8e2c0fffaded174498ef86c49" + url: "https://pub.dev" + source: hosted + version: "3.0.2" +sdks: + dart: ">=3.1.4 <4.0.0" + flutter: ">=3.0.0" diff --git a/flutter_inappwebview_macos/example/pubspec.yaml b/flutter_inappwebview_macos/example/pubspec.yaml new file mode 100644 index 00000000..95aef948 --- /dev/null +++ b/flutter_inappwebview_macos/example/pubspec.yaml @@ -0,0 +1,85 @@ +name: flutter_inappwebview_macos_example +description: Demonstrates how to use the flutter_inappwebview_macos plugin. +# The following line prevents the package from being accidentally published to +# pub.dev using `flutter pub publish`. This is preferred for private packages. +publish_to: 'none' # Remove this line if you wish to publish to pub.dev + +environment: + sdk: '>=3.1.4 <4.0.0' + +# Dependencies specify other packages that your package needs in order to work. +# To automatically upgrade your package dependencies to the latest versions +# consider running `flutter pub upgrade --major-versions`. Alternatively, +# dependencies can be manually updated by changing the version numbers below to +# the latest version available on pub.dev. To see which dependencies have newer +# versions available, run `flutter pub outdated`. +dependencies: + flutter: + sdk: flutter + + flutter_inappwebview_macos: + # When depending on this package from a real application you should use: + # flutter_inappwebview_macos: ^x.y.z + # See https://dart.dev/tools/pub/dependencies#version-constraints + # The example app is bundled with the plugin so we use a path dependency on + # the parent directory to use the current plugin's version. + path: ../ + + # The following adds the Cupertino Icons font to your application. + # Use with the CupertinoIcons class for iOS style icons. + cupertino_icons: ^1.0.2 + +dev_dependencies: + integration_test: + sdk: flutter + flutter_test: + sdk: flutter + + # The "flutter_lints" package below contains a set of recommended lints to + # encourage good coding practices. The lint set provided by the package is + # activated in the `analysis_options.yaml` file located at the root of your + # package. See that file for information about deactivating specific lint + # rules and activating additional ones. + flutter_lints: ^2.0.0 + +# For information on the generic Dart part of this file, see the +# following page: https://dart.dev/tools/pub/pubspec + +# The following section is specific to Flutter packages. +flutter: + + # The following line ensures that the Material Icons font is + # included with your application, so that you can use the icons in + # the material Icons class. + uses-material-design: true + + # To add assets to your application, add an assets section, like this: + # assets: + # - images/a_dot_burr.jpeg + # - images/a_dot_ham.jpeg + + # An image asset can refer to one or more resolution-specific "variants", see + # https://flutter.dev/assets-and-images/#resolution-aware + + # For details regarding adding assets from package dependencies, see + # https://flutter.dev/assets-and-images/#from-packages + + # To add custom fonts to your application, add a fonts section here, + # in this "flutter" section. Each entry in this list should have a + # "family" key with the font family name, and a "fonts" key with a + # list giving the asset and other descriptors for the font. For + # example: + # fonts: + # - family: Schyler + # fonts: + # - asset: fonts/Schyler-Regular.ttf + # - asset: fonts/Schyler-Italic.ttf + # style: italic + # - family: Trajan Pro + # fonts: + # - asset: fonts/TrajanPro.ttf + # - asset: fonts/TrajanPro_Bold.ttf + # weight: 700 + # + # For details regarding fonts from package dependencies, + # see https://flutter.dev/custom-fonts/#from-packages diff --git a/flutter_inappwebview_macos/example/test/widget_test.dart b/flutter_inappwebview_macos/example/test/widget_test.dart new file mode 100644 index 00000000..e69de29b diff --git a/flutter_inappwebview_macos/lib/flutter_inappwebview_macos.dart b/flutter_inappwebview_macos/lib/flutter_inappwebview_macos.dart new file mode 100644 index 00000000..b82fc696 --- /dev/null +++ b/flutter_inappwebview_macos/lib/flutter_inappwebview_macos.dart @@ -0,0 +1,3 @@ +library flutter_inappwebview_macos; + +export 'src/main.dart'; diff --git a/flutter_inappwebview_macos/lib/src/cookie_manager.dart b/flutter_inappwebview_macos/lib/src/cookie_manager.dart new file mode 100755 index 00000000..ca679132 --- /dev/null +++ b/flutter_inappwebview_macos/lib/src/cookie_manager.dart @@ -0,0 +1,439 @@ +import 'dart:async'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/services.dart'; + +import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; + +import 'in_app_webview/headless_in_app_webview.dart'; +import 'platform_util.dart'; + +/// Object specifying creation parameters for creating a [MacOSCookieManager]. +/// +/// When adding additional fields make sure they can be null or have a default +/// value to avoid breaking changes. See [PlatformCookieManagerCreationParams] for +/// more information. +@immutable +class MacOSCookieManagerCreationParams + extends PlatformCookieManagerCreationParams { + /// Creates a new [MacOSCookieManagerCreationParams] instance. + const MacOSCookieManagerCreationParams( + // This parameter prevents breaking changes later. + // ignore: avoid_unused_constructor_parameters + PlatformCookieManagerCreationParams params, + ) : super(); + + /// Creates a [MacOSCookieManagerCreationParams] instance based on [PlatformCookieManagerCreationParams]. + factory MacOSCookieManagerCreationParams.fromPlatformCookieManagerCreationParams( + PlatformCookieManagerCreationParams params) { + return MacOSCookieManagerCreationParams(params); + } +} + +///{@macro flutter_inappwebview_platform_interface.PlatformCookieManager} +class MacOSCookieManager extends PlatformCookieManager + with ChannelController { + /// Creates a new [MacOSCookieManager]. + MacOSCookieManager(PlatformCookieManagerCreationParams params) + : super.implementation( + params is MacOSCookieManagerCreationParams + ? params + : MacOSCookieManagerCreationParams + .fromPlatformCookieManagerCreationParams(params), + ) { + channel = const MethodChannel( + 'com.pichillilorenzo/flutter_inappwebview_cookiemanager'); + handler = handleMethod; + initMethodCallHandler(); + } + + static MacOSCookieManager? _instance; + + ///Gets the [MacOSCookieManager] shared instance. + static MacOSCookieManager instance() { + return (_instance != null) ? _instance! : _init(); + } + + static MacOSCookieManager _init() { + _instance = MacOSCookieManager(MacOSCookieManagerCreationParams( + const PlatformCookieManagerCreationParams())); + return _instance!; + } + + Future _handleMethod(MethodCall call) async {} + + @override + Future setCookie( + {required WebUri url, + required String name, + required String value, + String path = "/", + String? domain, + int? expiresDate, + int? maxAge, + bool? isSecure, + bool? isHttpOnly, + HTTPCookieSameSitePolicy? sameSite, + @Deprecated("Use webViewController instead") + PlatformInAppWebViewController? iosBelow11WebViewController, + PlatformInAppWebViewController? webViewController}) async { + webViewController = webViewController ?? iosBelow11WebViewController; + + assert(url.toString().isNotEmpty); + assert(name.isNotEmpty); + assert(value.isNotEmpty); + assert(path.isNotEmpty); + + if (await _shouldUseJavascript()) { + await _setCookieWithJavaScript( + url: url, + name: name, + value: value, + domain: domain, + path: path, + expiresDate: expiresDate, + maxAge: maxAge, + isSecure: isSecure, + sameSite: sameSite, + webViewController: webViewController); + return true; + } + + Map args = {}; + args.putIfAbsent('url', () => url.toString()); + args.putIfAbsent('name', () => name); + args.putIfAbsent('value', () => value); + args.putIfAbsent('domain', () => domain); + args.putIfAbsent('path', () => path); + args.putIfAbsent('expiresDate', () => expiresDate?.toString()); + args.putIfAbsent('maxAge', () => maxAge); + args.putIfAbsent('isSecure', () => isSecure); + args.putIfAbsent('isHttpOnly', () => isHttpOnly); + args.putIfAbsent('sameSite', () => sameSite?.toNativeValue()); + + return await channel?.invokeMethod('setCookie', args) ?? false; + } + + Future _setCookieWithJavaScript( + {required WebUri url, + required String name, + required String value, + String path = "/", + String? domain, + int? expiresDate, + int? maxAge, + bool? isSecure, + HTTPCookieSameSitePolicy? sameSite, + PlatformInAppWebViewController? webViewController}) async { + var cookieValue = name + "=" + value + "; Path=" + path; + + if (domain != null) cookieValue += "; Domain=" + domain; + + if (expiresDate != null) + cookieValue += "; Expires=" + await _getCookieExpirationDate(expiresDate); + + if (maxAge != null) cookieValue += "; Max-Age=" + maxAge.toString(); + + if (isSecure != null && isSecure) cookieValue += "; Secure"; + + if (sameSite != null) + cookieValue += "; SameSite=" + sameSite.toNativeValue(); + + cookieValue += ";"; + + if (webViewController != null) { + final javaScriptEnabled = + (await webViewController.getSettings())?.javaScriptEnabled ?? false; + if (javaScriptEnabled) { + await webViewController.evaluateJavascript( + source: 'document.cookie="$cookieValue"'); + return; + } + } + + final setCookieCompleter = Completer(); + final headlessWebView = + MacOSHeadlessInAppWebView(MacOSHeadlessInAppWebViewCreationParams( + initialUrlRequest: URLRequest(url: url), + onLoadStop: (controller, url) async { + await controller.evaluateJavascript( + source: 'document.cookie="$cookieValue"'); + setCookieCompleter.complete(); + })); + await headlessWebView.run(); + await setCookieCompleter.future; + await headlessWebView.dispose(); + } + + @override + Future> getCookies( + {required WebUri url, + @Deprecated("Use webViewController instead") + PlatformInAppWebViewController? iosBelow11WebViewController, + PlatformInAppWebViewController? webViewController}) async { + assert(url.toString().isNotEmpty); + + webViewController = webViewController ?? iosBelow11WebViewController; + + if (await _shouldUseJavascript()) { + return await _getCookiesWithJavaScript( + url: url, webViewController: webViewController); + } + + List cookies = []; + + Map args = {}; + args.putIfAbsent('url', () => url.toString()); + List cookieListMap = + await channel?.invokeMethod('getCookies', args) ?? []; + cookieListMap = cookieListMap.cast>(); + + cookieListMap.forEach((cookieMap) { + cookies.add(Cookie( + name: cookieMap["name"], + value: cookieMap["value"], + expiresDate: cookieMap["expiresDate"], + isSessionOnly: cookieMap["isSessionOnly"], + domain: cookieMap["domain"], + sameSite: + HTTPCookieSameSitePolicy.fromNativeValue(cookieMap["sameSite"]), + isSecure: cookieMap["isSecure"], + isHttpOnly: cookieMap["isHttpOnly"], + path: cookieMap["path"])); + }); + return cookies; + } + + Future> _getCookiesWithJavaScript( + {required WebUri url, + PlatformInAppWebViewController? webViewController}) async { + assert(url.toString().isNotEmpty); + + List cookies = []; + + if (webViewController != null) { + final javaScriptEnabled = + (await webViewController.getSettings())?.javaScriptEnabled ?? false; + if (javaScriptEnabled) { + List documentCookies = (await webViewController + .evaluateJavascript(source: 'document.cookie') as String) + .split(';') + .map((documentCookie) => documentCookie.trim()) + .toList(); + documentCookies.forEach((documentCookie) { + List cookie = documentCookie.split('='); + if (cookie.length > 1) { + cookies.add(Cookie( + name: cookie[0], + value: cookie[1], + )); + } + }); + return cookies; + } + } + + final pageLoaded = Completer(); + final headlessWebView = + MacOSHeadlessInAppWebView(MacOSHeadlessInAppWebViewCreationParams( + initialUrlRequest: URLRequest(url: url), + onLoadStop: (controller, url) async { + pageLoaded.complete(); + }, + )); + await headlessWebView.run(); + await pageLoaded.future; + + List documentCookies = (await headlessWebView.webViewController! + .evaluateJavascript(source: 'document.cookie') as String) + .split(';') + .map((documentCookie) => documentCookie.trim()) + .toList(); + documentCookies.forEach((documentCookie) { + List cookie = documentCookie.split('='); + if (cookie.length > 1) { + cookies.add(Cookie( + name: cookie[0], + value: cookie[1], + )); + } + }); + await headlessWebView.dispose(); + return cookies; + } + + @override + Future getCookie( + {required WebUri url, + required String name, + @Deprecated("Use webViewController instead") + PlatformInAppWebViewController? iosBelow11WebViewController, + PlatformInAppWebViewController? webViewController}) async { + assert(url.toString().isNotEmpty); + assert(name.isNotEmpty); + + webViewController = webViewController ?? iosBelow11WebViewController; + + if (await _shouldUseJavascript()) { + List cookies = await _getCookiesWithJavaScript( + url: url, webViewController: webViewController); + return cookies + .cast() + .firstWhere((cookie) => cookie!.name == name, orElse: () => null); + } + + Map args = {}; + args.putIfAbsent('url', () => url.toString()); + List cookies = + await channel?.invokeMethod('getCookies', args) ?? []; + cookies = cookies.cast>(); + for (var i = 0; i < cookies.length; i++) { + cookies[i] = cookies[i].cast(); + if (cookies[i]["name"] == name) + return Cookie( + name: cookies[i]["name"], + value: cookies[i]["value"], + expiresDate: cookies[i]["expiresDate"], + isSessionOnly: cookies[i]["isSessionOnly"], + domain: cookies[i]["domain"], + sameSite: HTTPCookieSameSitePolicy.fromNativeValue( + cookies[i]["sameSite"]), + isSecure: cookies[i]["isSecure"], + isHttpOnly: cookies[i]["isHttpOnly"], + path: cookies[i]["path"]); + } + return null; + } + + @override + Future deleteCookie( + {required WebUri url, + required String name, + String path = "/", + String? domain, + @Deprecated("Use webViewController instead") + PlatformInAppWebViewController? iosBelow11WebViewController, + PlatformInAppWebViewController? webViewController}) async { + assert(url.toString().isNotEmpty); + assert(name.isNotEmpty); + + webViewController = webViewController ?? iosBelow11WebViewController; + + if (await _shouldUseJavascript()) { + await _setCookieWithJavaScript( + url: url, + name: name, + value: "", + path: path, + domain: domain, + maxAge: -1, + webViewController: webViewController); + return; + } + + Map args = {}; + args.putIfAbsent('url', () => url.toString()); + args.putIfAbsent('name', () => name); + args.putIfAbsent('domain', () => domain); + args.putIfAbsent('path', () => path); + await channel?.invokeMethod('deleteCookie', args); + } + + @override + Future deleteCookies( + {required WebUri url, + String path = "/", + String? domain, + @Deprecated("Use webViewController instead") + PlatformInAppWebViewController? iosBelow11WebViewController, + PlatformInAppWebViewController? webViewController}) async { + assert(url.toString().isNotEmpty); + + webViewController = webViewController ?? iosBelow11WebViewController; + + if (await _shouldUseJavascript()) { + List cookies = await _getCookiesWithJavaScript( + url: url, webViewController: webViewController); + for (var i = 0; i < cookies.length; i++) { + await _setCookieWithJavaScript( + url: url, + name: cookies[i].name, + value: "", + path: path, + domain: domain, + maxAge: -1, + webViewController: webViewController); + } + return; + } + + Map args = {}; + args.putIfAbsent('url', () => url.toString()); + args.putIfAbsent('domain', () => domain); + args.putIfAbsent('path', () => path); + await channel?.invokeMethod('deleteCookies', args); + } + + @override + Future deleteAllCookies() async { + Map args = {}; + await channel?.invokeMethod('deleteAllCookies', args); + } + + @override + Future> getAllCookies() async { + List cookies = []; + + Map args = {}; + List cookieListMap = + await channel?.invokeMethod('getAllCookies', args) ?? []; + cookieListMap = cookieListMap.cast>(); + + cookieListMap.forEach((cookieMap) { + cookies.add(Cookie( + name: cookieMap["name"], + value: cookieMap["value"], + expiresDate: cookieMap["expiresDate"], + isSessionOnly: cookieMap["isSessionOnly"], + domain: cookieMap["domain"], + sameSite: + HTTPCookieSameSitePolicy.fromNativeValue(cookieMap["sameSite"]), + isSecure: cookieMap["isSecure"], + isHttpOnly: cookieMap["isHttpOnly"], + path: cookieMap["path"])); + }); + return cookies; + } + + Future _getCookieExpirationDate(int expiresDate) async { + var platformUtil = PlatformUtil.instance(); + var dateTime = DateTime.fromMillisecondsSinceEpoch(expiresDate).toUtc(); + return !kIsWeb + ? await platformUtil.formatDate( + date: dateTime, + format: 'EEE, dd MMM yyyy hh:mm:ss z', + locale: 'en_US', + timezone: 'GMT') + : await platformUtil.getWebCookieExpirationDate(date: dateTime); + } + + Future _shouldUseJavascript() async { + if (Util.isMacOS || Util.isMacOS) { + final platformUtil = PlatformUtil.instance(); + final systemVersion = await platformUtil.getSystemVersion(); + return Util.isMacOS + ? systemVersion.compareTo("11") == -1 + : systemVersion.compareTo("10.13") == -1; + } + return false; + } + + @override + void dispose() { + // empty + } +} + +extension InternalCookieManager on MacOSCookieManager { + get handleMethod => _handleMethod; +} diff --git a/flutter_inappwebview_macos/lib/src/find_interaction/find_interaction_controller.dart b/flutter_inappwebview_macos/lib/src/find_interaction/find_interaction_controller.dart new file mode 100644 index 00000000..e8810f26 --- /dev/null +++ b/flutter_inappwebview_macos/lib/src/find_interaction/find_interaction_controller.dart @@ -0,0 +1,125 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; + +/// Object specifying creation parameters for creating a [MacOSFindInteractionController]. +/// +/// When adding additional fields make sure they can be null or have a default +/// value to avoid breaking changes. See [PlatformFindInteractionControllerCreationParams] for +/// more information. +@immutable +class MacOSFindInteractionControllerCreationParams + extends PlatformFindInteractionControllerCreationParams { + /// Creates a new [MacOSFindInteractionControllerCreationParams] instance. + const MacOSFindInteractionControllerCreationParams( + {super.onFindResultReceived}); + + /// Creates a [MacOSFindInteractionControllerCreationParams] instance based on [PlatformFindInteractionControllerCreationParams]. + factory MacOSFindInteractionControllerCreationParams.fromPlatformFindInteractionControllerCreationParams( + // Recommended placeholder to prevent being broken by platform interface. + // ignore: avoid_unused_constructor_parameters + PlatformFindInteractionControllerCreationParams params) { + return MacOSFindInteractionControllerCreationParams( + onFindResultReceived: params.onFindResultReceived); + } +} + +///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController} +class MacOSFindInteractionController extends PlatformFindInteractionController + with ChannelController { + /// Constructs a [MacOSFindInteractionController]. + MacOSFindInteractionController( + PlatformFindInteractionControllerCreationParams params) + : super.implementation( + params is MacOSFindInteractionControllerCreationParams + ? params + : MacOSFindInteractionControllerCreationParams + .fromPlatformFindInteractionControllerCreationParams(params), + ); + + _debugLog(String method, dynamic args) { + debugLog( + className: this.runtimeType.toString(), + debugLoggingSettings: + PlatformFindInteractionController.debugLoggingSettings, + method: method, + args: args); + } + + Future _handleMethod(MethodCall call) async { + _debugLog(call.method, call.arguments); + + switch (call.method) { + case "onFindResultReceived": + if (onFindResultReceived != null) { + int activeMatchOrdinal = call.arguments["activeMatchOrdinal"]; + int numberOfMatches = call.arguments["numberOfMatches"]; + bool isDoneCounting = call.arguments["isDoneCounting"]; + onFindResultReceived!( + this, activeMatchOrdinal, numberOfMatches, isDoneCounting); + } + break; + default: + throw UnimplementedError("Unimplemented ${call.method} method"); + } + return null; + } + + ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.findAll} + Future findAll({String? find}) async { + Map args = {}; + args.putIfAbsent('find', () => find); + await channel?.invokeMethod('findAll', args); + } + + ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.findNext} + Future findNext({bool forward = true}) async { + Map args = {}; + args.putIfAbsent('forward', () => forward); + await channel?.invokeMethod('findNext', args); + } + + ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.clearMatches} + Future clearMatches() async { + Map args = {}; + await channel?.invokeMethod('clearMatches', args); + } + + ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.setSearchText} + Future setSearchText(String? searchText) async { + Map args = {}; + args.putIfAbsent('searchText', () => searchText); + await channel?.invokeMethod('setSearchText', args); + } + + ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.getSearchText} + Future getSearchText() async { + Map args = {}; + return await channel?.invokeMethod('getSearchText', args); + } + + ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.getActiveFindSession} + Future getActiveFindSession() async { + Map args = {}; + Map? result = + (await channel?.invokeMethod('getActiveFindSession', args)) + ?.cast(); + return FindSession.fromMap(result); + } + + ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.dispose} + @override + void dispose({bool isKeepAlive = false}) { + disposeChannel(removeMethodCallHandler: !isKeepAlive); + } +} + +extension InternalFindInteractionController + on MacOSFindInteractionController { + void init(dynamic id) { + channel = MethodChannel( + 'com.pichillilorenzo/flutter_inappwebview_find_interaction_$id'); + handler = _handleMethod; + initMethodCallHandler(); + } +} diff --git a/flutter_inappwebview_macos/lib/src/find_interaction/main.dart b/flutter_inappwebview_macos/lib/src/find_interaction/main.dart new file mode 100644 index 00000000..a7adaacf --- /dev/null +++ b/flutter_inappwebview_macos/lib/src/find_interaction/main.dart @@ -0,0 +1,2 @@ +export 'find_interaction_controller.dart' + hide InternalFindInteractionController; diff --git a/flutter_inappwebview_macos/lib/src/http_auth_credentials_database.dart b/flutter_inappwebview_macos/lib/src/http_auth_credentials_database.dart new file mode 100755 index 00000000..4b07865c --- /dev/null +++ b/flutter_inappwebview_macos/lib/src/http_auth_credentials_database.dart @@ -0,0 +1,155 @@ +import 'dart:async'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; + +/// Object specifying creation parameters for creating a [MacOSHttpAuthCredentialDatabase]. +/// +/// When adding additional fields make sure they can be null or have a default +/// value to avoid breaking changes. See [PlatformHttpAuthCredentialDatabaseCreationParams] for +/// more information. +@immutable +class MacOSHttpAuthCredentialDatabaseCreationParams + extends PlatformHttpAuthCredentialDatabaseCreationParams { + /// Creates a new [MacOSHttpAuthCredentialDatabaseCreationParams] instance. + const MacOSHttpAuthCredentialDatabaseCreationParams( + // This parameter prevents breaking changes later. + // ignore: avoid_unused_constructor_parameters + PlatformHttpAuthCredentialDatabaseCreationParams params, + ) : super(); + + /// Creates a [MacOSHttpAuthCredentialDatabaseCreationParams] instance based on [PlatformHttpAuthCredentialDatabaseCreationParams]. + factory MacOSHttpAuthCredentialDatabaseCreationParams.fromPlatformHttpAuthCredentialDatabaseCreationParams( + PlatformHttpAuthCredentialDatabaseCreationParams params) { + return MacOSHttpAuthCredentialDatabaseCreationParams(params); + } +} + +///{@macro flutter_inappwebview_platform_interface.PlatformHttpAuthCredentialDatabase} +class MacOSHttpAuthCredentialDatabase + extends PlatformHttpAuthCredentialDatabase with ChannelController { + /// Creates a new [MacOSHttpAuthCredentialDatabase]. + MacOSHttpAuthCredentialDatabase( + PlatformHttpAuthCredentialDatabaseCreationParams params) + : super.implementation( + params is MacOSHttpAuthCredentialDatabaseCreationParams + ? params + : MacOSHttpAuthCredentialDatabaseCreationParams + .fromPlatformHttpAuthCredentialDatabaseCreationParams(params), + ) { + channel = const MethodChannel( + 'com.pichillilorenzo/flutter_inappwebview_credential_database'); + handler = handleMethod; + initMethodCallHandler(); + } + + static MacOSHttpAuthCredentialDatabase? _instance; + + ///Gets the database shared instance. + static MacOSHttpAuthCredentialDatabase instance() { + return (_instance != null) ? _instance! : _init(); + } + + static MacOSHttpAuthCredentialDatabase _init() { + _instance = MacOSHttpAuthCredentialDatabase( + MacOSHttpAuthCredentialDatabaseCreationParams( + const PlatformHttpAuthCredentialDatabaseCreationParams())); + return _instance!; + } + + Future _handleMethod(MethodCall call) async {} + + @override + Future> + getAllAuthCredentials() async { + Map args = {}; + List allCredentials = + await channel?.invokeMethod('getAllAuthCredentials', args) ?? []; + + List result = []; + + for (Map map in allCredentials) { + var element = URLProtectionSpaceHttpAuthCredentials.fromMap( + map.cast()); + if (element != null) { + result.add(element); + } + } + return result; + } + + @override + Future> getHttpAuthCredentials( + {required URLProtectionSpace protectionSpace}) async { + Map args = {}; + args.putIfAbsent("host", () => protectionSpace.host); + args.putIfAbsent("protocol", () => protectionSpace.protocol); + args.putIfAbsent("realm", () => protectionSpace.realm); + args.putIfAbsent("port", () => protectionSpace.port); + List credentialList = + await channel?.invokeMethod('getHttpAuthCredentials', args) ?? []; + List credentials = []; + for (Map map in credentialList) { + var credential = URLCredential.fromMap(map.cast()); + if (credential != null) { + credentials.add(credential); + } + } + return credentials; + } + + @override + Future setHttpAuthCredential( + {required URLProtectionSpace protectionSpace, + required URLCredential credential}) async { + Map args = {}; + args.putIfAbsent("host", () => protectionSpace.host); + args.putIfAbsent("protocol", () => protectionSpace.protocol); + args.putIfAbsent("realm", () => protectionSpace.realm); + args.putIfAbsent("port", () => protectionSpace.port); + args.putIfAbsent("username", () => credential.username); + args.putIfAbsent("password", () => credential.password); + await channel?.invokeMethod('setHttpAuthCredential', args); + } + + @override + Future removeHttpAuthCredential( + {required URLProtectionSpace protectionSpace, + required URLCredential credential}) async { + Map args = {}; + args.putIfAbsent("host", () => protectionSpace.host); + args.putIfAbsent("protocol", () => protectionSpace.protocol); + args.putIfAbsent("realm", () => protectionSpace.realm); + args.putIfAbsent("port", () => protectionSpace.port); + args.putIfAbsent("username", () => credential.username); + args.putIfAbsent("password", () => credential.password); + await channel?.invokeMethod('removeHttpAuthCredential', args); + } + + @override + Future removeHttpAuthCredentials( + {required URLProtectionSpace protectionSpace}) async { + Map args = {}; + args.putIfAbsent("host", () => protectionSpace.host); + args.putIfAbsent("protocol", () => protectionSpace.protocol); + args.putIfAbsent("realm", () => protectionSpace.realm); + args.putIfAbsent("port", () => protectionSpace.port); + await channel?.invokeMethod('removeHttpAuthCredentials', args); + } + + @override + Future clearAllAuthCredentials() async { + Map args = {}; + await channel?.invokeMethod('clearAllAuthCredentials', args); + } + + @override + void dispose() { + // empty + } +} + +extension InternalHttpAuthCredentialDatabase + on MacOSHttpAuthCredentialDatabase { + get handleMethod => _handleMethod; +} diff --git a/flutter_inappwebview_macos/lib/src/in_app_browser/in_app_browser.dart b/flutter_inappwebview_macos/lib/src/in_app_browser/in_app_browser.dart new file mode 100755 index 00000000..19b360b6 --- /dev/null +++ b/flutter_inappwebview_macos/lib/src/in_app_browser/in_app_browser.dart @@ -0,0 +1,369 @@ +import 'dart:async'; +import 'dart:collection'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; + +import '../find_interaction/find_interaction_controller.dart'; +import '../in_app_webview/in_app_webview_controller.dart'; + +/// Object specifying creation parameters for creating a [MacOSInAppBrowser]. +/// +/// When adding additional fields make sure they can be null or have a default +/// value to avoid breaking changes. See [PlatformInAppBrowserCreationParams] for +/// more information. +class MacOSInAppBrowserCreationParams + extends PlatformInAppBrowserCreationParams { + /// Creates a new [MacOSInAppBrowserCreationParams] instance. + MacOSInAppBrowserCreationParams( + {super.contextMenu, + super.pullToRefreshController, + this.findInteractionController, + super.initialUserScripts, + super.windowId}); + + /// Creates a [MacOSInAppBrowserCreationParams] instance based on [PlatformInAppBrowserCreationParams]. + factory MacOSInAppBrowserCreationParams.fromPlatformInAppBrowserCreationParams( + // Recommended placeholder to prevent being broken by platform interface. + // ignore: avoid_unused_constructor_parameters + PlatformInAppBrowserCreationParams params) { + return MacOSInAppBrowserCreationParams( + contextMenu: params.contextMenu, + pullToRefreshController: params.pullToRefreshController, + findInteractionController: params.findInteractionController + as MacOSFindInteractionController?, + initialUserScripts: params.initialUserScripts, + windowId: params.windowId); + } + + @override + final MacOSFindInteractionController? findInteractionController; +} + +///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser} +class MacOSInAppBrowser extends PlatformInAppBrowser with ChannelController { + @override + final String id = IdGenerator.generate(); + + /// Constructs a [MacOSInAppBrowser]. + MacOSInAppBrowser(PlatformInAppBrowserCreationParams params) + : super.implementation( + params is MacOSInAppBrowserCreationParams + ? params + : MacOSInAppBrowserCreationParams + .fromPlatformInAppBrowserCreationParams(params), + ) { + _contextMenu = params.contextMenu; + } + + static final MacOSInAppBrowser _staticValue = + MacOSInAppBrowser(MacOSInAppBrowserCreationParams()); + + /// Provide static access. + factory MacOSInAppBrowser.static() { + return _staticValue; + } + + MacOSInAppBrowserCreationParams get _iosParams => + params as MacOSInAppBrowserCreationParams; + + static const MethodChannel _staticChannel = + const MethodChannel('com.pichillilorenzo/flutter_inappbrowser'); + + ContextMenu? _contextMenu; + + @override + ContextMenu? get contextMenu => _contextMenu; + + Map _menuItems = HashMap(); + bool _isOpened = false; + MacOSInAppWebViewController? _webViewController; + + @override + MacOSInAppWebViewController? get webViewController { + return _isOpened ? _webViewController : null; + } + + _init() { + channel = MethodChannel('com.pichillilorenzo/flutter_inappbrowser_$id'); + handler = _handleMethod; + initMethodCallHandler(); + + _webViewController = MacOSInAppWebViewController.fromInAppBrowser( + MacOSInAppWebViewControllerCreationParams(id: id), + channel!, + this, + this.initialUserScripts); + _iosParams.findInteractionController?.init(id); + } + + _debugLog(String method, dynamic args) { + debugLog( + className: this.runtimeType.toString(), + id: id, + debugLoggingSettings: PlatformInAppBrowser.debugLoggingSettings, + method: method, + args: args); + } + + Future _handleMethod(MethodCall call) async { + switch (call.method) { + case "onBrowserCreated": + _debugLog(call.method, call.arguments); + eventHandler?.onBrowserCreated(); + break; + case "onMenuItemClicked": + _debugLog(call.method, call.arguments); + int id = call.arguments["id"].toInt(); + if (this._menuItems[id] != null) { + if (this._menuItems[id]?.onClick != null) { + this._menuItems[id]?.onClick!(); + } + } + break; + case "onExit": + _debugLog(call.method, call.arguments); + _isOpened = false; + final onExit = eventHandler?.onExit; + dispose(); + onExit?.call(); + break; + default: + return _webViewController?.handleMethod(call); + } + } + + Map _prepareOpenRequest( + {@Deprecated('Use settings instead') InAppBrowserClassOptions? options, + InAppBrowserClassSettings? settings}) { + assert(!_isOpened, 'The browser is already opened.'); + _isOpened = true; + _init(); + + var initialSettings = settings?.toMap() ?? + options?.toMap() ?? + InAppBrowserClassSettings().toMap(); + + Map pullToRefreshSettings = + pullToRefreshController?.settings.toMap() ?? + pullToRefreshController?.options.toMap() ?? + PullToRefreshSettings(enabled: false).toMap(); + + List> menuItemList = []; + _menuItems.forEach((key, value) { + menuItemList.add(value.toMap()); + }); + + Map args = {}; + args.putIfAbsent('id', () => id); + args.putIfAbsent('settings', () => initialSettings); + args.putIfAbsent('contextMenu', () => contextMenu?.toMap() ?? {}); + args.putIfAbsent('windowId', () => windowId); + args.putIfAbsent('initialUserScripts', + () => initialUserScripts?.map((e) => e.toMap()).toList() ?? []); + args.putIfAbsent('pullToRefreshSettings', () => pullToRefreshSettings); + args.putIfAbsent('menuItems', () => menuItemList); + return args; + } + + @override + Future openUrlRequest( + {required URLRequest urlRequest, + // ignore: deprecated_member_use_from_same_package + @Deprecated('Use settings instead') InAppBrowserClassOptions? options, + InAppBrowserClassSettings? settings}) async { + assert(urlRequest.url != null && urlRequest.url.toString().isNotEmpty); + + Map args = + _prepareOpenRequest(options: options, settings: settings); + args.putIfAbsent('urlRequest', () => urlRequest.toMap()); + await _staticChannel.invokeMethod('open', args); + } + + @override + Future openFile( + {required String assetFilePath, + // ignore: deprecated_member_use_from_same_package + @Deprecated('Use settings instead') InAppBrowserClassOptions? options, + InAppBrowserClassSettings? settings}) async { + assert(assetFilePath.isNotEmpty); + + Map args = + _prepareOpenRequest(options: options, settings: settings); + args.putIfAbsent('assetFilePath', () => assetFilePath); + await _staticChannel.invokeMethod('open', args); + } + + @override + Future openData( + {required String data, + String mimeType = "text/html", + String encoding = "utf8", + WebUri? baseUrl, + @Deprecated("Use historyUrl instead") Uri? androidHistoryUrl, + WebUri? historyUrl, + // ignore: deprecated_member_use_from_same_package + @Deprecated('Use settings instead') InAppBrowserClassOptions? options, + InAppBrowserClassSettings? settings}) async { + Map args = + _prepareOpenRequest(options: options, settings: settings); + args.putIfAbsent('data', () => data); + args.putIfAbsent('mimeType', () => mimeType); + args.putIfAbsent('encoding', () => encoding); + args.putIfAbsent('baseUrl', () => baseUrl?.toString() ?? "about:blank"); + args.putIfAbsent('historyUrl', + () => (historyUrl ?? androidHistoryUrl)?.toString() ?? "about:blank"); + await _staticChannel.invokeMethod('open', args); + } + + @override + Future openWithSystemBrowser({required WebUri url}) async { + assert(url.toString().isNotEmpty); + + Map args = {}; + args.putIfAbsent('url', () => url.toString()); + return await _staticChannel.invokeMethod('openWithSystemBrowser', args); + } + + @override + void addMenuItem(InAppBrowserMenuItem menuItem) { + _menuItems[menuItem.id] = menuItem; + } + + @override + void addMenuItems(List menuItems) { + menuItems.forEach((menuItem) { + _menuItems[menuItem.id] = menuItem; + }); + } + + @override + bool removeMenuItem(InAppBrowserMenuItem menuItem) { + return _menuItems.remove(menuItem.id) != null; + } + + @override + void removeMenuItems(List menuItems) { + for (final menuItem in menuItems) { + removeMenuItem(menuItem); + } + } + + @override + void removeAllMenuItem() { + _menuItems.clear(); + } + + @override + bool hasMenuItem(InAppBrowserMenuItem menuItem) { + return _menuItems.containsKey(menuItem.id); + } + + @override + Future show() async { + assert(_isOpened, 'The browser is not opened.'); + + Map args = {}; + await channel?.invokeMethod('show', args); + } + + @override + Future hide() async { + assert(_isOpened, 'The browser is not opened.'); + + Map args = {}; + await channel?.invokeMethod('hide', args); + } + + @override + Future close() async { + assert(_isOpened, 'The browser is not opened.'); + + Map args = {}; + await channel?.invokeMethod('close', args); + } + + @override + Future isHidden() async { + assert(_isOpened, 'The browser is not opened.'); + + Map args = {}; + return await channel?.invokeMethod('isHidden', args) ?? false; + } + + @override + @Deprecated('Use setSettings instead') + Future setOptions({required InAppBrowserClassOptions options}) async { + assert(_isOpened, 'The browser is not opened.'); + + Map args = {}; + args.putIfAbsent('settings', () => options.toMap()); + await channel?.invokeMethod('setSettings', args); + } + + @override + @Deprecated('Use getSettings instead') + Future getOptions() async { + assert(_isOpened, 'The browser is not opened.'); + Map args = {}; + + Map? options = + await channel?.invokeMethod('getSettings', args); + if (options != null) { + options = options.cast(); + return InAppBrowserClassOptions.fromMap(options as Map); + } + + return null; + } + + @override + Future setSettings( + {required InAppBrowserClassSettings settings}) async { + assert(_isOpened, 'The browser is not opened.'); + + Map args = {}; + args.putIfAbsent('settings', () => settings.toMap()); + await channel?.invokeMethod('setSettings', args); + } + + @override + Future getSettings() async { + assert(_isOpened, 'The browser is not opened.'); + + Map args = {}; + + Map? settings = + await channel?.invokeMethod('getSettings', args); + if (settings != null) { + settings = settings.cast(); + return InAppBrowserClassSettings.fromMap( + settings as Map); + } + + return null; + } + + @override + bool isOpened() { + return this._isOpened; + } + + @override + @mustCallSuper + void dispose() { + disposeChannel(); + _webViewController?.dispose(); + _webViewController = null; + pullToRefreshController?.dispose(); + findInteractionController?.dispose(); + eventHandler = null; + } +} + +extension InternalInAppBrowser on MacOSInAppBrowser { + void setContextMenu(ContextMenu? contextMenu) { + _contextMenu = contextMenu; + } +} diff --git a/flutter_inappwebview_macos/lib/src/in_app_browser/main.dart b/flutter_inappwebview_macos/lib/src/in_app_browser/main.dart new file mode 100644 index 00000000..e11eb8b1 --- /dev/null +++ b/flutter_inappwebview_macos/lib/src/in_app_browser/main.dart @@ -0,0 +1 @@ +export 'in_app_browser.dart' hide InternalInAppBrowser; diff --git a/flutter_inappwebview_macos/lib/src/in_app_webview/_static_channel.dart b/flutter_inappwebview_macos/lib/src/in_app_webview/_static_channel.dart new file mode 100644 index 00000000..beb7de70 --- /dev/null +++ b/flutter_inappwebview_macos/lib/src/in_app_webview/_static_channel.dart @@ -0,0 +1,4 @@ +import 'package:flutter/services.dart'; + +const IN_APP_WEBVIEW_STATIC_CHANNEL = + MethodChannel('com.pichillilorenzo/flutter_inappwebview_manager'); diff --git a/flutter_inappwebview_macos/lib/src/in_app_webview/headless_in_app_webview.dart b/flutter_inappwebview_macos/lib/src/in_app_webview/headless_in_app_webview.dart new file mode 100644 index 00000000..13d09f59 --- /dev/null +++ b/flutter_inappwebview_macos/lib/src/in_app_webview/headless_in_app_webview.dart @@ -0,0 +1,434 @@ +import 'dart:ui'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; +import '../find_interaction/find_interaction_controller.dart'; +import 'in_app_webview_controller.dart'; + +/// Object specifying creation parameters for creating a [MacOSCookieManager]. +/// +/// When adding additional fields make sure they can be null or have a default +/// value to avoid breaking changes. See [PlatformHeadlessInAppWebViewCreationParams] for +/// more information. +@immutable +class MacOSHeadlessInAppWebViewCreationParams + extends PlatformHeadlessInAppWebViewCreationParams { + /// Creates a new [MacOSHeadlessInAppWebViewCreationParams] instance. + MacOSHeadlessInAppWebViewCreationParams( + {super.controllerFromPlatform, + super.initialSize, + super.windowId, + super.onWebViewCreated, + super.onLoadStart, + super.onLoadStop, + @Deprecated('Use onReceivedError instead') super.onLoadError, + super.onReceivedError, + @Deprecated("Use onReceivedHttpError instead") super.onLoadHttpError, + super.onReceivedHttpError, + super.onProgressChanged, + super.onConsoleMessage, + super.shouldOverrideUrlLoading, + super.onLoadResource, + super.onScrollChanged, + @Deprecated('Use onDownloadStartRequest instead') super.onDownloadStart, + super.onDownloadStartRequest, + @Deprecated('Use onLoadResourceWithCustomScheme instead') + super.onLoadResourceCustomScheme, + super.onLoadResourceWithCustomScheme, + super.onCreateWindow, + super.onCloseWindow, + super.onJsAlert, + super.onJsConfirm, + super.onJsPrompt, + super.onReceivedHttpAuthRequest, + super.onReceivedServerTrustAuthRequest, + super.onReceivedClientCertRequest, + @Deprecated('Use FindInteractionController.onFindResultReceived instead') + super.onFindResultReceived, + super.shouldInterceptAjaxRequest, + super.onAjaxReadyStateChange, + super.onAjaxProgress, + super.shouldInterceptFetchRequest, + super.onUpdateVisitedHistory, + @Deprecated("Use onPrintRequest instead") super.onPrint, + super.onPrintRequest, + super.onLongPressHitTestResult, + super.onEnterFullscreen, + super.onExitFullscreen, + super.onPageCommitVisible, + super.onTitleChanged, + super.onWindowFocus, + super.onWindowBlur, + super.onOverScrolled, + super.onZoomScaleChanged, + @Deprecated('Use onSafeBrowsingHit instead') + super.androidOnSafeBrowsingHit, + super.onSafeBrowsingHit, + @Deprecated('Use onPermissionRequest instead') + super.androidOnPermissionRequest, + super.onPermissionRequest, + @Deprecated('Use onGeolocationPermissionsShowPrompt instead') + super.androidOnGeolocationPermissionsShowPrompt, + super.onGeolocationPermissionsShowPrompt, + @Deprecated('Use onGeolocationPermissionsHidePrompt instead') + super.androidOnGeolocationPermissionsHidePrompt, + super.onGeolocationPermissionsHidePrompt, + @Deprecated('Use shouldInterceptRequest instead') + super.androidShouldInterceptRequest, + super.shouldInterceptRequest, + @Deprecated('Use onRenderProcessGone instead') + super.androidOnRenderProcessGone, + super.onRenderProcessGone, + @Deprecated('Use onRenderProcessResponsive instead') + super.androidOnRenderProcessResponsive, + super.onRenderProcessResponsive, + @Deprecated('Use onRenderProcessUnresponsive instead') + super.androidOnRenderProcessUnresponsive, + super.onRenderProcessUnresponsive, + @Deprecated('Use onFormResubmission instead') + super.androidOnFormResubmission, + super.onFormResubmission, + @Deprecated('Use onZoomScaleChanged instead') super.androidOnScaleChanged, + @Deprecated('Use onReceivedIcon instead') super.androidOnReceivedIcon, + super.onReceivedIcon, + @Deprecated('Use onReceivedTouchIconUrl instead') + super.androidOnReceivedTouchIconUrl, + super.onReceivedTouchIconUrl, + @Deprecated('Use onJsBeforeUnload instead') super.androidOnJsBeforeUnload, + super.onJsBeforeUnload, + @Deprecated('Use onReceivedLoginRequest instead') + super.androidOnReceivedLoginRequest, + super.onReceivedLoginRequest, + super.onPermissionRequestCanceled, + super.onRequestFocus, + @Deprecated('Use onWebContentProcessDidTerminate instead') + super.iosOnWebContentProcessDidTerminate, + super.onWebContentProcessDidTerminate, + @Deprecated( + 'Use onDidReceiveServerRedirectForProvisionalNavigation instead') + super.iosOnDidReceiveServerRedirectForProvisionalNavigation, + super.onDidReceiveServerRedirectForProvisionalNavigation, + @Deprecated('Use onNavigationResponse instead') + super.iosOnNavigationResponse, + super.onNavigationResponse, + @Deprecated('Use shouldAllowDeprecatedTLS instead') + super.iosShouldAllowDeprecatedTLS, + super.shouldAllowDeprecatedTLS, + super.onCameraCaptureStateChanged, + super.onMicrophoneCaptureStateChanged, + super.onContentSizeChanged, + super.initialUrlRequest, + super.initialFile, + super.initialData, + @Deprecated('Use initialSettings instead') super.initialOptions, + super.initialSettings, + super.contextMenu, + super.initialUserScripts, + super.pullToRefreshController, + this.findInteractionController}); + + /// Creates a [MacOSHeadlessInAppWebViewCreationParams] instance based on [PlatformHeadlessInAppWebViewCreationParams]. + MacOSHeadlessInAppWebViewCreationParams.fromPlatformHeadlessInAppWebViewCreationParams( + PlatformHeadlessInAppWebViewCreationParams params) + : this( + controllerFromPlatform: params.controllerFromPlatform, + initialSize: params.initialSize, + windowId: params.windowId, + onWebViewCreated: params.onWebViewCreated, + onLoadStart: params.onLoadStart, + onLoadStop: params.onLoadStop, + onLoadError: params.onLoadError, + onReceivedError: params.onReceivedError, + onLoadHttpError: params.onLoadHttpError, + onReceivedHttpError: params.onReceivedHttpError, + onProgressChanged: params.onProgressChanged, + onConsoleMessage: params.onConsoleMessage, + shouldOverrideUrlLoading: params.shouldOverrideUrlLoading, + onLoadResource: params.onLoadResource, + onScrollChanged: params.onScrollChanged, + onDownloadStart: params.onDownloadStart, + onDownloadStartRequest: params.onDownloadStartRequest, + onLoadResourceCustomScheme: params.onLoadResourceCustomScheme, + onLoadResourceWithCustomScheme: + params.onLoadResourceWithCustomScheme, + onCreateWindow: params.onCreateWindow, + onCloseWindow: params.onCloseWindow, + onJsAlert: params.onJsAlert, + onJsConfirm: params.onJsConfirm, + onJsPrompt: params.onJsPrompt, + onReceivedHttpAuthRequest: params.onReceivedHttpAuthRequest, + onReceivedServerTrustAuthRequest: + params.onReceivedServerTrustAuthRequest, + onReceivedClientCertRequest: params.onReceivedClientCertRequest, + onFindResultReceived: params.onFindResultReceived, + shouldInterceptAjaxRequest: params.shouldInterceptAjaxRequest, + onAjaxReadyStateChange: params.onAjaxReadyStateChange, + onAjaxProgress: params.onAjaxProgress, + shouldInterceptFetchRequest: params.shouldInterceptFetchRequest, + onUpdateVisitedHistory: params.onUpdateVisitedHistory, + onPrint: params.onPrint, + onPrintRequest: params.onPrintRequest, + onLongPressHitTestResult: params.onLongPressHitTestResult, + onEnterFullscreen: params.onEnterFullscreen, + onExitFullscreen: params.onExitFullscreen, + onPageCommitVisible: params.onPageCommitVisible, + onTitleChanged: params.onTitleChanged, + onWindowFocus: params.onWindowFocus, + onWindowBlur: params.onWindowBlur, + onOverScrolled: params.onOverScrolled, + onZoomScaleChanged: params.onZoomScaleChanged, + androidOnSafeBrowsingHit: params.androidOnSafeBrowsingHit, + onSafeBrowsingHit: params.onSafeBrowsingHit, + androidOnPermissionRequest: params.androidOnPermissionRequest, + onPermissionRequest: params.onPermissionRequest, + androidOnGeolocationPermissionsShowPrompt: + params.androidOnGeolocationPermissionsShowPrompt, + onGeolocationPermissionsShowPrompt: + params.onGeolocationPermissionsShowPrompt, + androidOnGeolocationPermissionsHidePrompt: + params.androidOnGeolocationPermissionsHidePrompt, + onGeolocationPermissionsHidePrompt: + params.onGeolocationPermissionsHidePrompt, + androidShouldInterceptRequest: params.androidShouldInterceptRequest, + shouldInterceptRequest: params.shouldInterceptRequest, + androidOnRenderProcessGone: params.androidOnRenderProcessGone, + onRenderProcessGone: params.onRenderProcessGone, + androidOnRenderProcessResponsive: + params.androidOnRenderProcessResponsive, + onRenderProcessResponsive: params.onRenderProcessResponsive, + androidOnRenderProcessUnresponsive: + params.androidOnRenderProcessUnresponsive, + onRenderProcessUnresponsive: params.onRenderProcessUnresponsive, + androidOnFormResubmission: params.androidOnFormResubmission, + onFormResubmission: params.onFormResubmission, + androidOnScaleChanged: params.androidOnScaleChanged, + androidOnReceivedIcon: params.androidOnReceivedIcon, + onReceivedIcon: params.onReceivedIcon, + androidOnReceivedTouchIconUrl: params.androidOnReceivedTouchIconUrl, + onReceivedTouchIconUrl: params.onReceivedTouchIconUrl, + androidOnJsBeforeUnload: params.androidOnJsBeforeUnload, + onJsBeforeUnload: params.onJsBeforeUnload, + androidOnReceivedLoginRequest: params.androidOnReceivedLoginRequest, + onReceivedLoginRequest: params.onReceivedLoginRequest, + onPermissionRequestCanceled: params.onPermissionRequestCanceled, + onRequestFocus: params.onRequestFocus, + iosOnWebContentProcessDidTerminate: + params.iosOnWebContentProcessDidTerminate, + onWebContentProcessDidTerminate: + params.onWebContentProcessDidTerminate, + iosOnDidReceiveServerRedirectForProvisionalNavigation: + params.iosOnDidReceiveServerRedirectForProvisionalNavigation, + onDidReceiveServerRedirectForProvisionalNavigation: + params.onDidReceiveServerRedirectForProvisionalNavigation, + iosOnNavigationResponse: params.iosOnNavigationResponse, + onNavigationResponse: params.onNavigationResponse, + iosShouldAllowDeprecatedTLS: params.iosShouldAllowDeprecatedTLS, + shouldAllowDeprecatedTLS: params.shouldAllowDeprecatedTLS, + onCameraCaptureStateChanged: params.onCameraCaptureStateChanged, + onMicrophoneCaptureStateChanged: + params.onMicrophoneCaptureStateChanged, + onContentSizeChanged: params.onContentSizeChanged, + initialUrlRequest: params.initialUrlRequest, + initialFile: params.initialFile, + initialData: params.initialData, + initialOptions: params.initialOptions, + initialSettings: params.initialSettings, + contextMenu: params.contextMenu, + initialUserScripts: params.initialUserScripts, + pullToRefreshController: params.pullToRefreshController, + findInteractionController: params.findInteractionController + as MacOSFindInteractionController?); + + @override + final MacOSFindInteractionController? findInteractionController; +} + +///{@macro flutter_inappwebview_platform_interface.PlatformHeadlessInAppWebView} +class MacOSHeadlessInAppWebView extends PlatformHeadlessInAppWebView + with ChannelController { + @override + late final String id; + + bool _started = false; + bool _running = false; + + static const MethodChannel _sharedChannel = + const MethodChannel('com.pichillilorenzo/flutter_headless_inappwebview'); + + MacOSInAppWebViewController? _webViewController; + + /// Constructs a [MacOSHeadlessInAppWebView]. + MacOSHeadlessInAppWebView(PlatformHeadlessInAppWebViewCreationParams params) + : super.implementation( + params is MacOSHeadlessInAppWebViewCreationParams + ? params + : MacOSHeadlessInAppWebViewCreationParams + .fromPlatformHeadlessInAppWebViewCreationParams(params), + ) { + id = IdGenerator.generate(); + } + + @override + MacOSInAppWebViewController? get webViewController => _webViewController; + + dynamic _controllerFromPlatform; + + MacOSHeadlessInAppWebViewCreationParams get _iosParams => + params as MacOSHeadlessInAppWebViewCreationParams; + + _init() { + _webViewController = MacOSInAppWebViewController( + MacOSInAppWebViewControllerCreationParams( + id: id, webviewParams: params), + ); + _controllerFromPlatform = + params.controllerFromPlatform?.call(_webViewController!) ?? + _webViewController!; + _iosParams.findInteractionController?.init(id); + channel = + MethodChannel('com.pichillilorenzo/flutter_headless_inappwebview_$id'); + handler = _handleMethod; + initMethodCallHandler(); + } + + Future _handleMethod(MethodCall call) async { + switch (call.method) { + case "onWebViewCreated": + if (params.onWebViewCreated != null && _webViewController != null) { + params.onWebViewCreated!(_controllerFromPlatform); + } + break; + default: + throw UnimplementedError("Unimplemented ${call.method} method"); + } + return null; + } + + Future run() async { + if (_started) { + return; + } + _started = true; + _init(); + + final initialSettings = params.initialSettings ?? InAppWebViewSettings(); + _inferInitialSettings(initialSettings); + + Map settingsMap = + (params.initialSettings != null ? initialSettings.toMap() : null) ?? + params.initialOptions?.toMap() ?? + initialSettings.toMap(); + + Map pullToRefreshSettings = + _iosParams.pullToRefreshController?.params.settings.toMap() ?? + _iosParams.pullToRefreshController?.params.options.toMap() ?? + PullToRefreshSettings(enabled: false).toMap(); + + Map args = {}; + args.putIfAbsent('id', () => id); + args.putIfAbsent( + 'params', + () => { + 'initialUrlRequest': params.initialUrlRequest?.toMap(), + 'initialFile': params.initialFile, + 'initialData': params.initialData?.toMap(), + 'initialSettings': settingsMap, + 'contextMenu': params.contextMenu?.toMap() ?? {}, + 'windowId': params.windowId, + 'initialUserScripts': + params.initialUserScripts?.map((e) => e.toMap()).toList() ?? + [], + 'pullToRefreshSettings': pullToRefreshSettings, + 'initialSize': params.initialSize.toMap() + }); + await _sharedChannel.invokeMethod('run', args); + _running = true; + } + + void _inferInitialSettings(InAppWebViewSettings settings) { + if (params.shouldOverrideUrlLoading != null && + settings.useShouldOverrideUrlLoading == null) { + settings.useShouldOverrideUrlLoading = true; + } + if (params.onLoadResource != null && settings.useOnLoadResource == null) { + settings.useOnLoadResource = true; + } + if (params.onDownloadStartRequest != null && + settings.useOnDownloadStart == null) { + settings.useOnDownloadStart = true; + } + if (params.shouldInterceptAjaxRequest != null && + settings.useShouldInterceptAjaxRequest == null) { + settings.useShouldInterceptAjaxRequest = true; + } + if (params.shouldInterceptFetchRequest != null && + settings.useShouldInterceptFetchRequest == null) { + settings.useShouldInterceptFetchRequest = true; + } + if (params.shouldInterceptRequest != null && + settings.useShouldInterceptRequest == null) { + settings.useShouldInterceptRequest = true; + } + if (params.onRenderProcessGone != null && + settings.useOnRenderProcessGone == null) { + settings.useOnRenderProcessGone = true; + } + if (params.onNavigationResponse != null && + settings.useOnNavigationResponse == null) { + settings.useOnNavigationResponse = true; + } + } + + @override + bool isRunning() { + return _running; + } + + @override + Future setSize(Size size) async { + if (!_running) { + return; + } + + Map args = {}; + args.putIfAbsent('size', () => size.toMap()); + await channel?.invokeMethod('setSize', args); + } + + @override + Future getSize() async { + if (!_running) { + return null; + } + + Map args = {}; + Map sizeMap = + (await channel?.invokeMethod('getSize', args))?.cast(); + return MapSize.fromMap(sizeMap); + } + + @override + Future dispose() async { + if (!_running) { + return; + } + Map args = {}; + await channel?.invokeMethod('dispose', args); + disposeChannel(); + _started = false; + _running = false; + _webViewController?.dispose(); + _webViewController = null; + _controllerFromPlatform = null; + _iosParams.pullToRefreshController?.dispose(); + _iosParams.findInteractionController?.dispose(); + } +} + +extension InternalHeadlessInAppWebView on MacOSHeadlessInAppWebView { + Future internalDispose() async { + _started = false; + _running = false; + } +} diff --git a/flutter_inappwebview_macos/lib/src/in_app_webview/in_app_webview.dart b/flutter_inappwebview_macos/lib/src/in_app_webview/in_app_webview.dart new file mode 100755 index 00000000..4fbbddea --- /dev/null +++ b/flutter_inappwebview_macos/lib/src/in_app_webview/in_app_webview.dart @@ -0,0 +1,418 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; +import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; +import 'headless_in_app_webview.dart'; + +import '../find_interaction/find_interaction_controller.dart'; +import 'in_app_webview_controller.dart'; + +/// Object specifying creation parameters for creating a [PlatformInAppWebViewWidget]. +/// +/// Platform specific implementations can add additional fields by extending +/// this class. +class MacOSInAppWebViewWidgetCreationParams + extends PlatformInAppWebViewWidgetCreationParams { + MacOSInAppWebViewWidgetCreationParams( + {super.controllerFromPlatform, + super.key, + super.layoutDirection, + super.gestureRecognizers, + super.headlessWebView, + super.keepAlive, + super.preventGestureDelay, + super.windowId, + super.onWebViewCreated, + super.onLoadStart, + super.onLoadStop, + @Deprecated('Use onReceivedError instead') super.onLoadError, + super.onReceivedError, + @Deprecated("Use onReceivedHttpError instead") super.onLoadHttpError, + super.onReceivedHttpError, + super.onProgressChanged, + super.onConsoleMessage, + super.shouldOverrideUrlLoading, + super.onLoadResource, + super.onScrollChanged, + @Deprecated('Use onDownloadStartRequest instead') super.onDownloadStart, + super.onDownloadStartRequest, + @Deprecated('Use onLoadResourceWithCustomScheme instead') + super.onLoadResourceCustomScheme, + super.onLoadResourceWithCustomScheme, + super.onCreateWindow, + super.onCloseWindow, + super.onJsAlert, + super.onJsConfirm, + super.onJsPrompt, + super.onReceivedHttpAuthRequest, + super.onReceivedServerTrustAuthRequest, + super.onReceivedClientCertRequest, + @Deprecated('Use FindInteractionController.onFindResultReceived instead') + super.onFindResultReceived, + super.shouldInterceptAjaxRequest, + super.onAjaxReadyStateChange, + super.onAjaxProgress, + super.shouldInterceptFetchRequest, + super.onUpdateVisitedHistory, + @Deprecated("Use onPrintRequest instead") super.onPrint, + super.onPrintRequest, + super.onLongPressHitTestResult, + super.onEnterFullscreen, + super.onExitFullscreen, + super.onPageCommitVisible, + super.onTitleChanged, + super.onWindowFocus, + super.onWindowBlur, + super.onOverScrolled, + super.onZoomScaleChanged, + @Deprecated('Use onSafeBrowsingHit instead') + super.androidOnSafeBrowsingHit, + super.onSafeBrowsingHit, + @Deprecated('Use onPermissionRequest instead') + super.androidOnPermissionRequest, + super.onPermissionRequest, + @Deprecated('Use onGeolocationPermissionsShowPrompt instead') + super.androidOnGeolocationPermissionsShowPrompt, + super.onGeolocationPermissionsShowPrompt, + @Deprecated('Use onGeolocationPermissionsHidePrompt instead') + super.androidOnGeolocationPermissionsHidePrompt, + super.onGeolocationPermissionsHidePrompt, + @Deprecated('Use shouldInterceptRequest instead') + super.androidShouldInterceptRequest, + super.shouldInterceptRequest, + @Deprecated('Use onRenderProcessGone instead') + super.androidOnRenderProcessGone, + super.onRenderProcessGone, + @Deprecated('Use onRenderProcessResponsive instead') + super.androidOnRenderProcessResponsive, + super.onRenderProcessResponsive, + @Deprecated('Use onRenderProcessUnresponsive instead') + super.androidOnRenderProcessUnresponsive, + super.onRenderProcessUnresponsive, + @Deprecated('Use onFormResubmission instead') + super.androidOnFormResubmission, + super.onFormResubmission, + @Deprecated('Use onZoomScaleChanged instead') super.androidOnScaleChanged, + @Deprecated('Use onReceivedIcon instead') super.androidOnReceivedIcon, + super.onReceivedIcon, + @Deprecated('Use onReceivedTouchIconUrl instead') + super.androidOnReceivedTouchIconUrl, + super.onReceivedTouchIconUrl, + @Deprecated('Use onJsBeforeUnload instead') super.androidOnJsBeforeUnload, + super.onJsBeforeUnload, + @Deprecated('Use onReceivedLoginRequest instead') + super.androidOnReceivedLoginRequest, + super.onReceivedLoginRequest, + super.onPermissionRequestCanceled, + super.onRequestFocus, + @Deprecated('Use onWebContentProcessDidTerminate instead') + super.iosOnWebContentProcessDidTerminate, + super.onWebContentProcessDidTerminate, + @Deprecated( + 'Use onDidReceiveServerRedirectForProvisionalNavigation instead') + super.iosOnDidReceiveServerRedirectForProvisionalNavigation, + super.onDidReceiveServerRedirectForProvisionalNavigation, + @Deprecated('Use onNavigationResponse instead') + super.iosOnNavigationResponse, + super.onNavigationResponse, + @Deprecated('Use shouldAllowDeprecatedTLS instead') + super.iosShouldAllowDeprecatedTLS, + super.shouldAllowDeprecatedTLS, + super.onCameraCaptureStateChanged, + super.onMicrophoneCaptureStateChanged, + super.onContentSizeChanged, + super.initialUrlRequest, + super.initialFile, + super.initialData, + @Deprecated('Use initialSettings instead') super.initialOptions, + super.initialSettings, + super.contextMenu, + super.initialUserScripts, + super.pullToRefreshController, + this.findInteractionController}); + + /// Constructs a [MacOSInAppWebViewWidgetCreationParams] using a + /// [PlatformInAppWebViewWidgetCreationParams]. + MacOSInAppWebViewWidgetCreationParams.fromPlatformInAppWebViewWidgetCreationParams( + PlatformInAppWebViewWidgetCreationParams params) + : this( + controllerFromPlatform: params.controllerFromPlatform, + key: params.key, + layoutDirection: params.layoutDirection, + gestureRecognizers: params.gestureRecognizers, + headlessWebView: params.headlessWebView, + keepAlive: params.keepAlive, + preventGestureDelay: params.preventGestureDelay, + windowId: params.windowId, + onWebViewCreated: params.onWebViewCreated, + onLoadStart: params.onLoadStart, + onLoadStop: params.onLoadStop, + onLoadError: params.onLoadError, + onReceivedError: params.onReceivedError, + onLoadHttpError: params.onLoadHttpError, + onReceivedHttpError: params.onReceivedHttpError, + onProgressChanged: params.onProgressChanged, + onConsoleMessage: params.onConsoleMessage, + shouldOverrideUrlLoading: params.shouldOverrideUrlLoading, + onLoadResource: params.onLoadResource, + onScrollChanged: params.onScrollChanged, + onDownloadStart: params.onDownloadStart, + onDownloadStartRequest: params.onDownloadStartRequest, + onLoadResourceCustomScheme: params.onLoadResourceCustomScheme, + onLoadResourceWithCustomScheme: + params.onLoadResourceWithCustomScheme, + onCreateWindow: params.onCreateWindow, + onCloseWindow: params.onCloseWindow, + onJsAlert: params.onJsAlert, + onJsConfirm: params.onJsConfirm, + onJsPrompt: params.onJsPrompt, + onReceivedHttpAuthRequest: params.onReceivedHttpAuthRequest, + onReceivedServerTrustAuthRequest: + params.onReceivedServerTrustAuthRequest, + onReceivedClientCertRequest: params.onReceivedClientCertRequest, + onFindResultReceived: params.onFindResultReceived, + shouldInterceptAjaxRequest: params.shouldInterceptAjaxRequest, + onAjaxReadyStateChange: params.onAjaxReadyStateChange, + onAjaxProgress: params.onAjaxProgress, + shouldInterceptFetchRequest: params.shouldInterceptFetchRequest, + onUpdateVisitedHistory: params.onUpdateVisitedHistory, + onPrint: params.onPrint, + onPrintRequest: params.onPrintRequest, + onLongPressHitTestResult: params.onLongPressHitTestResult, + onEnterFullscreen: params.onEnterFullscreen, + onExitFullscreen: params.onExitFullscreen, + onPageCommitVisible: params.onPageCommitVisible, + onTitleChanged: params.onTitleChanged, + onWindowFocus: params.onWindowFocus, + onWindowBlur: params.onWindowBlur, + onOverScrolled: params.onOverScrolled, + onZoomScaleChanged: params.onZoomScaleChanged, + androidOnSafeBrowsingHit: params.androidOnSafeBrowsingHit, + onSafeBrowsingHit: params.onSafeBrowsingHit, + androidOnPermissionRequest: params.androidOnPermissionRequest, + onPermissionRequest: params.onPermissionRequest, + androidOnGeolocationPermissionsShowPrompt: + params.androidOnGeolocationPermissionsShowPrompt, + onGeolocationPermissionsShowPrompt: + params.onGeolocationPermissionsShowPrompt, + androidOnGeolocationPermissionsHidePrompt: + params.androidOnGeolocationPermissionsHidePrompt, + onGeolocationPermissionsHidePrompt: + params.onGeolocationPermissionsHidePrompt, + androidShouldInterceptRequest: params.androidShouldInterceptRequest, + shouldInterceptRequest: params.shouldInterceptRequest, + androidOnRenderProcessGone: params.androidOnRenderProcessGone, + onRenderProcessGone: params.onRenderProcessGone, + androidOnRenderProcessResponsive: + params.androidOnRenderProcessResponsive, + onRenderProcessResponsive: params.onRenderProcessResponsive, + androidOnRenderProcessUnresponsive: + params.androidOnRenderProcessUnresponsive, + onRenderProcessUnresponsive: params.onRenderProcessUnresponsive, + androidOnFormResubmission: params.androidOnFormResubmission, + onFormResubmission: params.onFormResubmission, + androidOnScaleChanged: params.androidOnScaleChanged, + androidOnReceivedIcon: params.androidOnReceivedIcon, + onReceivedIcon: params.onReceivedIcon, + androidOnReceivedTouchIconUrl: params.androidOnReceivedTouchIconUrl, + onReceivedTouchIconUrl: params.onReceivedTouchIconUrl, + androidOnJsBeforeUnload: params.androidOnJsBeforeUnload, + onJsBeforeUnload: params.onJsBeforeUnload, + androidOnReceivedLoginRequest: params.androidOnReceivedLoginRequest, + onReceivedLoginRequest: params.onReceivedLoginRequest, + onPermissionRequestCanceled: params.onPermissionRequestCanceled, + onRequestFocus: params.onRequestFocus, + iosOnWebContentProcessDidTerminate: + params.iosOnWebContentProcessDidTerminate, + onWebContentProcessDidTerminate: + params.onWebContentProcessDidTerminate, + iosOnDidReceiveServerRedirectForProvisionalNavigation: + params.iosOnDidReceiveServerRedirectForProvisionalNavigation, + onDidReceiveServerRedirectForProvisionalNavigation: + params.onDidReceiveServerRedirectForProvisionalNavigation, + iosOnNavigationResponse: params.iosOnNavigationResponse, + onNavigationResponse: params.onNavigationResponse, + iosShouldAllowDeprecatedTLS: params.iosShouldAllowDeprecatedTLS, + shouldAllowDeprecatedTLS: params.shouldAllowDeprecatedTLS, + onCameraCaptureStateChanged: params.onCameraCaptureStateChanged, + onMicrophoneCaptureStateChanged: + params.onMicrophoneCaptureStateChanged, + onContentSizeChanged: params.onContentSizeChanged, + initialUrlRequest: params.initialUrlRequest, + initialFile: params.initialFile, + initialData: params.initialData, + initialOptions: params.initialOptions, + initialSettings: params.initialSettings, + contextMenu: params.contextMenu, + initialUserScripts: params.initialUserScripts, + pullToRefreshController: params.pullToRefreshController, + findInteractionController: params.findInteractionController + as MacOSFindInteractionController?); + + @override + final MacOSFindInteractionController? findInteractionController; +} + +///{@template flutter_inappwebview.InAppWebView} +///Flutter Widget for adding an **inline native WebView** integrated in the flutter widget tree. +/// +///**Supported Platforms/Implementations**: +///- MacOS native WebView +///- iOS +///- Web +///{@endtemplate} +class MacOSInAppWebViewWidget extends PlatformInAppWebViewWidget { + /// Constructs a [MacOSInAppWebViewWidget]. + MacOSInAppWebViewWidget(PlatformInAppWebViewWidgetCreationParams params) + : super.implementation( + params is MacOSInAppWebViewWidgetCreationParams + ? params + : MacOSInAppWebViewWidgetCreationParams + .fromPlatformInAppWebViewWidgetCreationParams(params), + ); + + MacOSInAppWebViewWidgetCreationParams get _iosParams => + params as MacOSInAppWebViewWidgetCreationParams; + + MacOSInAppWebViewController? _controller; + + MacOSHeadlessInAppWebView? get _iosHeadlessInAppWebView => + _iosParams.headlessWebView as MacOSHeadlessInAppWebView?; + + @override + Widget build(BuildContext context) { + final initialSettings = + _iosParams.initialSettings ?? InAppWebViewSettings(); + _inferInitialSettings(initialSettings); + + Map settingsMap = (_iosParams.initialSettings != null + ? initialSettings.toMap() + : null) ?? + // ignore: deprecated_member_use_from_same_package + _iosParams.initialOptions?.toMap() ?? + initialSettings.toMap(); + + Map pullToRefreshSettings = + _iosParams.pullToRefreshController?.params.settings.toMap() ?? + // ignore: deprecated_member_use_from_same_package + _iosParams.pullToRefreshController?.params.options.toMap() ?? + PullToRefreshSettings(enabled: false).toMap(); + + if ((_iosParams.headlessWebView?.isRunning() ?? false) && + _iosParams.keepAlive != null) { + final headlessId = _iosParams.headlessWebView?.id; + if (headlessId != null) { + // force keep alive id to match headless webview id + _iosParams.keepAlive?.id = headlessId; + } + } + + return UiKitView( + viewType: 'com.pichillilorenzo/flutter_inappwebview', + onPlatformViewCreated: _onPlatformViewCreated, + gestureRecognizers: _iosParams.gestureRecognizers, + creationParams: { + 'initialUrlRequest': _iosParams.initialUrlRequest?.toMap(), + 'initialFile': _iosParams.initialFile, + 'initialData': _iosParams.initialData?.toMap(), + 'initialSettings': settingsMap, + 'contextMenu': _iosParams.contextMenu?.toMap() ?? {}, + 'windowId': _iosParams.windowId, + 'headlessWebViewId': _iosParams.headlessWebView?.isRunning() ?? false + ? _iosParams.headlessWebView?.id + : null, + 'initialUserScripts': + _iosParams.initialUserScripts?.map((e) => e.toMap()).toList() ?? [], + 'pullToRefreshSettings': pullToRefreshSettings, + 'keepAliveId': _iosParams.keepAlive?.id, + 'preventGestureDelay': _iosParams.preventGestureDelay + }, + creationParamsCodec: const StandardMessageCodec(), + ); + } + + void _onPlatformViewCreated(int id) { + dynamic viewId = id; + if (!kIsWeb) { + if (_iosParams.headlessWebView?.isRunning() ?? false) { + viewId = _iosParams.headlessWebView?.id; + } + viewId = _iosParams.keepAlive?.id ?? viewId ?? id; + } + _iosHeadlessInAppWebView?.internalDispose(); + _controller = MacOSInAppWebViewController( + PlatformInAppWebViewControllerCreationParams( + id: viewId, webviewParams: params)); + _iosParams.findInteractionController?.init(viewId); + debugLog( + className: runtimeType.toString(), + id: viewId?.toString(), + debugLoggingSettings: + PlatformInAppWebViewController.debugLoggingSettings, + method: "onWebViewCreated", + args: []); + if (_iosParams.onWebViewCreated != null) { + _iosParams.onWebViewCreated!( + params.controllerFromPlatform?.call(_controller!) ?? _controller!); + } + } + + void _inferInitialSettings(InAppWebViewSettings settings) { + if (_iosParams.shouldOverrideUrlLoading != null && + settings.useShouldOverrideUrlLoading == null) { + settings.useShouldOverrideUrlLoading = true; + } + if (_iosParams.onLoadResource != null && + settings.useOnLoadResource == null) { + settings.useOnLoadResource = true; + } + if (_iosParams.onDownloadStartRequest != null && + settings.useOnDownloadStart == null) { + settings.useOnDownloadStart = true; + } + if (_iosParams.shouldInterceptAjaxRequest != null && + settings.useShouldInterceptAjaxRequest == null) { + settings.useShouldInterceptAjaxRequest = true; + } + if (_iosParams.shouldInterceptFetchRequest != null && + settings.useShouldInterceptFetchRequest == null) { + settings.useShouldInterceptFetchRequest = true; + } + if (_iosParams.shouldInterceptRequest != null && + settings.useShouldInterceptRequest == null) { + settings.useShouldInterceptRequest = true; + } + if (_iosParams.onRenderProcessGone != null && + settings.useOnRenderProcessGone == null) { + settings.useOnRenderProcessGone = true; + } + if (_iosParams.onNavigationResponse != null && + settings.useOnNavigationResponse == null) { + settings.useOnNavigationResponse = true; + } + } + + @override + void dispose() { + dynamic viewId = _controller?.getViewId(); + debugLog( + className: runtimeType.toString(), + id: viewId?.toString(), + debugLoggingSettings: + PlatformInAppWebViewController.debugLoggingSettings, + method: "dispose", + args: []); + final isKeepAlive = _iosParams.keepAlive != null; + _controller?.dispose(isKeepAlive: isKeepAlive); + _controller = null; + _iosParams.pullToRefreshController?.dispose(isKeepAlive: isKeepAlive); + _iosParams.findInteractionController?.dispose(isKeepAlive: isKeepAlive); + } + + @override + T controllerFromPlatform(PlatformInAppWebViewController controller) { + // unused + throw UnimplementedError(); + } +} diff --git a/flutter_inappwebview_macos/lib/src/in_app_webview/in_app_webview_controller.dart b/flutter_inappwebview_macos/lib/src/in_app_webview/in_app_webview_controller.dart new file mode 100644 index 00000000..41332671 --- /dev/null +++ b/flutter_inappwebview_macos/lib/src/in_app_webview/in_app_webview_controller.dart @@ -0,0 +1,2681 @@ +import 'dart:io'; +import 'dart:collection'; +import 'dart:convert'; +import 'dart:core'; +import 'dart:developer' as developer; +import 'dart:typed_data'; +import 'dart:ui'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; + +import '../web_message/main.dart'; + +import '../in_app_browser/in_app_browser.dart'; +import '../web_storage/web_storage.dart'; + +import 'headless_in_app_webview.dart'; +import '_static_channel.dart'; + +import '../print_job/main.dart'; + +///List of forbidden names for JavaScript handlers. +// ignore: non_constant_identifier_names +final _JAVASCRIPT_HANDLER_FORBIDDEN_NAMES = UnmodifiableListView([ + "onLoadResource", + "shouldInterceptAjaxRequest", + "onAjaxReadyStateChange", + "onAjaxProgress", + "shouldInterceptFetchRequest", + "onPrintRequest", + "onWindowFocus", + "onWindowBlur", + "callAsyncJavaScript", + "evaluateJavaScriptWithContentWorld" +]); + +/// Object specifying creation parameters for creating a [MacOSInAppWebViewController]. +/// +/// When adding additional fields make sure they can be null or have a default +/// value to avoid breaking changes. See [PlatformInAppWebViewControllerCreationParams] for +/// more information. +@immutable +class MacOSInAppWebViewControllerCreationParams + extends PlatformInAppWebViewControllerCreationParams { + /// Creates a new [MacOSInAppWebViewControllerCreationParams] instance. + const MacOSInAppWebViewControllerCreationParams( + {required super.id, super.webviewParams}); + + /// Creates a [MacOSInAppWebViewControllerCreationParams] instance based on [PlatformInAppWebViewControllerCreationParams]. + factory MacOSInAppWebViewControllerCreationParams.fromPlatformInAppWebViewControllerCreationParams( + // Recommended placeholder to prevent being broken by platform interface. + // ignore: avoid_unused_constructor_parameters + PlatformInAppWebViewControllerCreationParams params) { + return MacOSInAppWebViewControllerCreationParams( + id: params.id, webviewParams: params.webviewParams); + } +} + +///Controls a WebView, such as an [InAppWebView] widget instance, a [MacOSHeadlessInAppWebView] instance or [MacOSInAppBrowser] WebView instance. +/// +///If you are using the [InAppWebView] widget, an [InAppWebViewController] instance can be obtained by setting the [InAppWebView.onWebViewCreated] +///callback. Instead, if you are using an [MacOSInAppBrowser] instance, you can get it through the [MacOSInAppBrowser.webViewController] attribute. +class MacOSInAppWebViewController extends PlatformInAppWebViewController + with ChannelController { + static final MethodChannel _staticChannel = IN_APP_WEBVIEW_STATIC_CHANNEL; + + // List of properties to be saved and restored for keep alive feature + Map _javaScriptHandlersMap = + HashMap(); + Map> _userScripts = { + UserScriptInjectionTime.AT_DOCUMENT_START: [], + UserScriptInjectionTime.AT_DOCUMENT_END: [] + }; + Set _webMessageListenerObjNames = Set(); + Map _injectedScriptsFromURL = {}; + Set _webMessageChannels = Set(); + Set _webMessageListeners = Set(); + + // static map that contains the properties to be saved and restored for keep alive feature + static final Map + _keepAliveMap = {}; + + MacOSInAppBrowser? _inAppBrowser; + + PlatformInAppBrowserEvents? get _inAppBrowserEventHandler => + _inAppBrowser?.eventHandler; + + dynamic _controllerFromPlatform; + + @override + late MacOSWebStorage webStorage; + + MacOSInAppWebViewController( + PlatformInAppWebViewControllerCreationParams params) + : super.implementation(params + is MacOSInAppWebViewControllerCreationParams + ? params + : MacOSInAppWebViewControllerCreationParams + .fromPlatformInAppWebViewControllerCreationParams(params)) { + channel = MethodChannel('com.pichillilorenzo/flutter_inappwebview_$id'); + handler = handleMethod; + initMethodCallHandler(); + + final initialUserScripts = webviewParams?.initialUserScripts; + if (initialUserScripts != null) { + for (final userScript in initialUserScripts) { + if (userScript.injectionTime == + UserScriptInjectionTime.AT_DOCUMENT_START) { + this + ._userScripts[UserScriptInjectionTime.AT_DOCUMENT_START] + ?.add(userScript); + } else { + this + ._userScripts[UserScriptInjectionTime.AT_DOCUMENT_END] + ?.add(userScript); + } + } + } + + this._init(params); + } + + static final MacOSInAppWebViewController _staticValue = + MacOSInAppWebViewController( + MacOSInAppWebViewControllerCreationParams(id: null)); + + factory MacOSInAppWebViewController.static() { + return _staticValue; + } + + MacOSInAppWebViewController.fromInAppBrowser( + PlatformInAppWebViewControllerCreationParams params, + MethodChannel channel, + MacOSInAppBrowser inAppBrowser, + UnmodifiableListView? initialUserScripts) + : super.implementation( + params is MacOSInAppWebViewControllerCreationParams + ? params + : MacOSInAppWebViewControllerCreationParams + .fromPlatformInAppWebViewControllerCreationParams(params)) { + this.channel = channel; + this._inAppBrowser = inAppBrowser; + + if (initialUserScripts != null) { + for (final userScript in initialUserScripts) { + if (userScript.injectionTime == + UserScriptInjectionTime.AT_DOCUMENT_START) { + this + ._userScripts[UserScriptInjectionTime.AT_DOCUMENT_START] + ?.add(userScript); + } else { + this + ._userScripts[UserScriptInjectionTime.AT_DOCUMENT_END] + ?.add(userScript); + } + } + } + this._init(params); + } + + void _init(PlatformInAppWebViewControllerCreationParams params) { + _controllerFromPlatform = + params.webviewParams?.controllerFromPlatform?.call(this) ?? this; + + webStorage = MacOSWebStorage(MacOSWebStorageCreationParams( + localStorage: MacOSLocalStorage.defaultStorage(controller: this), + sessionStorage: + MacOSSessionStorage.defaultStorage(controller: this))); + + if (params.webviewParams is PlatformInAppWebViewWidgetCreationParams) { + final keepAlive = + (params.webviewParams as PlatformInAppWebViewWidgetCreationParams) + .keepAlive; + if (keepAlive != null) { + InAppWebViewControllerKeepAliveProps? props = _keepAliveMap[keepAlive]; + if (props == null) { + // save controller properties to restore it later + _keepAliveMap[keepAlive] = InAppWebViewControllerKeepAliveProps( + injectedScriptsFromURL: _injectedScriptsFromURL, + javaScriptHandlersMap: _javaScriptHandlersMap, + userScripts: _userScripts, + webMessageListenerObjNames: _webMessageListenerObjNames, + webMessageChannels: _webMessageChannels, + webMessageListeners: _webMessageListeners); + } else { + // restore controller properties + _injectedScriptsFromURL = props.injectedScriptsFromURL; + _javaScriptHandlersMap = props.javaScriptHandlersMap; + _userScripts = props.userScripts; + _webMessageListenerObjNames = props.webMessageListenerObjNames; + _webMessageChannels = + props.webMessageChannels as Set; + _webMessageListeners = + props.webMessageListeners as Set; + } + } + } + } + + _debugLog(String method, dynamic args) { + debugLog( + className: this.runtimeType.toString(), + name: _inAppBrowser == null + ? "WebView" + : _inAppBrowser.runtimeType.toString(), + id: (getViewId() ?? _inAppBrowser?.id).toString(), + debugLoggingSettings: + PlatformInAppWebViewController.debugLoggingSettings, + method: method, + args: args); + } + + Future _handleMethod(MethodCall call) async { + if (PlatformInAppWebViewController.debugLoggingSettings.enabled && + call.method != "onCallJsHandler") { + _debugLog(call.method, call.arguments); + } + + switch (call.method) { + case "onLoadStart": + _injectedScriptsFromURL.clear(); + if ((webviewParams != null && webviewParams!.onLoadStart != null) || + _inAppBrowserEventHandler != null) { + String? url = call.arguments["url"]; + WebUri? uri = url != null ? WebUri(url) : null; + if (webviewParams != null && webviewParams!.onLoadStart != null) + webviewParams!.onLoadStart!(_controllerFromPlatform, uri); + else + _inAppBrowserEventHandler!.onLoadStart(uri); + } + break; + case "onLoadStop": + if ((webviewParams != null && webviewParams!.onLoadStop != null) || + _inAppBrowserEventHandler != null) { + String? url = call.arguments["url"]; + WebUri? uri = url != null ? WebUri(url) : null; + if (webviewParams != null && webviewParams!.onLoadStop != null) + webviewParams!.onLoadStop!(_controllerFromPlatform, uri); + else + _inAppBrowserEventHandler!.onLoadStop(uri); + } + break; + case "onReceivedError": + if ((webviewParams != null && + (webviewParams!.onReceivedError != null || + // ignore: deprecated_member_use_from_same_package + webviewParams!.onLoadError != null)) || + _inAppBrowserEventHandler != null) { + WebResourceRequest request = WebResourceRequest.fromMap( + call.arguments["request"].cast())!; + WebResourceError error = WebResourceError.fromMap( + call.arguments["error"].cast())!; + var isForMainFrame = request.isForMainFrame ?? false; + + if (webviewParams != null) { + if (webviewParams!.onReceivedError != null) + webviewParams!.onReceivedError!( + _controllerFromPlatform, request, error); + else if (isForMainFrame) { + // ignore: deprecated_member_use_from_same_package + webviewParams!.onLoadError!(_controllerFromPlatform, request.url, + error.type.toNativeValue() ?? -1, error.description); + } + } else { + if (isForMainFrame) { + _inAppBrowserEventHandler!.onLoadError(request.url, + error.type.toNativeValue() ?? -1, error.description); + } + _inAppBrowserEventHandler!.onReceivedError(request, error); + } + } + break; + case "onReceivedHttpError": + if ((webviewParams != null && + (webviewParams!.onReceivedHttpError != null || + // ignore: deprecated_member_use_from_same_package + webviewParams!.onLoadHttpError != null)) || + _inAppBrowserEventHandler != null) { + WebResourceRequest request = WebResourceRequest.fromMap( + call.arguments["request"].cast())!; + WebResourceResponse errorResponse = WebResourceResponse.fromMap( + call.arguments["errorResponse"].cast())!; + var isForMainFrame = request.isForMainFrame ?? false; + + if (webviewParams != null) { + if (webviewParams!.onReceivedHttpError != null) + webviewParams!.onReceivedHttpError!( + _controllerFromPlatform, request, errorResponse); + else if (isForMainFrame) { + // ignore: deprecated_member_use_from_same_package + webviewParams!.onLoadHttpError!( + _controllerFromPlatform, + request.url, + errorResponse.statusCode ?? -1, + errorResponse.reasonPhrase ?? ''); + } + } else { + if (isForMainFrame) { + _inAppBrowserEventHandler!.onLoadHttpError( + request.url, + errorResponse.statusCode ?? -1, + errorResponse.reasonPhrase ?? ''); + } + _inAppBrowserEventHandler! + .onReceivedHttpError(request, errorResponse); + } + } + break; + case "onProgressChanged": + if ((webviewParams != null && + webviewParams!.onProgressChanged != null) || + _inAppBrowserEventHandler != null) { + int progress = call.arguments["progress"]; + if (webviewParams != null && webviewParams!.onProgressChanged != null) + webviewParams!.onProgressChanged!( + _controllerFromPlatform, progress); + else + _inAppBrowserEventHandler!.onProgressChanged(progress); + } + break; + case "shouldOverrideUrlLoading": + if ((webviewParams != null && + webviewParams!.shouldOverrideUrlLoading != null) || + _inAppBrowserEventHandler != null) { + Map arguments = + call.arguments.cast(); + NavigationAction navigationAction = + NavigationAction.fromMap(arguments)!; + + if (webviewParams != null && + webviewParams!.shouldOverrideUrlLoading != null) + return (await webviewParams!.shouldOverrideUrlLoading!( + _controllerFromPlatform, navigationAction)) + ?.toNativeValue(); + return (await _inAppBrowserEventHandler! + .shouldOverrideUrlLoading(navigationAction)) + ?.toNativeValue(); + } + break; + case "onConsoleMessage": + if ((webviewParams != null && + webviewParams!.onConsoleMessage != null) || + _inAppBrowserEventHandler != null) { + Map arguments = + call.arguments.cast(); + ConsoleMessage consoleMessage = ConsoleMessage.fromMap(arguments)!; + if (webviewParams != null && webviewParams!.onConsoleMessage != null) + webviewParams!.onConsoleMessage!( + _controllerFromPlatform, consoleMessage); + else + _inAppBrowserEventHandler!.onConsoleMessage(consoleMessage); + } + break; + case "onScrollChanged": + if ((webviewParams != null && webviewParams!.onScrollChanged != null) || + _inAppBrowserEventHandler != null) { + int x = call.arguments["x"]; + int y = call.arguments["y"]; + if (webviewParams != null && webviewParams!.onScrollChanged != null) + webviewParams!.onScrollChanged!(_controllerFromPlatform, x, y); + else + _inAppBrowserEventHandler!.onScrollChanged(x, y); + } + break; + case "onDownloadStartRequest": + if ((webviewParams != null && + // ignore: deprecated_member_use_from_same_package + (webviewParams!.onDownloadStart != null || + webviewParams!.onDownloadStartRequest != null)) || + _inAppBrowserEventHandler != null) { + Map arguments = + call.arguments.cast(); + DownloadStartRequest downloadStartRequest = + DownloadStartRequest.fromMap(arguments)!; + + if (webviewParams != null) { + if (webviewParams!.onDownloadStartRequest != null) + webviewParams!.onDownloadStartRequest!( + _controllerFromPlatform, downloadStartRequest); + else { + // ignore: deprecated_member_use_from_same_package + webviewParams!.onDownloadStart!( + _controllerFromPlatform, downloadStartRequest.url); + } + } else { + // ignore: deprecated_member_use_from_same_package + _inAppBrowserEventHandler! + .onDownloadStart(downloadStartRequest.url); + _inAppBrowserEventHandler! + .onDownloadStartRequest(downloadStartRequest); + } + } + break; + case "onLoadResourceWithCustomScheme": + if ((webviewParams != null && + (webviewParams!.onLoadResourceWithCustomScheme != null || + // ignore: deprecated_member_use_from_same_package + webviewParams!.onLoadResourceCustomScheme != null)) || + _inAppBrowserEventHandler != null) { + Map requestMap = + call.arguments["request"].cast(); + WebResourceRequest request = WebResourceRequest.fromMap(requestMap)!; + + if (webviewParams != null) { + if (webviewParams!.onLoadResourceWithCustomScheme != null) + return (await webviewParams!.onLoadResourceWithCustomScheme!( + _controllerFromPlatform, request)) + ?.toMap(); + else { + return (await params + .webviewParams! + // ignore: deprecated_member_use_from_same_package + .onLoadResourceCustomScheme!( + _controllerFromPlatform, request.url)) + ?.toMap(); + } + } else { + return ((await _inAppBrowserEventHandler! + .onLoadResourceWithCustomScheme(request)) ?? + (await _inAppBrowserEventHandler! + .onLoadResourceCustomScheme(request.url))) + ?.toMap(); + } + } + break; + case "onCreateWindow": + if ((webviewParams != null && webviewParams!.onCreateWindow != null) || + _inAppBrowserEventHandler != null) { + Map arguments = + call.arguments.cast(); + CreateWindowAction createWindowAction = + CreateWindowAction.fromMap(arguments)!; + + if (webviewParams != null && webviewParams!.onCreateWindow != null) + return await webviewParams!.onCreateWindow!( + _controllerFromPlatform, createWindowAction); + else + return await _inAppBrowserEventHandler! + .onCreateWindow(createWindowAction); + } + break; + case "onCloseWindow": + if (webviewParams != null && webviewParams!.onCloseWindow != null) + webviewParams!.onCloseWindow!(_controllerFromPlatform); + else if (_inAppBrowserEventHandler != null) + _inAppBrowserEventHandler!.onCloseWindow(); + break; + case "onTitleChanged": + if ((webviewParams != null && webviewParams!.onTitleChanged != null) || + _inAppBrowserEventHandler != null) { + String? title = call.arguments["title"]; + if (webviewParams != null && webviewParams!.onTitleChanged != null) + webviewParams!.onTitleChanged!(_controllerFromPlatform, title); + else + _inAppBrowserEventHandler!.onTitleChanged(title); + } + break; + case "onGeolocationPermissionsShowPrompt": + if ((webviewParams != null && + (webviewParams!.onGeolocationPermissionsShowPrompt != null || + // ignore: deprecated_member_use_from_same_package + webviewParams!.androidOnGeolocationPermissionsShowPrompt != + null)) || + _inAppBrowserEventHandler != null) { + String origin = call.arguments["origin"]; + + if (webviewParams != null) { + if (webviewParams!.onGeolocationPermissionsShowPrompt != null) + return (await webviewParams!.onGeolocationPermissionsShowPrompt!( + _controllerFromPlatform, origin)) + ?.toMap(); + else { + return (await params + .webviewParams! + // ignore: deprecated_member_use_from_same_package + .androidOnGeolocationPermissionsShowPrompt!( + _controllerFromPlatform, origin)) + ?.toMap(); + } + } else { + return ((await _inAppBrowserEventHandler! + .onGeolocationPermissionsShowPrompt(origin)) ?? + (await _inAppBrowserEventHandler! + .androidOnGeolocationPermissionsShowPrompt(origin))) + ?.toMap(); + } + } + break; + case "onGeolocationPermissionsHidePrompt": + if (webviewParams != null && + (webviewParams!.onGeolocationPermissionsHidePrompt != null || + // ignore: deprecated_member_use_from_same_package + webviewParams!.androidOnGeolocationPermissionsHidePrompt != + null)) { + if (webviewParams!.onGeolocationPermissionsHidePrompt != null) + webviewParams! + .onGeolocationPermissionsHidePrompt!(_controllerFromPlatform); + else { + // ignore: deprecated_member_use_from_same_package + webviewParams!.androidOnGeolocationPermissionsHidePrompt!( + _controllerFromPlatform); + } + } else if (_inAppBrowserEventHandler != null) { + _inAppBrowserEventHandler!.onGeolocationPermissionsHidePrompt(); + // ignore: deprecated_member_use_from_same_package + _inAppBrowserEventHandler! + .androidOnGeolocationPermissionsHidePrompt(); + } + break; + case "shouldInterceptRequest": + if ((webviewParams != null && + (webviewParams!.shouldInterceptRequest != null || + // ignore: deprecated_member_use_from_same_package + webviewParams!.androidShouldInterceptRequest != null)) || + _inAppBrowserEventHandler != null) { + Map arguments = + call.arguments.cast(); + WebResourceRequest request = WebResourceRequest.fromMap(arguments)!; + + if (webviewParams != null) { + if (webviewParams!.shouldInterceptRequest != null) + return (await webviewParams!.shouldInterceptRequest!( + _controllerFromPlatform, request)) + ?.toMap(); + else { + // ignore: deprecated_member_use_from_same_package + return (await webviewParams!.androidShouldInterceptRequest!( + _controllerFromPlatform, request)) + ?.toMap(); + } + } else { + return ((await _inAppBrowserEventHandler! + .shouldInterceptRequest(request)) ?? + (await _inAppBrowserEventHandler! + .androidShouldInterceptRequest(request))) + ?.toMap(); + } + } + break; + case "onRenderProcessUnresponsive": + if ((webviewParams != null && + (webviewParams!.onRenderProcessUnresponsive != null || + // ignore: deprecated_member_use_from_same_package + webviewParams!.androidOnRenderProcessUnresponsive != + null)) || + _inAppBrowserEventHandler != null) { + String? url = call.arguments["url"]; + WebUri? uri = url != null ? WebUri(url) : null; + + if (webviewParams != null) { + if (webviewParams!.onRenderProcessUnresponsive != null) + return (await webviewParams!.onRenderProcessUnresponsive!( + _controllerFromPlatform, uri)) + ?.toNativeValue(); + else { + // ignore: deprecated_member_use_from_same_package + return (await webviewParams!.androidOnRenderProcessUnresponsive!( + _controllerFromPlatform, uri)) + ?.toNativeValue(); + } + } else { + return ((await _inAppBrowserEventHandler! + .onRenderProcessUnresponsive(uri)) ?? + (await _inAppBrowserEventHandler! + .androidOnRenderProcessUnresponsive(uri))) + ?.toNativeValue(); + } + } + break; + case "onRenderProcessResponsive": + if ((webviewParams != null && + (webviewParams!.onRenderProcessResponsive != null || + // ignore: deprecated_member_use_from_same_package + webviewParams!.androidOnRenderProcessResponsive != null)) || + _inAppBrowserEventHandler != null) { + String? url = call.arguments["url"]; + WebUri? uri = url != null ? WebUri(url) : null; + + if (webviewParams != null) { + if (webviewParams!.onRenderProcessResponsive != null) + return (await webviewParams!.onRenderProcessResponsive!( + _controllerFromPlatform, uri)) + ?.toNativeValue(); + else { + // ignore: deprecated_member_use_from_same_package + return (await webviewParams!.androidOnRenderProcessResponsive!( + _controllerFromPlatform, uri)) + ?.toNativeValue(); + } + } else { + return ((await _inAppBrowserEventHandler! + .onRenderProcessResponsive(uri)) ?? + (await _inAppBrowserEventHandler! + .androidOnRenderProcessResponsive(uri))) + ?.toNativeValue(); + } + } + break; + case "onRenderProcessGone": + if ((webviewParams != null && + (webviewParams!.onRenderProcessGone != null || + // ignore: deprecated_member_use_from_same_package + webviewParams!.androidOnRenderProcessGone != null)) || + _inAppBrowserEventHandler != null) { + Map arguments = + call.arguments.cast(); + RenderProcessGoneDetail detail = + RenderProcessGoneDetail.fromMap(arguments)!; + + if (webviewParams != null) { + if (webviewParams!.onRenderProcessGone != null) + webviewParams!.onRenderProcessGone!( + _controllerFromPlatform, detail); + else { + // ignore: deprecated_member_use_from_same_package + webviewParams!.androidOnRenderProcessGone!( + _controllerFromPlatform, detail); + } + } else if (_inAppBrowserEventHandler != null) { + _inAppBrowserEventHandler!.onRenderProcessGone(detail); + // ignore: deprecated_member_use_from_same_package + _inAppBrowserEventHandler!.androidOnRenderProcessGone(detail); + } + } + break; + case "onFormResubmission": + if ((webviewParams != null && + (webviewParams!.onFormResubmission != null || + // ignore: deprecated_member_use_from_same_package + webviewParams!.androidOnFormResubmission != null)) || + _inAppBrowserEventHandler != null) { + String? url = call.arguments["url"]; + WebUri? uri = url != null ? WebUri(url) : null; + + if (webviewParams != null) { + if (webviewParams!.onFormResubmission != null) + return (await webviewParams!.onFormResubmission!( + _controllerFromPlatform, uri)) + ?.toNativeValue(); + else { + // ignore: deprecated_member_use_from_same_package + return (await webviewParams!.androidOnFormResubmission!( + _controllerFromPlatform, uri)) + ?.toNativeValue(); + } + } else { + return ((await _inAppBrowserEventHandler! + .onFormResubmission(uri)) ?? + // ignore: deprecated_member_use_from_same_package + (await _inAppBrowserEventHandler! + .androidOnFormResubmission(uri))) + ?.toNativeValue(); + } + } + break; + case "onZoomScaleChanged": + if ((webviewParams != null && + // ignore: deprecated_member_use_from_same_package + (webviewParams!.androidOnScaleChanged != null || + webviewParams!.onZoomScaleChanged != null)) || + _inAppBrowserEventHandler != null) { + double oldScale = call.arguments["oldScale"]; + double newScale = call.arguments["newScale"]; + + if (webviewParams != null) { + if (webviewParams!.onZoomScaleChanged != null) + webviewParams!.onZoomScaleChanged!( + _controllerFromPlatform, oldScale, newScale); + else { + // ignore: deprecated_member_use_from_same_package + webviewParams!.androidOnScaleChanged!( + _controllerFromPlatform, oldScale, newScale); + } + } else { + _inAppBrowserEventHandler!.onZoomScaleChanged(oldScale, newScale); + // ignore: deprecated_member_use_from_same_package + _inAppBrowserEventHandler! + .androidOnScaleChanged(oldScale, newScale); + } + } + break; + case "onReceivedIcon": + if ((webviewParams != null && + (webviewParams!.onReceivedIcon != null || + // ignore: deprecated_member_use_from_same_package + webviewParams!.androidOnReceivedIcon != null)) || + _inAppBrowserEventHandler != null) { + Uint8List icon = + Uint8List.fromList(call.arguments["icon"].cast()); + + if (webviewParams != null) { + if (webviewParams!.onReceivedIcon != null) + webviewParams!.onReceivedIcon!(_controllerFromPlatform, icon); + else { + // ignore: deprecated_member_use_from_same_package + webviewParams!.androidOnReceivedIcon!( + _controllerFromPlatform, icon); + } + } else { + _inAppBrowserEventHandler!.onReceivedIcon(icon); + // ignore: deprecated_member_use_from_same_package + _inAppBrowserEventHandler!.androidOnReceivedIcon(icon); + } + } + break; + case "onReceivedTouchIconUrl": + if ((webviewParams != null && + (webviewParams!.onReceivedTouchIconUrl != null || + // ignore: deprecated_member_use_from_same_package + webviewParams!.androidOnReceivedTouchIconUrl != null)) || + _inAppBrowserEventHandler != null) { + String url = call.arguments["url"]; + bool precomposed = call.arguments["precomposed"]; + WebUri uri = WebUri(url); + + if (webviewParams != null) { + if (webviewParams!.onReceivedTouchIconUrl != null) + webviewParams!.onReceivedTouchIconUrl!( + _controllerFromPlatform, uri, precomposed); + else { + // ignore: deprecated_member_use_from_same_package + webviewParams!.androidOnReceivedTouchIconUrl!( + _controllerFromPlatform, uri, precomposed); + } + } else { + _inAppBrowserEventHandler!.onReceivedTouchIconUrl(uri, precomposed); + // ignore: deprecated_member_use_from_same_package + _inAppBrowserEventHandler! + .androidOnReceivedTouchIconUrl(uri, precomposed); + } + } + break; + case "onJsAlert": + if ((webviewParams != null && webviewParams!.onJsAlert != null) || + _inAppBrowserEventHandler != null) { + Map arguments = + call.arguments.cast(); + JsAlertRequest jsAlertRequest = JsAlertRequest.fromMap(arguments)!; + + if (webviewParams != null && webviewParams!.onJsAlert != null) + return (await webviewParams!.onJsAlert!( + _controllerFromPlatform, jsAlertRequest)) + ?.toMap(); + else + return (await _inAppBrowserEventHandler!.onJsAlert(jsAlertRequest)) + ?.toMap(); + } + break; + case "onJsConfirm": + if ((webviewParams != null && webviewParams!.onJsConfirm != null) || + _inAppBrowserEventHandler != null) { + Map arguments = + call.arguments.cast(); + JsConfirmRequest jsConfirmRequest = + JsConfirmRequest.fromMap(arguments)!; + + if (webviewParams != null && webviewParams!.onJsConfirm != null) + return (await webviewParams!.onJsConfirm!( + _controllerFromPlatform, jsConfirmRequest)) + ?.toMap(); + else + return (await _inAppBrowserEventHandler! + .onJsConfirm(jsConfirmRequest)) + ?.toMap(); + } + break; + case "onJsPrompt": + if ((webviewParams != null && webviewParams!.onJsPrompt != null) || + _inAppBrowserEventHandler != null) { + Map arguments = + call.arguments.cast(); + JsPromptRequest jsPromptRequest = JsPromptRequest.fromMap(arguments)!; + + if (webviewParams != null && webviewParams!.onJsPrompt != null) + return (await webviewParams!.onJsPrompt!( + _controllerFromPlatform, jsPromptRequest)) + ?.toMap(); + else + return (await _inAppBrowserEventHandler! + .onJsPrompt(jsPromptRequest)) + ?.toMap(); + } + break; + case "onJsBeforeUnload": + if ((webviewParams != null && + (webviewParams!.onJsBeforeUnload != null || + // ignore: deprecated_member_use_from_same_package + webviewParams!.androidOnJsBeforeUnload != null)) || + _inAppBrowserEventHandler != null) { + Map arguments = + call.arguments.cast(); + JsBeforeUnloadRequest jsBeforeUnloadRequest = + JsBeforeUnloadRequest.fromMap(arguments)!; + + if (webviewParams != null) { + if (webviewParams!.onJsBeforeUnload != null) + return (await webviewParams!.onJsBeforeUnload!( + _controllerFromPlatform, jsBeforeUnloadRequest)) + ?.toMap(); + else { + // ignore: deprecated_member_use_from_same_package + return (await webviewParams!.androidOnJsBeforeUnload!( + _controllerFromPlatform, jsBeforeUnloadRequest)) + ?.toMap(); + } + } else { + return ((await _inAppBrowserEventHandler! + .onJsBeforeUnload(jsBeforeUnloadRequest)) ?? + (await _inAppBrowserEventHandler! + .androidOnJsBeforeUnload(jsBeforeUnloadRequest))) + ?.toMap(); + } + } + break; + case "onSafeBrowsingHit": + if ((webviewParams != null && + (webviewParams!.onSafeBrowsingHit != null || + // ignore: deprecated_member_use_from_same_package + webviewParams!.androidOnSafeBrowsingHit != null)) || + _inAppBrowserEventHandler != null) { + String url = call.arguments["url"]; + SafeBrowsingThreat? threatType = + SafeBrowsingThreat.fromNativeValue(call.arguments["threatType"]); + WebUri uri = WebUri(url); + + if (webviewParams != null) { + if (webviewParams!.onSafeBrowsingHit != null) + return (await webviewParams!.onSafeBrowsingHit!( + _controllerFromPlatform, uri, threatType)) + ?.toMap(); + else { + // ignore: deprecated_member_use_from_same_package + return (await webviewParams!.androidOnSafeBrowsingHit!( + _controllerFromPlatform, uri, threatType)) + ?.toMap(); + } + } else { + return ((await _inAppBrowserEventHandler! + .onSafeBrowsingHit(uri, threatType)) ?? + (await _inAppBrowserEventHandler! + .androidOnSafeBrowsingHit(uri, threatType))) + ?.toMap(); + } + } + break; + case "onReceivedLoginRequest": + if ((webviewParams != null && + (webviewParams!.onReceivedLoginRequest != null || + // ignore: deprecated_member_use_from_same_package + webviewParams!.androidOnReceivedLoginRequest != null)) || + _inAppBrowserEventHandler != null) { + Map arguments = + call.arguments.cast(); + LoginRequest loginRequest = LoginRequest.fromMap(arguments)!; + + if (webviewParams != null) { + if (webviewParams!.onReceivedLoginRequest != null) + webviewParams!.onReceivedLoginRequest!( + _controllerFromPlatform, loginRequest); + else { + // ignore: deprecated_member_use_from_same_package + webviewParams!.androidOnReceivedLoginRequest!( + _controllerFromPlatform, loginRequest); + } + } else { + _inAppBrowserEventHandler!.onReceivedLoginRequest(loginRequest); + // ignore: deprecated_member_use_from_same_package + _inAppBrowserEventHandler! + .androidOnReceivedLoginRequest(loginRequest); + } + } + break; + case "onPermissionRequestCanceled": + if ((webviewParams != null && + webviewParams!.onPermissionRequestCanceled != null) || + _inAppBrowserEventHandler != null) { + Map arguments = + call.arguments.cast(); + PermissionRequest permissionRequest = + PermissionRequest.fromMap(arguments)!; + + if (webviewParams != null && + webviewParams!.onPermissionRequestCanceled != null) + webviewParams!.onPermissionRequestCanceled!( + _controllerFromPlatform, permissionRequest); + else + _inAppBrowserEventHandler! + .onPermissionRequestCanceled(permissionRequest); + } + break; + case "onRequestFocus": + if ((webviewParams != null && webviewParams!.onRequestFocus != null) || + _inAppBrowserEventHandler != null) { + if (webviewParams != null && webviewParams!.onRequestFocus != null) + webviewParams!.onRequestFocus!(_controllerFromPlatform); + else + _inAppBrowserEventHandler!.onRequestFocus(); + } + break; + case "onReceivedHttpAuthRequest": + if ((webviewParams != null && + webviewParams!.onReceivedHttpAuthRequest != null) || + _inAppBrowserEventHandler != null) { + Map arguments = + call.arguments.cast(); + HttpAuthenticationChallenge challenge = + HttpAuthenticationChallenge.fromMap(arguments)!; + + if (webviewParams != null && + webviewParams!.onReceivedHttpAuthRequest != null) + return (await webviewParams!.onReceivedHttpAuthRequest!( + _controllerFromPlatform, challenge)) + ?.toMap(); + else + return (await _inAppBrowserEventHandler! + .onReceivedHttpAuthRequest(challenge)) + ?.toMap(); + } + break; + case "onReceivedServerTrustAuthRequest": + if ((webviewParams != null && + webviewParams!.onReceivedServerTrustAuthRequest != null) || + _inAppBrowserEventHandler != null) { + Map arguments = + call.arguments.cast(); + ServerTrustChallenge challenge = + ServerTrustChallenge.fromMap(arguments)!; + + if (webviewParams != null && + webviewParams!.onReceivedServerTrustAuthRequest != null) + return (await webviewParams!.onReceivedServerTrustAuthRequest!( + _controllerFromPlatform, challenge)) + ?.toMap(); + else + return (await _inAppBrowserEventHandler! + .onReceivedServerTrustAuthRequest(challenge)) + ?.toMap(); + } + break; + case "onReceivedClientCertRequest": + if ((webviewParams != null && + webviewParams!.onReceivedClientCertRequest != null) || + _inAppBrowserEventHandler != null) { + Map arguments = + call.arguments.cast(); + ClientCertChallenge challenge = + ClientCertChallenge.fromMap(arguments)!; + + if (webviewParams != null && + webviewParams!.onReceivedClientCertRequest != null) + return (await webviewParams!.onReceivedClientCertRequest!( + _controllerFromPlatform, challenge)) + ?.toMap(); + else + return (await _inAppBrowserEventHandler! + .onReceivedClientCertRequest(challenge)) + ?.toMap(); + } + break; + case "onFindResultReceived": + if ((webviewParams != null && + (webviewParams!.onFindResultReceived != null || + (webviewParams!.findInteractionController != null && + webviewParams!.findInteractionController!.params + .onFindResultReceived != + null))) || + _inAppBrowserEventHandler != null) { + int activeMatchOrdinal = call.arguments["activeMatchOrdinal"]; + int numberOfMatches = call.arguments["numberOfMatches"]; + bool isDoneCounting = call.arguments["isDoneCounting"]; + if (webviewParams != null) { + if (webviewParams!.findInteractionController != null && + webviewParams!.findInteractionController!.params + .onFindResultReceived != + null) + webviewParams! + .findInteractionController!.params.onFindResultReceived!( + webviewParams!.findInteractionController!, + activeMatchOrdinal, + numberOfMatches, + isDoneCounting); + else + webviewParams!.onFindResultReceived!(_controllerFromPlatform, + activeMatchOrdinal, numberOfMatches, isDoneCounting); + } else { + if (_inAppBrowser!.findInteractionController != null && + _inAppBrowser! + .findInteractionController!.onFindResultReceived != + null) + _inAppBrowser!.findInteractionController!.onFindResultReceived!( + webviewParams!.findInteractionController!, + activeMatchOrdinal, + numberOfMatches, + isDoneCounting); + else + _inAppBrowserEventHandler!.onFindResultReceived( + activeMatchOrdinal, numberOfMatches, isDoneCounting); + } + } + break; + case "onPermissionRequest": + if ((webviewParams != null && + (webviewParams!.onPermissionRequest != null || + // ignore: deprecated_member_use_from_same_package + webviewParams!.androidOnPermissionRequest != null)) || + _inAppBrowserEventHandler != null) { + String origin = call.arguments["origin"]; + List resources = call.arguments["resources"].cast(); + + Map arguments = + call.arguments.cast(); + PermissionRequest permissionRequest = + PermissionRequest.fromMap(arguments)!; + + if (webviewParams != null) { + if (webviewParams!.onPermissionRequest != null) + return (await webviewParams!.onPermissionRequest!( + _controllerFromPlatform, permissionRequest)) + ?.toMap(); + else { + return (await webviewParams!.androidOnPermissionRequest!( + _controllerFromPlatform, origin, resources)) + ?.toMap(); + } + } else { + return (await _inAppBrowserEventHandler! + .onPermissionRequest(permissionRequest)) + ?.toMap() ?? + (await _inAppBrowserEventHandler! + .androidOnPermissionRequest(origin, resources)) + ?.toMap(); + } + } + break; + case "onUpdateVisitedHistory": + if ((webviewParams != null && + webviewParams!.onUpdateVisitedHistory != null) || + _inAppBrowserEventHandler != null) { + String? url = call.arguments["url"]; + bool? isReload = call.arguments["isReload"]; + WebUri? uri = url != null ? WebUri(url) : null; + if (webviewParams != null && + webviewParams!.onUpdateVisitedHistory != null) + webviewParams!.onUpdateVisitedHistory!( + _controllerFromPlatform, uri, isReload); + else + _inAppBrowserEventHandler!.onUpdateVisitedHistory(uri, isReload); + } + break; + case "onWebContentProcessDidTerminate": + if (webviewParams != null && + (webviewParams!.onWebContentProcessDidTerminate != null || + // ignore: deprecated_member_use_from_same_package + webviewParams!.iosOnWebContentProcessDidTerminate != null)) { + if (webviewParams!.onWebContentProcessDidTerminate != null) + webviewParams! + .onWebContentProcessDidTerminate!(_controllerFromPlatform); + else { + // ignore: deprecated_member_use_from_same_package + webviewParams! + .iosOnWebContentProcessDidTerminate!(_controllerFromPlatform); + } + } else if (_inAppBrowserEventHandler != null) { + _inAppBrowserEventHandler!.onWebContentProcessDidTerminate(); + // ignore: deprecated_member_use_from_same_package + _inAppBrowserEventHandler!.iosOnWebContentProcessDidTerminate(); + } + break; + case "onPageCommitVisible": + if ((webviewParams != null && + webviewParams!.onPageCommitVisible != null) || + _inAppBrowserEventHandler != null) { + String? url = call.arguments["url"]; + WebUri? uri = url != null ? WebUri(url) : null; + if (webviewParams != null && + webviewParams!.onPageCommitVisible != null) + webviewParams!.onPageCommitVisible!(_controllerFromPlatform, uri); + else + _inAppBrowserEventHandler!.onPageCommitVisible(uri); + } + break; + case "onDidReceiveServerRedirectForProvisionalNavigation": + if (webviewParams != null && + (webviewParams! + .onDidReceiveServerRedirectForProvisionalNavigation != + null || + params + .webviewParams! + // ignore: deprecated_member_use_from_same_package + .iosOnDidReceiveServerRedirectForProvisionalNavigation != + null)) { + if (webviewParams! + .onDidReceiveServerRedirectForProvisionalNavigation != + null) + webviewParams!.onDidReceiveServerRedirectForProvisionalNavigation!( + _controllerFromPlatform); + else { + params + .webviewParams! + // ignore: deprecated_member_use_from_same_package + .iosOnDidReceiveServerRedirectForProvisionalNavigation!( + _controllerFromPlatform); + } + } else if (_inAppBrowserEventHandler != null) { + _inAppBrowserEventHandler! + .onDidReceiveServerRedirectForProvisionalNavigation(); + _inAppBrowserEventHandler! + .iosOnDidReceiveServerRedirectForProvisionalNavigation(); + } + break; + case "onNavigationResponse": + if ((webviewParams != null && + (webviewParams!.onNavigationResponse != null || + // ignore: deprecated_member_use_from_same_package + webviewParams!.iosOnNavigationResponse != null)) || + _inAppBrowserEventHandler != null) { + Map arguments = + call.arguments.cast(); + // ignore: deprecated_member_use_from_same_package + IOSWKNavigationResponse iosOnNavigationResponse = + // ignore: deprecated_member_use_from_same_package + IOSWKNavigationResponse.fromMap(arguments)!; + + NavigationResponse navigationResponse = + NavigationResponse.fromMap(arguments)!; + + if (webviewParams != null) { + if (webviewParams!.onNavigationResponse != null) + return (await webviewParams!.onNavigationResponse!( + _controllerFromPlatform, navigationResponse)) + ?.toNativeValue(); + else { + // ignore: deprecated_member_use_from_same_package + return (await webviewParams!.iosOnNavigationResponse!( + _controllerFromPlatform, iosOnNavigationResponse)) + ?.toNativeValue(); + } + } else { + return (await _inAppBrowserEventHandler! + .onNavigationResponse(navigationResponse)) + ?.toNativeValue() ?? + (await _inAppBrowserEventHandler! + .iosOnNavigationResponse(iosOnNavigationResponse)) + ?.toNativeValue(); + } + } + break; + case "shouldAllowDeprecatedTLS": + if ((webviewParams != null && + (webviewParams!.shouldAllowDeprecatedTLS != null || + // ignore: deprecated_member_use_from_same_package + webviewParams!.iosShouldAllowDeprecatedTLS != null)) || + _inAppBrowserEventHandler != null) { + Map arguments = + call.arguments.cast(); + URLAuthenticationChallenge challenge = + URLAuthenticationChallenge.fromMap(arguments)!; + + if (webviewParams != null) { + if (webviewParams!.shouldAllowDeprecatedTLS != null) + return (await webviewParams!.shouldAllowDeprecatedTLS!( + _controllerFromPlatform, challenge)) + ?.toNativeValue(); + else { + // ignore: deprecated_member_use_from_same_package + return (await webviewParams!.iosShouldAllowDeprecatedTLS!( + _controllerFromPlatform, challenge)) + ?.toNativeValue(); + } + } else { + return (await _inAppBrowserEventHandler! + .shouldAllowDeprecatedTLS(challenge)) + ?.toNativeValue() ?? + // ignore: deprecated_member_use_from_same_package + (await _inAppBrowserEventHandler! + .iosShouldAllowDeprecatedTLS(challenge)) + ?.toNativeValue(); + } + } + break; + case "onLongPressHitTestResult": + if ((webviewParams != null && + webviewParams!.onLongPressHitTestResult != null) || + _inAppBrowserEventHandler != null) { + Map arguments = + call.arguments.cast(); + InAppWebViewHitTestResult hitTestResult = + InAppWebViewHitTestResult.fromMap(arguments)!; + + if (webviewParams != null && + webviewParams!.onLongPressHitTestResult != null) + webviewParams!.onLongPressHitTestResult!( + _controllerFromPlatform, hitTestResult); + else + _inAppBrowserEventHandler!.onLongPressHitTestResult(hitTestResult); + } + break; + case "onCreateContextMenu": + ContextMenu? contextMenu; + if (webviewParams != null && webviewParams!.contextMenu != null) { + contextMenu = webviewParams!.contextMenu; + } else if (_inAppBrowserEventHandler != null && + _inAppBrowser!.contextMenu != null) { + contextMenu = _inAppBrowser!.contextMenu; + } + + if (contextMenu != null && contextMenu.onCreateContextMenu != null) { + Map arguments = + call.arguments.cast(); + InAppWebViewHitTestResult hitTestResult = + InAppWebViewHitTestResult.fromMap(arguments)!; + + contextMenu.onCreateContextMenu!(hitTestResult); + } + break; + case "onHideContextMenu": + ContextMenu? contextMenu; + if (webviewParams != null && webviewParams!.contextMenu != null) { + contextMenu = webviewParams!.contextMenu; + } else if (_inAppBrowserEventHandler != null && + _inAppBrowser!.contextMenu != null) { + contextMenu = _inAppBrowser!.contextMenu; + } + + if (contextMenu != null && contextMenu.onHideContextMenu != null) { + contextMenu.onHideContextMenu!(); + } + break; + case "onContextMenuActionItemClicked": + ContextMenu? contextMenu; + if (webviewParams != null && webviewParams!.contextMenu != null) { + contextMenu = webviewParams!.contextMenu; + } else if (_inAppBrowserEventHandler != null && + _inAppBrowser!.contextMenu != null) { + contextMenu = _inAppBrowser!.contextMenu; + } + + if (contextMenu != null) { + int? androidId = call.arguments["androidId"]; + String? iosId = call.arguments["iosId"]; + dynamic id = call.arguments["id"]; + String title = call.arguments["title"]; + + ContextMenuItem menuItemClicked = ContextMenuItem( + id: id, + // ignore: deprecated_member_use_from_same_package + androidId: androidId, + // ignore: deprecated_member_use_from_same_package + iosId: iosId, + title: title, + action: null); + + for (var menuItem in contextMenu.menuItems) { + if (menuItem.id == id) { + menuItemClicked = menuItem; + if (menuItem.action != null) { + menuItem.action!(); + } + break; + } + } + + if (contextMenu.onContextMenuActionItemClicked != null) { + contextMenu.onContextMenuActionItemClicked!(menuItemClicked); + } + } + break; + case "onEnterFullscreen": + if (webviewParams != null && webviewParams!.onEnterFullscreen != null) + webviewParams!.onEnterFullscreen!(_controllerFromPlatform); + else if (_inAppBrowserEventHandler != null) + _inAppBrowserEventHandler!.onEnterFullscreen(); + break; + case "onExitFullscreen": + if (webviewParams != null && webviewParams!.onExitFullscreen != null) + webviewParams!.onExitFullscreen!(_controllerFromPlatform); + else if (_inAppBrowserEventHandler != null) + _inAppBrowserEventHandler!.onExitFullscreen(); + break; + case "onOverScrolled": + if ((webviewParams != null && webviewParams!.onOverScrolled != null) || + _inAppBrowserEventHandler != null) { + int x = call.arguments["x"]; + int y = call.arguments["y"]; + bool clampedX = call.arguments["clampedX"]; + bool clampedY = call.arguments["clampedY"]; + + if (webviewParams != null && webviewParams!.onOverScrolled != null) + webviewParams!.onOverScrolled!( + _controllerFromPlatform, x, y, clampedX, clampedY); + else + _inAppBrowserEventHandler!.onOverScrolled(x, y, clampedX, clampedY); + } + break; + case "onWindowFocus": + if (webviewParams != null && webviewParams!.onWindowFocus != null) + webviewParams!.onWindowFocus!(_controllerFromPlatform); + else if (_inAppBrowserEventHandler != null) + _inAppBrowserEventHandler!.onWindowFocus(); + break; + case "onWindowBlur": + if (webviewParams != null && webviewParams!.onWindowBlur != null) + webviewParams!.onWindowBlur!(_controllerFromPlatform); + else if (_inAppBrowserEventHandler != null) + _inAppBrowserEventHandler!.onWindowBlur(); + break; + case "onPrintRequest": + if ((webviewParams != null && + (webviewParams!.onPrintRequest != null || + // ignore: deprecated_member_use_from_same_package + webviewParams!.onPrint != null)) || + _inAppBrowserEventHandler != null) { + String? url = call.arguments["url"]; + String? printJobId = call.arguments["printJobId"]; + WebUri? uri = url != null ? WebUri(url) : null; + MacOSPrintJobController? printJob = printJobId != null + ? MacOSPrintJobController( + MacOSPrintJobControllerCreationParams(id: printJobId)) + : null; + + if (webviewParams != null) { + if (webviewParams!.onPrintRequest != null) + return await webviewParams!.onPrintRequest!( + _controllerFromPlatform, uri, printJob); + else { + // ignore: deprecated_member_use_from_same_package + webviewParams!.onPrint!(_controllerFromPlatform, uri); + return false; + } + } else { + // ignore: deprecated_member_use_from_same_package + _inAppBrowserEventHandler!.onPrint(uri); + return await _inAppBrowserEventHandler! + .onPrintRequest(uri, printJob); + } + } + break; + case "onInjectedScriptLoaded": + String id = call.arguments[0]; + var onLoadCallback = _injectedScriptsFromURL[id]?.onLoad; + if ((webviewParams != null || _inAppBrowserEventHandler != null) && + onLoadCallback != null) { + onLoadCallback(); + } + break; + case "onInjectedScriptError": + String id = call.arguments[0]; + var onErrorCallback = _injectedScriptsFromURL[id]?.onError; + if ((webviewParams != null || _inAppBrowserEventHandler != null) && + onErrorCallback != null) { + onErrorCallback(); + } + break; + case "onCameraCaptureStateChanged": + if ((webviewParams != null && + webviewParams!.onCameraCaptureStateChanged != null) || + _inAppBrowserEventHandler != null) { + var oldState = + MediaCaptureState.fromNativeValue(call.arguments["oldState"]); + var newState = + MediaCaptureState.fromNativeValue(call.arguments["newState"]); + + if (webviewParams != null && + webviewParams!.onCameraCaptureStateChanged != null) + webviewParams!.onCameraCaptureStateChanged!( + _controllerFromPlatform, oldState, newState); + else + _inAppBrowserEventHandler! + .onCameraCaptureStateChanged(oldState, newState); + } + break; + case "onMicrophoneCaptureStateChanged": + if ((webviewParams != null && + webviewParams!.onMicrophoneCaptureStateChanged != null) || + _inAppBrowserEventHandler != null) { + var oldState = + MediaCaptureState.fromNativeValue(call.arguments["oldState"]); + var newState = + MediaCaptureState.fromNativeValue(call.arguments["newState"]); + + if (webviewParams != null && + webviewParams!.onMicrophoneCaptureStateChanged != null) + webviewParams!.onMicrophoneCaptureStateChanged!( + _controllerFromPlatform, oldState, newState); + else + _inAppBrowserEventHandler! + .onMicrophoneCaptureStateChanged(oldState, newState); + } + break; + case "onContentSizeChanged": + if ((webviewParams != null && + webviewParams!.onContentSizeChanged != null) || + _inAppBrowserEventHandler != null) { + var oldContentSize = MapSize.fromMap( + call.arguments["oldContentSize"]?.cast())!; + var newContentSize = MapSize.fromMap( + call.arguments["newContentSize"]?.cast())!; + + if (webviewParams != null && + webviewParams!.onContentSizeChanged != null) + webviewParams!.onContentSizeChanged!( + _controllerFromPlatform, oldContentSize, newContentSize); + else + _inAppBrowserEventHandler! + .onContentSizeChanged(oldContentSize, newContentSize); + } + break; + case "onCallJsHandler": + String handlerName = call.arguments["handlerName"]; + // decode args to json + List args = jsonDecode(call.arguments["args"]); + + _debugLog(handlerName, args); + + switch (handlerName) { + case "onLoadResource": + if ((webviewParams != null && + webviewParams!.onLoadResource != null) || + _inAppBrowserEventHandler != null) { + Map arguments = args[0].cast(); + arguments["startTime"] = arguments["startTime"] is int + ? arguments["startTime"].toDouble() + : arguments["startTime"]; + arguments["duration"] = arguments["duration"] is int + ? arguments["duration"].toDouble() + : arguments["duration"]; + + var response = LoadedResource.fromMap(arguments)!; + + if (webviewParams != null && + webviewParams!.onLoadResource != null) + webviewParams!.onLoadResource!( + _controllerFromPlatform, response); + else + _inAppBrowserEventHandler!.onLoadResource(response); + } + return null; + case "shouldInterceptAjaxRequest": + if ((webviewParams != null && + webviewParams!.shouldInterceptAjaxRequest != null) || + _inAppBrowserEventHandler != null) { + Map arguments = args[0].cast(); + AjaxRequest request = AjaxRequest.fromMap(arguments)!; + + if (webviewParams != null && + webviewParams!.shouldInterceptAjaxRequest != null) + return jsonEncode( + await params.webviewParams!.shouldInterceptAjaxRequest!( + _controllerFromPlatform, request)); + else + return jsonEncode(await _inAppBrowserEventHandler! + .shouldInterceptAjaxRequest(request)); + } + return null; + case "onAjaxReadyStateChange": + if ((webviewParams != null && + webviewParams!.onAjaxReadyStateChange != null) || + _inAppBrowserEventHandler != null) { + Map arguments = args[0].cast(); + AjaxRequest request = AjaxRequest.fromMap(arguments)!; + + if (webviewParams != null && + webviewParams!.onAjaxReadyStateChange != null) + return (await webviewParams!.onAjaxReadyStateChange!( + _controllerFromPlatform, request)) + ?.toNativeValue(); + else + return (await _inAppBrowserEventHandler! + .onAjaxReadyStateChange(request)) + ?.toNativeValue(); + } + return null; + case "onAjaxProgress": + if ((webviewParams != null && + webviewParams!.onAjaxProgress != null) || + _inAppBrowserEventHandler != null) { + Map arguments = args[0].cast(); + AjaxRequest request = AjaxRequest.fromMap(arguments)!; + + if (webviewParams != null && + webviewParams!.onAjaxProgress != null) + return (await webviewParams!.onAjaxProgress!( + _controllerFromPlatform, request)) + ?.toNativeValue(); + else + return (await _inAppBrowserEventHandler! + .onAjaxProgress(request)) + ?.toNativeValue(); + } + return null; + case "shouldInterceptFetchRequest": + if ((webviewParams != null && + webviewParams!.shouldInterceptFetchRequest != null) || + _inAppBrowserEventHandler != null) { + Map arguments = args[0].cast(); + FetchRequest request = FetchRequest.fromMap(arguments)!; + + if (webviewParams != null && + webviewParams!.shouldInterceptFetchRequest != null) + return jsonEncode( + await webviewParams!.shouldInterceptFetchRequest!( + _controllerFromPlatform, request)); + else + return jsonEncode(await _inAppBrowserEventHandler! + .shouldInterceptFetchRequest(request)); + } + return null; + case "onWindowFocus": + if (webviewParams != null && webviewParams!.onWindowFocus != null) + webviewParams!.onWindowFocus!(_controllerFromPlatform); + else if (_inAppBrowserEventHandler != null) + _inAppBrowserEventHandler!.onWindowFocus(); + return null; + case "onWindowBlur": + if (webviewParams != null && webviewParams!.onWindowBlur != null) + webviewParams!.onWindowBlur!(_controllerFromPlatform); + else if (_inAppBrowserEventHandler != null) + _inAppBrowserEventHandler!.onWindowBlur(); + return null; + case "onInjectedScriptLoaded": + String id = args[0]; + var onLoadCallback = _injectedScriptsFromURL[id]?.onLoad; + if ((webviewParams != null || _inAppBrowserEventHandler != null) && + onLoadCallback != null) { + onLoadCallback(); + } + return null; + case "onInjectedScriptError": + String id = args[0]; + var onErrorCallback = _injectedScriptsFromURL[id]?.onError; + if ((webviewParams != null || _inAppBrowserEventHandler != null) && + onErrorCallback != null) { + onErrorCallback(); + } + return null; + } + + if (_javaScriptHandlersMap.containsKey(handlerName)) { + // convert result to json + try { + return jsonEncode(await _javaScriptHandlersMap[handlerName]!(args)); + } catch (error, stacktrace) { + developer.log(error.toString() + '\n' + stacktrace.toString(), + name: 'JavaScript Handler "$handlerName"'); + throw Exception(error.toString().replaceFirst('Exception: ', '')); + } + } + break; + default: + throw UnimplementedError("Unimplemented ${call.method} method"); + } + return null; + } + + @override + Future getUrl() async { + Map args = {}; + String? url = await channel?.invokeMethod('getUrl', args); + return url != null ? WebUri(url) : null; + } + + @override + Future getTitle() async { + Map args = {}; + return await channel?.invokeMethod('getTitle', args); + } + + @override + Future getProgress() async { + Map args = {}; + return await channel?.invokeMethod('getProgress', args); + } + + @override + Future getHtml() async { + String? html; + + InAppWebViewSettings? settings = await getSettings(); + if (settings != null && settings.javaScriptEnabled == true) { + html = await evaluateJavascript( + source: "window.document.getElementsByTagName('html')[0].outerHTML;"); + if (html != null && html.isNotEmpty) return html; + } + + var webviewUrl = await getUrl(); + if (webviewUrl == null) { + return html; + } + + if (webviewUrl.isScheme("file")) { + var assetPathSplitted = webviewUrl.toString().split("/flutter_assets/"); + var assetPath = assetPathSplitted[assetPathSplitted.length - 1]; + try { + var bytes = await rootBundle.load(assetPath); + html = utf8.decode(bytes.buffer.asUint8List()); + } catch (e) {} + } else { + try { + HttpClient client = HttpClient(); + var htmlRequest = await client.getUrl(webviewUrl); + html = + await (await htmlRequest.close()).transform(Utf8Decoder()).join(); + } catch (e) { + developer.log(e.toString(), name: this.runtimeType.toString()); + } + } + + return html; + } + + @override + Future> getFavicons() async { + List favicons = []; + + var webviewUrl = await getUrl(); + + if (webviewUrl == null) { + return favicons; + } + + String? manifestUrl; + + var html = await getHtml(); + if (html == null || html.isEmpty) { + return favicons; + } + var assetPathBase; + + if (webviewUrl.isScheme("file")) { + var assetPathSplitted = webviewUrl.toString().split("/flutter_assets/"); + assetPathBase = assetPathSplitted[0] + "/flutter_assets/"; + } + + InAppWebViewSettings? settings = await getSettings(); + if (settings != null && settings.javaScriptEnabled == true) { + List> links = (await evaluateJavascript(source: """ +(function() { + var linkNodes = document.head.getElementsByTagName("link"); + var links = []; + for (var i = 0; i < linkNodes.length; i++) { + var linkNode = linkNodes[i]; + if (linkNode.rel === 'manifest') { + links.push( + { + rel: linkNode.rel, + href: linkNode.href, + sizes: null + } + ); + } else if (linkNode.rel != null && linkNode.rel.indexOf('icon') >= 0) { + links.push( + { + rel: linkNode.rel, + href: linkNode.href, + sizes: linkNode.sizes != null && linkNode.sizes.value != "" ? linkNode.sizes.value : null + } + ); + } + } + return links; +})(); +"""))?.cast>() ?? []; + for (var link in links) { + if (link["rel"] == "manifest") { + manifestUrl = link["href"]; + if (!_isUrlAbsolute(manifestUrl!)) { + if (manifestUrl.startsWith("/")) { + manifestUrl = manifestUrl.substring(1); + } + manifestUrl = ((assetPathBase == null) + ? webviewUrl.scheme + "://" + webviewUrl.host + "/" + : assetPathBase) + + manifestUrl; + } + continue; + } + favicons.addAll(_createFavicons(webviewUrl, assetPathBase, link["href"], + link["rel"], link["sizes"], false)); + } + } + + // try to get /favicon.ico + try { + HttpClient client = HttpClient(); + var faviconUrl = + webviewUrl.scheme + "://" + webviewUrl.host + "/favicon.ico"; + var faviconUri = WebUri(faviconUrl); + var headRequest = await client.headUrl(faviconUri); + var headResponse = await headRequest.close(); + if (headResponse.statusCode == 200) { + favicons.add(Favicon(url: faviconUri, rel: "shortcut icon")); + } + } catch (e) { + developer.log("/favicon.ico file not found: " + e.toString(), + name: this.runtimeType.toString()); + } + + // try to get the manifest file + HttpClientRequest? manifestRequest; + HttpClientResponse? manifestResponse; + bool manifestFound = false; + if (manifestUrl == null) { + manifestUrl = + webviewUrl.scheme + "://" + webviewUrl.host + "/manifest.json"; + } + try { + HttpClient client = HttpClient(); + manifestRequest = await client.getUrl(Uri.parse(manifestUrl)); + manifestResponse = await manifestRequest.close(); + manifestFound = manifestResponse.statusCode == 200 && + manifestResponse.headers.contentType?.mimeType == "application/json"; + } catch (e) { + developer.log("Manifest file not found: " + e.toString(), + name: this.runtimeType.toString()); + } + + if (manifestFound) { + try { + Map manifest = json + .decode(await manifestResponse!.transform(Utf8Decoder()).join()); + if (manifest.containsKey("icons")) { + for (Map icon in manifest["icons"]) { + favicons.addAll(_createFavicons(webviewUrl, assetPathBase, + icon["src"], icon["rel"], icon["sizes"], true)); + } + } + } on FormatException catch (_) { + /// The [manifestResponse] might not has a valid JSON string, catch and + /// ignore the error + } + } + + return favicons; + } + + bool _isUrlAbsolute(String url) { + return url.startsWith("http://") || url.startsWith("https://"); + } + + List _createFavicons(WebUri url, String? assetPathBase, + String urlIcon, String? rel, String? sizes, bool isManifest) { + List favicons = []; + + List urlSplitted = urlIcon.split("/"); + if (!_isUrlAbsolute(urlIcon)) { + if (urlIcon.startsWith("/")) { + urlIcon = urlIcon.substring(1); + } + urlIcon = ((assetPathBase == null) + ? url.scheme + "://" + url.host + "/" + : assetPathBase) + + urlIcon; + } + if (isManifest) { + rel = (sizes != null) + ? urlSplitted[urlSplitted.length - 1] + .replaceFirst("-" + sizes, "") + .split(" ")[0] + .split(".")[0] + : null; + } + if (sizes != null && sizes.isNotEmpty && sizes != "any") { + List sizesSplitted = sizes.split(" "); + for (String size in sizesSplitted) { + int width = int.parse(size.split("x")[0]); + int height = int.parse(size.split("x")[1]); + favicons.add(Favicon( + url: WebUri(urlIcon), rel: rel, width: width, height: height)); + } + } else { + favicons.add( + Favicon(url: WebUri(urlIcon), rel: rel, width: null, height: null)); + } + + return favicons; + } + + @override + Future loadUrl( + {required URLRequest urlRequest, + @Deprecated('Use allowingReadAccessTo instead') + Uri? iosAllowingReadAccessTo, + WebUri? allowingReadAccessTo}) async { + assert(urlRequest.url != null && urlRequest.url.toString().isNotEmpty); + assert( + allowingReadAccessTo == null || allowingReadAccessTo.isScheme("file")); + assert(iosAllowingReadAccessTo == null || + iosAllowingReadAccessTo.isScheme("file")); + + Map args = {}; + args.putIfAbsent('urlRequest', () => urlRequest.toMap()); + args.putIfAbsent( + 'allowingReadAccessTo', + () => + allowingReadAccessTo?.toString() ?? + iosAllowingReadAccessTo?.toString()); + await channel?.invokeMethod('loadUrl', args); + } + + @override + Future postUrl( + {required WebUri url, required Uint8List postData}) async { + assert(url.toString().isNotEmpty); + Map args = {}; + args.putIfAbsent('url', () => url.toString()); + args.putIfAbsent('postData', () => postData); + await channel?.invokeMethod('postUrl', args); + } + + @override + Future loadData( + {required String data, + String mimeType = "text/html", + String encoding = "utf8", + WebUri? baseUrl, + @Deprecated('Use historyUrl instead') Uri? androidHistoryUrl, + WebUri? historyUrl, + @Deprecated('Use allowingReadAccessTo instead') + Uri? iosAllowingReadAccessTo, + WebUri? allowingReadAccessTo}) async { + assert( + allowingReadAccessTo == null || allowingReadAccessTo.isScheme("file")); + assert(iosAllowingReadAccessTo == null || + iosAllowingReadAccessTo.isScheme("file")); + + Map args = {}; + args.putIfAbsent('data', () => data); + args.putIfAbsent('mimeType', () => mimeType); + args.putIfAbsent('encoding', () => encoding); + args.putIfAbsent('baseUrl', () => baseUrl?.toString() ?? "about:blank"); + args.putIfAbsent( + 'historyUrl', + () => + historyUrl?.toString() ?? + androidHistoryUrl?.toString() ?? + "about:blank"); + args.putIfAbsent( + 'allowingReadAccessTo', + () => + allowingReadAccessTo?.toString() ?? + iosAllowingReadAccessTo?.toString()); + await channel?.invokeMethod('loadData', args); + } + + @override + Future loadFile({required String assetFilePath}) async { + assert(assetFilePath.isNotEmpty); + Map args = {}; + args.putIfAbsent('assetFilePath', () => assetFilePath); + await channel?.invokeMethod('loadFile', args); + } + + @override + Future reload() async { + Map args = {}; + await channel?.invokeMethod('reload', args); + } + + @override + Future goBack() async { + Map args = {}; + await channel?.invokeMethod('goBack', args); + } + + @override + Future canGoBack() async { + Map args = {}; + return await channel?.invokeMethod('canGoBack', args) ?? false; + } + + @override + Future goForward() async { + Map args = {}; + await channel?.invokeMethod('goForward', args); + } + + @override + Future canGoForward() async { + Map args = {}; + return await channel?.invokeMethod('canGoForward', args) ?? false; + } + + @override + Future goBackOrForward({required int steps}) async { + Map args = {}; + args.putIfAbsent('steps', () => steps); + await channel?.invokeMethod('goBackOrForward', args); + } + + @override + Future canGoBackOrForward({required int steps}) async { + Map args = {}; + args.putIfAbsent('steps', () => steps); + return await channel?.invokeMethod('canGoBackOrForward', args) ?? + false; + } + + @override + Future goTo({required WebHistoryItem historyItem}) async { + var steps = historyItem.offset; + if (steps != null) { + await goBackOrForward(steps: steps); + } + } + + @override + Future isLoading() async { + Map args = {}; + return await channel?.invokeMethod('isLoading', args) ?? false; + } + + @override + Future stopLoading() async { + Map args = {}; + await channel?.invokeMethod('stopLoading', args); + } + + @override + Future evaluateJavascript( + {required String source, ContentWorld? contentWorld}) async { + Map args = {}; + args.putIfAbsent('source', () => source); + args.putIfAbsent('contentWorld', () => contentWorld?.toMap()); + var data = await channel?.invokeMethod('evaluateJavascript', args); + return data; + } + + @override + Future injectJavascriptFileFromUrl( + {required WebUri urlFile, + ScriptHtmlTagAttributes? scriptHtmlTagAttributes}) async { + assert(urlFile.toString().isNotEmpty); + var id = scriptHtmlTagAttributes?.id; + if (scriptHtmlTagAttributes != null && id != null) { + _injectedScriptsFromURL[id] = scriptHtmlTagAttributes; + } + Map args = {}; + args.putIfAbsent('urlFile', () => urlFile.toString()); + args.putIfAbsent( + 'scriptHtmlTagAttributes', () => scriptHtmlTagAttributes?.toMap()); + await channel?.invokeMethod('injectJavascriptFileFromUrl', args); + } + + @override + Future injectJavascriptFileFromAsset( + {required String assetFilePath}) async { + String source = await rootBundle.loadString(assetFilePath); + return await evaluateJavascript(source: source); + } + + @override + Future injectCSSCode({required String source}) async { + Map args = {}; + args.putIfAbsent('source', () => source); + await channel?.invokeMethod('injectCSSCode', args); + } + + @override + Future injectCSSFileFromUrl( + {required WebUri urlFile, + CSSLinkHtmlTagAttributes? cssLinkHtmlTagAttributes}) async { + assert(urlFile.toString().isNotEmpty); + Map args = {}; + args.putIfAbsent('urlFile', () => urlFile.toString()); + args.putIfAbsent( + 'cssLinkHtmlTagAttributes', () => cssLinkHtmlTagAttributes?.toMap()); + await channel?.invokeMethod('injectCSSFileFromUrl', args); + } + + @override + Future injectCSSFileFromAsset({required String assetFilePath}) async { + String source = await rootBundle.loadString(assetFilePath); + await injectCSSCode(source: source); + } + + @override + void addJavaScriptHandler( + {required String handlerName, + required JavaScriptHandlerCallback callback}) { + assert(!_JAVASCRIPT_HANDLER_FORBIDDEN_NAMES.contains(handlerName), + '"$handlerName" is a forbidden name!'); + this._javaScriptHandlersMap[handlerName] = (callback); + } + + @override + JavaScriptHandlerCallback? removeJavaScriptHandler( + {required String handlerName}) { + return this._javaScriptHandlersMap.remove(handlerName); + } + + @override + bool hasJavaScriptHandler({required String handlerName}) { + return this._javaScriptHandlersMap.containsKey(handlerName); + } + + @override + Future takeScreenshot( + {ScreenshotConfiguration? screenshotConfiguration}) async { + Map args = {}; + args.putIfAbsent( + 'screenshotConfiguration', () => screenshotConfiguration?.toMap()); + return await channel?.invokeMethod('takeScreenshot', args); + } + + @override + @Deprecated('Use setSettings instead') + Future setOptions({required InAppWebViewGroupOptions options}) async { + InAppWebViewSettings settings = + InAppWebViewSettings.fromMap(options.toMap()) ?? InAppWebViewSettings(); + await setSettings(settings: settings); + } + + @override + @Deprecated('Use getSettings instead') + Future getOptions() async { + InAppWebViewSettings? settings = await getSettings(); + + Map? options = settings?.toMap(); + if (options != null) { + options = options.cast(); + return InAppWebViewGroupOptions.fromMap(options as Map); + } + + return null; + } + + @override + Future setSettings({required InAppWebViewSettings settings}) async { + Map args = {}; + + args.putIfAbsent('settings', () => settings.toMap()); + await channel?.invokeMethod('setSettings', args); + } + + @override + Future getSettings() async { + Map args = {}; + + Map? settings = + await channel?.invokeMethod('getSettings', args); + if (settings != null) { + settings = settings.cast(); + return InAppWebViewSettings.fromMap(settings as Map); + } + + return null; + } + + @override + Future getCopyBackForwardList() async { + Map args = {}; + Map? result = + (await channel?.invokeMethod('getCopyBackForwardList', args)) + ?.cast(); + return WebHistory.fromMap(result); + } + + @override + Future clearCache() async { + Map args = {}; + await channel?.invokeMethod('clearCache', args); + } + + @override + @Deprecated("Use FindInteractionController.findAll instead") + Future findAllAsync({required String find}) async { + Map args = {}; + args.putIfAbsent('find', () => find); + await channel?.invokeMethod('findAll', args); + } + + @override + @Deprecated("Use FindInteractionController.findNext instead") + Future findNext({required bool forward}) async { + Map args = {}; + args.putIfAbsent('forward', () => forward); + await channel?.invokeMethod('findNext', args); + } + + @override + @Deprecated("Use FindInteractionController.clearMatches instead") + Future clearMatches() async { + Map args = {}; + await channel?.invokeMethod('clearMatches', args); + } + + @override + @Deprecated("Use tRexRunnerHtml instead") + Future getTRexRunnerHtml() async { + return await tRexRunnerHtml; + } + + @override + @Deprecated("Use tRexRunnerCss instead") + Future getTRexRunnerCss() async { + return await tRexRunnerCss; + } + + @override + Future scrollTo( + {required int x, required int y, bool animated = false}) async { + Map args = {}; + args.putIfAbsent('x', () => x); + args.putIfAbsent('y', () => y); + args.putIfAbsent('animated', () => animated); + await channel?.invokeMethod('scrollTo', args); + } + + @override + Future scrollBy( + {required int x, required int y, bool animated = false}) async { + Map args = {}; + args.putIfAbsent('x', () => x); + args.putIfAbsent('y', () => y); + args.putIfAbsent('animated', () => animated); + await channel?.invokeMethod('scrollBy', args); + } + + @override + Future pauseTimers() async { + Map args = {}; + await channel?.invokeMethod('pauseTimers', args); + } + + @override + Future resumeTimers() async { + Map args = {}; + await channel?.invokeMethod('resumeTimers', args); + } + + @override + Future printCurrentPage( + {PrintJobSettings? settings}) async { + Map args = {}; + args.putIfAbsent("settings", () => settings?.toMap()); + String? jobId = + await channel?.invokeMethod('printCurrentPage', args); + if (jobId != null) { + return MacOSPrintJobController( + PlatformPrintJobControllerCreationParams(id: jobId)); + } + return null; + } + + @override + Future getContentHeight() async { + Map args = {}; + var height = await channel?.invokeMethod('getContentHeight', args); + if (height == null || height == 0) { + // try to use javascript + var scrollHeight = await evaluateJavascript( + source: "document.documentElement.scrollHeight;"); + if (scrollHeight != null && scrollHeight is num) { + height = scrollHeight.toInt(); + } + } + return height; + } + + @override + Future getContentWidth() async { + Map args = {}; + var height = await channel?.invokeMethod('getContentWidth', args); + if (height == null || height == 0) { + // try to use javascript + var scrollHeight = await evaluateJavascript( + source: "document.documentElement.scrollWidth;"); + if (scrollHeight != null && scrollHeight is num) { + height = scrollHeight.toInt(); + } + } + return height; + } + + @override + Future zoomBy( + {required double zoomFactor, + @Deprecated('Use animated instead') bool? iosAnimated, + bool animated = false}) async { + Map args = {}; + args.putIfAbsent('zoomFactor', () => zoomFactor); + args.putIfAbsent('animated', () => iosAnimated ?? animated); + return await channel?.invokeMethod('zoomBy', args); + } + + @override + Future getOriginalUrl() async { + Map args = {}; + String? url = await channel?.invokeMethod('getOriginalUrl', args); + return url != null ? WebUri(url) : null; + } + + @override + @Deprecated('Use getZoomScale instead') + Future getScale() async { + return await getZoomScale(); + } + + @override + Future getSelectedText() async { + Map args = {}; + return await channel?.invokeMethod('getSelectedText', args); + } + + @override + Future> getMetaTags() async { + List metaTags = []; + + List>? metaTagList = + (await evaluateJavascript(source: """ +(function() { + var metaTags = []; + var metaTagNodes = document.head.getElementsByTagName('meta'); + for (var i = 0; i < metaTagNodes.length; i++) { + var metaTagNode = metaTagNodes[i]; + + var otherAttributes = metaTagNode.getAttributeNames(); + var nameIndex = otherAttributes.indexOf("name"); + if (nameIndex !== -1) otherAttributes.splice(nameIndex, 1); + var contentIndex = otherAttributes.indexOf("content"); + if (contentIndex !== -1) otherAttributes.splice(contentIndex, 1); + + var attrs = []; + for (var j = 0; j < otherAttributes.length; j++) { + var otherAttribute = otherAttributes[j]; + attrs.push( + { + name: otherAttribute, + value: metaTagNode.getAttribute(otherAttribute) + } + ); + } + + metaTags.push( + { + name: metaTagNode.name, + content: metaTagNode.content, + attrs: attrs + } + ); + } + return metaTags; +})(); + """))?.cast>(); + + if (metaTagList == null) { + return metaTags; + } + + for (var metaTag in metaTagList) { + var attrs = []; + + for (var metaTagAttr in metaTag["attrs"]) { + attrs.add(MetaTagAttribute( + name: metaTagAttr["name"], value: metaTagAttr["value"])); + } + + metaTags.add(MetaTag( + name: metaTag["name"], content: metaTag["content"], attrs: attrs)); + } + + return metaTags; + } + + @override + Future getMetaThemeColor() async { + Color? themeColor; + + try { + Map args = {}; + themeColor = UtilColor.fromStringRepresentation( + await channel?.invokeMethod('getMetaThemeColor', args)); + return themeColor; + } catch (e) { + // not implemented + } + + // try using javascript + var metaTags = await getMetaTags(); + MetaTag? metaTagThemeColor; + + for (var metaTag in metaTags) { + if (metaTag.name == "theme-color") { + metaTagThemeColor = metaTag; + break; + } + } + + if (metaTagThemeColor == null) { + return null; + } + + var colorValue = metaTagThemeColor.content; + + themeColor = colorValue != null + ? UtilColor.fromStringRepresentation(colorValue) + : null; + + return themeColor; + } + + @override + Future getScrollX() async { + Map args = {}; + return await channel?.invokeMethod('getScrollX', args); + } + + @override + Future getScrollY() async { + Map args = {}; + return await channel?.invokeMethod('getScrollY', args); + } + + @override + Future getCertificate() async { + Map args = {}; + Map? sslCertificateMap = + (await channel?.invokeMethod('getCertificate', args)) + ?.cast(); + return SslCertificate.fromMap(sslCertificateMap); + } + + @override + Future addUserScript({required UserScript userScript}) async { + assert(webviewParams?.windowId == null); + + Map args = {}; + args.putIfAbsent('userScript', () => userScript.toMap()); + if (!(_userScripts[userScript.injectionTime]?.contains(userScript) ?? + false)) { + _userScripts[userScript.injectionTime]?.add(userScript); + await channel?.invokeMethod('addUserScript', args); + } + } + + @override + Future addUserScripts({required List userScripts}) async { + assert(webviewParams?.windowId == null); + + for (var i = 0; i < userScripts.length; i++) { + await addUserScript(userScript: userScripts[i]); + } + } + + @override + Future removeUserScript({required UserScript userScript}) async { + assert(webviewParams?.windowId == null); + + var index = _userScripts[userScript.injectionTime]?.indexOf(userScript); + if (index == null || index == -1) { + return false; + } + + _userScripts[userScript.injectionTime]?.remove(userScript); + Map args = {}; + args.putIfAbsent('userScript', () => userScript.toMap()); + args.putIfAbsent('index', () => index); + await channel?.invokeMethod('removeUserScript', args); + + return true; + } + + @override + Future removeUserScriptsByGroupName({required String groupName}) async { + assert(webviewParams?.windowId == null); + + final List userScriptsAtDocumentStart = List.from( + _userScripts[UserScriptInjectionTime.AT_DOCUMENT_START] ?? []); + for (final userScript in userScriptsAtDocumentStart) { + if (userScript.groupName == groupName) { + _userScripts[userScript.injectionTime]?.remove(userScript); + } + } + + final List userScriptsAtDocumentEnd = + List.from(_userScripts[UserScriptInjectionTime.AT_DOCUMENT_END] ?? []); + for (final userScript in userScriptsAtDocumentEnd) { + if (userScript.groupName == groupName) { + _userScripts[userScript.injectionTime]?.remove(userScript); + } + } + + Map args = {}; + args.putIfAbsent('groupName', () => groupName); + await channel?.invokeMethod('removeUserScriptsByGroupName', args); + } + + @override + Future removeUserScripts( + {required List userScripts}) async { + assert(webviewParams?.windowId == null); + + for (final userScript in userScripts) { + await removeUserScript(userScript: userScript); + } + } + + @override + Future removeAllUserScripts() async { + assert(webviewParams?.windowId == null); + + _userScripts[UserScriptInjectionTime.AT_DOCUMENT_START]?.clear(); + _userScripts[UserScriptInjectionTime.AT_DOCUMENT_END]?.clear(); + + Map args = {}; + await channel?.invokeMethod('removeAllUserScripts', args); + } + + @override + bool hasUserScript({required UserScript userScript}) { + return _userScripts[userScript.injectionTime]?.contains(userScript) ?? + false; + } + + @override + Future callAsyncJavaScript( + {required String functionBody, + Map arguments = const {}, + ContentWorld? contentWorld}) async { + Map args = {}; + args.putIfAbsent('functionBody', () => functionBody); + args.putIfAbsent('arguments', () => arguments); + args.putIfAbsent('contentWorld', () => contentWorld?.toMap()); + var data = await channel?.invokeMethod('callAsyncJavaScript', args); + if (data == null) { + return null; + } + return CallAsyncJavaScriptResult( + value: data["value"], error: data["error"]); + } + + @override + Future saveWebArchive( + {required String filePath, bool autoname = false}) async { + if (!autoname) { + assert(filePath + .endsWith("." + WebArchiveFormat.WEBARCHIVE.toNativeValue())); + } + + Map args = {}; + args.putIfAbsent("filePath", () => filePath); + args.putIfAbsent("autoname", () => autoname); + return await channel?.invokeMethod('saveWebArchive', args); + } + + @override + Future isSecureContext() async { + Map args = {}; + return await channel?.invokeMethod('isSecureContext', args) ?? false; + } + + @override + Future createWebMessageChannel() async { + Map args = {}; + Map? result = + (await channel?.invokeMethod('createWebMessageChannel', args)) + ?.cast(); + final webMessageChannel = MacOSWebMessageChannel.static().fromMap(result); + if (webMessageChannel != null) { + _webMessageChannels.add(webMessageChannel); + } + return webMessageChannel; + } + + @override + Future postWebMessage( + {required WebMessage message, WebUri? targetOrigin}) async { + if (targetOrigin == null) { + targetOrigin = WebUri(''); + } + Map args = {}; + args.putIfAbsent('message', () => message.toMap()); + args.putIfAbsent('targetOrigin', () => targetOrigin.toString()); + await channel?.invokeMethod('postWebMessage', args); + } + + @override + Future addWebMessageListener( + PlatformWebMessageListener webMessageListener) async { + assert(!_webMessageListeners.contains(webMessageListener), + "${webMessageListener} was already added."); + assert( + !_webMessageListenerObjNames + .contains(webMessageListener.params.jsObjectName), + "jsObjectName ${webMessageListener.params.jsObjectName} was already added."); + _webMessageListeners.add(webMessageListener as MacOSWebMessageListener); + _webMessageListenerObjNames.add(webMessageListener.params.jsObjectName); + + Map args = {}; + args.putIfAbsent('webMessageListener', () => webMessageListener.toMap()); + await channel?.invokeMethod('addWebMessageListener', args); + } + + @override + bool hasWebMessageListener(PlatformWebMessageListener webMessageListener) { + return _webMessageListeners.contains(webMessageListener) || + _webMessageListenerObjNames + .contains(webMessageListener.params.jsObjectName); + } + + @override + Future canScrollVertically() async { + Map args = {}; + return await channel?.invokeMethod('canScrollVertically', args) ?? + false; + } + + @override + Future canScrollHorizontally() async { + Map args = {}; + return await channel?.invokeMethod('canScrollHorizontally', args) ?? + false; + } + + @override + Future reloadFromOrigin() async { + Map args = {}; + await channel?.invokeMethod('reloadFromOrigin', args); + } + + @override + Future createPdf( + {@Deprecated("Use pdfConfiguration instead") + // ignore: deprecated_member_use_from_same_package + IOSWKPDFConfiguration? iosWKPdfConfiguration, + PDFConfiguration? pdfConfiguration}) async { + Map args = {}; + args.putIfAbsent('pdfConfiguration', + () => pdfConfiguration?.toMap() ?? iosWKPdfConfiguration?.toMap()); + return await channel?.invokeMethod('createPdf', args); + } + + @override + Future createWebArchiveData() async { + Map args = {}; + return await channel?.invokeMethod('createWebArchiveData', args); + } + + @override + Future hasOnlySecureContent() async { + Map args = {}; + return await channel?.invokeMethod('hasOnlySecureContent', args) ?? + false; + } + + @override + Future pauseAllMediaPlayback() async { + Map args = {}; + return await channel?.invokeMethod('pauseAllMediaPlayback', args); + } + + @override + Future setAllMediaPlaybackSuspended({required bool suspended}) async { + Map args = {}; + args.putIfAbsent("suspended", () => suspended); + return await channel?.invokeMethod('setAllMediaPlaybackSuspended', args); + } + + @override + Future closeAllMediaPresentations() async { + Map args = {}; + return await channel?.invokeMethod('closeAllMediaPresentations', args); + } + + @override + Future requestMediaPlaybackState() async { + Map args = {}; + return MediaPlaybackState.fromNativeValue( + await channel?.invokeMethod('requestMediaPlaybackState', args)); + } + + @override + Future isInFullscreen() async { + Map args = {}; + return await channel?.invokeMethod('isInFullscreen', args) ?? false; + } + + @override + Future getCameraCaptureState() async { + Map args = {}; + return MediaCaptureState.fromNativeValue( + await channel?.invokeMethod('getCameraCaptureState', args)); + } + + @override + Future setCameraCaptureState({required MediaCaptureState state}) async { + Map args = {}; + args.putIfAbsent('state', () => state.toNativeValue()); + await channel?.invokeMethod('setCameraCaptureState', args); + } + + @override + Future getMicrophoneCaptureState() async { + Map args = {}; + return MediaCaptureState.fromNativeValue( + await channel?.invokeMethod('getMicrophoneCaptureState', args)); + } + + @override + Future setMicrophoneCaptureState( + {required MediaCaptureState state}) async { + Map args = {}; + args.putIfAbsent('state', () => state.toNativeValue()); + await channel?.invokeMethod('setMicrophoneCaptureState', args); + } + + @override + Future loadSimulatedRequest( + {required URLRequest urlRequest, + required Uint8List data, + URLResponse? urlResponse}) async { + Map args = {}; + args.putIfAbsent('urlRequest', () => urlRequest.toMap()); + args.putIfAbsent('data', () => data); + args.putIfAbsent('urlResponse', () => urlResponse?.toMap()); + await channel?.invokeMethod('loadSimulatedRequest', args); + } + + @override + Future getDefaultUserAgent() async { + Map args = {}; + return await _staticChannel.invokeMethod( + 'getDefaultUserAgent', args) ?? + ''; + } + + @override + Future handlesURLScheme(String urlScheme) async { + Map args = {}; + args.putIfAbsent('urlScheme', () => urlScheme); + return await _staticChannel.invokeMethod('handlesURLScheme', args); + } + + @override + Future disposeKeepAlive(InAppWebViewKeepAlive keepAlive) async { + Map args = {}; + args.putIfAbsent('keepAliveId', () => keepAlive.id); + await _staticChannel.invokeMethod('disposeKeepAlive', args); + _keepAliveMap[keepAlive] = null; + } + + @override + Future get tRexRunnerHtml async => await rootBundle.loadString( + 'packages/flutter_inappwebview/assets/t_rex_runner/t-rex.html'); + + @override + Future get tRexRunnerCss async => await rootBundle.loadString( + 'packages/flutter_inappwebview/assets/t_rex_runner/t-rex.css'); + + @override + dynamic getViewId() { + return id; + } + + @override + void dispose({bool isKeepAlive = false}) { + disposeChannel(removeMethodCallHandler: !isKeepAlive); + _inAppBrowser = null; + webStorage.dispose(); + if (!isKeepAlive) { + _controllerFromPlatform = null; + _javaScriptHandlersMap.clear(); + _userScripts.clear(); + _webMessageListenerObjNames.clear(); + _injectedScriptsFromURL.clear(); + for (final webMessageChannel in _webMessageChannels) { + webMessageChannel.dispose(); + } + _webMessageChannels.clear(); + for (final webMessageListener in _webMessageListeners) { + webMessageListener.dispose(); + } + _webMessageListeners.clear(); + } + } +} + +extension InternalInAppWebViewController on MacOSInAppWebViewController { + get handleMethod => _handleMethod; +} diff --git a/flutter_inappwebview_macos/lib/src/in_app_webview/main.dart b/flutter_inappwebview_macos/lib/src/in_app_webview/main.dart new file mode 100644 index 00000000..b83b0611 --- /dev/null +++ b/flutter_inappwebview_macos/lib/src/in_app_webview/main.dart @@ -0,0 +1,3 @@ +export 'in_app_webview_controller.dart' hide InternalInAppWebViewController; +export 'in_app_webview.dart'; +export 'headless_in_app_webview.dart' hide InternalHeadlessInAppWebView; diff --git a/flutter_inappwebview_macos/lib/src/inappwebview_platform.dart b/flutter_inappwebview_macos/lib/src/inappwebview_platform.dart new file mode 100644 index 00000000..2fe7bfbe --- /dev/null +++ b/flutter_inappwebview_macos/lib/src/inappwebview_platform.dart @@ -0,0 +1,240 @@ +import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; + +import 'cookie_manager.dart'; +import 'http_auth_credentials_database.dart'; +import 'find_interaction/main.dart'; +import 'in_app_browser/in_app_browser.dart'; +import 'in_app_webview/main.dart'; +import 'print_job/main.dart'; +import 'web_message/main.dart'; +import 'web_storage/main.dart'; +import 'web_authentication_session/main.dart'; + +/// Implementation of [InAppWebViewPlatform] using the WebKit API. +class MacOSInAppWebViewPlatform extends InAppWebViewPlatform { + /// Registers this class as the default instance of [InAppWebViewPlatform]. + static void registerWith() { + InAppWebViewPlatform.instance = MacOSInAppWebViewPlatform(); + } + + /// Creates a new [MacOSCookieManager]. + /// + /// This function should only be called by the app-facing package. + /// Look at using [CookieManager] in `flutter_inappwebview` instead. + @override + MacOSCookieManager createPlatformCookieManager( + PlatformCookieManagerCreationParams params, + ) { + return MacOSCookieManager(params); + } + + /// Creates a new [MacOSInAppWebViewController]. + /// + /// This function should only be called by the app-facing package. + /// Look at using [InAppWebViewController] in `flutter_inappwebview` instead. + @override + MacOSInAppWebViewController createPlatformInAppWebViewController( + PlatformInAppWebViewControllerCreationParams params, + ) { + return MacOSInAppWebViewController(params); + } + + /// Creates a new empty [MacOSInAppWebViewController] to access static methods. + /// + /// This function should only be called by the app-facing package. + /// Look at using [InAppWebViewController] in `flutter_inappwebview` instead. + @override + MacOSInAppWebViewController createPlatformInAppWebViewControllerStatic() { + return MacOSInAppWebViewController.static(); + } + + /// Creates a new [MacOSInAppWebViewWidget]. + /// + /// This function should only be called by the app-facing package. + /// Look at using [InAppWebView] in `flutter_inappwebview` instead. + @override + MacOSInAppWebViewWidget createPlatformInAppWebViewWidget( + PlatformInAppWebViewWidgetCreationParams params, + ) { + return MacOSInAppWebViewWidget(params); + } + + /// Creates a new [MacOSFindInteractionController]. + /// + /// This function should only be called by the app-facing package. + /// Look at using [FindInteractionController] in `flutter_inappwebview` instead. + @override + MacOSFindInteractionController createPlatformFindInteractionController( + PlatformFindInteractionControllerCreationParams params, + ) { + return MacOSFindInteractionController(params); + } + + /// Creates a new [MacOSPrintJobController]. + /// + /// This function should only be called by the app-facing package. + /// Look at using [PrintJobController] in `flutter_inappwebview` instead. + @override + MacOSPrintJobController createPlatformPrintJobController( + PlatformPrintJobControllerCreationParams params, + ) { + return MacOSPrintJobController(params); + } + + /// Creates a new [MacOSWebMessageChannel]. + /// + /// This function should only be called by the app-facing package. + /// Look at using [WebMessageChannel] in `flutter_inappwebview` instead. + @override + MacOSWebMessageChannel createPlatformWebMessageChannel( + PlatformWebMessageChannelCreationParams params, + ) { + return MacOSWebMessageChannel(params); + } + + /// Creates a new empty [MacOSWebMessageChannel] to access static methods. + /// + /// This function should only be called by the app-facing package. + /// Look at using [WebMessageChannel] in `flutter_inappwebview` instead. + @override + MacOSWebMessageChannel createPlatformWebMessageChannelStatic() { + return MacOSWebMessageChannel.static(); + } + + /// Creates a new [MacOSWebMessageListener]. + /// + /// This function should only be called by the app-facing package. + /// Look at using [WebMessageListener] in `flutter_inappwebview` instead. + @override + MacOSWebMessageListener createPlatformWebMessageListener( + PlatformWebMessageListenerCreationParams params, + ) { + return MacOSWebMessageListener(params); + } + + /// Creates a new [MacOSJavaScriptReplyProxy]. + /// + /// This function should only be called by the app-facing package. + /// Look at using [JavaScriptReplyProxy] in `flutter_inappwebview` instead. + @override + MacOSJavaScriptReplyProxy createPlatformJavaScriptReplyProxy( + PlatformJavaScriptReplyProxyCreationParams params, + ) { + return MacOSJavaScriptReplyProxy(params); + } + + /// Creates a new [MacOSWebMessagePort]. + /// + /// This function should only be called by the app-facing package. + /// Look at using [WebMessagePort] in `flutter_inappwebview` instead. + @override + MacOSWebMessagePort createPlatformWebMessagePort( + PlatformWebMessagePortCreationParams params, + ) { + return MacOSWebMessagePort(params); + } + + /// Creates a new [MacOSWebStorage]. + /// + /// This function should only be called by the app-facing package. + /// Look at using [MacOSWebStorage] in `flutter_inappwebview` instead. + @override + MacOSWebStorage createPlatformWebStorage( + PlatformWebStorageCreationParams params, + ) { + return MacOSWebStorage(params); + } + + /// Creates a new [MacOSLocalStorage]. + /// + /// This function should only be called by the app-facing package. + /// Look at using [MacOSLocalStorage] in `flutter_inappwebview` instead. + @override + MacOSLocalStorage createPlatformLocalStorage( + PlatformLocalStorageCreationParams params, + ) { + return MacOSLocalStorage(params); + } + + /// Creates a new [MacOSSessionStorage]. + /// + /// This function should only be called by the app-facing package. + /// Look at using [PlatformSessionStorage] in `flutter_inappwebview` instead. + @override + MacOSSessionStorage createPlatformSessionStorage( + PlatformSessionStorageCreationParams params, + ) { + return MacOSSessionStorage(params); + } + + /// Creates a new [MacOSHeadlessInAppWebView]. + /// + /// This function should only be called by the app-facing package. + /// Look at using [HeadlessInAppWebView] in `flutter_inappwebview` instead. + @override + MacOSHeadlessInAppWebView createPlatformHeadlessInAppWebView( + PlatformHeadlessInAppWebViewCreationParams params, + ) { + return MacOSHeadlessInAppWebView(params); + } + + /// Creates a new [MacOSHttpAuthCredentialDatabase]. + /// + /// This function should only be called by the app-facing package. + /// Look at using [HttpAuthCredentialDatabase] in `flutter_inappwebview` instead. + @override + MacOSHttpAuthCredentialDatabase createPlatformHttpAuthCredentialDatabase( + PlatformHttpAuthCredentialDatabaseCreationParams params, + ) { + return MacOSHttpAuthCredentialDatabase(params); + } + + /// Creates a new [MacOSInAppBrowser]. + /// + /// This function should only be called by the app-facing package. + /// Look at using [InAppBrowser] in `flutter_inappwebview` instead. + @override + MacOSInAppBrowser createPlatformInAppBrowser( + PlatformInAppBrowserCreationParams params, + ) { + return MacOSInAppBrowser(params); + } + + /// Creates a new empty [MacOSInAppBrowser] to access static methods. + /// + /// This function should only be called by the app-facing package. + /// Look at using [InAppBrowser] in `flutter_inappwebview` instead. + @override + MacOSInAppBrowser createPlatformInAppBrowserStatic() { + return MacOSInAppBrowser.static(); + } + + /// Creates a new empty [MacOSWebStorageManager] to access static methods. + /// + /// This function should only be called by the app-facing package. + /// Look at using [WebStorageManager] in `flutter_inappwebview` instead. + @override + MacOSWebStorageManager createPlatformWebStorageManager( + PlatformWebStorageManagerCreationParams params) { + return MacOSWebStorageManager(params); + } + + /// Creates a new [MacOSWebAuthenticationSession]. + /// + /// This function should only be called by the app-facing package. + /// Look at using [WebAuthenticationSession] in `flutter_inappwebview` instead. + @override + MacOSWebAuthenticationSession createPlatformWebAuthenticationSession( + PlatformWebAuthenticationSessionCreationParams params) { + return MacOSWebAuthenticationSession(params); + } + + /// Creates a new empty [MacOSWebAuthenticationSession] to access static methods. + /// + /// This function should only be called by the app-facing package. + /// Look at using [WebAuthenticationSession] in `flutter_inappwebview` instead. + @override + MacOSWebAuthenticationSession createPlatformWebAuthenticationSessionStatic() { + return MacOSWebAuthenticationSession.static(); + } +} diff --git a/flutter_inappwebview_macos/lib/src/main.dart b/flutter_inappwebview_macos/lib/src/main.dart new file mode 100644 index 00000000..e58414ae --- /dev/null +++ b/flutter_inappwebview_macos/lib/src/main.dart @@ -0,0 +1,11 @@ +export 'inappwebview_platform.dart'; +export 'in_app_webview/main.dart'; +export 'in_app_browser/main.dart'; +export 'web_storage/main.dart'; +export 'cookie_manager.dart' hide InternalCookieManager; +export 'http_auth_credentials_database.dart' + hide InternalHttpAuthCredentialDatabase; +export 'web_message/main.dart'; +export 'print_job/main.dart'; +export 'find_interaction/main.dart'; +export 'web_authentication_session/main.dart'; diff --git a/flutter_inappwebview_macos/lib/src/platform_util.dart b/flutter_inappwebview_macos/lib/src/platform_util.dart new file mode 100644 index 00000000..27e96478 --- /dev/null +++ b/flutter_inappwebview_macos/lib/src/platform_util.dart @@ -0,0 +1,64 @@ +import 'package:flutter/services.dart'; + +///Platform native utilities +class PlatformUtil { + static PlatformUtil? _instance; + static const MethodChannel _channel = + MethodChannel('com.pichillilorenzo/flutter_inappwebview_platformutil'); + + PlatformUtil._(); + + ///Get [PlatformUtil] instance. + static PlatformUtil instance() { + return (_instance != null) ? _instance! : _init(); + } + + static PlatformUtil _init() { + _channel.setMethodCallHandler((call) async { + try { + return await _handleMethod(call); + } on Error catch (e) { + print(e); + print(e.stackTrace); + } + }); + _instance = PlatformUtil._(); + return _instance!; + } + + static Future _handleMethod(MethodCall call) async {} + + String? _cachedSystemVersion; + + ///Get current platform system version. + Future getSystemVersion() async { + if (_cachedSystemVersion != null) { + return _cachedSystemVersion!; + } + Map args = {}; + _cachedSystemVersion = + await _channel.invokeMethod('getSystemVersion', args); + return _cachedSystemVersion!; + } + + ///Format date. + Future formatDate( + {required DateTime date, + required String format, + String locale = "en_US", + String timezone = "UTC"}) async { + Map args = {}; + args.putIfAbsent('date', () => date.millisecondsSinceEpoch); + args.putIfAbsent('format', () => format); + args.putIfAbsent('locale', () => locale); + args.putIfAbsent('timezone', () => timezone); + return await _channel.invokeMethod('formatDate', args); + } + + ///Get cookie expiration date used by Web platform. + Future getWebCookieExpirationDate({required DateTime date}) async { + Map args = {}; + args.putIfAbsent('date', () => date.millisecondsSinceEpoch); + return await _channel.invokeMethod('getWebCookieExpirationDate', args); + } +} diff --git a/flutter_inappwebview_macos/lib/src/print_job/main.dart b/flutter_inappwebview_macos/lib/src/print_job/main.dart new file mode 100644 index 00000000..4e70ad94 --- /dev/null +++ b/flutter_inappwebview_macos/lib/src/print_job/main.dart @@ -0,0 +1 @@ +export 'print_job_controller.dart'; diff --git a/flutter_inappwebview_macos/lib/src/print_job/print_job_controller.dart b/flutter_inappwebview_macos/lib/src/print_job/print_job_controller.dart new file mode 100644 index 00000000..b1a95ce2 --- /dev/null +++ b/flutter_inappwebview_macos/lib/src/print_job/print_job_controller.dart @@ -0,0 +1,72 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; + +/// Object specifying creation parameters for creating a [MacOSPrintJobController]. +/// +/// When adding additional fields make sure they can be null or have a default +/// value to avoid breaking changes. See [PlatformPrintJobControllerCreationParams] for +/// more information. +@immutable +class MacOSPrintJobControllerCreationParams + extends PlatformPrintJobControllerCreationParams { + /// Creates a new [MacOSPrintJobControllerCreationParams] instance. + const MacOSPrintJobControllerCreationParams( + {required super.id, super.onComplete}); + + /// Creates a [MacOSPrintJobControllerCreationParams] instance based on [PlatformPrintJobControllerCreationParams]. + factory MacOSPrintJobControllerCreationParams.fromPlatformPrintJobControllerCreationParams( + // Recommended placeholder to prevent being broken by platform interface. + // ignore: avoid_unused_constructor_parameters + PlatformPrintJobControllerCreationParams params) { + return MacOSPrintJobControllerCreationParams( + id: params.id, onComplete: params.onComplete); + } +} + +///{@macro flutter_inappwebview_platform_interface.PlatformPrintJobController} +class MacOSPrintJobController extends PlatformPrintJobController + with ChannelController { + /// Constructs a [MacOSPrintJobController]. + MacOSPrintJobController(PlatformPrintJobControllerCreationParams params) + : super.implementation( + params is MacOSPrintJobControllerCreationParams + ? params + : MacOSPrintJobControllerCreationParams + .fromPlatformPrintJobControllerCreationParams(params), + ) { + channel = MethodChannel( + 'com.pichillilorenzo/flutter_inappwebview_printjobcontroller_${params.id}'); + handler = _handleMethod; + initMethodCallHandler(); + } + + Future _handleMethod(MethodCall call) async { + switch (call.method) { + case "onComplete": + bool completed = call.arguments["completed"]; + String? error = call.arguments["error"]; + if (params.onComplete != null) { + params.onComplete!(completed, error); + } + break; + default: + throw UnimplementedError("Unimplemented ${call.method} method"); + } + } + + @override + Future getInfo() async { + Map args = {}; + Map? infoMap = + (await channel?.invokeMethod('getInfo', args))?.cast(); + return PrintJobInfo.fromMap(infoMap); + } + + @override + Future dispose() async { + Map args = {}; + await channel?.invokeMethod('dispose', args); + disposeChannel(); + } +} diff --git a/flutter_inappwebview_macos/lib/src/web_authentication_session/main.dart b/flutter_inappwebview_macos/lib/src/web_authentication_session/main.dart new file mode 100644 index 00000000..37ca0c24 --- /dev/null +++ b/flutter_inappwebview_macos/lib/src/web_authentication_session/main.dart @@ -0,0 +1 @@ +export 'web_authenticate_session.dart'; diff --git a/flutter_inappwebview_macos/lib/src/web_authentication_session/web_authenticate_session.dart b/flutter_inappwebview_macos/lib/src/web_authentication_session/web_authenticate_session.dart new file mode 100755 index 00000000..1cff8fda --- /dev/null +++ b/flutter_inappwebview_macos/lib/src/web_authentication_session/web_authenticate_session.dart @@ -0,0 +1,165 @@ +import 'dart:async'; + +import 'package:flutter/services.dart'; +import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; + +/// Object specifying creation parameters for creating a [MacOSWebAuthenticationSession]. +/// +/// When adding additional fields make sure they can be null or have a default +/// value to avoid breaking changes. See [PlatformWebAuthenticationSessionCreationParams] for +/// more information. +class MacOSWebAuthenticationSessionCreationParams + extends PlatformWebAuthenticationSessionCreationParams { + /// Creates a new [MacOSWebAuthenticationSessionCreationParams] instance. + const MacOSWebAuthenticationSessionCreationParams(); + + /// Creates a [MacOSWebAuthenticationSessionCreationParams] instance based on [PlatformWebAuthenticationSessionCreationParams]. + factory MacOSWebAuthenticationSessionCreationParams.fromPlatformWebAuthenticationSessionCreationParams( + // Recommended placeholder to prevent being broken by platform interface. + // ignore: avoid_unused_constructor_parameters + PlatformWebAuthenticationSessionCreationParams params) { + return MacOSWebAuthenticationSessionCreationParams(); + } +} + +///{@macro flutter_inappwebview_platform_interface.PlatformWebAuthenticationSession} +class MacOSWebAuthenticationSession extends PlatformWebAuthenticationSession + with ChannelController { + /// Constructs a [MacOSWebAuthenticationSession]. + MacOSWebAuthenticationSession( + PlatformWebAuthenticationSessionCreationParams params) + : super.implementation( + params is MacOSWebAuthenticationSessionCreationParams + ? params + : MacOSWebAuthenticationSessionCreationParams + .fromPlatformWebAuthenticationSessionCreationParams(params), + ); + + static final MacOSWebAuthenticationSession _staticValue = + MacOSWebAuthenticationSession(MacOSWebAuthenticationSessionCreationParams()); + + /// Provide static access. + factory MacOSWebAuthenticationSession.static() { + return _staticValue; + } + + @override + final String id = IdGenerator.generate(); + + @override + late final WebUri url; + + @override + late final String? callbackURLScheme; + + @override + late final WebAuthenticationSessionSettings? initialSettings; + + @override + late final WebAuthenticationSessionCompletionHandler onComplete; + + static const MethodChannel _staticChannel = const MethodChannel( + 'com.pichillilorenzo/flutter_webauthenticationsession'); + + @override + Future create( + {required WebUri url, + String? callbackURLScheme, + WebAuthenticationSessionCompletionHandler onComplete, + WebAuthenticationSessionSettings? initialSettings}) async { + var session = MacOSWebAuthenticationSession._create( + url: url, + callbackURLScheme: callbackURLScheme, + onComplete: onComplete, + initialSettings: initialSettings); + initialSettings = + session.initialSettings ?? WebAuthenticationSessionSettings(); + Map args = {}; + args.putIfAbsent("id", () => session.id); + args.putIfAbsent("url", () => session.url.toString()); + args.putIfAbsent("callbackURLScheme", () => session.callbackURLScheme); + args.putIfAbsent("initialSettings", () => initialSettings?.toMap()); + await _staticChannel.invokeMethod('create', args); + return session; + } + + MacOSWebAuthenticationSession._create( + {required this.url, + this.callbackURLScheme, + this.onComplete, + WebAuthenticationSessionSettings? initialSettings}) + : super.implementation(MacOSWebAuthenticationSessionCreationParams()) { + assert(url.toString().isNotEmpty); + if (Util.isMacOS || Util.isMacOS) { + assert(['http', 'https'].contains(url.scheme), + 'The specified URL has an unsupported scheme. Only HTTP and HTTPS URLs are supported on iOS.'); + } + + this.initialSettings = + initialSettings ?? WebAuthenticationSessionSettings(); + channel = MethodChannel( + 'com.pichillilorenzo/flutter_webauthenticationsession_$id'); + handler = _handleMethod; + initMethodCallHandler(); + } + + _debugLog(String method, dynamic args) { + debugLog( + className: this.runtimeType.toString(), + debugLoggingSettings: + PlatformWebAuthenticationSession.debugLoggingSettings, + id: id, + method: method, + args: args); + } + + Future _handleMethod(MethodCall call) async { + _debugLog(call.method, call.arguments); + + switch (call.method) { + case "onComplete": + String? url = call.arguments["url"]; + WebUri? uri = url != null ? WebUri(url) : null; + var error = WebAuthenticationSessionError.fromNativeValue( + call.arguments["errorCode"]); + if (onComplete != null) { + onComplete!(uri, error); + } + break; + default: + throw UnimplementedError("Unimplemented ${call.method} method"); + } + } + + @override + Future canStart() async { + Map args = {}; + return await channel?.invokeMethod('canStart', args) ?? false; + } + + @override + Future start() async { + Map args = {}; + return await channel?.invokeMethod('start', args) ?? false; + } + + @override + Future cancel() async { + Map args = {}; + await channel?.invokeMethod("cancel", args); + } + + @override + Future dispose() async { + Map args = {}; + await channel?.invokeMethod("dispose", args); + disposeChannel(); + } + + @override + Future isAvailable() async { + Map args = {}; + return await _staticChannel.invokeMethod("isAvailable", args) ?? + false; + } +} diff --git a/flutter_inappwebview_macos/lib/src/web_message/main.dart b/flutter_inappwebview_macos/lib/src/web_message/main.dart new file mode 100644 index 00000000..d41e30c7 --- /dev/null +++ b/flutter_inappwebview_macos/lib/src/web_message/main.dart @@ -0,0 +1,3 @@ +export 'web_message_port.dart' hide InternalWebMessagePort; +export 'web_message_channel.dart' hide InternalWebMessageChannel; +export 'web_message_listener.dart'; diff --git a/flutter_inappwebview_macos/lib/src/web_message/web_message_channel.dart b/flutter_inappwebview_macos/lib/src/web_message/web_message_channel.dart new file mode 100644 index 00000000..adbaa2f6 --- /dev/null +++ b/flutter_inappwebview_macos/lib/src/web_message/web_message_channel.dart @@ -0,0 +1,120 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; +import 'web_message_port.dart'; + +/// Object specifying creation parameters for creating a [MacOSWebMessageChannel]. +/// +/// When adding additional fields make sure they can be null or have a default +/// value to avoid breaking changes. See [PlatformWebMessageChannelCreationParams] for +/// more information. +@immutable +class MacOSWebMessageChannelCreationParams + extends PlatformWebMessageChannelCreationParams { + /// Creates a new [MacOSWebMessageChannelCreationParams] instance. + const MacOSWebMessageChannelCreationParams( + {required super.id, required super.port1, required super.port2}); + + /// Creates a [MacOSWebMessageChannelCreationParams] instance based on [PlatformWebMessageChannelCreationParams]. + factory MacOSWebMessageChannelCreationParams.fromPlatformWebMessageChannelCreationParams( + // Recommended placeholder to prevent being broken by platform interface. + // ignore: avoid_unused_constructor_parameters + PlatformWebMessageChannelCreationParams params) { + return MacOSWebMessageChannelCreationParams( + id: params.id, port1: params.port1, port2: params.port2); + } + + @override + String toString() { + return 'MacOSWebMessageChannelCreationParams{id: $id, port1: $port1, port2: $port2}'; + } +} + +///{@macro flutter_inappwebview_platform_interface.PlatformWebMessageChannel} +class MacOSWebMessageChannel extends PlatformWebMessageChannel + with ChannelController { + /// Constructs a [MacOSWebMessageChannel]. + MacOSWebMessageChannel(PlatformWebMessageChannelCreationParams params) + : super.implementation( + params is MacOSWebMessageChannelCreationParams + ? params + : MacOSWebMessageChannelCreationParams + .fromPlatformWebMessageChannelCreationParams(params), + ) { + channel = MethodChannel( + 'com.pichillilorenzo/flutter_inappwebview_web_message_channel_${params.id}'); + handler = _handleMethod; + initMethodCallHandler(); + } + + static final MacOSWebMessageChannel _staticValue = MacOSWebMessageChannel( + MacOSWebMessageChannelCreationParams( + id: '', + port1: MacOSWebMessagePort( + MacOSWebMessagePortCreationParams(index: 0)), + port2: MacOSWebMessagePort( + MacOSWebMessagePortCreationParams(index: 1)))); + + /// Provide static access. + factory MacOSWebMessageChannel.static() { + return _staticValue; + } + + MacOSWebMessagePort get _iosPort1 => port1 as MacOSWebMessagePort; + + MacOSWebMessagePort get _iosPort2 => port2 as MacOSWebMessagePort; + + static MacOSWebMessageChannel? _fromMap(Map? map) { + if (map == null) { + return null; + } + var webMessageChannel = MacOSWebMessageChannel( + MacOSWebMessageChannelCreationParams( + id: map["id"], + port1: MacOSWebMessagePort( + MacOSWebMessagePortCreationParams(index: 0)), + port2: MacOSWebMessagePort( + MacOSWebMessagePortCreationParams(index: 1)))); + webMessageChannel._iosPort1.webMessageChannel = webMessageChannel; + webMessageChannel._iosPort2.webMessageChannel = webMessageChannel; + return webMessageChannel; + } + + Future _handleMethod(MethodCall call) async { + switch (call.method) { + case "onMessage": + int index = call.arguments["index"]; + var port = index == 0 ? _iosPort1 : _iosPort2; + if (port.onMessage != null) { + WebMessage? message = call.arguments["message"] != null + ? WebMessage.fromMap( + call.arguments["message"].cast()) + : null; + port.onMessage!(message); + } + break; + default: + throw UnimplementedError("Unimplemented ${call.method} method"); + } + return null; + } + + @override + MacOSWebMessageChannel? fromMap(Map? map) { + return _fromMap(map); + } + + @override + void dispose() { + disposeChannel(); + } + + @override + String toString() { + return 'MacOSWebMessageChannel{id: $id, port1: $port1, port2: $port2}'; + } +} + +extension InternalWebMessageChannel on MacOSWebMessageChannel { + MethodChannel? get internalChannel => channel; +} diff --git a/flutter_inappwebview_macos/lib/src/web_message/web_message_listener.dart b/flutter_inappwebview_macos/lib/src/web_message/web_message_listener.dart new file mode 100644 index 00000000..87b66bf7 --- /dev/null +++ b/flutter_inappwebview_macos/lib/src/web_message/web_message_listener.dart @@ -0,0 +1,164 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; + +/// Object specifying creation parameters for creating a [MacOSWebMessageListener]. +/// +/// When adding additional fields make sure they can be null or have a default +/// value to avoid breaking changes. See [PlatformWebMessageListenerCreationParams] for +/// more information. +@immutable +class MacOSWebMessageListenerCreationParams + extends PlatformWebMessageListenerCreationParams { + /// Creates a new [MacOSWebMessageListenerCreationParams] instance. + const MacOSWebMessageListenerCreationParams( + {required this.allowedOriginRules, + required super.jsObjectName, + super.onPostMessage}); + + /// Creates a [MacOSWebMessageListenerCreationParams] instance based on [PlatformWebMessageListenerCreationParams]. + factory MacOSWebMessageListenerCreationParams.fromPlatformWebMessageListenerCreationParams( + // Recommended placeholder to prevent being broken by platform interface. + // ignore: avoid_unused_constructor_parameters + PlatformWebMessageListenerCreationParams params) { + return MacOSWebMessageListenerCreationParams( + allowedOriginRules: params.allowedOriginRules ?? Set.from(["*"]), + jsObjectName: params.jsObjectName, + onPostMessage: params.onPostMessage); + } + + @override + final Set allowedOriginRules; + + @override + String toString() { + return 'MacOSWebMessageListenerCreationParams{jsObjectName: $jsObjectName, allowedOriginRules: $allowedOriginRules, onPostMessage: $onPostMessage}'; + } +} + +///{@macro flutter_inappwebview_platform_interface.PlatformWebMessageListener} +class MacOSWebMessageListener extends PlatformWebMessageListener + with ChannelController { + /// Constructs a [MacOSWebMessageListener]. + MacOSWebMessageListener(PlatformWebMessageListenerCreationParams params) + : super.implementation( + params is MacOSWebMessageListenerCreationParams + ? params + : MacOSWebMessageListenerCreationParams + .fromPlatformWebMessageListenerCreationParams(params), + ) { + assert(!this._iosParams.allowedOriginRules.contains(""), + "allowedOriginRules cannot contain empty strings"); + channel = MethodChannel( + 'com.pichillilorenzo/flutter_inappwebview_web_message_listener_${_id}_${params.jsObjectName}'); + handler = _handleMethod; + initMethodCallHandler(); + } + + ///Message Listener ID used internally. + final String _id = IdGenerator.generate(); + + MacOSJavaScriptReplyProxy? _replyProxy; + + MacOSWebMessageListenerCreationParams get _iosParams => + params as MacOSWebMessageListenerCreationParams; + + Future _handleMethod(MethodCall call) async { + switch (call.method) { + case "onPostMessage": + if (_replyProxy == null) { + _replyProxy = MacOSJavaScriptReplyProxy( + PlatformJavaScriptReplyProxyCreationParams( + webMessageListener: this)); + } + if (onPostMessage != null) { + WebMessage? message = call.arguments["message"] != null + ? WebMessage.fromMap( + call.arguments["message"].cast()) + : null; + WebUri? sourceOrigin = call.arguments["sourceOrigin"] != null + ? WebUri(call.arguments["sourceOrigin"]) + : null; + bool isMainFrame = call.arguments["isMainFrame"]; + onPostMessage!(message, sourceOrigin, isMainFrame, _replyProxy!); + } + break; + default: + throw UnimplementedError("Unimplemented ${call.method} method"); + } + return null; + } + + @override + void dispose() { + disposeChannel(); + } + + @override + Map toMap() { + return { + "id": _id, + "jsObjectName": params.jsObjectName, + "allowedOriginRules": _iosParams.allowedOriginRules.toList(), + }; + } + + @override + Map toJson() { + return this.toMap(); + } + + @override + String toString() { + return 'MacOSWebMessageListener{id: ${_id}, jsObjectName: ${params.jsObjectName}, allowedOriginRules: ${params.allowedOriginRules}, replyProxy: $_replyProxy}'; + } +} + +/// Object specifying creation parameters for creating a [MacOSJavaScriptReplyProxy]. +/// +/// When adding additional fields make sure they can be null or have a default +/// value to avoid breaking changes. See [PlatformJavaScriptReplyProxyCreationParams] for +/// more information. +@immutable +class MacOSJavaScriptReplyProxyCreationParams + extends PlatformJavaScriptReplyProxyCreationParams { + /// Creates a new [MacOSJavaScriptReplyProxyCreationParams] instance. + const MacOSJavaScriptReplyProxyCreationParams( + {required super.webMessageListener}); + + /// Creates a [MacOSJavaScriptReplyProxyCreationParams] instance based on [PlatformJavaScriptReplyProxyCreationParams]. + factory MacOSJavaScriptReplyProxyCreationParams.fromPlatformJavaScriptReplyProxyCreationParams( + // Recommended placeholder to prevent being broken by platform interface. + // ignore: avoid_unused_constructor_parameters + PlatformJavaScriptReplyProxyCreationParams params) { + return MacOSJavaScriptReplyProxyCreationParams( + webMessageListener: params.webMessageListener); + } +} + +///{@macro flutter_inappwebview_platform_interface.JavaScriptReplyProxy} +class MacOSJavaScriptReplyProxy extends PlatformJavaScriptReplyProxy { + /// Constructs a [MacOSWebMessageListener]. + MacOSJavaScriptReplyProxy(PlatformJavaScriptReplyProxyCreationParams params) + : super.implementation( + params is MacOSJavaScriptReplyProxyCreationParams + ? params + : MacOSJavaScriptReplyProxyCreationParams + .fromPlatformJavaScriptReplyProxyCreationParams(params), + ); + + MacOSWebMessageListener get _iosWebMessageListener => + params.webMessageListener as MacOSWebMessageListener; + + @override + Future postMessage(WebMessage message) async { + Map args = {}; + args.putIfAbsent('message', () => message.toMap()); + await _iosWebMessageListener.channel?.invokeMethod('postMessage', args); + } + + @override + String toString() { + return 'MacOSJavaScriptReplyProxy{}'; + } +} diff --git a/flutter_inappwebview_macos/lib/src/web_message/web_message_port.dart b/flutter_inappwebview_macos/lib/src/web_message/web_message_port.dart new file mode 100644 index 00000000..c0682298 --- /dev/null +++ b/flutter_inappwebview_macos/lib/src/web_message/web_message_port.dart @@ -0,0 +1,95 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; + +import 'web_message_channel.dart'; + +/// Object specifying creation parameters for creating a [MacOSWebMessagePort]. +/// +/// When adding additional fields make sure they can be null or have a default +/// value to avoid breaking changes. See [PlatformWebMessagePortCreationParams] for +/// more information. +@immutable +class MacOSWebMessagePortCreationParams + extends PlatformWebMessagePortCreationParams { + /// Creates a new [MacOSWebMessagePortCreationParams] instance. + const MacOSWebMessagePortCreationParams({required super.index}); + + /// Creates a [MacOSWebMessagePortCreationParams] instance based on [PlatformWebMessagePortCreationParams]. + factory MacOSWebMessagePortCreationParams.fromPlatformWebMessagePortCreationParams( + // Recommended placeholder to prevent being broken by platform interface. + // ignore: avoid_unused_constructor_parameters + PlatformWebMessagePortCreationParams params) { + return MacOSWebMessagePortCreationParams(index: params.index); + } + + @override + String toString() { + return 'MacOSWebMessagePortCreationParams{index: $index}'; + } +} + +///{@macro flutter_inappwebview_platform_interface.PlatformWebMessagePort} +class MacOSWebMessagePort extends PlatformWebMessagePort { + WebMessageCallback? _onMessage; + late MacOSWebMessageChannel _webMessageChannel; + + /// Constructs a [MacOSWebMessagePort]. + MacOSWebMessagePort(PlatformWebMessagePortCreationParams params) + : super.implementation( + params is MacOSWebMessagePortCreationParams + ? params + : MacOSWebMessagePortCreationParams + .fromPlatformWebMessagePortCreationParams(params), + ); + + @override + Future setWebMessageCallback(WebMessageCallback? onMessage) async { + Map args = {}; + args.putIfAbsent('index', () => params.index); + await _webMessageChannel.internalChannel + ?.invokeMethod('setWebMessageCallback', args); + this._onMessage = onMessage; + } + + @override + Future postMessage(WebMessage message) async { + Map args = {}; + args.putIfAbsent('index', () => params.index); + args.putIfAbsent('message', () => message.toMap()); + await _webMessageChannel.internalChannel?.invokeMethod('postMessage', args); + } + + @override + Future close() async { + Map args = {}; + args.putIfAbsent('index', () => params.index); + await _webMessageChannel.internalChannel?.invokeMethod('close', args); + } + + @override + Map toMap() { + return { + "index": params.index, + "webMessageChannelId": this._webMessageChannel.params.id + }; + } + + @override + Map toJson() { + return toMap(); + } + + @override + String toString() { + return 'MacOSWebMessagePort{index: ${params.index}}'; + } +} + +extension InternalWebMessagePort on MacOSWebMessagePort { + WebMessageCallback? get onMessage => _onMessage; + void set onMessage(WebMessageCallback? value) => _onMessage = value; + + MacOSWebMessageChannel get webMessageChannel => _webMessageChannel; + void set webMessageChannel(MacOSWebMessageChannel value) => + _webMessageChannel = value; +} diff --git a/flutter_inappwebview_macos/lib/src/web_storage/main.dart b/flutter_inappwebview_macos/lib/src/web_storage/main.dart new file mode 100644 index 00000000..7265ae52 --- /dev/null +++ b/flutter_inappwebview_macos/lib/src/web_storage/main.dart @@ -0,0 +1,2 @@ +export 'web_storage.dart'; +export 'web_storage_manager.dart' hide InternalWebStorageManager; diff --git a/flutter_inappwebview_macos/lib/src/web_storage/web_storage.dart b/flutter_inappwebview_macos/lib/src/web_storage/web_storage.dart new file mode 100644 index 00000000..25299efb --- /dev/null +++ b/flutter_inappwebview_macos/lib/src/web_storage/web_storage.dart @@ -0,0 +1,257 @@ +import 'dart:convert'; + +import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; + +import '../in_app_webview/in_app_webview_controller.dart'; + +/// Object specifying creation parameters for creating a [MacOSWebStorage]. +/// +/// When adding additional fields make sure they can be null or have a default +/// value to avoid breaking changes. See [PlatformWebStorageCreationParams] for +/// more information. +class MacOSWebStorageCreationParams extends PlatformWebStorageCreationParams { + /// Creates a new [MacOSWebStorageCreationParams] instance. + MacOSWebStorageCreationParams( + {required super.localStorage, required super.sessionStorage}); + + /// Creates a [MacOSWebStorageCreationParams] instance based on [PlatformWebStorageCreationParams]. + factory MacOSWebStorageCreationParams.fromPlatformWebStorageCreationParams( + // Recommended placeholder to prevent being broken by platform interface. + // ignore: avoid_unused_constructor_parameters + PlatformWebStorageCreationParams params) { + return MacOSWebStorageCreationParams( + localStorage: params.localStorage, + sessionStorage: params.sessionStorage); + } +} + +///{@macro flutter_inappwebview_platform_interface.PlatformWebStorage} +class MacOSWebStorage extends PlatformWebStorage { + /// Constructs a [MacOSWebStorage]. + MacOSWebStorage(PlatformWebStorageCreationParams params) + : super.implementation( + params is MacOSWebStorageCreationParams + ? params + : MacOSWebStorageCreationParams + .fromPlatformWebStorageCreationParams(params), + ); + + @override + PlatformLocalStorage get localStorage => params.localStorage; + + @override + PlatformSessionStorage get sessionStorage => params.sessionStorage; + + @override + void dispose() { + localStorage.dispose(); + sessionStorage.dispose(); + } +} + +/// Object specifying creation parameters for creating a [MacOSStorage]. +/// +/// When adding additional fields make sure they can be null or have a default +/// value to avoid breaking changes. See [PlatformStorageCreationParams] for +/// more information. +class MacOSStorageCreationParams extends PlatformStorageCreationParams { + /// Creates a new [MacOSStorageCreationParams] instance. + MacOSStorageCreationParams( + {required super.controller, required super.webStorageType}); + + /// Creates a [MacOSStorageCreationParams] instance based on [PlatformStorageCreationParams]. + factory MacOSStorageCreationParams.fromPlatformStorageCreationParams( + // Recommended placeholder to prevent being broken by platform interface. + // ignore: avoid_unused_constructor_parameters + PlatformStorageCreationParams params) { + return MacOSStorageCreationParams( + controller: params.controller, webStorageType: params.webStorageType); + } +} + +///{@macro flutter_inappwebview_platform_interface.PlatformStorage} +abstract class MacOSStorage implements PlatformStorage { + @override + MacOSInAppWebViewController? controller; + + @override + Future length() async { + var result = await controller?.evaluateJavascript(source: """ + window.$webStorageType.length; + """); + return result != null ? int.parse(json.decode(result)) : null; + } + + @override + Future setItem({required String key, required dynamic value}) async { + var encodedValue = json.encode(value); + await controller?.evaluateJavascript(source: """ + window.$webStorageType.setItem("$key", ${value is String ? encodedValue : "JSON.stringify($encodedValue)"}); + """); + } + + @override + Future getItem({required String key}) async { + var itemValue = await controller?.evaluateJavascript(source: """ + window.$webStorageType.getItem("$key"); + """); + + if (itemValue == null) { + return null; + } + + try { + return json.decode(itemValue); + } catch (e) {} + + return itemValue; + } + + @override + Future removeItem({required String key}) async { + await controller?.evaluateJavascript(source: """ + window.$webStorageType.removeItem("$key"); + """); + } + + @override + Future> getItems() async { + var webStorageItems = []; + + List>? items = + (await controller?.evaluateJavascript(source: """ +(function() { + var webStorageItems = []; + for(var i = 0; i < window.$webStorageType.length; i++){ + var key = window.$webStorageType.key(i); + webStorageItems.push( + { + key: key, + value: window.$webStorageType.getItem(key) + } + ); + } + return webStorageItems; +})(); + """))?.cast>(); + + if (items == null) { + return webStorageItems; + } + + for (var item in items) { + webStorageItems + .add(WebStorageItem(key: item["key"], value: item["value"])); + } + + return webStorageItems; + } + + @override + Future clear() async { + await controller?.evaluateJavascript(source: """ + window.$webStorageType.clear(); + """); + } + + @override + Future key({required int index}) async { + var result = await controller?.evaluateJavascript(source: """ + window.$webStorageType.key($index); + """); + return result != null ? json.decode(result) : null; + } + + @override + void dispose() { + controller = null; + } +} + +/// Object specifying creation parameters for creating a [MacOSLocalStorage]. +/// +/// When adding additional fields make sure they can be null or have a default +/// value to avoid breaking changes. See [PlatformLocalStorageCreationParams] for +/// more information. +class MacOSLocalStorageCreationParams + extends PlatformLocalStorageCreationParams { + /// Creates a new [MacOSLocalStorageCreationParams] instance. + MacOSLocalStorageCreationParams(super.params); + + /// Creates a [MacOSLocalStorageCreationParams] instance based on [PlatformLocalStorageCreationParams]. + factory MacOSLocalStorageCreationParams.fromPlatformLocalStorageCreationParams( + // Recommended placeholder to prevent being broken by platform interface. + // ignore: avoid_unused_constructor_parameters + PlatformLocalStorageCreationParams params) { + return MacOSLocalStorageCreationParams(params); + } +} + +///{@macro flutter_inappwebview_platform_interface.PlatformLocalStorage} +class MacOSLocalStorage extends PlatformLocalStorage with MacOSStorage { + /// Constructs a [MacOSLocalStorage]. + MacOSLocalStorage(PlatformLocalStorageCreationParams params) + : super.implementation( + params is MacOSLocalStorageCreationParams + ? params + : MacOSLocalStorageCreationParams + .fromPlatformLocalStorageCreationParams(params), + ); + + /// Default storage + factory MacOSLocalStorage.defaultStorage( + {required PlatformInAppWebViewController? controller}) { + return MacOSLocalStorage(MacOSLocalStorageCreationParams( + PlatformLocalStorageCreationParams(PlatformStorageCreationParams( + controller: controller, + webStorageType: WebStorageType.LOCAL_STORAGE)))); + } + + @override + MacOSInAppWebViewController? get controller => + params.controller as MacOSInAppWebViewController?; +} + +/// Object specifying creation parameters for creating a [MacOSSessionStorage]. +/// +/// When adding additional fields make sure they can be null or have a default +/// value to avoid breaking changes. See [PlatformSessionStorageCreationParams] for +/// more information. +class MacOSSessionStorageCreationParams + extends PlatformSessionStorageCreationParams { + /// Creates a new [MacOSSessionStorageCreationParams] instance. + MacOSSessionStorageCreationParams(super.params); + + /// Creates a [MacOSSessionStorageCreationParams] instance based on [PlatformSessionStorageCreationParams]. + factory MacOSSessionStorageCreationParams.fromPlatformSessionStorageCreationParams( + // Recommended placeholder to prevent being broken by platform interface. + // ignore: avoid_unused_constructor_parameters + PlatformSessionStorageCreationParams params) { + return MacOSSessionStorageCreationParams(params); + } +} + +///{@macro flutter_inappwebview_platform_interface.PlatformSessionStorage} +class MacOSSessionStorage extends PlatformSessionStorage with MacOSStorage { + /// Constructs a [MacOSSessionStorage]. + MacOSSessionStorage(PlatformSessionStorageCreationParams params) + : super.implementation( + params is MacOSSessionStorageCreationParams + ? params + : MacOSSessionStorageCreationParams + .fromPlatformSessionStorageCreationParams(params), + ); + + /// Default storage + factory MacOSSessionStorage.defaultStorage( + {required PlatformInAppWebViewController? controller}) { + return MacOSSessionStorage(MacOSSessionStorageCreationParams( + PlatformSessionStorageCreationParams(PlatformStorageCreationParams( + controller: controller, + webStorageType: WebStorageType.SESSION_STORAGE)))); + } + + @override + MacOSInAppWebViewController? get controller => + params.controller as MacOSInAppWebViewController?; +} diff --git a/flutter_inappwebview_macos/lib/src/web_storage/web_storage_manager.dart b/flutter_inappwebview_macos/lib/src/web_storage/web_storage_manager.dart new file mode 100755 index 00000000..b281f0d7 --- /dev/null +++ b/flutter_inappwebview_macos/lib/src/web_storage/web_storage_manager.dart @@ -0,0 +1,134 @@ +import 'dart:async'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; + +/// Object specifying creation parameters for creating a [MacOSWebStorageManager]. +/// +/// When adding additional fields make sure they can be null or have a default +/// value to avoid breaking changes. See [PlatformWebStorageManagerCreationParams] for +/// more information. +@immutable +class MacOSWebStorageManagerCreationParams + extends PlatformWebStorageManagerCreationParams { + /// Creates a new [MacOSWebStorageManagerCreationParams] instance. + const MacOSWebStorageManagerCreationParams( + // This parameter prevents breaking changes later. + // ignore: avoid_unused_constructor_parameters + PlatformWebStorageManagerCreationParams params, + ) : super(); + + /// Creates a [MacOSWebStorageManagerCreationParams] instance based on [PlatformWebStorageManagerCreationParams]. + factory MacOSWebStorageManagerCreationParams.fromPlatformWebStorageManagerCreationParams( + PlatformWebStorageManagerCreationParams params) { + return MacOSWebStorageManagerCreationParams(params); + } +} + +///{@macro flutter_inappwebview_platform_interface.PlatformWebStorageManager} +class MacOSWebStorageManager extends PlatformWebStorageManager + with ChannelController { + /// Creates a new [MacOSWebStorageManager]. + MacOSWebStorageManager(PlatformWebStorageManagerCreationParams params) + : super.implementation( + params is MacOSWebStorageManagerCreationParams + ? params + : MacOSWebStorageManagerCreationParams + .fromPlatformWebStorageManagerCreationParams(params), + ) { + channel = const MethodChannel( + 'com.pichillilorenzo/flutter_inappwebview_webstoragemanager'); + handler = handleMethod; + initMethodCallHandler(); + } + + static MacOSWebStorageManager? _instance; + + ///Gets the WebStorage manager shared instance. + static MacOSWebStorageManager instance() { + return (_instance != null) ? _instance! : _init(); + } + + static MacOSWebStorageManager _init() { + _instance = MacOSWebStorageManager(MacOSWebStorageManagerCreationParams( + const PlatformWebStorageManagerCreationParams())); + return _instance!; + } + + Future _handleMethod(MethodCall call) async {} + + @override + Future> fetchDataRecords( + {required Set dataTypes}) async { + List recordList = []; + List dataTypesList = []; + for (var dataType in dataTypes) { + dataTypesList.add(dataType.toNativeValue()); + } + Map args = {}; + args.putIfAbsent("dataTypes", () => dataTypesList); + List> records = + (await channel?.invokeMethod('fetchDataRecords', args)) + ?.cast>() ?? + []; + for (var record in records) { + List dataTypesString = record["dataTypes"].cast(); + Set dataTypes = Set(); + for (var dataTypeValue in dataTypesString) { + var dataType = WebsiteDataType.fromNativeValue(dataTypeValue); + if (dataType != null) { + dataTypes.add(dataType); + } + } + recordList.add(WebsiteDataRecord( + displayName: record["displayName"], dataTypes: dataTypes)); + } + return recordList; + } + + @override + Future removeDataFor( + {required Set dataTypes, + required List dataRecords}) async { + List dataTypesList = []; + for (var dataType in dataTypes) { + dataTypesList.add(dataType.toNativeValue()); + } + + List> recordList = []; + for (var record in dataRecords) { + recordList.add(record.toMap()); + } + + Map args = {}; + args.putIfAbsent("dataTypes", () => dataTypesList); + args.putIfAbsent("recordList", () => recordList); + await channel?.invokeMethod('removeDataFor', args); + } + + @override + Future removeDataModifiedSince( + {required Set dataTypes, required DateTime date}) async { + List dataTypesList = []; + for (var dataType in dataTypes) { + dataTypesList.add(dataType.toNativeValue()); + } + + var timestamp = date.millisecondsSinceEpoch; + + Map args = {}; + args.putIfAbsent("dataTypes", () => dataTypesList); + args.putIfAbsent("timestamp", () => timestamp); + await channel?.invokeMethod('removeDataModifiedSince', args); + } + + @override + void dispose() { + // empty + } +} + +extension InternalWebStorageManager on MacOSWebStorageManager { + get handleMethod => _handleMethod; +} diff --git a/macos/Classes/CredentialDatabase.swift b/flutter_inappwebview_macos/macos/Classes/CredentialDatabase.swift similarity index 100% rename from macos/Classes/CredentialDatabase.swift rename to flutter_inappwebview_macos/macos/Classes/CredentialDatabase.swift diff --git a/macos/Classes/FindInteraction/FindInteractionChannelDelegate.swift b/flutter_inappwebview_macos/macos/Classes/FindInteraction/FindInteractionChannelDelegate.swift similarity index 100% rename from macos/Classes/FindInteraction/FindInteractionChannelDelegate.swift rename to flutter_inappwebview_macos/macos/Classes/FindInteraction/FindInteractionChannelDelegate.swift diff --git a/macos/Classes/FindInteraction/FindInteractionController.swift b/flutter_inappwebview_macos/macos/Classes/FindInteraction/FindInteractionController.swift similarity index 100% rename from macos/Classes/FindInteraction/FindInteractionController.swift rename to flutter_inappwebview_macos/macos/Classes/FindInteraction/FindInteractionController.swift diff --git a/macos/Classes/FindInteraction/FindInteractionSettings.swift b/flutter_inappwebview_macos/macos/Classes/FindInteraction/FindInteractionSettings.swift similarity index 100% rename from macos/Classes/FindInteraction/FindInteractionSettings.swift rename to flutter_inappwebview_macos/macos/Classes/FindInteraction/FindInteractionSettings.swift diff --git a/macos/Classes/HeadlessInAppWebView/HeadlessInAppWebView.swift b/flutter_inappwebview_macos/macos/Classes/HeadlessInAppWebView/HeadlessInAppWebView.swift similarity index 100% rename from macos/Classes/HeadlessInAppWebView/HeadlessInAppWebView.swift rename to flutter_inappwebview_macos/macos/Classes/HeadlessInAppWebView/HeadlessInAppWebView.swift diff --git a/macos/Classes/HeadlessInAppWebView/HeadlessInAppWebViewManager.swift b/flutter_inappwebview_macos/macos/Classes/HeadlessInAppWebView/HeadlessInAppWebViewManager.swift similarity index 100% rename from macos/Classes/HeadlessInAppWebView/HeadlessInAppWebViewManager.swift rename to flutter_inappwebview_macos/macos/Classes/HeadlessInAppWebView/HeadlessInAppWebViewManager.swift diff --git a/macos/Classes/HeadlessInAppWebView/HeadlessWebViewChannelDelegate.swift b/flutter_inappwebview_macos/macos/Classes/HeadlessInAppWebView/HeadlessWebViewChannelDelegate.swift similarity index 100% rename from macos/Classes/HeadlessInAppWebView/HeadlessWebViewChannelDelegate.swift rename to flutter_inappwebview_macos/macos/Classes/HeadlessInAppWebView/HeadlessWebViewChannelDelegate.swift diff --git a/macos/Classes/ISettings.swift b/flutter_inappwebview_macos/macos/Classes/ISettings.swift similarity index 100% rename from macos/Classes/ISettings.swift rename to flutter_inappwebview_macos/macos/Classes/ISettings.swift diff --git a/macos/Classes/InAppBrowser/InAppBrowserChannelDelegate.swift b/flutter_inappwebview_macos/macos/Classes/InAppBrowser/InAppBrowserChannelDelegate.swift similarity index 100% rename from macos/Classes/InAppBrowser/InAppBrowserChannelDelegate.swift rename to flutter_inappwebview_macos/macos/Classes/InAppBrowser/InAppBrowserChannelDelegate.swift diff --git a/macos/Classes/InAppBrowser/InAppBrowserDelegate.swift b/flutter_inappwebview_macos/macos/Classes/InAppBrowser/InAppBrowserDelegate.swift similarity index 100% rename from macos/Classes/InAppBrowser/InAppBrowserDelegate.swift rename to flutter_inappwebview_macos/macos/Classes/InAppBrowser/InAppBrowserDelegate.swift diff --git a/macos/Classes/InAppBrowser/InAppBrowserManager.swift b/flutter_inappwebview_macos/macos/Classes/InAppBrowser/InAppBrowserManager.swift similarity index 100% rename from macos/Classes/InAppBrowser/InAppBrowserManager.swift rename to flutter_inappwebview_macos/macos/Classes/InAppBrowser/InAppBrowserManager.swift diff --git a/macos/Classes/InAppBrowser/InAppBrowserSettings.swift b/flutter_inappwebview_macos/macos/Classes/InAppBrowser/InAppBrowserSettings.swift similarity index 100% rename from macos/Classes/InAppBrowser/InAppBrowserSettings.swift rename to flutter_inappwebview_macos/macos/Classes/InAppBrowser/InAppBrowserSettings.swift diff --git a/macos/Classes/InAppBrowser/InAppBrowserWebViewController.swift b/flutter_inappwebview_macos/macos/Classes/InAppBrowser/InAppBrowserWebViewController.swift similarity index 100% rename from macos/Classes/InAppBrowser/InAppBrowserWebViewController.swift rename to flutter_inappwebview_macos/macos/Classes/InAppBrowser/InAppBrowserWebViewController.swift diff --git a/macos/Classes/InAppBrowser/InAppBrowserWindow.swift b/flutter_inappwebview_macos/macos/Classes/InAppBrowser/InAppBrowserWindow.swift similarity index 100% rename from macos/Classes/InAppBrowser/InAppBrowserWindow.swift rename to flutter_inappwebview_macos/macos/Classes/InAppBrowser/InAppBrowserWindow.swift diff --git a/macos/Classes/InAppWebView/ContextMenuSettings.swift b/flutter_inappwebview_macos/macos/Classes/InAppWebView/ContextMenuSettings.swift similarity index 100% rename from macos/Classes/InAppWebView/ContextMenuSettings.swift rename to flutter_inappwebview_macos/macos/Classes/InAppWebView/ContextMenuSettings.swift diff --git a/macos/Classes/InAppWebView/CustomSchemeHandler.swift b/flutter_inappwebview_macos/macos/Classes/InAppWebView/CustomSchemeHandler.swift similarity index 100% rename from macos/Classes/InAppWebView/CustomSchemeHandler.swift rename to flutter_inappwebview_macos/macos/Classes/InAppWebView/CustomSchemeHandler.swift diff --git a/macos/Classes/InAppWebView/FlutterWebViewController.swift b/flutter_inappwebview_macos/macos/Classes/InAppWebView/FlutterWebViewController.swift similarity index 100% rename from macos/Classes/InAppWebView/FlutterWebViewController.swift rename to flutter_inappwebview_macos/macos/Classes/InAppWebView/FlutterWebViewController.swift diff --git a/macos/Classes/InAppWebView/FlutterWebViewFactory.swift b/flutter_inappwebview_macos/macos/Classes/InAppWebView/FlutterWebViewFactory.swift similarity index 100% rename from macos/Classes/InAppWebView/FlutterWebViewFactory.swift rename to flutter_inappwebview_macos/macos/Classes/InAppWebView/FlutterWebViewFactory.swift diff --git a/macos/Classes/InAppWebView/InAppWebView.swift b/flutter_inappwebview_macos/macos/Classes/InAppWebView/InAppWebView.swift similarity index 100% rename from macos/Classes/InAppWebView/InAppWebView.swift rename to flutter_inappwebview_macos/macos/Classes/InAppWebView/InAppWebView.swift diff --git a/macos/Classes/InAppWebView/InAppWebViewManager.swift b/flutter_inappwebview_macos/macos/Classes/InAppWebView/InAppWebViewManager.swift similarity index 100% rename from macos/Classes/InAppWebView/InAppWebViewManager.swift rename to flutter_inappwebview_macos/macos/Classes/InAppWebView/InAppWebViewManager.swift diff --git a/macos/Classes/InAppWebView/InAppWebViewSettings.swift b/flutter_inappwebview_macos/macos/Classes/InAppWebView/InAppWebViewSettings.swift similarity index 100% rename from macos/Classes/InAppWebView/InAppWebViewSettings.swift rename to flutter_inappwebview_macos/macos/Classes/InAppWebView/InAppWebViewSettings.swift diff --git a/macos/Classes/InAppWebView/WebMessage/WebMessageChannel.swift b/flutter_inappwebview_macos/macos/Classes/InAppWebView/WebMessage/WebMessageChannel.swift similarity index 100% rename from macos/Classes/InAppWebView/WebMessage/WebMessageChannel.swift rename to flutter_inappwebview_macos/macos/Classes/InAppWebView/WebMessage/WebMessageChannel.swift diff --git a/macos/Classes/InAppWebView/WebMessage/WebMessageChannelChannelDelegate.swift b/flutter_inappwebview_macos/macos/Classes/InAppWebView/WebMessage/WebMessageChannelChannelDelegate.swift similarity index 100% rename from macos/Classes/InAppWebView/WebMessage/WebMessageChannelChannelDelegate.swift rename to flutter_inappwebview_macos/macos/Classes/InAppWebView/WebMessage/WebMessageChannelChannelDelegate.swift diff --git a/macos/Classes/InAppWebView/WebMessage/WebMessageListener.swift b/flutter_inappwebview_macos/macos/Classes/InAppWebView/WebMessage/WebMessageListener.swift similarity index 100% rename from macos/Classes/InAppWebView/WebMessage/WebMessageListener.swift rename to flutter_inappwebview_macos/macos/Classes/InAppWebView/WebMessage/WebMessageListener.swift diff --git a/macos/Classes/InAppWebView/WebMessage/WebMessageListenerChannelDelegate.swift b/flutter_inappwebview_macos/macos/Classes/InAppWebView/WebMessage/WebMessageListenerChannelDelegate.swift similarity index 100% rename from macos/Classes/InAppWebView/WebMessage/WebMessageListenerChannelDelegate.swift rename to flutter_inappwebview_macos/macos/Classes/InAppWebView/WebMessage/WebMessageListenerChannelDelegate.swift diff --git a/macos/Classes/InAppWebView/WebViewChannelDelegate.swift b/flutter_inappwebview_macos/macos/Classes/InAppWebView/WebViewChannelDelegate.swift similarity index 100% rename from macos/Classes/InAppWebView/WebViewChannelDelegate.swift rename to flutter_inappwebview_macos/macos/Classes/InAppWebView/WebViewChannelDelegate.swift diff --git a/macos/Classes/InAppWebView/WebViewChannelDelegateMethods.swift b/flutter_inappwebview_macos/macos/Classes/InAppWebView/WebViewChannelDelegateMethods.swift similarity index 100% rename from macos/Classes/InAppWebView/WebViewChannelDelegateMethods.swift rename to flutter_inappwebview_macos/macos/Classes/InAppWebView/WebViewChannelDelegateMethods.swift diff --git a/macos/Classes/InAppWebViewFlutterPlugin.swift b/flutter_inappwebview_macos/macos/Classes/InAppWebViewFlutterPlugin.swift similarity index 100% rename from macos/Classes/InAppWebViewFlutterPlugin.swift rename to flutter_inappwebview_macos/macos/Classes/InAppWebViewFlutterPlugin.swift diff --git a/macos/Classes/LeakAvoider.swift b/flutter_inappwebview_macos/macos/Classes/LeakAvoider.swift similarity index 100% rename from macos/Classes/LeakAvoider.swift rename to flutter_inappwebview_macos/macos/Classes/LeakAvoider.swift diff --git a/macos/Classes/MyCookieManager.swift b/flutter_inappwebview_macos/macos/Classes/MyCookieManager.swift similarity index 100% rename from macos/Classes/MyCookieManager.swift rename to flutter_inappwebview_macos/macos/Classes/MyCookieManager.swift diff --git a/macos/Classes/MyWebStorageManager.swift b/flutter_inappwebview_macos/macos/Classes/MyWebStorageManager.swift similarity index 100% rename from macos/Classes/MyWebStorageManager.swift rename to flutter_inappwebview_macos/macos/Classes/MyWebStorageManager.swift diff --git a/macos/Classes/PlatformUtil.swift b/flutter_inappwebview_macos/macos/Classes/PlatformUtil.swift similarity index 100% rename from macos/Classes/PlatformUtil.swift rename to flutter_inappwebview_macos/macos/Classes/PlatformUtil.swift diff --git a/macos/Classes/PluginScriptsJS/CallAsyncJavaScriptBelowIOS14WrapperJS.swift b/flutter_inappwebview_macos/macos/Classes/PluginScriptsJS/CallAsyncJavaScriptBelowIOS14WrapperJS.swift similarity index 100% rename from macos/Classes/PluginScriptsJS/CallAsyncJavaScriptBelowIOS14WrapperJS.swift rename to flutter_inappwebview_macos/macos/Classes/PluginScriptsJS/CallAsyncJavaScriptBelowIOS14WrapperJS.swift diff --git a/macos/Classes/PluginScriptsJS/ConsoleLogJS.swift b/flutter_inappwebview_macos/macos/Classes/PluginScriptsJS/ConsoleLogJS.swift similarity index 100% rename from macos/Classes/PluginScriptsJS/ConsoleLogJS.swift rename to flutter_inappwebview_macos/macos/Classes/PluginScriptsJS/ConsoleLogJS.swift diff --git a/macos/Classes/PluginScriptsJS/EnableViewportScaleJS.swift b/flutter_inappwebview_macos/macos/Classes/PluginScriptsJS/EnableViewportScaleJS.swift similarity index 100% rename from macos/Classes/PluginScriptsJS/EnableViewportScaleJS.swift rename to flutter_inappwebview_macos/macos/Classes/PluginScriptsJS/EnableViewportScaleJS.swift diff --git a/macos/Classes/PluginScriptsJS/FindElementsAtPointJS.swift b/flutter_inappwebview_macos/macos/Classes/PluginScriptsJS/FindElementsAtPointJS.swift similarity index 100% rename from macos/Classes/PluginScriptsJS/FindElementsAtPointJS.swift rename to flutter_inappwebview_macos/macos/Classes/PluginScriptsJS/FindElementsAtPointJS.swift diff --git a/macos/Classes/PluginScriptsJS/FindTextHighlightJS.swift b/flutter_inappwebview_macos/macos/Classes/PluginScriptsJS/FindTextHighlightJS.swift similarity index 100% rename from macos/Classes/PluginScriptsJS/FindTextHighlightJS.swift rename to flutter_inappwebview_macos/macos/Classes/PluginScriptsJS/FindTextHighlightJS.swift diff --git a/macos/Classes/PluginScriptsJS/InterceptAjaxRequestJS.swift b/flutter_inappwebview_macos/macos/Classes/PluginScriptsJS/InterceptAjaxRequestJS.swift similarity index 100% rename from macos/Classes/PluginScriptsJS/InterceptAjaxRequestJS.swift rename to flutter_inappwebview_macos/macos/Classes/PluginScriptsJS/InterceptAjaxRequestJS.swift diff --git a/macos/Classes/PluginScriptsJS/InterceptFetchRequestJS.swift b/flutter_inappwebview_macos/macos/Classes/PluginScriptsJS/InterceptFetchRequestJS.swift similarity index 100% rename from macos/Classes/PluginScriptsJS/InterceptFetchRequestJS.swift rename to flutter_inappwebview_macos/macos/Classes/PluginScriptsJS/InterceptFetchRequestJS.swift diff --git a/macos/Classes/PluginScriptsJS/JavaScriptBridgeJS.swift b/flutter_inappwebview_macos/macos/Classes/PluginScriptsJS/JavaScriptBridgeJS.swift similarity index 100% rename from macos/Classes/PluginScriptsJS/JavaScriptBridgeJS.swift rename to flutter_inappwebview_macos/macos/Classes/PluginScriptsJS/JavaScriptBridgeJS.swift diff --git a/macos/Classes/PluginScriptsJS/OnLoadResourceJS.swift b/flutter_inappwebview_macos/macos/Classes/PluginScriptsJS/OnLoadResourceJS.swift similarity index 100% rename from macos/Classes/PluginScriptsJS/OnLoadResourceJS.swift rename to flutter_inappwebview_macos/macos/Classes/PluginScriptsJS/OnLoadResourceJS.swift diff --git a/macos/Classes/PluginScriptsJS/OnScrollChangedJS.swift b/flutter_inappwebview_macos/macos/Classes/PluginScriptsJS/OnScrollChangedJS.swift similarity index 100% rename from macos/Classes/PluginScriptsJS/OnScrollChangedJS.swift rename to flutter_inappwebview_macos/macos/Classes/PluginScriptsJS/OnScrollChangedJS.swift diff --git a/macos/Classes/PluginScriptsJS/OnWindowBlurEventJS.swift b/flutter_inappwebview_macos/macos/Classes/PluginScriptsJS/OnWindowBlurEventJS.swift similarity index 100% rename from macos/Classes/PluginScriptsJS/OnWindowBlurEventJS.swift rename to flutter_inappwebview_macos/macos/Classes/PluginScriptsJS/OnWindowBlurEventJS.swift diff --git a/macos/Classes/PluginScriptsJS/OnWindowFocusEventJS.swift b/flutter_inappwebview_macos/macos/Classes/PluginScriptsJS/OnWindowFocusEventJS.swift similarity index 100% rename from macos/Classes/PluginScriptsJS/OnWindowFocusEventJS.swift rename to flutter_inappwebview_macos/macos/Classes/PluginScriptsJS/OnWindowFocusEventJS.swift diff --git a/macos/Classes/PluginScriptsJS/OriginalViewPortMetaTagContentJS.swift b/flutter_inappwebview_macos/macos/Classes/PluginScriptsJS/OriginalViewPortMetaTagContentJS.swift similarity index 100% rename from macos/Classes/PluginScriptsJS/OriginalViewPortMetaTagContentJS.swift rename to flutter_inappwebview_macos/macos/Classes/PluginScriptsJS/OriginalViewPortMetaTagContentJS.swift diff --git a/macos/Classes/PluginScriptsJS/PluginScriptsUtil.swift b/flutter_inappwebview_macos/macos/Classes/PluginScriptsJS/PluginScriptsUtil.swift similarity index 100% rename from macos/Classes/PluginScriptsJS/PluginScriptsUtil.swift rename to flutter_inappwebview_macos/macos/Classes/PluginScriptsJS/PluginScriptsUtil.swift diff --git a/macos/Classes/PluginScriptsJS/PrintJS.swift b/flutter_inappwebview_macos/macos/Classes/PluginScriptsJS/PrintJS.swift similarity index 100% rename from macos/Classes/PluginScriptsJS/PrintJS.swift rename to flutter_inappwebview_macos/macos/Classes/PluginScriptsJS/PrintJS.swift diff --git a/macos/Classes/PluginScriptsJS/PromisePolyfillJS.swift b/flutter_inappwebview_macos/macos/Classes/PluginScriptsJS/PromisePolyfillJS.swift similarity index 100% rename from macos/Classes/PluginScriptsJS/PromisePolyfillJS.swift rename to flutter_inappwebview_macos/macos/Classes/PluginScriptsJS/PromisePolyfillJS.swift diff --git a/macos/Classes/PluginScriptsJS/SupportZoomJS.swift b/flutter_inappwebview_macos/macos/Classes/PluginScriptsJS/SupportZoomJS.swift similarity index 100% rename from macos/Classes/PluginScriptsJS/SupportZoomJS.swift rename to flutter_inappwebview_macos/macos/Classes/PluginScriptsJS/SupportZoomJS.swift diff --git a/macos/Classes/PluginScriptsJS/WebMessageChannelJS.swift b/flutter_inappwebview_macos/macos/Classes/PluginScriptsJS/WebMessageChannelJS.swift similarity index 100% rename from macos/Classes/PluginScriptsJS/WebMessageChannelJS.swift rename to flutter_inappwebview_macos/macos/Classes/PluginScriptsJS/WebMessageChannelJS.swift diff --git a/macos/Classes/PluginScriptsJS/WebMessageListenerJS.swift b/flutter_inappwebview_macos/macos/Classes/PluginScriptsJS/WebMessageListenerJS.swift similarity index 100% rename from macos/Classes/PluginScriptsJS/WebMessageListenerJS.swift rename to flutter_inappwebview_macos/macos/Classes/PluginScriptsJS/WebMessageListenerJS.swift diff --git a/macos/Classes/PluginScriptsJS/WindowIdJS.swift b/flutter_inappwebview_macos/macos/Classes/PluginScriptsJS/WindowIdJS.swift similarity index 100% rename from macos/Classes/PluginScriptsJS/WindowIdJS.swift rename to flutter_inappwebview_macos/macos/Classes/PluginScriptsJS/WindowIdJS.swift diff --git a/macos/Classes/PrintJob/CustomUIPrintPageRenderer.swift b/flutter_inappwebview_macos/macos/Classes/PrintJob/CustomUIPrintPageRenderer.swift similarity index 100% rename from macos/Classes/PrintJob/CustomUIPrintPageRenderer.swift rename to flutter_inappwebview_macos/macos/Classes/PrintJob/CustomUIPrintPageRenderer.swift diff --git a/macos/Classes/PrintJob/PrintAttributes.swift b/flutter_inappwebview_macos/macos/Classes/PrintJob/PrintAttributes.swift similarity index 100% rename from macos/Classes/PrintJob/PrintAttributes.swift rename to flutter_inappwebview_macos/macos/Classes/PrintJob/PrintAttributes.swift diff --git a/macos/Classes/PrintJob/PrintJobChannelDelegate.swift b/flutter_inappwebview_macos/macos/Classes/PrintJob/PrintJobChannelDelegate.swift similarity index 100% rename from macos/Classes/PrintJob/PrintJobChannelDelegate.swift rename to flutter_inappwebview_macos/macos/Classes/PrintJob/PrintJobChannelDelegate.swift diff --git a/macos/Classes/PrintJob/PrintJobController.swift b/flutter_inappwebview_macos/macos/Classes/PrintJob/PrintJobController.swift similarity index 100% rename from macos/Classes/PrintJob/PrintJobController.swift rename to flutter_inappwebview_macos/macos/Classes/PrintJob/PrintJobController.swift diff --git a/macos/Classes/PrintJob/PrintJobInfo.swift b/flutter_inappwebview_macos/macos/Classes/PrintJob/PrintJobInfo.swift similarity index 100% rename from macos/Classes/PrintJob/PrintJobInfo.swift rename to flutter_inappwebview_macos/macos/Classes/PrintJob/PrintJobInfo.swift diff --git a/macos/Classes/PrintJob/PrintJobManager.swift b/flutter_inappwebview_macos/macos/Classes/PrintJob/PrintJobManager.swift similarity index 100% rename from macos/Classes/PrintJob/PrintJobManager.swift rename to flutter_inappwebview_macos/macos/Classes/PrintJob/PrintJobManager.swift diff --git a/macos/Classes/PrintJob/PrintJobSettings.swift b/flutter_inappwebview_macos/macos/Classes/PrintJob/PrintJobSettings.swift similarity index 100% rename from macos/Classes/PrintJob/PrintJobSettings.swift rename to flutter_inappwebview_macos/macos/Classes/PrintJob/PrintJobSettings.swift diff --git a/macos/Classes/Types/BaseCallbackResult.swift b/flutter_inappwebview_macos/macos/Classes/Types/BaseCallbackResult.swift similarity index 100% rename from macos/Classes/Types/BaseCallbackResult.swift rename to flutter_inappwebview_macos/macos/Classes/Types/BaseCallbackResult.swift diff --git a/macos/Classes/Types/CGRect.swift b/flutter_inappwebview_macos/macos/Classes/Types/CGRect.swift similarity index 100% rename from macos/Classes/Types/CGRect.swift rename to flutter_inappwebview_macos/macos/Classes/Types/CGRect.swift diff --git a/macos/Classes/Types/CallbackResult.swift b/flutter_inappwebview_macos/macos/Classes/Types/CallbackResult.swift similarity index 100% rename from macos/Classes/Types/CallbackResult.swift rename to flutter_inappwebview_macos/macos/Classes/Types/CallbackResult.swift diff --git a/macos/Classes/Types/ChannelDelegate.swift b/flutter_inappwebview_macos/macos/Classes/Types/ChannelDelegate.swift similarity index 100% rename from macos/Classes/Types/ChannelDelegate.swift rename to flutter_inappwebview_macos/macos/Classes/Types/ChannelDelegate.swift diff --git a/macos/Classes/Types/ClientCertChallenge.swift b/flutter_inappwebview_macos/macos/Classes/Types/ClientCertChallenge.swift similarity index 100% rename from macos/Classes/Types/ClientCertChallenge.swift rename to flutter_inappwebview_macos/macos/Classes/Types/ClientCertChallenge.swift diff --git a/macos/Classes/Types/ClientCertResponse.swift b/flutter_inappwebview_macos/macos/Classes/Types/ClientCertResponse.swift similarity index 100% rename from macos/Classes/Types/ClientCertResponse.swift rename to flutter_inappwebview_macos/macos/Classes/Types/ClientCertResponse.swift diff --git a/macos/Classes/Types/CreateWindowAction.swift b/flutter_inappwebview_macos/macos/Classes/Types/CreateWindowAction.swift similarity index 100% rename from macos/Classes/Types/CreateWindowAction.swift rename to flutter_inappwebview_macos/macos/Classes/Types/CreateWindowAction.swift diff --git a/macos/Classes/Types/CustomSchemeResponse.swift b/flutter_inappwebview_macos/macos/Classes/Types/CustomSchemeResponse.swift similarity index 100% rename from macos/Classes/Types/CustomSchemeResponse.swift rename to flutter_inappwebview_macos/macos/Classes/Types/CustomSchemeResponse.swift diff --git a/macos/Classes/Types/Disposable.swift b/flutter_inappwebview_macos/macos/Classes/Types/Disposable.swift similarity index 100% rename from macos/Classes/Types/Disposable.swift rename to flutter_inappwebview_macos/macos/Classes/Types/Disposable.swift diff --git a/macos/Classes/Types/DownloadStartRequest.swift b/flutter_inappwebview_macos/macos/Classes/Types/DownloadStartRequest.swift similarity index 100% rename from macos/Classes/Types/DownloadStartRequest.swift rename to flutter_inappwebview_macos/macos/Classes/Types/DownloadStartRequest.swift diff --git a/macos/Classes/Types/FindSession.swift b/flutter_inappwebview_macos/macos/Classes/Types/FindSession.swift similarity index 100% rename from macos/Classes/Types/FindSession.swift rename to flutter_inappwebview_macos/macos/Classes/Types/FindSession.swift diff --git a/macos/Classes/Types/FlutterMethodCallDelegate.swift b/flutter_inappwebview_macos/macos/Classes/Types/FlutterMethodCallDelegate.swift similarity index 100% rename from macos/Classes/Types/FlutterMethodCallDelegate.swift rename to flutter_inappwebview_macos/macos/Classes/Types/FlutterMethodCallDelegate.swift diff --git a/macos/Classes/Types/FlutterMethodChannel.swift b/flutter_inappwebview_macos/macos/Classes/Types/FlutterMethodChannel.swift similarity index 100% rename from macos/Classes/Types/FlutterMethodChannel.swift rename to flutter_inappwebview_macos/macos/Classes/Types/FlutterMethodChannel.swift diff --git a/macos/Classes/Types/HitTestResult.swift b/flutter_inappwebview_macos/macos/Classes/Types/HitTestResult.swift similarity index 100% rename from macos/Classes/Types/HitTestResult.swift rename to flutter_inappwebview_macos/macos/Classes/Types/HitTestResult.swift diff --git a/macos/Classes/Types/HttpAuthResponse.swift b/flutter_inappwebview_macos/macos/Classes/Types/HttpAuthResponse.swift similarity index 100% rename from macos/Classes/Types/HttpAuthResponse.swift rename to flutter_inappwebview_macos/macos/Classes/Types/HttpAuthResponse.swift diff --git a/macos/Classes/Types/HttpAuthenticationChallenge.swift b/flutter_inappwebview_macos/macos/Classes/Types/HttpAuthenticationChallenge.swift similarity index 100% rename from macos/Classes/Types/HttpAuthenticationChallenge.swift rename to flutter_inappwebview_macos/macos/Classes/Types/HttpAuthenticationChallenge.swift diff --git a/macos/Classes/Types/InAppBrowserMenuItem.swift b/flutter_inappwebview_macos/macos/Classes/Types/InAppBrowserMenuItem.swift similarity index 100% rename from macos/Classes/Types/InAppBrowserMenuItem.swift rename to flutter_inappwebview_macos/macos/Classes/Types/InAppBrowserMenuItem.swift diff --git a/macos/Classes/Types/InAppBrowserWindowType.swift b/flutter_inappwebview_macos/macos/Classes/Types/InAppBrowserWindowType.swift similarity index 100% rename from macos/Classes/Types/InAppBrowserWindowType.swift rename to flutter_inappwebview_macos/macos/Classes/Types/InAppBrowserWindowType.swift diff --git a/macos/Classes/Types/JsAlertResponse.swift b/flutter_inappwebview_macos/macos/Classes/Types/JsAlertResponse.swift similarity index 100% rename from macos/Classes/Types/JsAlertResponse.swift rename to flutter_inappwebview_macos/macos/Classes/Types/JsAlertResponse.swift diff --git a/macos/Classes/Types/JsConfirmResponse.swift b/flutter_inappwebview_macos/macos/Classes/Types/JsConfirmResponse.swift similarity index 100% rename from macos/Classes/Types/JsConfirmResponse.swift rename to flutter_inappwebview_macos/macos/Classes/Types/JsConfirmResponse.swift diff --git a/macos/Classes/Types/JsPromptResponse.swift b/flutter_inappwebview_macos/macos/Classes/Types/JsPromptResponse.swift similarity index 100% rename from macos/Classes/Types/JsPromptResponse.swift rename to flutter_inappwebview_macos/macos/Classes/Types/JsPromptResponse.swift diff --git a/macos/Classes/Types/MethodChannelResult.swift b/flutter_inappwebview_macos/macos/Classes/Types/MethodChannelResult.swift similarity index 100% rename from macos/Classes/Types/MethodChannelResult.swift rename to flutter_inappwebview_macos/macos/Classes/Types/MethodChannelResult.swift diff --git a/macos/Classes/Types/NSAttributedString.swift b/flutter_inappwebview_macos/macos/Classes/Types/NSAttributedString.swift similarity index 100% rename from macos/Classes/Types/NSAttributedString.swift rename to flutter_inappwebview_macos/macos/Classes/Types/NSAttributedString.swift diff --git a/macos/Classes/Types/NSColor.swift b/flutter_inappwebview_macos/macos/Classes/Types/NSColor.swift similarity index 100% rename from macos/Classes/Types/NSColor.swift rename to flutter_inappwebview_macos/macos/Classes/Types/NSColor.swift diff --git a/macos/Classes/Types/NSEdgeInsets.swift b/flutter_inappwebview_macos/macos/Classes/Types/NSEdgeInsets.swift similarity index 100% rename from macos/Classes/Types/NSEdgeInsets.swift rename to flutter_inappwebview_macos/macos/Classes/Types/NSEdgeInsets.swift diff --git a/macos/Classes/Types/NSImage.swift b/flutter_inappwebview_macos/macos/Classes/Types/NSImage.swift similarity index 100% rename from macos/Classes/Types/NSImage.swift rename to flutter_inappwebview_macos/macos/Classes/Types/NSImage.swift diff --git a/macos/Classes/Types/NSPrinter.swift b/flutter_inappwebview_macos/macos/Classes/Types/NSPrinter.swift similarity index 100% rename from macos/Classes/Types/NSPrinter.swift rename to flutter_inappwebview_macos/macos/Classes/Types/NSPrinter.swift diff --git a/macos/Classes/Types/PermissionRequest.swift b/flutter_inappwebview_macos/macos/Classes/Types/PermissionRequest.swift similarity index 100% rename from macos/Classes/Types/PermissionRequest.swift rename to flutter_inappwebview_macos/macos/Classes/Types/PermissionRequest.swift diff --git a/macos/Classes/Types/PermissionResponse.swift b/flutter_inappwebview_macos/macos/Classes/Types/PermissionResponse.swift similarity index 100% rename from macos/Classes/Types/PermissionResponse.swift rename to flutter_inappwebview_macos/macos/Classes/Types/PermissionResponse.swift diff --git a/macos/Classes/Types/PluginScript.swift b/flutter_inappwebview_macos/macos/Classes/Types/PluginScript.swift similarity index 100% rename from macos/Classes/Types/PluginScript.swift rename to flutter_inappwebview_macos/macos/Classes/Types/PluginScript.swift diff --git a/macos/Classes/Types/SecCertificate.swift b/flutter_inappwebview_macos/macos/Classes/Types/SecCertificate.swift similarity index 100% rename from macos/Classes/Types/SecCertificate.swift rename to flutter_inappwebview_macos/macos/Classes/Types/SecCertificate.swift diff --git a/macos/Classes/Types/ServerTrustAuthResponse.swift b/flutter_inappwebview_macos/macos/Classes/Types/ServerTrustAuthResponse.swift similarity index 100% rename from macos/Classes/Types/ServerTrustAuthResponse.swift rename to flutter_inappwebview_macos/macos/Classes/Types/ServerTrustAuthResponse.swift diff --git a/macos/Classes/Types/ServerTrustChallenge.swift b/flutter_inappwebview_macos/macos/Classes/Types/ServerTrustChallenge.swift similarity index 100% rename from macos/Classes/Types/ServerTrustChallenge.swift rename to flutter_inappwebview_macos/macos/Classes/Types/ServerTrustChallenge.swift diff --git a/macos/Classes/Types/Size2D.swift b/flutter_inappwebview_macos/macos/Classes/Types/Size2D.swift similarity index 100% rename from macos/Classes/Types/Size2D.swift rename to flutter_inappwebview_macos/macos/Classes/Types/Size2D.swift diff --git a/macos/Classes/Types/SslCertificate.swift b/flutter_inappwebview_macos/macos/Classes/Types/SslCertificate.swift similarity index 100% rename from macos/Classes/Types/SslCertificate.swift rename to flutter_inappwebview_macos/macos/Classes/Types/SslCertificate.swift diff --git a/macos/Classes/Types/SslError.swift b/flutter_inappwebview_macos/macos/Classes/Types/SslError.swift similarity index 100% rename from macos/Classes/Types/SslError.swift rename to flutter_inappwebview_macos/macos/Classes/Types/SslError.swift diff --git a/macos/Classes/Types/StringOrInt.swift b/flutter_inappwebview_macos/macos/Classes/Types/StringOrInt.swift similarity index 100% rename from macos/Classes/Types/StringOrInt.swift rename to flutter_inappwebview_macos/macos/Classes/Types/StringOrInt.swift diff --git a/macos/Classes/Types/URLAuthenticationChallenge.swift b/flutter_inappwebview_macos/macos/Classes/Types/URLAuthenticationChallenge.swift similarity index 100% rename from macos/Classes/Types/URLAuthenticationChallenge.swift rename to flutter_inappwebview_macos/macos/Classes/Types/URLAuthenticationChallenge.swift diff --git a/macos/Classes/Types/URLCredential.swift b/flutter_inappwebview_macos/macos/Classes/Types/URLCredential.swift similarity index 100% rename from macos/Classes/Types/URLCredential.swift rename to flutter_inappwebview_macos/macos/Classes/Types/URLCredential.swift diff --git a/macos/Classes/Types/URLProtectionSpace.swift b/flutter_inappwebview_macos/macos/Classes/Types/URLProtectionSpace.swift similarity index 100% rename from macos/Classes/Types/URLProtectionSpace.swift rename to flutter_inappwebview_macos/macos/Classes/Types/URLProtectionSpace.swift diff --git a/macos/Classes/Types/URLRequest.swift b/flutter_inappwebview_macos/macos/Classes/Types/URLRequest.swift similarity index 100% rename from macos/Classes/Types/URLRequest.swift rename to flutter_inappwebview_macos/macos/Classes/Types/URLRequest.swift diff --git a/macos/Classes/Types/URLResponse.swift b/flutter_inappwebview_macos/macos/Classes/Types/URLResponse.swift similarity index 100% rename from macos/Classes/Types/URLResponse.swift rename to flutter_inappwebview_macos/macos/Classes/Types/URLResponse.swift diff --git a/macos/Classes/Types/UserScript.swift b/flutter_inappwebview_macos/macos/Classes/Types/UserScript.swift similarity index 100% rename from macos/Classes/Types/UserScript.swift rename to flutter_inappwebview_macos/macos/Classes/Types/UserScript.swift diff --git a/macos/Classes/Types/WKContentWorld.swift b/flutter_inappwebview_macos/macos/Classes/Types/WKContentWorld.swift similarity index 100% rename from macos/Classes/Types/WKContentWorld.swift rename to flutter_inappwebview_macos/macos/Classes/Types/WKContentWorld.swift diff --git a/macos/Classes/Types/WKFrameInfo.swift b/flutter_inappwebview_macos/macos/Classes/Types/WKFrameInfo.swift similarity index 100% rename from macos/Classes/Types/WKFrameInfo.swift rename to flutter_inappwebview_macos/macos/Classes/Types/WKFrameInfo.swift diff --git a/macos/Classes/Types/WKNavigationAction.swift b/flutter_inappwebview_macos/macos/Classes/Types/WKNavigationAction.swift similarity index 100% rename from macos/Classes/Types/WKNavigationAction.swift rename to flutter_inappwebview_macos/macos/Classes/Types/WKNavigationAction.swift diff --git a/macos/Classes/Types/WKNavigationResponse.swift b/flutter_inappwebview_macos/macos/Classes/Types/WKNavigationResponse.swift similarity index 100% rename from macos/Classes/Types/WKNavigationResponse.swift rename to flutter_inappwebview_macos/macos/Classes/Types/WKNavigationResponse.swift diff --git a/macos/Classes/Types/WKSecurityOrigin.swift b/flutter_inappwebview_macos/macos/Classes/Types/WKSecurityOrigin.swift similarity index 100% rename from macos/Classes/Types/WKSecurityOrigin.swift rename to flutter_inappwebview_macos/macos/Classes/Types/WKSecurityOrigin.swift diff --git a/macos/Classes/Types/WKUserContentController.swift b/flutter_inappwebview_macos/macos/Classes/Types/WKUserContentController.swift similarity index 100% rename from macos/Classes/Types/WKUserContentController.swift rename to flutter_inappwebview_macos/macos/Classes/Types/WKUserContentController.swift diff --git a/macos/Classes/Types/WKWindowFeatures.swift b/flutter_inappwebview_macos/macos/Classes/Types/WKWindowFeatures.swift similarity index 100% rename from macos/Classes/Types/WKWindowFeatures.swift rename to flutter_inappwebview_macos/macos/Classes/Types/WKWindowFeatures.swift diff --git a/macos/Classes/Types/WebMessage.swift b/flutter_inappwebview_macos/macos/Classes/Types/WebMessage.swift similarity index 100% rename from macos/Classes/Types/WebMessage.swift rename to flutter_inappwebview_macos/macos/Classes/Types/WebMessage.swift diff --git a/macos/Classes/Types/WebMessagePort.swift b/flutter_inappwebview_macos/macos/Classes/Types/WebMessagePort.swift similarity index 100% rename from macos/Classes/Types/WebMessagePort.swift rename to flutter_inappwebview_macos/macos/Classes/Types/WebMessagePort.swift diff --git a/macos/Classes/Types/WebResourceError.swift b/flutter_inappwebview_macos/macos/Classes/Types/WebResourceError.swift similarity index 100% rename from macos/Classes/Types/WebResourceError.swift rename to flutter_inappwebview_macos/macos/Classes/Types/WebResourceError.swift diff --git a/macos/Classes/Types/WebResourceRequest.swift b/flutter_inappwebview_macos/macos/Classes/Types/WebResourceRequest.swift similarity index 100% rename from macos/Classes/Types/WebResourceRequest.swift rename to flutter_inappwebview_macos/macos/Classes/Types/WebResourceRequest.swift diff --git a/macos/Classes/Types/WebResourceResponse.swift b/flutter_inappwebview_macos/macos/Classes/Types/WebResourceResponse.swift similarity index 100% rename from macos/Classes/Types/WebResourceResponse.swift rename to flutter_inappwebview_macos/macos/Classes/Types/WebResourceResponse.swift diff --git a/macos/Classes/Types/WebViewTransport.swift b/flutter_inappwebview_macos/macos/Classes/Types/WebViewTransport.swift similarity index 100% rename from macos/Classes/Types/WebViewTransport.swift rename to flutter_inappwebview_macos/macos/Classes/Types/WebViewTransport.swift diff --git a/macos/Classes/Util.swift b/flutter_inappwebview_macos/macos/Classes/Util.swift similarity index 100% rename from macos/Classes/Util.swift rename to flutter_inappwebview_macos/macos/Classes/Util.swift diff --git a/macos/Classes/WKProcessPoolManager.swift b/flutter_inappwebview_macos/macos/Classes/WKProcessPoolManager.swift similarity index 100% rename from macos/Classes/WKProcessPoolManager.swift rename to flutter_inappwebview_macos/macos/Classes/WKProcessPoolManager.swift diff --git a/macos/Classes/WebAuthenticationSession/WebAuthenticationSession.swift b/flutter_inappwebview_macos/macos/Classes/WebAuthenticationSession/WebAuthenticationSession.swift similarity index 100% rename from macos/Classes/WebAuthenticationSession/WebAuthenticationSession.swift rename to flutter_inappwebview_macos/macos/Classes/WebAuthenticationSession/WebAuthenticationSession.swift diff --git a/macos/Classes/WebAuthenticationSession/WebAuthenticationSessionChannelDelegate.swift b/flutter_inappwebview_macos/macos/Classes/WebAuthenticationSession/WebAuthenticationSessionChannelDelegate.swift similarity index 94% rename from macos/Classes/WebAuthenticationSession/WebAuthenticationSessionChannelDelegate.swift rename to flutter_inappwebview_macos/macos/Classes/WebAuthenticationSession/WebAuthenticationSessionChannelDelegate.swift index 7c476a6a..6cdf5dbe 100644 --- a/macos/Classes/WebAuthenticationSession/WebAuthenticationSessionChannelDelegate.swift +++ b/flutter_inappwebview_macos/macos/Classes/WebAuthenticationSession/WebAuthenticationSessionChannelDelegate.swift @@ -60,7 +60,9 @@ public class WebAuthenticationSessionChannelDelegate : ChannelDelegate { "url": url?.absoluteString, "errorCode": errorCode ] - channel?.invokeMethod("onComplete", arguments: arguments) + DispatchQueue.main.async { [weak self] in + self?.channel?.invokeMethod("onComplete", arguments: arguments) + } } public override func dispose() { diff --git a/macos/Classes/WebAuthenticationSession/WebAuthenticationSessionManager.swift b/flutter_inappwebview_macos/macos/Classes/WebAuthenticationSession/WebAuthenticationSessionManager.swift similarity index 100% rename from macos/Classes/WebAuthenticationSession/WebAuthenticationSessionManager.swift rename to flutter_inappwebview_macos/macos/Classes/WebAuthenticationSession/WebAuthenticationSessionManager.swift diff --git a/macos/Classes/WebAuthenticationSession/WebAuthenticationSessionSettings.swift b/flutter_inappwebview_macos/macos/Classes/WebAuthenticationSession/WebAuthenticationSessionSettings.swift similarity index 100% rename from macos/Classes/WebAuthenticationSession/WebAuthenticationSessionSettings.swift rename to flutter_inappwebview_macos/macos/Classes/WebAuthenticationSession/WebAuthenticationSessionSettings.swift diff --git a/macos/flutter_inappwebview.podspec b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos.podspec similarity index 85% rename from macos/flutter_inappwebview.podspec rename to flutter_inappwebview_macos/macos/flutter_inappwebview_macos.podspec index 97601f6f..3f43bea6 100644 --- a/macos/flutter_inappwebview.podspec +++ b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos.podspec @@ -1,9 +1,9 @@ # # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html. -# Run `pod lib lint flutter_inappwebview.podspec` to validate before publishing. +# Run `pod lib lint flutter_inappwebview_macos.podspec` to validate before publishing. # Pod::Spec.new do |s| - s.name = 'flutter_inappwebview' + s.name = 'flutter_inappwebview_macos' s.version = '0.0.1' s.summary = 'A new Flutter plugin project.' s.description = <<-DESC diff --git a/flutter_inappwebview_macos/pubspec.yaml b/flutter_inappwebview_macos/pubspec.yaml new file mode 100644 index 00000000..330028b2 --- /dev/null +++ b/flutter_inappwebview_macos/pubspec.yaml @@ -0,0 +1,81 @@ +name: flutter_inappwebview_macos +description: macOS implementation of the flutter_inappwebview plugin. +version: 1.0.0 +homepage: https://inappwebview.dev/ +repository: https://github.com/pichillilorenzo/flutter_inappwebview/tree/master/flutter_inappwebview_macos +issue_tracker: https://github.com/pichillilorenzo/flutter_inappwebview/issues +topics: + - html + - webview + - webview-flutter + - inappwebview + - browser + +environment: + sdk: ">=2.17.0 <4.0.0" + flutter: ">=3.0.0" + +dependencies: + flutter: + sdk: flutter + flutter_inappwebview_platform_interface: + path: ../flutter_inappwebview_platform_interface + +dev_dependencies: + flutter_test: + sdk: flutter + flutter_lints: ^2.0.0 + plugin_platform_interface: ^2.0.2 + +# For information on the generic Dart part of this file, see the +# following page: https://dart.dev/tools/pub/pubspec + +# The following section is specific to Flutter packages. +flutter: + # This section identifies this Flutter project as a plugin project. + # The 'pluginClass' specifies the class (in Java, Kotlin, Swift, Objective-C, etc.) + # which should be registered in the plugin registry. This is required for + # using method channels. + # The Android 'package' specifies package in which the registered class is. + # This is required for using method channels on Android. + # The 'ffiPlugin' specifies that native code should be built and bundled. + # This is required for using `dart:ffi`. + # All these are used by the tooling to maintain consistency when + # adding or updating assets for this project. + plugin: + implements: flutter_inappwebview + platforms: + macos: + pluginClass: InAppWebViewFlutterPlugin + dartPluginClass: MacOSInAppWebViewPlatform + + # To add assets to your plugin package, add an assets section, like this: + # assets: + # - images/a_dot_burr.jpeg + # - images/a_dot_ham.jpeg + # + # For details regarding assets in packages, see + # https://flutter.dev/assets-and-images/#from-packages + # + # An image asset can refer to one or more resolution-specific "variants", see + # https://flutter.dev/assets-and-images/#resolution-aware + + # To add custom fonts to your plugin package, add a fonts section here, + # in this "flutter" section. Each entry in this list should have a + # "family" key with the font family name, and a "fonts" key with a + # list giving the asset and other descriptors for the font. For + # example: + # fonts: + # - family: Schyler + # fonts: + # - asset: fonts/Schyler-Regular.ttf + # - asset: fonts/Schyler-Italic.ttf + # style: italic + # - family: Trajan Pro + # fonts: + # - asset: fonts/TrajanPro.ttf + # - asset: fonts/TrajanPro_Bold.ttf + # weight: 700 + # + # For details regarding fonts in packages, see + # https://flutter.dev/custom-fonts/#from-packages diff --git a/flutter_inappwebview_macos/test/flutter_inappwebview_macos_test.dart b/flutter_inappwebview_macos/test/flutter_inappwebview_macos_test.dart new file mode 100644 index 00000000..e69de29b diff --git a/flutter_inappwebview_platform_interface/build.yaml b/flutter_inappwebview_platform_interface/build.yaml new file mode 100644 index 00000000..e2b3acf3 --- /dev/null +++ b/flutter_inappwebview_platform_interface/build.yaml @@ -0,0 +1,5 @@ +targets: + $default: + sources: + exclude: + - example/**.dart diff --git a/flutter_inappwebview_platform_interface/lib/src/web_authentication_session/platform_web_authenticate_session.dart b/flutter_inappwebview_platform_interface/lib/src/web_authentication_session/platform_web_authenticate_session.dart index 4e3c9155..3bb6f3c1 100755 --- a/flutter_inappwebview_platform_interface/lib/src/web_authentication_session/platform_web_authenticate_session.dart +++ b/flutter_inappwebview_platform_interface/lib/src/web_authentication_session/platform_web_authenticate_session.dart @@ -154,6 +154,7 @@ abstract class PlatformWebAuthenticationSession extends PlatformInterface /// ///**Officially Supported Platforms/Implementations**: ///- iOS ([Official API - ASWebAuthenticationSession.canStart](https://developer.apple.com/documentation/authenticationservices/aswebauthenticationsession/3516277-canstart)) + ///- MacOS ([Official API - ASWebAuthenticationSession.canStart](https://developer.apple.com/documentation/authenticationservices/aswebauthenticationsession/3516277-canstart)) ///{@endtemplate} Future canStart() { throw UnimplementedError( @@ -170,6 +171,7 @@ abstract class PlatformWebAuthenticationSession extends PlatformInterface /// ///**Officially Supported Platforms/Implementations**: ///- iOS ([Official API - ASWebAuthenticationSession.start](https://developer.apple.com/documentation/authenticationservices/aswebauthenticationsession/2990953-start)) + ///- MacOS ([Official API - ASWebAuthenticationSession.start](https://developer.apple.com/documentation/authenticationservices/aswebauthenticationsession/2990953-start)) ///{@endtemplate} Future start() { throw UnimplementedError( @@ -184,6 +186,7 @@ abstract class PlatformWebAuthenticationSession extends PlatformInterface /// ///**Officially Supported Platforms/Implementations**: ///- iOS ([Official API - ASWebAuthenticationSession.cancel](https://developer.apple.com/documentation/authenticationservices/aswebauthenticationsession/2990951-cancel)) + ///- MacOS ([Official API - ASWebAuthenticationSession.cancel](https://developer.apple.com/documentation/authenticationservices/aswebauthenticationsession/2990951-cancel)) ///{@endtemplate} Future cancel() { throw UnimplementedError( @@ -195,6 +198,7 @@ abstract class PlatformWebAuthenticationSession extends PlatformInterface /// ///**Officially Supported Platforms/Implementations**: ///- iOS + ///- MacOS ///{@endtemplate} @override Future dispose() { @@ -209,6 +213,7 @@ abstract class PlatformWebAuthenticationSession extends PlatformInterface /// ///**Officially Supported Platforms/Implementations**: ///- iOS + ///- MacOS ///{@endtemplate} Future isAvailable() { throw UnimplementedError( diff --git a/pubspec.yaml b/pubspec.yaml index 248f9307..e97a456e 100755 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -27,6 +27,8 @@ dependencies: path: flutter_inappwebview_android flutter_inappwebview_ios: path: flutter_inappwebview_ios + flutter_inappwebview_macos: + path: flutter_inappwebview_macos dev_dependencies: flutter_test: @@ -50,7 +52,7 @@ flutter: ios: default_package: flutter_inappwebview_ios macos: - pluginClass: InAppWebViewFlutterPlugin + default_package: flutter_inappwebview_macos web: pluginClass: FlutterInAppWebViewWebPlatform fileName: flutter_inappwebview.dart