added initial web support
This commit is contained in:
parent
3ef7d1949d
commit
176d41d328
|
@ -0,0 +1,10 @@
|
||||||
|
# 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: c860cba910319332564e1e9d470a17074c1f2dfd
|
||||||
|
channel: stable
|
||||||
|
|
||||||
|
project_type: plugin
|
|
@ -1,6 +1,7 @@
|
||||||
## 6.0.0
|
## 6.0.0
|
||||||
|
|
||||||
- Deprecated old classes/properties/methods to make them eventually compatible with other operating systems and WebView engines.
|
- Deprecated old classes/properties/methods to make them eventually compatible with other operating systems and WebView engines.
|
||||||
|
- Added Web support
|
||||||
- Added `pauseAllMediaPlayback`, `setAllMediaPlaybackSuspended`, `closeAllMediaPresentations`, `requestMediaPlaybackState` WebView controller methods
|
- Added `pauseAllMediaPlayback`, `setAllMediaPlaybackSuspended`, `closeAllMediaPresentations`, `requestMediaPlaybackState` WebView controller methods
|
||||||
- Added `underPageBackgroundColor`, `isTextInteractionEnabled`, `isSiteSpecificQuirksModeEnabled`, `upgradeKnownHostsToHTTPS` WebView settings
|
- Added `underPageBackgroundColor`, `isTextInteractionEnabled`, `isSiteSpecificQuirksModeEnabled`, `upgradeKnownHostsToHTTPS` WebView settings
|
||||||
- Added support for `onPermissionRequest` event on iOS 15.0+
|
- Added support for `onPermissionRequest` event on iOS 15.0+
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
include: package:flutter_lints/flutter.yaml
|
||||||
|
|
||||||
|
# Additional information about this file can be found at
|
||||||
|
# https://dart.dev/guides/language/analysis-options
|
|
@ -0,0 +1,29 @@
|
||||||
|
# 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-lang.github.io/linter/lints/index.html.
|
||||||
|
#
|
||||||
|
# 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
|
|
@ -0,0 +1,13 @@
|
||||||
|
gradle-wrapper.jar
|
||||||
|
/.gradle
|
||||||
|
/captures/
|
||||||
|
/gradlew
|
||||||
|
/gradlew.bat
|
||||||
|
/local.properties
|
||||||
|
GeneratedPluginRegistrant.java
|
||||||
|
|
||||||
|
# Remember to never publicly share your keystore.
|
||||||
|
# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
|
||||||
|
key.properties
|
||||||
|
**/*.keystore
|
||||||
|
**/*.jks
|
|
@ -0,0 +1,7 @@
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
package="com.pichillilorenzo.flutterwebviewexample">
|
||||||
|
<!-- Flutter needs it to communicate with the running application
|
||||||
|
to allow setting breakpoints, to provide hot reload, etc.
|
||||||
|
-->
|
||||||
|
<uses-permission android:name="android.permission.INTERNET"/>
|
||||||
|
</manifest>
|
|
@ -0,0 +1,12 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Modify this file to customize your launch splash screen -->
|
||||||
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item android:drawable="?android:colorBackground" />
|
||||||
|
|
||||||
|
<!-- You can insert your own image assets here -->
|
||||||
|
<!-- <item>
|
||||||
|
<bitmap
|
||||||
|
android:gravity="center"
|
||||||
|
android:src="@mipmap/launch_image" />
|
||||||
|
</item> -->
|
||||||
|
</layer-list>
|
|
@ -0,0 +1,18 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->
|
||||||
|
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||||
|
<!-- Show a splash screen on the activity. Automatically removed when
|
||||||
|
Flutter draws its first frame -->
|
||||||
|
<item name="android:windowBackground">@drawable/launch_background</item>
|
||||||
|
</style>
|
||||||
|
<!-- Theme applied to the Android Window as soon as the process has started.
|
||||||
|
This theme determines the color of the Android Window while your
|
||||||
|
Flutter UI initializes, as well as behind your Flutter UI while its
|
||||||
|
running.
|
||||||
|
|
||||||
|
This Theme is only used starting with V2 of Flutter's Android embedding. -->
|
||||||
|
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||||
|
<item name="android:windowBackground">?android:colorBackground</item>
|
||||||
|
</style>
|
||||||
|
</resources>
|
|
@ -0,0 +1,7 @@
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
package="com.pichillilorenzo.flutterwebviewexample">
|
||||||
|
<!-- Flutter needs it to communicate with the running application
|
||||||
|
to allow setting breakpoints, to provide hot reload, etc.
|
||||||
|
-->
|
||||||
|
<uses-permission android:name="android.permission.INTERNET"/>
|
||||||
|
</manifest>
|
|
@ -0,0 +1,34 @@
|
||||||
|
**/dgph
|
||||||
|
*.mode1v3
|
||||||
|
*.mode2v3
|
||||||
|
*.moved-aside
|
||||||
|
*.pbxuser
|
||||||
|
*.perspectivev3
|
||||||
|
**/*sync/
|
||||||
|
.sconsign.dblite
|
||||||
|
.tags*
|
||||||
|
**/.vagrant/
|
||||||
|
**/DerivedData/
|
||||||
|
Icon?
|
||||||
|
**/Pods/
|
||||||
|
**/.symlinks/
|
||||||
|
profile
|
||||||
|
xcuserdata
|
||||||
|
**/.generated/
|
||||||
|
Flutter/App.framework
|
||||||
|
Flutter/Flutter.framework
|
||||||
|
Flutter/Flutter.podspec
|
||||||
|
Flutter/Generated.xcconfig
|
||||||
|
Flutter/ephemeral/
|
||||||
|
Flutter/app.flx
|
||||||
|
Flutter/app.zip
|
||||||
|
Flutter/flutter_assets/
|
||||||
|
Flutter/flutter_export_environment.sh
|
||||||
|
ServiceDefinitions.json
|
||||||
|
Runner/GeneratedPluginRegistrant.*
|
||||||
|
|
||||||
|
# Exceptions to above rules.
|
||||||
|
!default.mode1v3
|
||||||
|
!default.mode2v3
|
||||||
|
!default.pbxuser
|
||||||
|
!default.perspectivev3
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>IDEDidComputeMac32BitWarning</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>PreviewsEnabled</key>
|
||||||
|
<false/>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>PreviewsEnabled</key>
|
||||||
|
<false/>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
|
@ -0,0 +1,18 @@
|
||||||
|
//
|
||||||
|
// Generated file. Do not edit.
|
||||||
|
//
|
||||||
|
|
||||||
|
// ignore_for_file: directives_ordering
|
||||||
|
// ignore_for_file: lines_longer_than_80_chars
|
||||||
|
|
||||||
|
import 'package:flutter_inappwebview/flutter_inappwebview_web.dart';
|
||||||
|
import 'package:url_launcher_web/url_launcher_web.dart';
|
||||||
|
|
||||||
|
import 'package:flutter_web_plugins/flutter_web_plugins.dart';
|
||||||
|
|
||||||
|
// ignore: public_member_api_docs
|
||||||
|
void registerPlugins(Registrar registrar) {
|
||||||
|
FlutterInAppWebViewWebPlatform.registerWith(registrar);
|
||||||
|
UrlLauncherPlugin.registerWith(registrar);
|
||||||
|
registrar.registerMessageHandler();
|
||||||
|
}
|
|
@ -3,6 +3,7 @@ import 'dart:collection';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
// import 'dart:typed_data';
|
// import 'dart:typed_data';
|
||||||
|
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
|
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
|
||||||
// import 'package:path_provider/path_provider.dart';
|
// import 'package:path_provider/path_provider.dart';
|
||||||
|
@ -28,7 +29,7 @@ class _InAppWebViewExampleScreenState extends State<InAppWebViewExampleScreen> {
|
||||||
allowsInlineMediaPlayback: true
|
allowsInlineMediaPlayback: true
|
||||||
);
|
);
|
||||||
|
|
||||||
late PullToRefreshController pullToRefreshController;
|
PullToRefreshController? pullToRefreshController;
|
||||||
late ContextMenu contextMenu;
|
late ContextMenu contextMenu;
|
||||||
String url = "";
|
String url = "";
|
||||||
double progress = 0;
|
double progress = 0;
|
||||||
|
@ -69,7 +70,7 @@ class _InAppWebViewExampleScreenState extends State<InAppWebViewExampleScreen> {
|
||||||
contextMenuItemClicked.title);
|
contextMenuItemClicked.title);
|
||||||
});
|
});
|
||||||
|
|
||||||
pullToRefreshController = PullToRefreshController(
|
pullToRefreshController = !kIsWeb ? PullToRefreshController(
|
||||||
settings: PullToRefreshSettings(
|
settings: PullToRefreshSettings(
|
||||||
color: Colors.blue,
|
color: Colors.blue,
|
||||||
),
|
),
|
||||||
|
@ -81,7 +82,7 @@ class _InAppWebViewExampleScreenState extends State<InAppWebViewExampleScreen> {
|
||||||
urlRequest: URLRequest(url: await webViewController?.getUrl()));
|
urlRequest: URLRequest(url: await webViewController?.getUrl()));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -118,7 +119,7 @@ class _InAppWebViewExampleScreenState extends State<InAppWebViewExampleScreen> {
|
||||||
key: webViewKey,
|
key: webViewKey,
|
||||||
// contextMenu: contextMenu,
|
// contextMenu: contextMenu,
|
||||||
initialUrlRequest:
|
initialUrlRequest:
|
||||||
URLRequest(url: Uri.parse("http://github.com/flutter/")),
|
URLRequest(url: Uri.parse("http://flutter.dev/")),
|
||||||
// initialFile: "assets/index.html",
|
// initialFile: "assets/index.html",
|
||||||
initialUserScripts: UnmodifiableListView<UserScript>([]),
|
initialUserScripts: UnmodifiableListView<UserScript>([]),
|
||||||
initialSettings: settings,
|
initialSettings: settings,
|
||||||
|
@ -162,18 +163,18 @@ class _InAppWebViewExampleScreenState extends State<InAppWebViewExampleScreen> {
|
||||||
return NavigationActionPolicy.ALLOW;
|
return NavigationActionPolicy.ALLOW;
|
||||||
},
|
},
|
||||||
onLoadStop: (controller, url) async {
|
onLoadStop: (controller, url) async {
|
||||||
pullToRefreshController.endRefreshing();
|
pullToRefreshController?.endRefreshing();
|
||||||
setState(() {
|
setState(() {
|
||||||
this.url = url.toString();
|
this.url = url.toString();
|
||||||
urlController.text = this.url;
|
urlController.text = this.url;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
onLoadError: (controller, url, code, message) {
|
onLoadError: (controller, url, code, message) {
|
||||||
pullToRefreshController.endRefreshing();
|
pullToRefreshController?.endRefreshing();
|
||||||
},
|
},
|
||||||
onProgressChanged: (controller, progress) {
|
onProgressChanged: (controller, progress) {
|
||||||
if (progress == 100) {
|
if (progress == 100) {
|
||||||
pullToRefreshController.endRefreshing();
|
pullToRefreshController?.endRefreshing();
|
||||||
}
|
}
|
||||||
setState(() {
|
setState(() {
|
||||||
this.progress = progress / 100;
|
this.progress = progress / 100;
|
||||||
|
@ -190,7 +191,7 @@ class _InAppWebViewExampleScreenState extends State<InAppWebViewExampleScreen> {
|
||||||
print(consoleMessage);
|
print(consoleMessage);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
progress < 1.0
|
!kIsWeb && progress < 1.0
|
||||||
? LinearProgressIndicator(value: progress)
|
? LinearProgressIndicator(value: progress)
|
||||||
: Container(),
|
: Container(),
|
||||||
],
|
],
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:io';
|
|
||||||
|
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
|
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ Future main() async {
|
||||||
// await Permission.microphone.request();
|
// await Permission.microphone.request();
|
||||||
// await Permission.storage.request();
|
// await Permission.storage.request();
|
||||||
|
|
||||||
if (Platform.isAndroid) {
|
if (defaultTargetPlatform == TargetPlatform.android) {
|
||||||
await InAppWebViewController.setWebContentsDebuggingEnabled(true);
|
await InAppWebViewController.setWebContentsDebuggingEnabled(true);
|
||||||
|
|
||||||
var swAvailable = await WebViewFeature.isFeatureSupported(
|
var swAvailable = await WebViewFeature.isFeatureSupported(
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 917 B |
Binary file not shown.
After Width: | Height: | Size: 5.2 KiB |
Binary file not shown.
After Width: | Height: | Size: 8.1 KiB |
Binary file not shown.
After Width: | Height: | Size: 5.5 KiB |
Binary file not shown.
After Width: | Height: | Size: 20 KiB |
|
@ -0,0 +1,104 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<!--
|
||||||
|
If you are serving your web app in a path other than the root, change the
|
||||||
|
href value below to reflect the base path you are serving from.
|
||||||
|
|
||||||
|
The path provided below has to start and end with a slash "/" in order for
|
||||||
|
it to work correctly.
|
||||||
|
|
||||||
|
For more details:
|
||||||
|
* https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base
|
||||||
|
|
||||||
|
This is a placeholder for base href that will be replaced by the value of
|
||||||
|
the `--base-href` argument provided to `flutter build`.
|
||||||
|
-->
|
||||||
|
<base href="$FLUTTER_BASE_HREF">
|
||||||
|
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta content="IE=Edge" http-equiv="X-UA-Compatible">
|
||||||
|
<meta name="description" content="Demonstrates how to use the flutter_inappwebview plugin.">
|
||||||
|
|
||||||
|
<!-- iOS meta tags & icons -->
|
||||||
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||||
|
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
||||||
|
<meta name="apple-mobile-web-app-title" content="flutter_inappwebview_example">
|
||||||
|
<link rel="apple-touch-icon" href="icons/Icon-192.png">
|
||||||
|
|
||||||
|
<!-- Favicon -->
|
||||||
|
<link rel="icon" type="image/png" href="favicon.png"/>
|
||||||
|
|
||||||
|
<title>flutter_inappwebview_example</title>
|
||||||
|
<link rel="manifest" href="manifest.json">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<!-- This script installs service_worker.js to provide PWA functionality to
|
||||||
|
application. For more information, see:
|
||||||
|
https://developers.google.com/web/fundamentals/primers/service-workers -->
|
||||||
|
<script>
|
||||||
|
var serviceWorkerVersion = null;
|
||||||
|
var scriptLoaded = false;
|
||||||
|
function loadMainDartJs() {
|
||||||
|
if (scriptLoaded) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
scriptLoaded = true;
|
||||||
|
var scriptTag = document.createElement('script');
|
||||||
|
scriptTag.src = 'main.dart.js';
|
||||||
|
scriptTag.type = 'application/javascript';
|
||||||
|
document.body.append(scriptTag);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('serviceWorker' in navigator) {
|
||||||
|
// Service workers are supported. Use them.
|
||||||
|
window.addEventListener('load', function () {
|
||||||
|
// Wait for registration to finish before dropping the <script> tag.
|
||||||
|
// Otherwise, the browser will load the script multiple times,
|
||||||
|
// potentially different versions.
|
||||||
|
var serviceWorkerUrl = 'flutter_service_worker.js?v=' + serviceWorkerVersion;
|
||||||
|
navigator.serviceWorker.register(serviceWorkerUrl)
|
||||||
|
.then((reg) => {
|
||||||
|
function waitForActivation(serviceWorker) {
|
||||||
|
serviceWorker.addEventListener('statechange', () => {
|
||||||
|
if (serviceWorker.state == 'activated') {
|
||||||
|
console.log('Installed new service worker.');
|
||||||
|
loadMainDartJs();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (!reg.active && (reg.installing || reg.waiting)) {
|
||||||
|
// No active web worker and we have installed or are installing
|
||||||
|
// one for the first time. Simply wait for it to activate.
|
||||||
|
waitForActivation(reg.installing || reg.waiting);
|
||||||
|
} else if (!reg.active.scriptURL.endsWith(serviceWorkerVersion)) {
|
||||||
|
// When the app updates the serviceWorkerVersion changes, so we
|
||||||
|
// need to ask the service worker to update.
|
||||||
|
console.log('New service worker available.');
|
||||||
|
reg.update();
|
||||||
|
waitForActivation(reg.installing);
|
||||||
|
} else {
|
||||||
|
// Existing service worker is still good.
|
||||||
|
console.log('Loading app from service worker.');
|
||||||
|
loadMainDartJs();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// If service worker doesn't succeed in a reasonable amount of time,
|
||||||
|
// fallback to plaint <script> tag.
|
||||||
|
setTimeout(() => {
|
||||||
|
if (!scriptLoaded) {
|
||||||
|
console.warn(
|
||||||
|
'Failed to load app from service worker. Falling back to plain <script> tag.',
|
||||||
|
);
|
||||||
|
loadMainDartJs();
|
||||||
|
}
|
||||||
|
}, 4000);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Service workers not supported. Just drop the <script> tag.
|
||||||
|
loadMainDartJs();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,35 @@
|
||||||
|
{
|
||||||
|
"name": "flutter_inappwebview_example",
|
||||||
|
"short_name": "flutter_inappwebview_example",
|
||||||
|
"start_url": ".",
|
||||||
|
"display": "standalone",
|
||||||
|
"background_color": "#0175C2",
|
||||||
|
"theme_color": "#0175C2",
|
||||||
|
"description": "Demonstrates how to use the flutter_inappwebview plugin.",
|
||||||
|
"orientation": "portrait-primary",
|
||||||
|
"prefer_related_applications": false,
|
||||||
|
"icons": [
|
||||||
|
{
|
||||||
|
"src": "icons/Icon-192.png",
|
||||||
|
"sizes": "192x192",
|
||||||
|
"type": "image/png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "icons/Icon-512.png",
|
||||||
|
"sizes": "512x512",
|
||||||
|
"type": "image/png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "icons/Icon-maskable-192.png",
|
||||||
|
"sizes": "192x192",
|
||||||
|
"type": "image/png",
|
||||||
|
"purpose": "maskable"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "icons/Icon-maskable-512.png",
|
||||||
|
"sizes": "512x512",
|
||||||
|
"type": "image/png",
|
||||||
|
"purpose": "maskable"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
library flutter_inappwebview;
|
||||||
|
|
||||||
|
export 'src/main.dart';
|
||||||
|
export 'src/web/main.dart';
|
|
@ -1,4 +1,3 @@
|
||||||
import 'dart:io';
|
|
||||||
import 'dart:ui';
|
import 'dart:ui';
|
||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
|
@ -227,7 +226,7 @@ class ChromeSafariBrowserSettings implements ChromeSafariBrowserOptions {
|
||||||
|
|
||||||
static ChromeSafariBrowserSettings fromMap(Map<String, dynamic> map) {
|
static ChromeSafariBrowserSettings fromMap(Map<String, dynamic> map) {
|
||||||
ChromeSafariBrowserSettings settings = new ChromeSafariBrowserSettings();
|
ChromeSafariBrowserSettings settings = new ChromeSafariBrowserSettings();
|
||||||
if (Platform.isAndroid) {
|
if (defaultTargetPlatform == TargetPlatform.android) {
|
||||||
settings.shareState = map["shareState"];
|
settings.shareState = map["shareState"];
|
||||||
settings.showTitle = map["showTitle"];
|
settings.showTitle = map["showTitle"];
|
||||||
settings.toolbarBackgroundColor =
|
settings.toolbarBackgroundColor =
|
||||||
|
@ -252,7 +251,7 @@ class ChromeSafariBrowserSettings implements ChromeSafariBrowserOptions {
|
||||||
}
|
}
|
||||||
settings.screenOrientation = map["screenOrientation"];
|
settings.screenOrientation = map["screenOrientation"];
|
||||||
}
|
}
|
||||||
if (Platform.isIOS || Platform.isMacOS) {
|
if (defaultTargetPlatform == TargetPlatform.iOS || defaultTargetPlatform == TargetPlatform.macOS) {
|
||||||
settings.entersReaderIfAvailable = map["entersReaderIfAvailable"];
|
settings.entersReaderIfAvailable = map["entersReaderIfAvailable"];
|
||||||
settings.barCollapsingEnabled = map["barCollapsingEnabled"];
|
settings.barCollapsingEnabled = map["barCollapsingEnabled"];
|
||||||
settings.dismissButtonStyle =
|
settings.dismissButtonStyle =
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import 'dart:io';
|
|
||||||
import 'dart:ui';
|
import 'dart:ui';
|
||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
|
@ -281,7 +280,7 @@ class InAppBrowserSettings
|
||||||
UtilColor.fromHex(map["toolbarTopBackgroundColor"]);
|
UtilColor.fromHex(map["toolbarTopBackgroundColor"]);
|
||||||
settings.hideUrlBar = map["hideUrlBar"];
|
settings.hideUrlBar = map["hideUrlBar"];
|
||||||
settings.hideProgressBar = map["hideProgressBar"];
|
settings.hideProgressBar = map["hideProgressBar"];
|
||||||
if (Platform.isAndroid) {
|
if (defaultTargetPlatform == TargetPlatform.android) {
|
||||||
settings.hideTitleBar = map["hideTitleBar"];
|
settings.hideTitleBar = map["hideTitleBar"];
|
||||||
settings.toolbarTopFixedTitle = map["toolbarTopFixedTitle"];
|
settings.toolbarTopFixedTitle = map["toolbarTopFixedTitle"];
|
||||||
settings.closeOnCannotGoBack = map["closeOnCannotGoBack"];
|
settings.closeOnCannotGoBack = map["closeOnCannotGoBack"];
|
||||||
|
@ -289,7 +288,7 @@ class InAppBrowserSettings
|
||||||
settings.shouldCloseOnBackButtonPressed =
|
settings.shouldCloseOnBackButtonPressed =
|
||||||
map["shouldCloseOnBackButtonPressed"];
|
map["shouldCloseOnBackButtonPressed"];
|
||||||
}
|
}
|
||||||
if (Platform.isIOS || Platform.isMacOS) {
|
if (defaultTargetPlatform == TargetPlatform.iOS || defaultTargetPlatform == TargetPlatform.macOS) {
|
||||||
settings.toolbarTopTranslucent = map["toolbarTopTranslucent"];
|
settings.toolbarTopTranslucent = map["toolbarTopTranslucent"];
|
||||||
settings.toolbarTopTintColor =
|
settings.toolbarTopTintColor =
|
||||||
UtilColor.fromHex(map["toolbarTopTintColor"]);
|
UtilColor.fromHex(map["toolbarTopTintColor"]);
|
||||||
|
|
|
@ -9,6 +9,8 @@ import 'package:flutter/services.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
import 'package:flutter/gestures.dart';
|
import 'package:flutter/gestures.dart';
|
||||||
|
|
||||||
|
import '../web/web_platform_manager.dart';
|
||||||
|
|
||||||
import '../context_menu.dart';
|
import '../context_menu.dart';
|
||||||
import '../types.dart';
|
import '../types.dart';
|
||||||
|
|
||||||
|
@ -29,6 +31,7 @@ class InAppWebView extends StatefulWidget implements WebView {
|
||||||
final Set<Factory<OneSequenceGestureRecognizer>>? gestureRecognizers;
|
final Set<Factory<OneSequenceGestureRecognizer>>? gestureRecognizers;
|
||||||
|
|
||||||
///The window id of a [CreateWindowAction.windowId].
|
///The window id of a [CreateWindowAction.windowId].
|
||||||
|
@override
|
||||||
final int? windowId;
|
final int? windowId;
|
||||||
|
|
||||||
const InAppWebView({
|
const InAppWebView({
|
||||||
|
@ -537,7 +540,21 @@ class _InAppWebViewState extends State<InAppWebView> {
|
||||||
widget.pullToRefreshController?.options.toMap() ??
|
widget.pullToRefreshController?.options.toMap() ??
|
||||||
PullToRefreshSettings(enabled: false).toMap();
|
PullToRefreshSettings(enabled: false).toMap();
|
||||||
|
|
||||||
if (defaultTargetPlatform == TargetPlatform.android) {
|
if (kIsWeb) {
|
||||||
|
return HtmlElementView(
|
||||||
|
viewType: 'com.pichillilorenzo/flutter_inappwebview',
|
||||||
|
onPlatformViewCreated: (int viewId) {
|
||||||
|
var webViewHtmlElement = WebPlatformManager.webViews[viewId]!;
|
||||||
|
webViewHtmlElement.initialSettings = widget.initialSettings;
|
||||||
|
webViewHtmlElement.initialUrlRequest = widget.initialUrlRequest;
|
||||||
|
webViewHtmlElement.initialFile = widget.initialFile;
|
||||||
|
webViewHtmlElement.initialData = widget.initialData;
|
||||||
|
webViewHtmlElement.prepare();
|
||||||
|
webViewHtmlElement.makeInitialLoad();
|
||||||
|
_onPlatformViewCreated(viewId);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
} else if (defaultTargetPlatform == TargetPlatform.android) {
|
||||||
var useHybridComposition = (widget.initialSettings != null
|
var useHybridComposition = (widget.initialSettings != null
|
||||||
? widget.initialSettings?.useHybridComposition
|
? widget.initialSettings?.useHybridComposition
|
||||||
:
|
:
|
||||||
|
@ -642,6 +659,10 @@ class _InAppWebViewState extends State<InAppWebView> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
|
int viewId = _controller.getViewId();
|
||||||
|
if (kIsWeb && WebPlatformManager.webViews.containsKey(viewId)) {
|
||||||
|
WebPlatformManager.webViews.remove(viewId);
|
||||||
|
}
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -75,8 +75,7 @@ class InAppWebViewController
|
||||||
|
|
||||||
InAppWebViewController(dynamic id, WebView webview) {
|
InAppWebViewController(dynamic id, WebView webview) {
|
||||||
this._id = id;
|
this._id = id;
|
||||||
this._channel =
|
this._channel = MethodChannel('com.pichillilorenzo/flutter_inappwebview_$id');
|
||||||
MethodChannel('com.pichillilorenzo/flutter_inappwebview_$id');
|
|
||||||
this._channel.setMethodCallHandler(handleMethod);
|
this._channel.setMethodCallHandler(handleMethod);
|
||||||
this._webview = webview;
|
this._webview = webview;
|
||||||
this._userScripts =
|
this._userScripts =
|
||||||
|
@ -2103,7 +2102,7 @@ class InAppWebViewController
|
||||||
}
|
}
|
||||||
|
|
||||||
///Gets the URL that was originally requested for the current page.
|
///Gets the URL that was originally requested for the current page.
|
||||||
///This is not always the same as the URL passed to [InAppWebView.onLoadStarted] because although the load for that URL has begun,
|
///This is not always the same as the URL passed to [InAppWebView.onLoadStart] because although the load for that URL has begun,
|
||||||
///the current page may not have changed. Also, there may have been redirects resulting in a different URL to that originally requested.
|
///the current page may not have changed. Also, there may have been redirects resulting in a different URL to that originally requested.
|
||||||
///
|
///
|
||||||
///**Supported Platforms/Implementations**:
|
///**Supported Platforms/Implementations**:
|
||||||
|
@ -2781,7 +2780,7 @@ class InAppWebViewController
|
||||||
/// // Flutter App
|
/// // Flutter App
|
||||||
/// child: InAppWebView(
|
/// child: InAppWebView(
|
||||||
/// onWebViewCreated: (controller) async {
|
/// onWebViewCreated: (controller) async {
|
||||||
/// if (!Platform.isAndroid || await WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_LISTENER)) {
|
/// if (defaultTargetPlatform != TargetPlatform.android || await WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_LISTENER)) {
|
||||||
/// await controller.addWebMessageListener(WebMessageListener(
|
/// await controller.addWebMessageListener(WebMessageListener(
|
||||||
/// jsObjectName: "myObject",
|
/// jsObjectName: "myObject",
|
||||||
/// onPostMessage: (message, sourceOrigin, isMainFrame, replyProxy) {
|
/// onPostMessage: (message, sourceOrigin, isMainFrame, replyProxy) {
|
||||||
|
@ -2834,6 +2833,15 @@ class InAppWebViewController
|
||||||
return await _channel.invokeMethod('canScrollHorizontally', args);
|
return await _channel.invokeMethod('canScrollHorizontally', args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///Returns the iframe `id` attribute used on the Web platform.
|
||||||
|
///
|
||||||
|
///**Supported Platforms/Implementations**:
|
||||||
|
///- Web
|
||||||
|
Future<String?> getIFrameId() async {
|
||||||
|
Map<String, dynamic> args = <String, dynamic>{};
|
||||||
|
return await _channel.invokeMethod('getIFrameId', args);
|
||||||
|
}
|
||||||
|
|
||||||
///Gets the default user agent.
|
///Gets the default user agent.
|
||||||
///
|
///
|
||||||
///**Supported Platforms/Implementations**:
|
///**Supported Platforms/Implementations**:
|
||||||
|
@ -2948,4 +2956,14 @@ class InAppWebViewController
|
||||||
args.putIfAbsent('urlScheme', () => urlScheme);
|
args.putIfAbsent('urlScheme', () => urlScheme);
|
||||||
return await _staticChannel.invokeMethod('handlesURLScheme', args);
|
return await _staticChannel.invokeMethod('handlesURLScheme', args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///Used internally.
|
||||||
|
MethodChannel getChannel() {
|
||||||
|
return _channel;
|
||||||
|
}
|
||||||
|
|
||||||
|
///Used internally.
|
||||||
|
int getViewId() {
|
||||||
|
return _id;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import 'dart:io';
|
|
||||||
import 'dart:ui';
|
import 'dart:ui';
|
||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
|
@ -996,6 +995,56 @@ class InAppWebViewSettings
|
||||||
///- iOS
|
///- iOS
|
||||||
bool upgradeKnownHostsToHTTPS;
|
bool upgradeKnownHostsToHTTPS;
|
||||||
|
|
||||||
|
///Specifies a feature policy for the iframe. A list of origins the frame is allowed to display content from.
|
||||||
|
///This attribute also accepts the values `self` and `src` which represent the origin in the iframe's src attribute.
|
||||||
|
///The default value is `src`.
|
||||||
|
///
|
||||||
|
///**Supported Platforms/Implementations**:
|
||||||
|
///- Web
|
||||||
|
String? iframeAllow;
|
||||||
|
|
||||||
|
///A boolean value indicating whether the inline frame is willing to be placed into full screen mode.
|
||||||
|
///
|
||||||
|
///**Supported Platforms/Implementations**:
|
||||||
|
///- Web
|
||||||
|
bool? iframeAllowFullscreen;
|
||||||
|
|
||||||
|
///A DOMTokenList that reflects the sandbox HTML attribute, indicating extra restrictions on the behavior of the nested content.
|
||||||
|
///
|
||||||
|
///**Supported Platforms/Implementations**:
|
||||||
|
///- Web
|
||||||
|
String? iframeSandox;
|
||||||
|
|
||||||
|
///A string that reflects the width HTML attribute, indicating the width of the frame.
|
||||||
|
///
|
||||||
|
///**Supported Platforms/Implementations**:
|
||||||
|
///- Web
|
||||||
|
String? iframeWidth;
|
||||||
|
|
||||||
|
///A string that reflects the height HTML attribute, indicating the height of the frame.
|
||||||
|
///
|
||||||
|
///**Supported Platforms/Implementations**:
|
||||||
|
///- Web
|
||||||
|
String? iframeHeight;
|
||||||
|
|
||||||
|
///A string that reflects the `referrerpolicy` HTML attribute indicating which referrer to use when fetching the linked resource.
|
||||||
|
///
|
||||||
|
///**Supported Platforms/Implementations**:
|
||||||
|
///- Web
|
||||||
|
String? iframeReferrerPolicy;
|
||||||
|
|
||||||
|
///A string that reflects the `name` HTML attribute, containing a name by which to refer to the frame.
|
||||||
|
///
|
||||||
|
///**Supported Platforms/Implementations**:
|
||||||
|
///- Web
|
||||||
|
String? iframeName;
|
||||||
|
|
||||||
|
///Specifies the Content Security Policy that an embedded document must agree to enforce upon itself.
|
||||||
|
///
|
||||||
|
///**Supported Platforms/Implementations**:
|
||||||
|
///- Web
|
||||||
|
String? iframeCsp;
|
||||||
|
|
||||||
InAppWebViewSettings(
|
InAppWebViewSettings(
|
||||||
{this.useShouldOverrideUrlLoading = false,
|
{this.useShouldOverrideUrlLoading = false,
|
||||||
this.useOnLoadResource = false,
|
this.useOnLoadResource = false,
|
||||||
|
@ -1115,7 +1164,15 @@ class InAppWebViewSettings
|
||||||
this.underPageBackgroundColor,
|
this.underPageBackgroundColor,
|
||||||
this.isTextInteractionEnabled = true,
|
this.isTextInteractionEnabled = true,
|
||||||
this.isSiteSpecificQuirksModeEnabled = true,
|
this.isSiteSpecificQuirksModeEnabled = true,
|
||||||
this.upgradeKnownHostsToHTTPS = true}) {
|
this.upgradeKnownHostsToHTTPS = true,
|
||||||
|
this.iframeAllow,
|
||||||
|
this.iframeAllowFullscreen,
|
||||||
|
this.iframeSandox,
|
||||||
|
this.iframeWidth,
|
||||||
|
this.iframeHeight,
|
||||||
|
this.iframeReferrerPolicy,
|
||||||
|
this.iframeName,
|
||||||
|
this.iframeCsp,}) {
|
||||||
if (this.minimumFontSize == null)
|
if (this.minimumFontSize == null)
|
||||||
this.minimumFontSize =
|
this.minimumFontSize =
|
||||||
defaultTargetPlatform == TargetPlatform.android ? 8 : 0;
|
defaultTargetPlatform == TargetPlatform.android ? 8 : 0;
|
||||||
|
@ -1257,7 +1314,15 @@ class InAppWebViewSettings
|
||||||
"underPageBackgroundColor": underPageBackgroundColor?.toHex(),
|
"underPageBackgroundColor": underPageBackgroundColor?.toHex(),
|
||||||
"isTextInteractionEnabled": isTextInteractionEnabled,
|
"isTextInteractionEnabled": isTextInteractionEnabled,
|
||||||
"isSiteSpecificQuirksModeEnabled": isSiteSpecificQuirksModeEnabled,
|
"isSiteSpecificQuirksModeEnabled": isSiteSpecificQuirksModeEnabled,
|
||||||
"upgradeKnownHostsToHTTPS": upgradeKnownHostsToHTTPS
|
"upgradeKnownHostsToHTTPS": upgradeKnownHostsToHTTPS,
|
||||||
|
"iframeAllow": iframeAllow,
|
||||||
|
"iframeAllowFullscreen": iframeAllowFullscreen,
|
||||||
|
"iframeSandox": iframeSandox,
|
||||||
|
"iframeWidth": iframeWidth,
|
||||||
|
"iframeHeight": iframeHeight,
|
||||||
|
"iframeReferrerPolicy": iframeReferrerPolicy,
|
||||||
|
"iframeName": iframeName,
|
||||||
|
"iframeCsp": iframeCsp,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1314,7 +1379,17 @@ class InAppWebViewSettings
|
||||||
settings.allowFileAccessFromFileURLs = map["allowFileAccessFromFileURLs"];
|
settings.allowFileAccessFromFileURLs = map["allowFileAccessFromFileURLs"];
|
||||||
settings.allowUniversalAccessFromFileURLs =
|
settings.allowUniversalAccessFromFileURLs =
|
||||||
map["allowUniversalAccessFromFileURLs"];
|
map["allowUniversalAccessFromFileURLs"];
|
||||||
if (Platform.isAndroid) {
|
if (kIsWeb) {
|
||||||
|
settings.iframeAllow = map["iframeAllow"];
|
||||||
|
settings.iframeAllowFullscreen = map["iframeAllowFullscreen"];
|
||||||
|
settings.iframeSandox = map["iframeSandox"];
|
||||||
|
settings.iframeWidth = map["iframeWidth"];
|
||||||
|
settings.iframeHeight = map["iframeHeight"];
|
||||||
|
settings.iframeReferrerPolicy = map["iframeReferrerPolicy"];
|
||||||
|
settings.iframeName = map["iframeName"];
|
||||||
|
settings.iframeCsp = map["iframeCsp"];
|
||||||
|
}
|
||||||
|
if (defaultTargetPlatform == TargetPlatform.android) {
|
||||||
settings.textZoom = map["textZoom"];
|
settings.textZoom = map["textZoom"];
|
||||||
settings.clearSessionCache = map["clearSessionCache"];
|
settings.clearSessionCache = map["clearSessionCache"];
|
||||||
settings.builtInZoomControls = map["builtInZoomControls"];
|
settings.builtInZoomControls = map["builtInZoomControls"];
|
||||||
|
@ -1382,7 +1457,7 @@ class InAppWebViewSettings
|
||||||
settings.horizontalScrollbarTrackColor =
|
settings.horizontalScrollbarTrackColor =
|
||||||
UtilColor.fromHex(map["horizontalScrollbarTrackColor"]);
|
UtilColor.fromHex(map["horizontalScrollbarTrackColor"]);
|
||||||
}
|
}
|
||||||
if (Platform.isIOS || Platform.isMacOS) {
|
if (defaultTargetPlatform == TargetPlatform.iOS || defaultTargetPlatform == TargetPlatform.macOS) {
|
||||||
settings.disallowOverScroll = map["disallowOverScroll"];
|
settings.disallowOverScroll = map["disallowOverScroll"];
|
||||||
settings.enableViewportScale = map["enableViewportScale"];
|
settings.enableViewportScale = map["enableViewportScale"];
|
||||||
settings.suppressesIncrementalRendering =
|
settings.suppressesIncrementalRendering =
|
||||||
|
|
|
@ -791,12 +791,27 @@ abstract class WebView {
|
||||||
///Initial url request that will be loaded.
|
///Initial url request that will be loaded.
|
||||||
///
|
///
|
||||||
///**NOTE for Android**: when loading an URL Request using "POST" method, headers are ignored.
|
///**NOTE for Android**: when loading an URL Request using "POST" method, headers are ignored.
|
||||||
|
///
|
||||||
|
///**Supported Platforms/Implementations**:
|
||||||
|
///- Android native WebView
|
||||||
|
///- iOS
|
||||||
|
///- Web
|
||||||
final URLRequest? initialUrlRequest;
|
final URLRequest? initialUrlRequest;
|
||||||
|
|
||||||
///Initial asset file that will be loaded. See [InAppWebViewController.loadFile] for explanation.
|
///Initial asset file that will be loaded. See [InAppWebViewController.loadFile] for explanation.
|
||||||
|
///
|
||||||
|
///**Supported Platforms/Implementations**:
|
||||||
|
///- Android native WebView
|
||||||
|
///- iOS
|
||||||
|
///- Web
|
||||||
final String? initialFile;
|
final String? initialFile;
|
||||||
|
|
||||||
///Initial [InAppWebViewInitialData] that will be loaded.
|
///Initial [InAppWebViewInitialData] that will be loaded.
|
||||||
|
///
|
||||||
|
///**Supported Platforms/Implementations**:
|
||||||
|
///- Android native WebView
|
||||||
|
///- iOS
|
||||||
|
///- Web
|
||||||
final InAppWebViewInitialData? initialData;
|
final InAppWebViewInitialData? initialData;
|
||||||
|
|
||||||
///Use [initialSettings] instead.
|
///Use [initialSettings] instead.
|
||||||
|
@ -804,9 +819,18 @@ abstract class WebView {
|
||||||
final InAppWebViewGroupOptions? initialOptions;
|
final InAppWebViewGroupOptions? initialOptions;
|
||||||
|
|
||||||
///Initial settings that will be used.
|
///Initial settings that will be used.
|
||||||
|
///
|
||||||
|
///**Supported Platforms/Implementations**:
|
||||||
|
///- Android native WebView
|
||||||
|
///- iOS
|
||||||
|
///- Web
|
||||||
final InAppWebViewSettings? initialSettings;
|
final InAppWebViewSettings? initialSettings;
|
||||||
|
|
||||||
///Context menu which contains custom menu items to be shown when [ContextMenu] is presented.
|
///Context menu which contains custom menu items to be shown when [ContextMenu] is presented.
|
||||||
|
///
|
||||||
|
///**Supported Platforms/Implementations**:
|
||||||
|
///- Android native WebView
|
||||||
|
///- iOS
|
||||||
final ContextMenu? contextMenu;
|
final ContextMenu? contextMenu;
|
||||||
|
|
||||||
///Initial list of user scripts to be loaded at start or end of a page loading.
|
///Initial list of user scripts to be loaded at start or end of a page loading.
|
||||||
|
@ -816,11 +840,19 @@ abstract class WebView {
|
||||||
///**NOTE for iOS**: this property will be ignored if the [WebView.windowId] has been set.
|
///**NOTE for iOS**: this property will be ignored if the [WebView.windowId] has been set.
|
||||||
///There isn't any way to add/remove user scripts specific to iOS window WebViews.
|
///There isn't any way to add/remove user scripts specific to iOS window WebViews.
|
||||||
///This is a limitation of the native iOS WebKit APIs.
|
///This is a limitation of the native iOS WebKit APIs.
|
||||||
|
///
|
||||||
|
///**Supported Platforms/Implementations**:
|
||||||
|
///- Android native WebView
|
||||||
|
///- iOS
|
||||||
final UnmodifiableListView<UserScript>? initialUserScripts;
|
final UnmodifiableListView<UserScript>? initialUserScripts;
|
||||||
|
|
||||||
///Represents the pull-to-refresh feature controller.
|
///Represents the pull-to-refresh feature controller.
|
||||||
///
|
///
|
||||||
///**NOTE for Android**: to be able to use the "pull-to-refresh" feature, [InAppWebViewSettings.useHybridComposition] must be `true`.
|
///**NOTE for Android**: to be able to use the "pull-to-refresh" feature, [InAppWebViewSettings.useHybridComposition] must be `true`.
|
||||||
|
///
|
||||||
|
///**Supported Platforms/Implementations**:
|
||||||
|
///- Android native WebView
|
||||||
|
///- iOS
|
||||||
final PullToRefreshController? pullToRefreshController;
|
final PullToRefreshController? pullToRefreshController;
|
||||||
|
|
||||||
///Represents the WebView native implementation to be used.
|
///Represents the WebView native implementation to be used.
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import 'dart:collection';
|
import 'dart:collection';
|
||||||
import 'dart:io';
|
|
||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:ui';
|
import 'dart:ui';
|
||||||
|
@ -4780,9 +4779,9 @@ class PermissionResourceType {
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
try {
|
try {
|
||||||
Set<PermissionResourceType> valueList = <PermissionResourceType>[].toSet();
|
Set<PermissionResourceType> valueList = <PermissionResourceType>[].toSet();
|
||||||
if (Platform.isAndroid) {
|
if (defaultTargetPlatform == TargetPlatform.android) {
|
||||||
valueList = PermissionResourceType._androidValues;
|
valueList = PermissionResourceType._androidValues;
|
||||||
} else if (Platform.isIOS || Platform.isMacOS) {
|
} else if (defaultTargetPlatform == TargetPlatform.iOS || defaultTargetPlatform == TargetPlatform.macOS) {
|
||||||
valueList = PermissionResourceType._appleValues;
|
valueList = PermissionResourceType._appleValues;
|
||||||
}
|
}
|
||||||
return valueList.firstWhere((element) => element.toValue() == value);
|
return valueList.firstWhere((element) => element.toValue() == value);
|
||||||
|
@ -7360,9 +7359,9 @@ class SslErrorType {
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
try {
|
try {
|
||||||
Set<SslErrorType> valueList = <SslErrorType>[].toSet();
|
Set<SslErrorType> valueList = <SslErrorType>[].toSet();
|
||||||
if (Platform.isAndroid) {
|
if (defaultTargetPlatform == TargetPlatform.android) {
|
||||||
valueList = SslErrorType._androidValues;
|
valueList = SslErrorType._androidValues;
|
||||||
} else if (Platform.isIOS || Platform.isMacOS) {
|
} else if (defaultTargetPlatform == TargetPlatform.iOS || defaultTargetPlatform == TargetPlatform.macOS) {
|
||||||
valueList = SslErrorType._appleValues;
|
valueList = SslErrorType._appleValues;
|
||||||
}
|
}
|
||||||
return valueList.firstWhere((element) => element.toValue() == value);
|
return valueList.firstWhere((element) => element.toValue() == value);
|
||||||
|
@ -7377,7 +7376,7 @@ class SslErrorType {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
if (Platform.isAndroid) {
|
if (defaultTargetPlatform == TargetPlatform.android) {
|
||||||
switch (_value) {
|
switch (_value) {
|
||||||
case 1:
|
case 1:
|
||||||
return "SSL_EXPIRED";
|
return "SSL_EXPIRED";
|
||||||
|
@ -7393,7 +7392,7 @@ class SslErrorType {
|
||||||
default:
|
default:
|
||||||
return "SSL_NOTYETVALID";
|
return "SSL_NOTYETVALID";
|
||||||
}
|
}
|
||||||
} else if (Platform.isIOS || Platform.isMacOS) {
|
} else if (defaultTargetPlatform == TargetPlatform.iOS || defaultTargetPlatform == TargetPlatform.macOS) {
|
||||||
switch (_value) {
|
switch (_value) {
|
||||||
case 3:
|
case 3:
|
||||||
return "DENY";
|
return "DENY";
|
||||||
|
|
|
@ -0,0 +1,148 @@
|
||||||
|
import 'dart:async';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'dart:html';
|
||||||
|
|
||||||
|
import '../in_app_webview/in_app_webview_settings.dart';
|
||||||
|
import '../types.dart';
|
||||||
|
|
||||||
|
class InAppWebViewWebElement {
|
||||||
|
late int _viewId;
|
||||||
|
late BinaryMessenger _messenger;
|
||||||
|
late IFrameElement iframe;
|
||||||
|
late MethodChannel _channel;
|
||||||
|
InAppWebViewSettings? initialSettings;
|
||||||
|
URLRequest? initialUrlRequest;
|
||||||
|
InAppWebViewInitialData? initialData;
|
||||||
|
String? initialFile;
|
||||||
|
|
||||||
|
late InAppWebViewSettings settings;
|
||||||
|
|
||||||
|
InAppWebViewWebElement({required int viewId, required BinaryMessenger messenger}) {
|
||||||
|
this._viewId = viewId;
|
||||||
|
this._messenger = messenger;
|
||||||
|
iframe = IFrameElement()
|
||||||
|
..id = 'flutter_inappwebview-$_viewId'
|
||||||
|
..style.border = 'none';
|
||||||
|
|
||||||
|
_channel = MethodChannel(
|
||||||
|
'com.pichillilorenzo/flutter_inappwebview_$_viewId',
|
||||||
|
const StandardMethodCodec(),
|
||||||
|
_messenger,
|
||||||
|
);
|
||||||
|
|
||||||
|
this._channel.setMethodCallHandler(handleMethodCall);
|
||||||
|
|
||||||
|
iframe.addEventListener('load', (event) async {
|
||||||
|
var obj = {
|
||||||
|
"url": iframe.src
|
||||||
|
};
|
||||||
|
_channel.invokeMethod("onLoadStart", obj);
|
||||||
|
await Future.delayed(Duration(milliseconds: 100));
|
||||||
|
_channel.invokeMethod("onLoadStop", obj);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Handles method calls over the MethodChannel of this plugin.
|
||||||
|
Future<dynamic> handleMethodCall(MethodCall call) async {
|
||||||
|
switch (call.method) {
|
||||||
|
case "loadUrl":
|
||||||
|
URLRequest urlRequest = URLRequest.fromMap(call.arguments["urlRequest"].cast<String, dynamic>())!;
|
||||||
|
await _loadUrl(urlRequest: urlRequest);
|
||||||
|
break;
|
||||||
|
case "loadData":
|
||||||
|
String data = call.arguments["data"];
|
||||||
|
String mimeType = call.arguments["mimeType"];
|
||||||
|
await _loadData(data: data, mimeType: mimeType);
|
||||||
|
break;
|
||||||
|
case "loadFile":
|
||||||
|
String assetFilePath = call.arguments["assetFilePath"];
|
||||||
|
await _loadFile(assetFilePath: assetFilePath);
|
||||||
|
break;
|
||||||
|
case "reload":
|
||||||
|
await _reload();
|
||||||
|
break;
|
||||||
|
case "getIFrameId":
|
||||||
|
return iframe.id;
|
||||||
|
default:
|
||||||
|
throw PlatformException(
|
||||||
|
code: 'Unimplemented',
|
||||||
|
details: 'flutter_inappwebview for web doesn\'t implement \'${call.method}\'',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void prepare() {
|
||||||
|
settings = initialSettings ?? InAppWebViewSettings();
|
||||||
|
iframe.allow = settings.iframeAllow ?? iframe.allow;
|
||||||
|
iframe.allowFullscreen = settings.iframeAllowFullscreen ?? iframe.allowFullscreen;
|
||||||
|
if (settings.iframeSandox != null) {
|
||||||
|
iframe.setAttribute("sandbox", settings.iframeSandox ?? "");
|
||||||
|
}
|
||||||
|
var width = settings.iframeWidth ?? iframe.width;
|
||||||
|
if (width == null || width.isEmpty) {
|
||||||
|
width = '100%';
|
||||||
|
}
|
||||||
|
var height = settings.iframeHeight ?? iframe.height;
|
||||||
|
if (height == null || height.isEmpty) {
|
||||||
|
height = '100%';
|
||||||
|
}
|
||||||
|
iframe.width = iframe.style.width = width;
|
||||||
|
iframe.height = iframe.style.height = height;
|
||||||
|
iframe.referrerPolicy = settings.iframeReferrerPolicy ?? iframe.referrerPolicy;
|
||||||
|
iframe.name = settings.iframeName ?? iframe.name;
|
||||||
|
iframe.csp = settings.iframeCsp ?? iframe.csp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void makeInitialLoad() async {
|
||||||
|
if (initialUrlRequest != null) {
|
||||||
|
_loadUrl(urlRequest: initialUrlRequest!);
|
||||||
|
} else if (initialData != null) {
|
||||||
|
_loadData(data: initialData!.data, mimeType: initialData!.mimeType);
|
||||||
|
} else if (initialFile != null) {
|
||||||
|
_loadFile(assetFilePath: initialFile!);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<HttpRequest> _makeRequest(URLRequest urlRequest, {bool? withCredentials, String? responseType, String? mimeType, void onProgress(ProgressEvent e)?}) {
|
||||||
|
return HttpRequest.request(
|
||||||
|
urlRequest.url?.toString() ?? 'about:blank',
|
||||||
|
method: urlRequest.method,
|
||||||
|
requestHeaders: urlRequest.headers,
|
||||||
|
sendData: urlRequest.body,
|
||||||
|
withCredentials: withCredentials,
|
||||||
|
responseType: responseType,
|
||||||
|
mimeType: mimeType,
|
||||||
|
onProgress: onProgress
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
String _convertHttpResponseToData(HttpRequest httpRequest) {
|
||||||
|
final String contentType =
|
||||||
|
httpRequest.getResponseHeader('content-type') ?? 'text/html';
|
||||||
|
return 'data:$contentType,' + Uri.encodeFull(httpRequest.responseText ?? '');
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _loadUrl({required URLRequest urlRequest}) async {
|
||||||
|
if ((urlRequest.method == null || urlRequest.method == "GET") &&
|
||||||
|
(urlRequest.headers == null || urlRequest.headers!.isEmpty)) {
|
||||||
|
iframe.src = urlRequest.url.toString();
|
||||||
|
} else {
|
||||||
|
iframe.src = _convertHttpResponseToData(await _makeRequest(urlRequest));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _loadData({required String data, String mimeType = "text/html"}) async {
|
||||||
|
iframe.src = 'data:$mimeType,' + Uri.encodeFull(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _loadFile({required String assetFilePath}) async {
|
||||||
|
iframe.src = assetFilePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _reload() async {
|
||||||
|
var src = iframe.src;
|
||||||
|
if (src != null) {
|
||||||
|
iframe.contentWindow?.location.href = src;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
export 'web_platform.dart';
|
|
@ -0,0 +1 @@
|
||||||
|
export 'dart_ui_fake.dart' if (dart.library.html) 'dart_ui_real.dart';
|
|
@ -0,0 +1,29 @@
|
||||||
|
import 'dart:html' as html;
|
||||||
|
|
||||||
|
// Fake interface for the logic that this package needs from (web-only) dart:ui.
|
||||||
|
// This is conditionally exported so the analyzer sees these methods as available.
|
||||||
|
|
||||||
|
// ignore_for_file: avoid_classes_with_only_static_members
|
||||||
|
// ignore_for_file: camel_case_types
|
||||||
|
|
||||||
|
/// Shim for web_ui engine.PlatformViewRegistry
|
||||||
|
/// https://github.com/flutter/engine/blob/master/lib/web_ui/lib/ui.dart#L62
|
||||||
|
class platformViewRegistry {
|
||||||
|
/// Shim for registerViewFactory
|
||||||
|
/// https://github.com/flutter/engine/blob/master/lib/web_ui/lib/ui.dart#L72
|
||||||
|
static bool registerViewFactory(
|
||||||
|
String viewTypeId, html.Element Function(int viewId) viewFactory) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Shim for web_ui engine.AssetManager.
|
||||||
|
/// https://github.com/flutter/engine/blob/master/lib/web_ui/lib/src/engine/assets.dart#L12
|
||||||
|
class webOnlyAssetManager {
|
||||||
|
/// Shim for getAssetUrl.
|
||||||
|
/// https://github.com/flutter/engine/blob/master/lib/web_ui/lib/src/engine/assets.dart#L45
|
||||||
|
static String getAssetUrl(String asset) => '';
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Signature of callbacks that have no arguments and return no data.
|
||||||
|
typedef VoidCallback = void Function();
|
|
@ -0,0 +1 @@
|
||||||
|
export 'dart:ui';
|
|
@ -0,0 +1,39 @@
|
||||||
|
import 'dart:async';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'web_platform_manager.dart';
|
||||||
|
import 'package:flutter_web_plugins/flutter_web_plugins.dart';
|
||||||
|
import 'shims/dart_ui.dart' as ui;
|
||||||
|
|
||||||
|
import 'in_app_web_view_web_element.dart';
|
||||||
|
|
||||||
|
/// Builds an iframe based WebView.
|
||||||
|
///
|
||||||
|
/// This is used as the default implementation for [WebView] on web.
|
||||||
|
class FlutterInAppWebViewWebPlatform {
|
||||||
|
|
||||||
|
/// Constructs a new instance of [FlutterInAppWebViewWebPlatform].
|
||||||
|
FlutterInAppWebViewWebPlatform(Registrar registrar) {
|
||||||
|
ui.platformViewRegistry.registerViewFactory(
|
||||||
|
'com.pichillilorenzo/flutter_inappwebview',
|
||||||
|
(int viewId) {
|
||||||
|
var webView = InAppWebViewWebElement(viewId: viewId, messenger: registrar);
|
||||||
|
WebPlatformManager.webViews.putIfAbsent(viewId, () => webView);
|
||||||
|
return webView.iframe;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static void registerWith(Registrar registrar) {
|
||||||
|
final pluginInstance = FlutterInAppWebViewWebPlatform(registrar);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Handles method calls over the MethodChannel of this plugin.
|
||||||
|
Future<dynamic> handleMethodCall(MethodCall call) async {
|
||||||
|
switch (call.method) {
|
||||||
|
default:
|
||||||
|
throw PlatformException(
|
||||||
|
code: 'Unimplemented',
|
||||||
|
details: 'flutter_inappwebview for web doesn\'t implement \'${call.method}\'',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
class WebPlatformManager {
|
||||||
|
static final Map<int, dynamic> webViews = {};
|
||||||
|
}
|
|
@ -14,6 +14,8 @@ dependencies:
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
|
flutter_web_plugins:
|
||||||
|
sdk: flutter
|
||||||
pedantic: ^1.11.1
|
pedantic: ^1.11.1
|
||||||
|
|
||||||
# For information on the generic Dart part of this file, see the
|
# For information on the generic Dart part of this file, see the
|
||||||
|
@ -28,6 +30,10 @@ flutter:
|
||||||
pluginClass: InAppWebViewFlutterPlugin
|
pluginClass: InAppWebViewFlutterPlugin
|
||||||
ios:
|
ios:
|
||||||
pluginClass: InAppWebViewFlutterPlugin
|
pluginClass: InAppWebViewFlutterPlugin
|
||||||
|
web:
|
||||||
|
pluginClass: FlutterInAppWebViewWebPlatform
|
||||||
|
fileName: flutter_inappwebview_web.dart
|
||||||
|
|
||||||
|
|
||||||
assets:
|
assets:
|
||||||
- packages/flutter_inappwebview/assets/t_rex_runner/t-rex.html
|
- packages/flutter_inappwebview/assets/t_rex_runner/t-rex.html
|
||||||
|
|
Loading…
Reference in New Issue