Commit 02c3de92 authored by Lorenzo Pichilli's avatar Lorenzo Pichilli

added HeadlessInAppWebView class, added close, addMenuItem and addMenuItems...

added HeadlessInAppWebView class, added close, addMenuItem and addMenuItems methods to ChromeSafariBrowser, added ChromeSafariBrowserMenuItem class, fixed InAppWebView.channel null exception on android, fix #305, fix #245, fix #299
parent f9ed06cc
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<option name="OTHER_INDENT_OPTIONS">
<value>
<option name="INDENT_SIZE" value="2" />
<option name="TAB_SIZE" value="2" />
</value>
</option>
<codeStyleSettings language="XML">
<indentOptions>
<option name="CONTINUATION_INDENT_SIZE" value="4" />
......
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
</state>
</component>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="MarkdownEnhProjectSettings">
<AnnotatorSettings targetHasSpaces="true" linkCaseMismatch="true" wikiCaseMismatch="true" wikiLinkHasDashes="true" notUnderWikiHome="true" targetNotWikiPageExt="true" notUnderSourceWikiHome="true" targetNameHasAnchor="true" targetPathHasAnchor="true" wikiLinkHasSlash="true" wikiLinkHasSubdir="true" wikiLinkHasOnlyAnchor="true" linkTargetsWikiHasExt="true" linkTargetsWikiHasBadExt="true" notUnderSameRepo="true" targetNotUnderVcs="false" linkNeedsExt="true" linkHasBadExt="true" linkTargetNeedsExt="true" linkTargetHasBadExt="true" wikiLinkNotInWiki="true" imageTargetNotInRaw="true" repoRelativeAcrossVcsRoots="true" multipleWikiTargetsMatch="true" unresolvedLinkReference="true" linkIsIgnored="true" anchorIsIgnored="true" anchorIsUnresolved="true" anchorLineReferenceIsUnresolved="true" anchorLineReferenceFormat="true" anchorHasDuplicates="true" abbreviationDuplicates="true" abbreviationNotUsed="true" attributeIdDuplicateDefinition="true" attributeIdNotUsed="true" footnoteDuplicateDefinition="true" footnoteUnresolved="true" footnoteDuplicates="true" footnoteNotUsed="true" macroDuplicateDefinition="true" macroUnresolved="true" macroDuplicates="true" macroNotUsed="true" referenceDuplicateDefinition="true" referenceUnresolved="true" referenceDuplicates="true" referenceNotUsed="true" referenceUnresolvedNumericId="true" enumRefDuplicateDefinition="true" enumRefUnresolved="true" enumRefDuplicates="true" enumRefNotUsed="true" enumRefLinkUnresolved="true" enumRefLinkDuplicates="true" simTocUpdateNeeded="true" simTocTitleSpaceNeeded="true" />
<HtmlExportSettings updateOnSave="false" parentDir="" targetDir="" cssDir="css" scriptDir="js" plainHtml="false" imageDir="" copyLinkedImages="false" imagePathType="0" targetPathType="2" targetExt="" useTargetExt="false" noCssNoScripts="false" useElementStyleAttribute="false" linkToExportedHtml="true" exportOnSettingsChange="true" regenerateOnProjectOpen="false" linkFormatType="HTTP_ABSOLUTE" />
<LinkMapSettings>
<textMaps />
</LinkMapSettings>
</component>
<component name="MarkdownNavigatorHistory">
<PasteImageHistory checkeredTransparentBackground="false" filename="image" directory="" onPasteImageTargetRef="3" onPasteLinkText="0" onPasteImageElement="1" onPasteLinkElement="1" onPasteReferenceElement="2" cornerRadius="20" borderColor="0" transparentColor="16777215" borderWidth="1" trimTop="0" trimBottom="0" trimLeft="0" trimRight="0" transparent="false" roundCorners="false" showPreview="true" bordered="false" scaled="false" cropped="false" hideInapplicableOperations="false" preserveLinkFormat="false" scale="50" scalingInterpolation="1" transparentTolerance="0" saveAsDefaultOnOK="false" linkFormat="0" addHighlights="false" showHighlightCoordinates="true" showHighlights="false" mouseSelectionAddsHighlight="false" outerFilled="false" outerFillColor="0" outerFillTransparent="true" outerFillAlpha="30">
<highlightList />
<directories />
<filenames />
</PasteImageHistory>
<CopyImageHistory checkeredTransparentBackground="false" filename="image" directory="" onPasteImageTargetRef="3" onPasteLinkText="0" onPasteImageElement="1" onPasteLinkElement="1" onPasteReferenceElement="2" cornerRadius="20" borderColor="0" transparentColor="16777215" borderWidth="1" trimTop="0" trimBottom="0" trimLeft="0" trimRight="0" transparent="false" roundCorners="false" showPreview="true" bordered="false" scaled="false" cropped="false" hideInapplicableOperations="false" preserveLinkFormat="false" scale="50" scalingInterpolation="1" transparentTolerance="0" saveAsDefaultOnOK="false" linkFormat="0" addHighlights="false" showHighlightCoordinates="true" showHighlights="false" mouseSelectionAddsHighlight="false" outerFilled="false" outerFillColor="0" outerFillTransparent="true" outerFillAlpha="30">
<highlightList />
<directories />
<filenames />
</CopyImageHistory>
<PasteLinkHistory onPasteImageTargetRef="3" onPasteTargetRef="1" onPasteLinkText="0" onPasteImageElement="1" onPasteLinkElement="1" onPasteWikiElement="2" onPasteReferenceElement="2" hideInapplicableOperations="false" preserveLinkFormat="false" useHeadingForLinkText="false" linkFormat="0" saveAsDefaultOnOK="false" />
<TableToJsonHistory>
<entries />
</TableToJsonHistory>
<TableSortHistory>
<entries />
</TableSortHistory>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="MarkdownProjectSettings" wasCopied="false">
<PreviewSettings splitEditorLayout="SPLIT" splitEditorPreview="PREVIEW" useGrayscaleRendering="false" zoomFactor="1.0" maxImageWidth="0" showGitHubPageIfSynced="false" allowBrowsingInPreview="false" synchronizePreviewPosition="true" highlightPreviewType="NONE" highlightFadeOut="5" highlightOnTyping="true" synchronizeSourcePosition="true" verticallyAlignSourceAndPreviewSyncPosition="true" showSearchHighlightsInPreview="false" showSelectionInPreview="true" openRemoteLinks="true" replaceUnicodeEmoji="false" lastLayoutSetsDefault="false">
<component name="FlexmarkProjectSettings">
<FlexmarkHtmlSettings flexmarkSpecExampleRendering="0" flexmarkSpecExampleRenderHtml="false">
<flexmarkSectionLanguages>
<option name="1" value="Markdown" />
<option name="2" value="HTML" />
<option name="3" value="flexmark-ast:1" />
</flexmarkSectionLanguages>
</FlexmarkHtmlSettings>
</component>
<component name="MarkdownProjectSettings">
<PreviewSettings splitEditorLayout="SPLIT" splitEditorPreview="PREVIEW" useGrayscaleRendering="false" zoomFactor="1.0" maxImageWidth="0" synchronizePreviewPosition="true" highlightPreviewType="NONE" highlightFadeOut="5" highlightOnTyping="true" synchronizeSourcePosition="true" verticallyAlignSourceAndPreviewSyncPosition="true" showSearchHighlightsInPreview="false" showSelectionInPreview="true" lastLayoutSetsDefault="false">
<PanelProvider>
<provider providerId="com.vladsch.idea.multimarkdown.editor.swing.html.panel" providerName="Default - Swing" />
<provider providerId="com.vladsch.md.nav.editor.swing.html.panel" providerName="Default - Swing" />
</PanelProvider>
</PreviewSettings>
<ParserSettings gitHubSyntaxChange="false" emojiShortcuts="1" emojiImages="0">
<ParserSettings gitHubSyntaxChange="false" correctedInvalidSettings="false" emojiShortcuts="1" emojiImages="0">
<PegdownExtensions>
<option name="ABBREVIATIONS" value="false" />
<option name="ANCHORLINKS" value="true" />
<option name="ASIDE" value="false" />
<option name="ATXHEADERSPACE" value="true" />
<option name="AUTOLINKS" value="true" />
<option name="DEFINITIONS" value="false" />
<option name="DEFINITION_BREAK_DOUBLE_BLANK_LINE" value="false" />
<option name="FENCED_CODE_BLOCKS" value="true" />
<option name="FOOTNOTES" value="false" />
<option name="HARDWRAPS" value="false" />
<option name="HTML_DEEP_PARSER" value="false" />
<option name="INSERTED" value="false" />
<option name="QUOTES" value="false" />
<option name="INTELLIJ_DUMMY_IDENTIFIER" value="true" />
<option name="RELAXEDHRULES" value="true" />
<option name="SMARTS" value="false" />
<option name="STRIKETHROUGH" value="true" />
<option name="SUBSCRIPT" value="false" />
<option name="SUPERSCRIPT" value="false" />
<option name="SUPPRESS_HTML_BLOCKS" value="false" />
<option name="SUPPRESS_INLINE_HTML" value="false" />
<option name="TABLES" value="true" />
<option name="TASKLISTITEMS" value="true" />
<option name="TOC" value="false" />
<option name="WIKILINKS" value="true" />
</PegdownExtensions>
<ParserOptions>
<option name="ADMONITION_EXT" value="false" />
<option name="ATTRIBUTES_EXT" value="false" />
<option name="COMMONMARK_LISTS" value="true" />
<option name="DUMMY" value="false" />
<option name="EMOJI_SHORTCUTS" value="true" />
<option name="ENUMERATED_REFERENCES_EXT" value="false" />
<option name="FLEXMARK_FRONT_MATTER" value="false" />
<option name="GFM_LOOSE_BLANK_LINE_AFTER_ITEM_PARA" value="false" />
<option name="GFM_TABLE_RENDERING" value="true" />
<option name="GITBOOK_URL_ENCODING" value="false" />
<option name="GITHUB_LISTS" value="false" />
<option name="GITHUB_WIKI_LINKS" value="true" />
<option name="GITLAB_EXT" value="false" />
<option name="GITLAB_MATH_EXT" value="false" />
<option name="GITLAB_MERMAID_EXT" value="false" />
<option name="HEADER_ID_NO_DUPED_DASHES" value="false" />
<option name="JEKYLL_FRONT_MATTER" value="false" />
<option name="MACROS_EXT" value="false" />
<option name="NO_TEXT_ATTRIBUTES" value="false" />
<option name="PARSE_HTML_ANCHOR_ID" value="false" />
<option name="PRODUCTION_SPEC_PARSER" value="true" />
<option name="SIM_TOC_BLANK_LINE_SPACER" value="true" />
</ParserOptions>
</ParserSettings>
<HtmlSettings headerTopEnabled="false" headerBottomEnabled="false" bodyTopEnabled="false" bodyBottomEnabled="false" embedUrlContent="false" addPageHeader="true" embedImages="false" embedHttpImages="false" imageUriSerials="false" addDocTypeHtml="true">
<HtmlSettings headerTopEnabled="false" headerBottomEnabled="false" bodyTopEnabled="false" bodyBottomEnabled="false" addPageHeader="true" imageUriSerials="false" addDocTypeHtml="true" noParaTags="false" plantUmlConversion="0">
<GeneratorProvider>
<provider providerId="com.vladsch.idea.multimarkdown.editor.swing.html.generator" providerName="Default Swing HTML Generator" />
<provider providerId="com.vladsch.md.nav.editor.swing.html.generator" providerName="Default Swing HTML Generator" />
</GeneratorProvider>
<headerTop />
<headerBottom />
......@@ -68,15 +47,11 @@
</HtmlSettings>
<CssSettings previewScheme="UI_SCHEME" cssUri="" isCssUriEnabled="false" isCssUriSerial="true" isCssTextEnabled="false" isDynamicPageWidth="true">
<StylesheetProvider>
<provider providerId="com.vladsch.idea.multimarkdown.editor.swing.html.css" providerName="Default Swing Stylesheet" />
<provider providerId="com.vladsch.md.nav.editor.swing.html.css" providerName="Default Swing Stylesheet" />
</StylesheetProvider>
<ScriptProviders />
<cssText />
<cssUriHistory />
</CssSettings>
<HtmlExportSettings updateOnSave="false" parentDir="" targetDir="" cssDir="" scriptDir="" plainHtml="false" imageDir="" copyLinkedImages="false" imageUniquifyType="0" targetExt="" useTargetExt="false" noCssNoScripts="false" linkToExportedHtml="true" exportOnSettingsChange="true" regenerateOnProjectOpen="false" linkFormatType="HTTP_ABSOLUTE" />
<LinkMapSettings>
<textMaps />
</LinkMapSettings>
</component>
</project>
\ No newline at end of file
<component name="MarkdownNavigator.ProfileManager">
<settings default="" pdf-export="" />
</component>
\ No newline at end of file
## 3.1.0
- Added `HeadlessInAppWebView` class to be able to use WebView in headless mode
- Added `close`, `addMenuItem`, `addMenuItems` methods to `ChromeSafariBrowser`
- Added `ChromeSafariBrowserMenuItem` class in order to create custom menu item for `ChromeSafariBrowser`.
- Fixed `InAppWebView.channel` null when used by `InAppBrowserActivity` on android
- Fixed iOS presentationStyle affecting only dismiss animation [#305](https://github.com/pichillilorenzo/flutter_inappwebview/issues/305)
### BREAKING CHANGES
- Renamed `InAppWebViewWidgetOptions` to `InAppWebViewGroupOptions`.
## 3.0.0
- Added `Promise` javascript [polyfill](https://github.com/tildeio/rsvp.js) for webviews that doesn't support it for `window.flutter_inappwebview.callHandler`
......
......@@ -68,6 +68,7 @@ First, add `flutter_inappwebview` as a [dependency in your pubspec.yaml file](ht
Classes:
- [InAppWebView](#inappwebview-class): Flutter Widget for adding an **inline native WebView** integrated into the flutter widget tree. To use `InAppWebView` class on iOS you need to opt-in for the embedded views preview by adding a boolean property to the app's `Info.plist` file, with the key `io.flutter.embedded_views_preview` and the value `YES`.
- [HeadlessInAppWebView](#headlessinappwebview-class): Class that represents a WebView in headless mode. It can be used to run a WebView in background without attaching an `InAppWebView` to the widget tree.
- [InAppBrowser](#inappbrowser-class): In-App Browser using native WebView.
- [ChromeSafariBrowser](#chromesafaribrowser-class): In-App Browser using [Chrome Custom Tabs](https://developer.android.com/reference/android/support/customtabs/package-summary) on Android / [SFSafariViewController](https://developer.apple.com/documentation/safariservices/sfsafariviewcontroller) on iOS.
- [InAppLocalhostServer](#inapplocalhostserver-class): This class allows you to create a simple server on `http://localhost:[port]/`. The default `port` value is `8080`.
......@@ -132,7 +133,7 @@ Future main() async {
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => new _MyAppState();
}
}z
class _MyAppState extends State<MyApp> {
......@@ -177,7 +178,7 @@ class _MyAppState extends State<MyApp> {
child: InAppWebView(
initialUrl: "https://flutter.dev/",
initialHeaders: {},
initialOptions: InAppWebViewWidgetOptions(
initialOptions: InAppWebViewGroupOptions(
crossPlatform: InAppWebViewOptions(
debuggingEnabled: true,
)
......@@ -280,7 +281,7 @@ Screenshots:
* `addJavaScriptHandler({@required String handlerName, @required JavaScriptHandlerCallback callback})`: Adds a JavaScript message handler callback that listen to post messages sent from JavaScript by the handler with name `handlerName`.
* `removeJavaScriptHandler({@required String handlerName})`: Removes a JavaScript message handler previously added with the `addJavaScriptHandler()` associated to `handlerName` key.
* `takeScreenshot`: Takes a screenshot (in PNG format) of the WebView's visible viewport and returns a `Uint8List`. Returns `null` if it wasn't be able to take it.
* `setOptions({@required InAppWebViewWidgetOptions options})`: Sets the WebView options with the new options and evaluates them.
* `setOptions({@required InAppWebViewGroupOptions options})`: Sets the WebView options with the new options and evaluates them.
* `getOptions`: Gets the current WebView options. Returns the options with `null` value if they are not set yet.
* `getCopyBackForwardList`: Gets the `WebHistory` for this WebView. This contains the back/forward list for use in querying each item in the history stack.
* `clearCache`: Clears all the webview's cache.
......@@ -333,8 +334,8 @@ This event will be dispatched as soon as the platform (Android or iOS) is ready
```
`window.flutter_inappwebview.callHandler` returns a JavaScript [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)
that can be used to get the json result returned by [JavaScriptHandlerCallback].
In this case, simply return data that you want to send and it will be automatically json encoded using [jsonEncode] from the `dart:convert` library.
that can be used to get the json result returned by `JavaScriptHandlerCallback.
In this case, simply return data that you want to send and it will be automatically json encoded using `jsonEncode` from the `dart:convert` library.
So, on the JavaScript side, to get data coming from the Dart side, you will use:
```html
......@@ -498,6 +499,127 @@ Event names that starts with `android` or `ios` are events platform-specific.
* `iosOnDidCommit`: Called when the web view begins to receive web content (available only on iOS).
* `iosOnDidReceiveServerRedirectForProvisionalNavigation`: Called when a web view receives a server redirect (available only on iOS).
### `HeadlessInAppWebView` class
Class that represents a WebView in headless mode. It can be used to run a WebView in background without attaching an `InAppWebView` to the widget tree.
Remember to dispose it when you don't need it anymore.
As `InAppWebView`, it has the same options and events. Use `InAppWebViewController` to control the WebView instance.
Example:
```dart
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
Future main() async {
WidgetsFlutterBinding.ensureInitialized();
runApp(new MyApp());
}
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => new _MyAppState();
}
class _MyAppState extends State<MyApp> {
HeadlessInAppWebView headlessWebView;
String url = "";
@override
void initState() {
super.initState();
headlessWebView = new HeadlessInAppWebView(
initialUrl: "https://flutter.dev/",
initialOptions: InAppWebViewGroupOptions(
crossPlatform: InAppWebViewOptions(
debuggingEnabled: true,
),
),
onWebViewCreated: (controller) {
print('HeadlessInAppWebView created!');
},
onConsoleMessage: (controller, consoleMessage) {
print("CONSOLE MESSAGE: " + consoleMessage.message);
},
onLoadStart: (controller, url) async {
print("onLoadStart $url");
setState(() {
this.url = url;
});
},
onLoadStop: (controller, url) async {
print("onLoadStop $url");
setState(() {
this.url = url;
});
},
onUpdateVisitedHistory: (InAppWebViewController controller, String url, bool androidIsReload) {
print("onUpdateVisitedHistory $url");
setState(() {
this.url = url;
});
},
);
}
@override
void dispose() {
super.dispose();
headlessWebView.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
"HeadlessInAppWebView",
)),
drawer: myDrawer(context: context),
body: SafeArea(
child: Column(children: <Widget>[
Container(
padding: EdgeInsets.all(20.0),
child: Text(
"CURRENT URL\n${(url.length > 50) ? url.substring(0, 50) + "..." : url}"),
),
Center(
child: RaisedButton(
onPressed: () async {
await headlessWebView.dispose();
await headlessWebView.run();
},
child: Text("Run HeadlessInAppWebView")),
),
Center(
child: RaisedButton(
onPressed: () async {
try {
await headlessWebView.webViewController.evaluateJavascript(source: """console.log('Here is the message!');""");
} on MissingPluginException catch(e) {
print("HeadlessInAppWebView is not running. Click on \"Run HeadlessInAppWebView\"!");
}
},
child: Text("Send console.log message")),
),
Center(
child: RaisedButton(
onPressed: () {
headlessWebView.dispose();
},
child: Text("Dispose HeadlessInAppWebView")),
)
])
)
);
}
}
```
### `InAppBrowser` class
In-App Browser using native WebView.
......@@ -596,7 +718,7 @@ class _MyAppState extends State<MyApp> {
widget.browser.openFile(
assetFilePath: "assets/index.html",
options: InAppBrowserClassOptions(
inAppWebViewWidgetOptions: InAppWebViewWidgetOptions(
inAppWebViewGroupOptions: InAppWebViewGroupOptions(
crossPlatform: InAppWebViewOptions(
useShouldOverrideUrlLoading: true,
useOnLoadResource: true,
......@@ -744,6 +866,16 @@ class _MyAppState extends State<MyApp> {
@override
void initState() {
widget.browser.addMenuItem(new ChromeSafariBrowserMenuItem(id: 1, label: 'Custom item menu 1', action: (url, title) {
print('Custom item menu 1 clicked!');
print(url);
print(title);
}));
widget.browser.addMenuItem(new ChromeSafariBrowserMenuItem(id: 2, label: 'Custom item menu 2', action: (url, title) {
print('Custom item menu 2 clicked!');
print(url);
print(title);
}));
super.initState();
}
......@@ -785,6 +917,9 @@ Screenshots:
* `open({@required String url, ChromeSafariBrowserClassOptions options, Map<String, String> headersFallback = const {}, InAppBrowserClassOptions optionsFallback})`: Opens an `url` in a new `ChromeSafariBrowser` instance.
* `isOpened`: Returns `true` if the `ChromeSafariBrowser` instance is opened, otherwise `false`.
* `close`: Closes the `ChromeSafariBrowser` instance.
* `addMenuItem`: Adds a `ChromeSafariBrowserMenuItem` to the menu.
* `addMenuItems`: Adds a list of `ChromeSafariBrowserMenuItem` to the menu.
#### `ChromeSafariBrowser` options
......@@ -846,7 +981,7 @@ Future main() async {
child: InAppWebView(
initialUrl: "http://localhost:8080/assets/index.html",
initialHeaders: {},
initialOptions: InAppWebViewWidgetOptions(
initialOptions: InAppWebViewGroupOptions(
inAppWebViewOptions: InAppWebViewOptions(
debuggingEnabled: true,
)
......
......@@ -2,8 +2,9 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.pichillilorenzo.flutter_inappwebview">
<application>
<activity android:theme="@style/AppTheme" android:name="com.pichillilorenzo.flutter_inappwebview.InAppBrowserActivity" android:configChanges="orientation|screenSize"></activity>
<activity android:theme="@style/AppTheme" android:name="com.pichillilorenzo.flutter_inappwebview.InAppBrowser.InAppBrowserActivity" android:configChanges="orientation|screenSize"></activity>
<activity android:theme="@style/ThemeTransparent" android:name="com.pichillilorenzo.flutter_inappwebview.ChromeCustomTabs.ChromeCustomTabsActivity" android:configChanges="orientation|screenSize"></activity>
<receiver android:name="com.pichillilorenzo.flutter_inappwebview.ChromeCustomTabs.ActionBroadcastReceiver" />
</application>
</manifest>
\ No newline at end of file
package com.pichillilorenzo.flutter_inappwebview.ChromeCustomTabs;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import com.pichillilorenzo.flutter_inappwebview.Shared;
import java.util.HashMap;
import java.util.Map;
import io.flutter.plugin.common.MethodChannel;
public class ActionBroadcastReceiver extends BroadcastReceiver {
protected static final String LOG_TAG = "ActionBroadcastReceiver";
public static final String KEY_ACTION_ID = "com.pichillilorenzo.flutter_inappwebview.ChromeCustomTabs.ACTION_ID";
public static final String KEY_ACTION_UUID = "com.pichillilorenzo.flutter_inappwebview.ChromeCustomTabs.ACTION_UUID";
public static final String KEY_URL_TITLE = "android.intent.extra.SUBJECT";
@Override
public void onReceive(Context context, Intent intent) {
String url = intent.getDataString();
if (url != null) {
Bundle b = intent.getExtras();
String uuid = b.getString(KEY_ACTION_UUID);
int id = b.getInt(KEY_ACTION_ID);
String title = b.getString(KEY_URL_TITLE);
MethodChannel channel = new MethodChannel(Shared.messenger, "com.pichillilorenzo/flutter_chromesafaribrowser_" + uuid);
Map<String, Object> obj = new HashMap<>();
obj.put("url", url);
obj.put("title", title);
obj.put("id", id);
channel.invokeMethod("onChromeSafariBrowserMenuItemActionPerform", obj);
}
}
}
package com.pichillilorenzo.flutter_inappwebview.ChromeCustomTabs;
import android.app.Activity;
import android.app.PendingIntent;
import android.content.Intent;
import android.graphics.Color;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import androidx.browser.customtabs.CustomTabsCallback;
import androidx.browser.customtabs.CustomTabsIntent;
import androidx.browser.customtabs.CustomTabsService;
import androidx.browser.customtabs.CustomTabsSession;
import com.pichillilorenzo.flutter_inappwebview.InAppWebViewFlutterPlugin;
import com.pichillilorenzo.flutter_inappwebview.R;
import com.pichillilorenzo.flutter_inappwebview.Shared;
import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import io.flutter.plugin.common.MethodCall;
......@@ -52,6 +55,8 @@ public class ChromeCustomTabsActivity extends Activity implements MethodChannel.
options = new ChromeCustomTabsOptions();
options.parse((HashMap<String, Object>) b.getSerializable("options"));
final List<HashMap<String, Object>> menuItemList = (List<HashMap<String, Object>>) b.getSerializable("menuItemList");
final ChromeCustomTabsActivity chromeCustomTabsActivity = this;
customTabActivityHelper = new CustomTabActivityHelper();
......@@ -63,18 +68,17 @@ public class ChromeCustomTabsActivity extends Activity implements MethodChannel.
customTabActivityHelper.mayLaunchUrl(uri, null, null);
builder = new CustomTabsIntent.Builder(customTabsSession);
prepareCustomTabs(menuItemList);
CustomTabsIntent customTabsIntent = builder.build();
prepareCustomTabs(customTabsIntent);
prepareCustomTabsIntent(customTabsIntent);
CustomTabActivityHelper.openCustomTab(chromeCustomTabsActivity, customTabsIntent, uri, CHROME_CUSTOM_TAB_REQUEST_CODE);
}
@Override
public void onCustomTabsDisconnected() {
customTabsSession = null;
finish();
Map<String, Object> obj = new HashMap<>();
obj.put("uuid", uuid);
channel.invokeMethod("onChromeSafariBrowserClosed", obj);
chromeCustomTabsActivity.close();
}
});
......@@ -122,12 +126,23 @@ public class ChromeCustomTabsActivity extends Activity implements MethodChannel.
@Override
public void onMethodCall(final MethodCall call, final MethodChannel.Result result) {
switch (call.method) {
case "close":
this.onStop();
this.onDestroy();
this.close();
// https://stackoverflow.com/a/41596629/4637638
Intent myIntent = new Intent(Shared.activity, Shared.activity.getClass());
myIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
myIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
Shared.activity.startActivity(myIntent);
break;
default:
result.notImplemented();
}
}
private void prepareCustomTabs(CustomTabsIntent customTabsIntent) {
private void prepareCustomTabs(List<HashMap<String, Object>> menuItemList) {
if (options.addDefaultShareMenuItem)
builder.addDefaultShareMenuItem();
......@@ -141,6 +156,14 @@ public class ChromeCustomTabsActivity extends Activity implements MethodChannel.
builder.setInstantAppsEnabled(options.instantAppsEnabled);
for (HashMap<String, Object> menuItem : menuItemList) {
int id = (int) menuItem.get("id");
String label = (String) menuItem.get("label");
builder.addMenuItem(label, createPendingIntent(id));
}
}
private void prepareCustomTabsIntent(CustomTabsIntent customTabsIntent) {
if (options.packageName != null)
customTabsIntent.intent.setPackage(options.packageName);
else
......@@ -165,12 +188,27 @@ public class ChromeCustomTabsActivity extends Activity implements MethodChannel.
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == CHROME_CUSTOM_TAB_REQUEST_CODE) {
customTabsSession = null;
finish();
Map<String, Object> obj = new HashMap<>();
obj.put("uuid", uuid);
InAppWebViewFlutterPlugin.inAppBrowserManager.channel.invokeMethod("onChromeSafariBrowserClosed", obj);
close();
}
}
public void close() {
customTabsSession = null;
finish();
Map<String, Object> obj = new HashMap<>();
obj.put("uuid", uuid);
channel.invokeMethod("onChromeSafariBrowserClosed", obj);
}
private PendingIntent createPendingIntent(int actionSourceId) {
Intent actionIntent = new Intent(this, ActionBroadcastReceiver.class);
Bundle extras = new Bundle();
extras.putInt(ActionBroadcastReceiver.KEY_ACTION_ID, actionSourceId);
extras.putString(ActionBroadcastReceiver.KEY_ACTION_UUID, uuid);
actionIntent.putExtras(extras);
return PendingIntent.getBroadcast(
this, actionSourceId, actionIntent, 0);
}
}
......@@ -7,9 +7,12 @@ import android.util.Log;
import com.pichillilorenzo.flutter_inappwebview.ChromeCustomTabs.ChromeCustomTabsActivity;
import com.pichillilorenzo.flutter_inappwebview.ChromeCustomTabs.CustomTabActivityHelper;
import com.pichillilorenzo.flutter_inappwebview.InAppBrowser.InAppBrowserActivity;
import com.pichillilorenzo.flutter_inappwebview.InAppBrowser.InAppBrowserOptions;
import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import io.flutter.plugin.common.BinaryMessenger;
......@@ -40,7 +43,8 @@ public class ChromeSafariBrowserManager implements MethodChannel.MethodCallHandl
String uuidFallback = (String) call.argument("uuidFallback");
Map<String, String> headersFallback = (Map<String, String>) call.argument("headersFallback");
HashMap<String, Object> optionsFallback = (HashMap<String, Object>) call.argument("optionsFallback");
open(activity, uuid, url, options, uuidFallback, headersFallback, optionsFallback, result);
List<HashMap<String, Object>> menuItemList = (List<HashMap<String, Object>>) call.argument("menuItemList");
open(activity, uuid, url, options, uuidFallback, headersFallback, optionsFallback, menuItemList, result);
}
break;
default:
......@@ -48,7 +52,8 @@ public class ChromeSafariBrowserManager implements MethodChannel.MethodCallHandl
}
}
public void open(Activity activity, String uuid, String url, HashMap<String, Object> options, String uuidFallback, Map<String, String> headersFallback, HashMap<String, Object> optionsFallback, MethodChannel.Result result) {
public void open(Activity activity, String uuid, String url, HashMap<String, Object> options, String uuidFallback,
Map<String, String> headersFallback, HashMap<String, Object> optionsFallback, List<HashMap<String, Object>> menuItemList, MethodChannel.Result result) {
Intent intent = null;
Bundle extras = new Bundle();
......@@ -58,6 +63,7 @@ public class ChromeSafariBrowserManager implements MethodChannel.MethodCallHandl
extras.putString("uuid", uuid);
extras.putSerializable("options", options);
extras.putSerializable("headers", (Serializable) headersFallback);
extras.putSerializable("menuItemList", (Serializable) menuItemList);
if (CustomTabActivityHelper.isAvailable(activity)) {
intent = new Intent(activity, ChromeCustomTabsActivity.class);
......
/*
*
* 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.
*
*/
package com.pichillilorenzo.flutter_inappwebview;
import android.app.Activity;
import com.pichillilorenzo.flutter_inappwebview.InAppWebView.FlutterWebView;
import java.util.HashMap;
import java.util.Map;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.Result;
/**
* InAppBrowserManager
*/
public class HeadlessInAppWebViewManager implements MethodChannel.MethodCallHandler {
public MethodChannel channel;
protected static final String LOG_TAG = "HeadlessInAppWebViewManager";
Map<String, FlutterWebView> flutterWebViews = new HashMap<>();
public HeadlessInAppWebViewManager(BinaryMessenger messenger) {
channel = new MethodChannel(messenger, "com.pichillilorenzo/flutter_headless_inappwebview");
channel.setMethodCallHandler(this);
}
@Override
public void onMethodCall(final MethodCall call, final Result result) {
final Activity activity = Shared.activity;
final String uuid = (String) call.argument("uuid");
switch (call.method) {
case "createHeadlessWebView":
{
HashMap<String, Object> params = (HashMap<String, Object>) call.argument("params");
createHeadlessWebView(activity, uuid, params);
}
result.success(true);
break;
case "disposeHeadlessWebView":
disposeHeadlessWebView(uuid);
result.success(true);
break;
default:
result.notImplemented();
}
}
public void createHeadlessWebView(Activity activity, String uuid, HashMap<String, Object> params) {
FlutterWebView flutterWebView = new FlutterWebView(Shared.messenger, activity, uuid, params, null);
flutterWebViews.put(uuid, flutterWebView);
}
public void disposeHeadlessWebView(String uuid) {
if (flutterWebViews.containsKey(uuid)) {
flutterWebViews.get(uuid).dispose();
flutterWebViews.remove(uuid);
}
}
public void dispose() {
channel.setMethodCallHandler(null);
}
}
package com.pichillilorenzo.flutter_inappwebview;
package com.pichillilorenzo.flutter_inappwebview.InAppBrowser;
import android.content.Intent;
import android.graphics.Bitmap;
......@@ -26,6 +26,8 @@ import androidx.appcompat.app.AppCompatActivity;
import com.pichillilorenzo.flutter_inappwebview.InAppWebView.InAppWebView;
import com.pichillilorenzo.flutter_inappwebview.InAppWebView.InAppWebViewOptions;
import com.pichillilorenzo.flutter_inappwebview.R;
import com.pichillilorenzo.flutter_inappwebview.Shared;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
......@@ -65,6 +67,7 @@ public class InAppBrowserActivity extends AppCompatActivity implements MethodCha
webView = findViewById(R.id.webView);
webView.inAppBrowserActivity = this;
webView.channel = channel;
fromActivity = b.getString("fromActivity");
......
package com.pichillilorenzo.flutter_inappwebview;
package com.pichillilorenzo.flutter_inappwebview.InAppBrowser;
import com.pichillilorenzo.flutter_inappwebview.Options;
import java.util.HashMap;
import java.util.Map;
......
......@@ -32,6 +32,8 @@ import android.os.Bundle;
import android.webkit.MimeTypeMap;
import android.util.Log;
import com.pichillilorenzo.flutter_inappwebview.InAppBrowser.InAppBrowserActivity;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
......
package com.pichillilorenzo.flutter_inappwebview;
package com.pichillilorenzo.flutter_inappwebview.InAppWebView;
import android.app.Activity;
import android.content.Context;
......@@ -14,6 +14,8 @@ import android.webkit.WebViewClient;
import com.pichillilorenzo.flutter_inappwebview.InAppWebView.DisplayListenerProxy;
import com.pichillilorenzo.flutter_inappwebview.InAppWebView.InAppWebView;
import com.pichillilorenzo.flutter_inappwebview.InAppWebView.InAppWebViewOptions;
import com.pichillilorenzo.flutter_inappwebview.Shared;
import com.pichillilorenzo.flutter_inappwebview.Util;
import java.io.IOException;
import java.lang.reflect.Field;
......@@ -37,7 +39,7 @@ public class FlutterWebView implements PlatformView, MethodCallHandler {
public InAppWebView webView;
public final MethodChannel channel;
public FlutterWebView(BinaryMessenger messenger, final Context context, int id, HashMap<String, Object> params, View containerView) {
public FlutterWebView(BinaryMessenger messenger, final Context context, Object id, HashMap<String, Object> params, View containerView) {
channel = new MethodChannel(messenger, "com.pichillilorenzo/flutter_inappwebview_" + id);
channel.setMethodCallHandler(this);
......@@ -93,6 +95,12 @@ public class FlutterWebView implements PlatformView, MethodCallHandler {
}
else
webView.loadUrl(initialUrl, initialHeaders);
if (containerView == null && id instanceof String) {
Map<String, Object> obj = new HashMap<>();
obj.put("uuid", id);
channel.invokeMethod("onHeadlessWebViewCreated", obj);
}
}
@Override
......
package com.pichillilorenzo.flutter_inappwebview;
package com.pichillilorenzo.flutter_inappwebview.InAppWebView;
import android.content.Context;
import android.view.View;
import com.pichillilorenzo.flutter_inappwebview.InAppWebView.FlutterWebView;
import java.util.HashMap;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.PluginRegistry.Registrar;
import io.flutter.plugin.common.StandardMessageCodec;
import io.flutter.plugin.platform.PlatformView;
import io.flutter.plugin.platform.PlatformViewFactory;
......
......@@ -5,19 +5,16 @@ import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.print.PrintAttributes;
import android.print.PrintDocumentAdapter;
import android.print.PrintManager;
import android.util.AttributeSet;
import android.util.Log;
import android.view.ContextMenu;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewParent;
import android.webkit.CookieManager;
import android.webkit.DownloadListener;
import android.webkit.ValueCallback;
......@@ -27,17 +24,12 @@ import android.webkit.WebSettings;
import android.webkit.WebStorage;
import androidx.annotation.RequiresApi;
import androidx.appcompat.widget.PopupMenu;
import android.view.ActionMode;
import android.webkit.WebView;
import com.pichillilorenzo.flutter_inappwebview.ContentBlocker.ContentBlocker;
import com.pichillilorenzo.flutter_inappwebview.ContentBlocker.ContentBlockerAction;
import com.pichillilorenzo.flutter_inappwebview.ContentBlocker.ContentBlockerHandler;
import com.pichillilorenzo.flutter_inappwebview.ContentBlocker.ContentBlockerTrigger;
import com.pichillilorenzo.flutter_inappwebview.FlutterWebView;
import com.pichillilorenzo.flutter_inappwebview.InAppBrowserActivity;
import com.pichillilorenzo.flutter_inappwebview.InAppBrowser.InAppBrowserActivity;
import com.pichillilorenzo.flutter_inappwebview.JavaScriptBridgeInterface;
import com.pichillilorenzo.flutter_inappwebview.Shared;
import com.pichillilorenzo.flutter_inappwebview.Util;
......@@ -62,7 +54,7 @@ final public class InAppWebView extends InputAwareWebView {
public InAppBrowserActivity inAppBrowserActivity;
public FlutterWebView flutterWebView;
public MethodChannel channel;
public int id;
public Object id;
public InAppWebViewClient inAppWebViewClient;
public InAppWebViewChromeClient inAppWebViewChromeClient;
public InAppWebViewOptions options;
......@@ -527,7 +519,7 @@ final public class InAppWebView extends InputAwareWebView {
super(context, attrs, defaultStyle);
}
public InAppWebView(Context context, Object obj, int id, InAppWebViewOptions options, View containerView) {
public InAppWebView(Context context, Object obj, Object id, InAppWebViewOptions options, View containerView) {
super(context, containerView);
if (obj instanceof InAppBrowserActivity)
this.inAppBrowserActivity = (InAppBrowserActivity) obj;
......@@ -891,7 +883,8 @@ final public class InAppWebView extends InputAwareWebView {
}
public void takeScreenshot(final MethodChannel.Result result) {
post(new Runnable() {
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
@Override
public void run() {
int height = (int) (getContentHeight() * scale + 0.5);
......@@ -1199,7 +1192,8 @@ final public class InAppWebView extends InputAwareWebView {
scriptToInject = String.format(jsWrapper, jsonSourceString);
}
final String finalScriptToInject = scriptToInject;
post(new Runnable() {
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
@Override
public void run() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
......
......@@ -27,8 +27,7 @@ import android.widget.LinearLayout;
import androidx.appcompat.app.AlertDialog;
import com.pichillilorenzo.flutter_inappwebview.FlutterWebView;
import com.pichillilorenzo.flutter_inappwebview.InAppBrowserActivity;
import com.pichillilorenzo.flutter_inappwebview.InAppBrowser.InAppBrowserActivity;
import com.pichillilorenzo.flutter_inappwebview.InAppWebViewFlutterPlugin;
import com.pichillilorenzo.flutter_inappwebview.R;
import com.pichillilorenzo.flutter_inappwebview.Shared;
......
......@@ -24,9 +24,7 @@ import androidx.annotation.RequiresApi;
import com.pichillilorenzo.flutter_inappwebview.CredentialDatabase.Credential;
import com.pichillilorenzo.flutter_inappwebview.CredentialDatabase.CredentialDatabase;
import com.pichillilorenzo.flutter_inappwebview.FlutterWebView;
import com.pichillilorenzo.flutter_inappwebview.InAppBrowserActivity;
import com.pichillilorenzo.flutter_inappwebview.InAppWebViewFlutterPlugin;
import com.pichillilorenzo.flutter_inappwebview.InAppBrowser.InAppBrowserActivity;
import com.pichillilorenzo.flutter_inappwebview.JavaScriptBridgeInterface;
import com.pichillilorenzo.flutter_inappwebview.Util;
......
......@@ -6,6 +6,8 @@ import android.net.Uri;
import android.os.Build;
import android.webkit.ValueCallback;
import com.pichillilorenzo.flutter_inappwebview.InAppWebView.FlutterWebViewFactory;
import io.flutter.embedding.engine.plugins.activity.ActivityAware;
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding;
import io.flutter.plugin.common.BinaryMessenger;
......@@ -19,6 +21,7 @@ public class InAppWebViewFlutterPlugin implements FlutterPlugin, ActivityAware {
protected static final String LOG_TAG = "InAppWebViewFlutterPL";
public static InAppBrowserManager inAppBrowserManager;
public static HeadlessInAppWebViewManager headlessInAppWebViewManager;
public static ChromeSafariBrowserManager chromeSafariBrowserManager;
public static InAppWebViewStatic inAppWebViewStatic;
public static MyCookieManager myCookieManager;
......@@ -49,6 +52,7 @@ public class InAppWebViewFlutterPlugin implements FlutterPlugin, ActivityAware {
Shared.messenger = messenger;
inAppBrowserManager = new InAppBrowserManager(messenger);
headlessInAppWebViewManager = new HeadlessInAppWebViewManager(messenger);
chromeSafariBrowserManager = new ChromeSafariBrowserManager(messenger);
platformViewRegistry.registerViewFactory(
......@@ -67,6 +71,10 @@ public class InAppWebViewFlutterPlugin implements FlutterPlugin, ActivityAware {
inAppBrowserManager.dispose();
inAppBrowserManager = null;
}
if (headlessInAppWebViewManager != null) {
headlessInAppWebViewManager.dispose();
headlessInAppWebViewManager = null;
}
if (chromeSafariBrowserManager != null) {
chromeSafariBrowserManager.dispose();
chromeSafariBrowserManager = null;
......
......@@ -7,6 +7,8 @@ import android.util.Log;
import android.webkit.JavascriptInterface;
import android.webkit.ValueCallback;
import com.pichillilorenzo.flutter_inappwebview.InAppBrowser.InAppBrowserActivity;
import com.pichillilorenzo.flutter_inappwebview.InAppWebView.FlutterWebView;
import com.pichillilorenzo.flutter_inappwebview.InAppWebView.InAppWebView;
import java.util.HashMap;
......
......@@ -7,7 +7,7 @@
android:layout_height="match_parent"
android:clickable="true"
android:focusableInTouchMode="true"
tools:context=".InAppBrowserActivity"
tools:context=".InAppBrowser.InAppBrowserActivity"
android:focusable="true">
<com.pichillilorenzo.flutter_inappwebview.InAppWebView.InAppWebView
......
......@@ -3,7 +3,7 @@
xmlns:appcompat="http://schemas.android.com/apk/res-auto"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".InAppBrowserActivity">
tools:context=".InAppBrowser.InAppBrowserActivity">
<item
android:id="@+id/action_go_back"
......
{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"connectivity","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/connectivity-0.4.8+5/","dependencies":[]},{"name":"flutter_downloader","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_downloader-1.4.4/","dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/lorenzopichilli/Desktop/flutter_inappwebview/","dependencies":[]},{"name":"path_provider","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider-1.6.7/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/permission_handler-3.3.0/","dependencies":[]}],"android":[{"name":"connectivity","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/connectivity-0.4.8+5/","dependencies":[]},{"name":"flutter_downloader","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_downloader-1.4.4/","dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/lorenzopichilli/Desktop/flutter_inappwebview/","dependencies":[]},{"name":"path_provider","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider-1.6.7/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/permission_handler-3.3.0/","dependencies":[]}],"macos":[{"name":"connectivity_macos","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/connectivity_macos-0.1.0+3/","dependencies":[]},{"name":"path_provider_macos","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-0.0.4+2/","dependencies":[]}],"linux":[],"windows":[],"web":[]},"dependencyGraph":[{"name":"connectivity","dependencies":["connectivity_macos"]},{"name":"connectivity_macos","dependencies":[]},{"name":"flutter_downloader","dependencies":[]},{"name":"flutter_inappwebview","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_macos"]},{"name":"path_provider_macos","dependencies":[]},{"name":"permission_handler","dependencies":[]}],"date_created":"2020-05-09 04:59:17.693618","version":"1.17.0"}
\ No newline at end of file
{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"connectivity","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/connectivity-0.4.8+5/","dependencies":[]},{"name":"flutter_downloader","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_downloader-1.4.4/","dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/lorenzopichilli/Desktop/flutter_inappwebview/","dependencies":[]},{"name":"path_provider","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider-1.6.7/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/permission_handler-3.3.0/","dependencies":[]}],"android":[{"name":"connectivity","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/connectivity-0.4.8+5/","dependencies":[]},{"name":"flutter_downloader","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_downloader-1.4.4/","dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/lorenzopichilli/Desktop/flutter_inappwebview/","dependencies":[]},{"name":"path_provider","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider-1.6.7/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/permission_handler-3.3.0/","dependencies":[]}],"macos":[{"name":"connectivity_macos","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/connectivity_macos-0.1.0+3/","dependencies":[]},{"name":"path_provider_macos","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-0.0.4+2/","dependencies":[]}],"linux":[],"windows":[],"web":[]},"dependencyGraph":[{"name":"connectivity","dependencies":["connectivity_macos"]},{"name":"connectivity_macos","dependencies":[]},{"name":"flutter_downloader","dependencies":[]},{"name":"flutter_inappwebview","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_macos"]},{"name":"path_provider_macos","dependencies":[]},{"name":"permission_handler","dependencies":[]}],"date_created":"2020-05-11 02:42:13.697935","version":"1.17.0"}
\ No newline at end of file
#!/bin/sh
# This is a generated file; do not edit or check into version control.
export "FLUTTER_ROOT=/Users/lorenzopichilli/flutter"
export "FLUTTER_APPLICATION_PATH=/Users/lorenzopichilli/Desktop/flutter_inappwebview/example"
export "FLUTTER_TARGET=/Users/lorenzopichilli/Desktop/flutter_inappwebview/example/lib/main.dart"
export "FLUTTER_BUILD_DIR=build"
export "SYMROOT=${SOURCE_ROOT}/../build/ios"
export "OTHER_LDFLAGS=$(inherited) -framework Flutter"
export "FLUTTER_FRAMEWORK_DIR=/Users/lorenzopichilli/flutter/bin/cache/artifacts/engine/ios"
export "FLUTTER_BUILD_NAME=1.0.0"
export "FLUTTER_BUILD_NUMBER=1"
export "TRACK_WIDGET_CREATION=true"
......@@ -35,6 +35,16 @@ class _ChromeSafariBrowserExampleScreenState
extends State<ChromeSafariBrowserExampleScreen> {
@override
void initState() {
widget.browser.addMenuItem(new ChromeSafariBrowserMenuItem(id: 1, label: 'Custom item menu 1', action: (url, title) {
print('Custom item menu 1 clicked!');
print(url);
print(title);
}));
widget.browser.addMenuItem(new ChromeSafariBrowserMenuItem(id: 2, label: 'Custom item menu 2', action: (url, title) {
print('Custom item menu 2 clicked!');
print(url);
print(title);
}));
super.initState();
}
......@@ -53,7 +63,10 @@ class _ChromeSafariBrowserExampleScreenState
url: "https://flutter.dev/",
options: ChromeSafariBrowserClassOptions(
android: AndroidChromeCustomTabsOptions(addDefaultShareMenuItem: false, keepAliveEnabled: true),
ios: IOSSafariOptions(barCollapsingEnabled: true)));
ios: IOSSafariOptions(
dismissButtonStyle: IOSSafariDismissButtonStyle.CLOSE,
presentationStyle: IOSUIModalPresentationStyle.OVER_FULL_SCREEN
)));
},
child: Text("Open Chrome Safari Browser")),
));
......
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'main.dart';
class HeadlessInAppWebViewExampleScreen extends StatefulWidget {
@override
_HeadlessInAppWebViewExampleScreenState createState() =>
new _HeadlessInAppWebViewExampleScreenState();
}
class _HeadlessInAppWebViewExampleScreenState extends State<HeadlessInAppWebViewExampleScreen> {
HeadlessInAppWebView headlessWebView;
String url = "";
@override
void initState() {
super.initState();
headlessWebView = new HeadlessInAppWebView(
initialUrl: "https://flutter.dev/",
initialOptions: InAppWebViewGroupOptions(
crossPlatform: InAppWebViewOptions(
debuggingEnabled: true,
),
),
onWebViewCreated: (controller) {
print('HeadlessInAppWebView created!');
},
onConsoleMessage: (controller, consoleMessage) {
print("CONSOLE MESSAGE: " + consoleMessage.message);
},
onLoadStart: (controller, url) async {
print("onLoadStart $url");
setState(() {
this.url = url;
});
},
onLoadStop: (controller, url) async {
print("onLoadStop $url");
setState(() {
this.url = url;
});
},
onUpdateVisitedHistory: (InAppWebViewController controller, String url, bool androidIsReload) {
print("onUpdateVisitedHistory $url");
setState(() {
this.url = url;
});
},
);
}
@override
void dispose() {
super.dispose();
headlessWebView.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
"HeadlessInAppWebView",
)),
drawer: myDrawer(context: context),
body: SafeArea(
child: Column(children: <Widget>[
Container(
padding: EdgeInsets.all(20.0),
child: Text(
"CURRENT URL\n${(url.length > 50) ? url.substring(0, 50) + "..." : url}"),
),
Center(
child: RaisedButton(
onPressed: () async {
await headlessWebView.dispose();
await headlessWebView.run();
},
child: Text("Run HeadlessInAppWebView")),
),
Center(
child: RaisedButton(
onPressed: () async {
try {
await headlessWebView.webViewController.evaluateJavascript(source: """console.log('Here is the message!');""");
} on MissingPluginException catch(e) {
print("HeadlessInAppWebView is not running. Click on \"Run HeadlessInAppWebView\"!");
}
},
child: Text("Send console.log message")),
),
Center(
child: RaisedButton(
onPressed: () {
headlessWebView.dispose();
},
child: Text("Dispose HeadlessInAppWebView")),
)
])
)
);
}
}
......@@ -90,7 +90,7 @@ class _InAppBrowserExampleScreenState extends State<InAppBrowserExampleScreen> {
await widget.browser.openFile(
assetFilePath: "assets/index.html",
options: InAppBrowserClassOptions(
inAppWebViewWidgetOptions: InAppWebViewWidgetOptions(
inAppWebViewGroupOptions: InAppWebViewGroupOptions(
crossPlatform: InAppWebViewOptions(
debuggingEnabled: true,
useShouldOverrideUrlLoading: true,
......
......@@ -52,7 +52,7 @@ class _InAppWebViewExampleScreenState extends State<InAppWebViewExampleScreen> {
initialUrl: "https://flutter.dev/",
// initialFile: "assets/index.html",
initialHeaders: {},
initialOptions: InAppWebViewWidgetOptions(
initialOptions: InAppWebViewGroupOptions(
crossPlatform: InAppWebViewOptions(
debuggingEnabled: true,
),
......
......@@ -2,8 +2,8 @@ import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:flutter_inappwebview_example/chrome_safari_browser_example.screen.dart';
import 'package:flutter_inappwebview_example/headless_in_app_webview.screen.dart';
import 'package:flutter_inappwebview_example/in_app_webiew_example.screen.dart';
import 'package:flutter_inappwebview_example/in_app_browser_example.screen.dart';
......@@ -44,6 +44,12 @@ Drawer myDrawer({@required BuildContext context}) {
Navigator.pushReplacementNamed(context, '/');
},
),
ListTile(
title: Text('HeadlessInAppWebView'),
onTap: () {
Navigator.pushReplacementNamed(context, '/HeadlessInAppWebView');
},
),
],
),
);
......@@ -74,6 +80,7 @@ class _MyAppState extends State<MyApp> {
'/': (context) => InAppWebViewExampleScreen(),
'/InAppBrowser': (context) => InAppBrowserExampleScreen(),
'/ChromeSafariBrowser': (context) => ChromeSafariBrowserExampleScreen(),
'/HeadlessInAppWebView': (context) => HeadlessInAppWebViewExampleScreen(),
}
);
}
......
......@@ -56,7 +56,7 @@ class InAppWebViewAjaxTestState extends WidgetTestState {
</html>
"""),
initialHeaders: {},
initialOptions: InAppWebViewWidgetOptions(
initialOptions: InAppWebViewGroupOptions(
crossPlatform: InAppWebViewOptions(
clearCache: true,
debuggingEnabled: true,
......
......@@ -29,7 +29,7 @@ class InAppWebViewContentBlockerTestState extends WidgetTestState {
child: InAppWebView(
initialUrl: "https://flutter.dev/",
initialHeaders: {},
initialOptions: InAppWebViewWidgetOptions(
initialOptions: InAppWebViewGroupOptions(
crossPlatform: InAppWebViewOptions(
clearCache: true,
debuggingEnabled: true,
......
......@@ -30,7 +30,7 @@ class InAppWebViewCookieManagerTestState extends WidgetTestState {
child: InAppWebView(
initialUrl: "https://flutter.dev/",
initialHeaders: {},
initialOptions: InAppWebViewWidgetOptions(
initialOptions: InAppWebViewGroupOptions(
crossPlatform: InAppWebViewOptions(
clearCache: true,
debuggingEnabled: true
......
......@@ -74,7 +74,7 @@ class InAppWebViewFetchTestState extends WidgetTestState {
</html>
"""),
initialHeaders: {},
initialOptions: InAppWebViewWidgetOptions(
initialOptions: InAppWebViewGroupOptions(
crossPlatform: InAppWebViewOptions(
clearCache: true,
debuggingEnabled: true,
......
......@@ -37,7 +37,7 @@ class InAppWebViewHttpAuthCredentialDatabaseTestState extends WidgetTestState {
child: InAppWebView(
initialUrl: "http://${environment["NODE_SERVER_IP"]}:8081/",
initialHeaders: {},
initialOptions: InAppWebViewWidgetOptions(
initialOptions: InAppWebViewGroupOptions(
crossPlatform: InAppWebViewOptions(
clearCache: true,
debuggingEnabled: true
......
......@@ -65,7 +65,7 @@ class InAppWebViewInitialDataTestState extends WidgetTestState {
</html>
"""),
initialHeaders: {},
initialOptions: InAppWebViewWidgetOptions(
initialOptions: InAppWebViewGroupOptions(
crossPlatform: InAppWebViewOptions(
clearCache: true,
debuggingEnabled: true
......
......@@ -28,7 +28,7 @@ class InAppWebViewInitialFileTestState extends WidgetTestState {
child: InAppWebView(
initialFile: "test_assets/in_app_webview_initial_file_test.html",
initialHeaders: {},
initialOptions: InAppWebViewWidgetOptions(
initialOptions: InAppWebViewGroupOptions(
crossPlatform: InAppWebViewOptions(
clearCache: true,
debuggingEnabled: true
......
......@@ -29,7 +29,7 @@ class InAppWebViewInitialUrlTestState extends WidgetTestState {
child: InAppWebView(
initialUrl: "https://flutter.dev/",
initialHeaders: {},
initialOptions: InAppWebViewWidgetOptions(
initialOptions: InAppWebViewGroupOptions(
crossPlatform: InAppWebViewOptions(
clearCache: true,
debuggingEnabled: true
......
......@@ -43,7 +43,7 @@ class InAppWebViewJavaScriptHandlerTestState extends WidgetTestState {
child: InAppWebView(
initialFile: "test_assets/in_app_webview_javascript_handler_test.html",
initialHeaders: {},
initialOptions: InAppWebViewWidgetOptions(
initialOptions: InAppWebViewGroupOptions(
crossPlatform: InAppWebViewOptions(
clearCache: true,
debuggingEnabled: true
......
......@@ -28,7 +28,7 @@ class InAppWebViewOnConsoleMessageTestState extends WidgetTestState {
child: InAppWebView(
initialFile: "test_assets/in_app_webview_on_console_message_test.html",
initialHeaders: {},
initialOptions: InAppWebViewWidgetOptions(
initialOptions: InAppWebViewGroupOptions(
crossPlatform: InAppWebViewOptions(
clearCache: true,
debuggingEnabled: true
......
......@@ -28,7 +28,7 @@ class InAppWebViewOnCreateWindowTestState extends WidgetTestState {
child: InAppWebView(
initialFile: "test_assets/in_app_webview_on_create_window_test.html",
initialHeaders: {},
initialOptions: InAppWebViewWidgetOptions(
initialOptions: InAppWebViewGroupOptions(
crossPlatform: InAppWebViewOptions(
clearCache: true,
debuggingEnabled: true,
......
......@@ -48,7 +48,7 @@ class InAppWebViewOnDownloadStartTestState extends WidgetTestState {
</html>
"""),
initialHeaders: {},
initialOptions: InAppWebViewWidgetOptions(
initialOptions: InAppWebViewGroupOptions(
crossPlatform: InAppWebViewOptions(
clearCache: true,
debuggingEnabled: true,
......
......@@ -28,7 +28,7 @@ class InAppWebViewOnFindResultReceivedTestState extends WidgetTestState {
child: InAppWebView(
initialFile: "test_assets/in_app_webview_initial_file_test.html",
initialHeaders: {},
initialOptions: InAppWebViewWidgetOptions(
initialOptions: InAppWebViewGroupOptions(
crossPlatform: InAppWebViewOptions(
clearCache: true,
debuggingEnabled: true
......
......@@ -36,7 +36,7 @@ class InAppWebViewOnJsDialogTestState extends WidgetTestState {
child: InAppWebView(
initialFile: "test_assets/in_app_webview_on_js_dialog_test.html",
initialHeaders: {},
initialOptions: InAppWebViewWidgetOptions(
initialOptions: InAppWebViewGroupOptions(
crossPlatform: InAppWebViewOptions(
clearCache: true,
debuggingEnabled: true
......
......@@ -29,7 +29,7 @@ class InAppWebViewOnLoadErrorTestState extends WidgetTestState {
child: InAppWebView(
initialUrl: "https://not-existing-domain.org/",
initialHeaders: {},
initialOptions: InAppWebViewWidgetOptions(
initialOptions: InAppWebViewGroupOptions(
crossPlatform: InAppWebViewOptions(
clearCache: true,
debuggingEnabled: true
......
......@@ -29,7 +29,7 @@ class InAppWebViewOnLoadHttpErrorTestState extends WidgetTestState {
child: InAppWebView(
initialUrl: "https://google.com/404",
initialHeaders: {},
initialOptions: InAppWebViewWidgetOptions(
initialOptions: InAppWebViewGroupOptions(
crossPlatform: InAppWebViewOptions(
clearCache: true,
debuggingEnabled: true
......
......@@ -29,7 +29,7 @@ class InAppWebViewOnLoadResourceCustomSchemeTestState extends WidgetTestState {
child: InAppWebView(
initialFile: "test_assets/in_app_webview_on_load_resource_custom_scheme_test.html",
initialHeaders: {},
initialOptions: InAppWebViewWidgetOptions(
initialOptions: InAppWebViewGroupOptions(
crossPlatform: InAppWebViewOptions(
clearCache: true,
debuggingEnabled: true,
......
......@@ -34,7 +34,7 @@ class InAppWebViewOnLoadResourceTestState extends WidgetTestState {
child: InAppWebView(
initialFile: "test_assets/in_app_webview_on_load_resource_test.html",
initialHeaders: {},
initialOptions: InAppWebViewWidgetOptions(
initialOptions: InAppWebViewGroupOptions(
crossPlatform: InAppWebViewOptions(
clearCache: true,
debuggingEnabled: true,
......
......@@ -28,7 +28,7 @@ class InAppWebViewOnNavigationStateChangeTestState extends WidgetTestState {
child: InAppWebView(
initialUrl: "https://flutter.dev/",
initialHeaders: {},
initialOptions: InAppWebViewWidgetOptions(
initialOptions: InAppWebViewGroupOptions(
crossPlatform: InAppWebViewOptions(
clearCache: true,
debuggingEnabled: true
......
......@@ -29,7 +29,7 @@ class InAppWebViewOnProgressChangedTestState extends WidgetTestState {
child: InAppWebView(
initialUrl: "https://flutter.dev/",
initialHeaders: {},
initialOptions: InAppWebViewWidgetOptions(
initialOptions: InAppWebViewGroupOptions(
crossPlatform: InAppWebViewOptions(
clearCache: true,
debuggingEnabled: true
......
......@@ -30,7 +30,7 @@ class InAppWebViewOnReceivedHttpAuthRequestTestState extends WidgetTestState {
child: InAppWebView(
initialUrl: "http://${environment["NODE_SERVER_IP"]}:8081/",
initialHeaders: {},
initialOptions: InAppWebViewWidgetOptions(
initialOptions: InAppWebViewGroupOptions(
crossPlatform: InAppWebViewOptions(
clearCache: true,
debuggingEnabled: true
......
......@@ -31,7 +31,7 @@ class InAppWebViewOnSafeBrowsingHitTestState extends WidgetTestState {
child: InAppWebView(
initialUrl: (Platform.isAndroid) ? "chrome://safe-browsing/match?type=malware" : "https://flutter.dev/",
initialHeaders: {},
initialOptions: InAppWebViewWidgetOptions(
initialOptions: InAppWebViewGroupOptions(
crossPlatform: InAppWebViewOptions(
// if I set javaScriptEnabled to true, it will crash!
javaScriptEnabled: false,
......
......@@ -30,7 +30,7 @@ class InAppWebViewOnScrollChangedTestState extends WidgetTestState {
child: InAppWebView(
initialUrl: "https://flutter.dev/",
initialHeaders: {},
initialOptions: InAppWebViewWidgetOptions(
initialOptions: InAppWebViewGroupOptions(
crossPlatform: InAppWebViewOptions(
clearCache: true,
debuggingEnabled: true
......
......@@ -28,7 +28,7 @@ class InAppWebViewShouldOverrideUrlLoadingTestState extends WidgetTestState {
child: InAppWebView(
initialFile: "test_assets/in_app_webview_initial_file_test.html",
initialHeaders: {},
initialOptions: InAppWebViewWidgetOptions(
initialOptions: InAppWebViewGroupOptions(
crossPlatform: InAppWebViewOptions(
clearCache: true,
debuggingEnabled: true,
......
......@@ -30,7 +30,7 @@ class InAppWebViewSslRequestTestState extends WidgetTestState {
child: InAppWebView(
initialUrl: "https://${environment["NODE_SERVER_IP"]}:4433/",
initialHeaders: {},
initialOptions: InAppWebViewWidgetOptions(
initialOptions: InAppWebViewGroupOptions(
crossPlatform: InAppWebViewOptions(
clearCache: true,
debuggingEnabled: true
......
......@@ -26,6 +26,7 @@
<excludeFolder url="file://$MODULE_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/example/.dart_tool" />
<excludeFolder url="file://$MODULE_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/example/.pub" />
<excludeFolder url="file://$MODULE_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/example/build" />
<excludeFolder url="file://$MODULE_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/example/ios/Flutter/App.framework/flutter_assets/packages" />
<excludeFolder url="file://$MODULE_DIR$/example/ios/Flutter/App.framework/flutter_assets/packages" />
<excludeFolder url="file://$MODULE_DIR$/flutter_inappbrowser_tests/.dart_tool" />
<excludeFolder url="file://$MODULE_DIR$/flutter_inappbrowser_tests/.pub" />
......
......@@ -41,7 +41,8 @@ public class ChromeSafariBrowserManager: NSObject, FlutterPlugin {
let uuidFallback: String = arguments!["uuidFallback"] as! String
let headersFallback = arguments!["headersFallback"] as! [String: String]
let optionsFallback = arguments!["optionsFallback"] as! [String: Any?]
open(uuid: uuid, url: url, options: options, uuidFallback: uuidFallback, headersFallback: headersFallback, optionsFallback: optionsFallback, result: result)
let menuItemList = arguments!["menuItemList"] as! [[String: Any]]
open(uuid: uuid, url: url, options: options, uuidFallback: uuidFallback, headersFallback: headersFallback, optionsFallback: optionsFallback, menuItemList: menuItemList, result: result)
break
default:
result(FlutterMethodNotImplemented)
......@@ -49,7 +50,7 @@ public class ChromeSafariBrowserManager: NSObject, FlutterPlugin {
}
}
public func open(uuid: String, url: String, options: [String: Any?], uuidFallback: String?, headersFallback: [String: String], optionsFallback: [String: Any?], result: @escaping FlutterResult) {
public func open(uuid: String, url: String, options: [String: Any?], uuidFallback: String?, headersFallback: [String: String], optionsFallback: [String: Any?], menuItemList: [[String: Any]], result: @escaping FlutterResult) {
let absoluteUrl = URL(string: url)!.absoluteURL
if self.previousStatusBarStyle == -1 {
......@@ -85,10 +86,12 @@ public class ChromeSafariBrowserManager: NSObject, FlutterPlugin {
}
safari.uuid = uuid
safari.menuItemList = menuItemList
safari.prepareMethodChannel()
safari.delegate = safari
safari.tmpWindow = tmpWindow
safari.safariOptions = safariOptions
safari.prepareSafariBrowser()
tmpController.present(safari, animated: true) {
result(true)
......
......@@ -12,22 +12,27 @@ public class FlutterWebViewController: FlutterMethodCallDelegate, FlutterPlatfor
private weak var registrar: FlutterPluginRegistrar?
var webView: InAppWebView?
var viewId: Int64 = 0
var viewId: Any = 0
var channel: FlutterMethodChannel?
var myView: UIView?
init(registrar: FlutterPluginRegistrar, withFrame frame: CGRect, viewIdentifier viewId: Int64, arguments args: NSDictionary) {
init(registrar: FlutterPluginRegistrar, withFrame frame: CGRect, viewIdentifier viewId: Any, arguments args: NSDictionary) {
super.init()
self.registrar = registrar
self.viewId = viewId
myView = UIView(frame: frame)
let channelName = "com.pichillilorenzo/flutter_inappwebview_" + String(viewId)
var channelName = ""
if let id = viewId as? Int64 {
channelName = "com.pichillilorenzo/flutter_inappwebview_" + String(id)
} else if let id = viewId as? String {
channelName = "com.pichillilorenzo/flutter_inappwebview_" + id
}
channel = FlutterMethodChannel(name: channelName, binaryMessenger: registrar.messenger())
channel!.setMethodCallHandler(LeakAvoider(delegate: self).handle)
myView = UIView(frame: frame)
let initialUrl = args["initialUrl"] as? String
let initialFile = args["initialFile"] as? String
let initialData = args["initialData"] as? [String: String]
......@@ -74,6 +79,20 @@ public class FlutterWebViewController: FlutterMethodCallDelegate, FlutterPlatfor
}
}
load(initialUrl: initialUrl, initialFile: initialFile, initialData: initialData, initialHeaders: initialHeaders)
if (frame.isEmpty && viewId is String) {
/// Note: The WKWebView behaves very unreliable when rendering offscreen
/// on a device. This is especially true with JavaScript, which simply
/// won't be executed sometimes.
/// Therefore, I decided to add this very ugly hack where the rendering
/// webview will be added to the view hierarchy (between the
/// rootViewController's view and the key window).
self.myView!.alpha = 0.01
UIApplication.shared.keyWindow!.insertSubview(self.myView!, at: 0)
let arguments: [String: Any] = ["uuid": viewId]
channel!.invokeMethod("onHeadlessWebViewCreated", arguments: arguments)
}
}
deinit {
......
//
// HeadlessInAppWebViewManager.swift
// flutter_inappwebview
//
// Created by Lorenzo Pichilli on 10/05/2020.
//
import Foundation
import Flutter
import UIKit
import WebKit
import Foundation
import AVFoundation
public class HeadlessInAppWebViewManager: NSObject, FlutterPlugin {
static var registrar: FlutterPluginRegistrar?
static var channel: FlutterMethodChannel?
var flutterWebViews: [String: FlutterWebViewController] = [:]
public static func register(with registrar: FlutterPluginRegistrar) {
}
init(registrar: FlutterPluginRegistrar) {
super.init()
HeadlessInAppWebViewManager.registrar = registrar
HeadlessInAppWebViewManager.channel = FlutterMethodChannel(name: "com.pichillilorenzo/flutter_headless_inappwebview", binaryMessenger: registrar.messenger())
registrar.addMethodCallDelegate(self, channel: HeadlessInAppWebViewManager.channel!)
}
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
let arguments = call.arguments as? NSDictionary
let uuid: String = arguments!["uuid"] as! String
switch call.method {
case "createHeadlessWebView":
let params = arguments!["params"] as! [String: Any?]
createHeadlessWebView(uuid: uuid, params: params)
result(true)
break
case "disposeHeadlessWebView":
disposeHeadlessWebView(uuid: uuid)
result(true)
break
default:
result(FlutterMethodNotImplemented)
break
}
}
public func createHeadlessWebView(uuid: String, params: [String: Any?]) {
let controller = FlutterWebViewController(registrar: HeadlessInAppWebViewManager.registrar!,
withFrame: CGRect.zero,
viewIdentifier: uuid,
arguments: params as NSDictionary)
flutterWebViews[uuid] = controller
}
public func disposeHeadlessWebView(uuid: String) {
if let _ = flutterWebViews[uuid] {
flutterWebViews.removeValue(forKey: uuid)
}
}
}
......@@ -15,6 +15,7 @@ public class SafariViewController: SFSafariViewController, FlutterPlugin, SFSafa
var tmpWindow: UIWindow?
var safariOptions: SafariBrowserOptions?
var uuid: String = ""
var menuItemList: [[String: Any]] = []
public static func register(with registrar: FlutterPluginRegistrar) {
......@@ -30,11 +31,20 @@ public class SafariViewController: SFSafariViewController, FlutterPlugin, SFSafa
}
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
let arguments = call.arguments as? NSDictionary
switch call.method {
case "close":
close()
break
default:
result(FlutterMethodNotImplemented)
break
}
}
public override func viewWillAppear(_ animated: Bool) {
prepareSafariBrowser()
// prepareSafariBrowser()
super.viewWillAppear(animated)
onChromeSafariBrowserOpened()
}
......@@ -83,23 +93,25 @@ public class SafariViewController: SFSafariViewController, FlutterPlugin, SFSafa
}
public func safariViewController(_ controller: SFSafariViewController, activityItemsFor URL: URL, title: String?) -> [UIActivity] {
// print("activityItemsFor")
// print(URL)
// print(title)
return []
var uiActivities: [UIActivity] = []
menuItemList.forEach { (menuItem) in
let activity = CustomUIActivity(uuid: uuid, id: menuItem["id"] as! Int64, url: URL, title: title, label: menuItem["label"] as? String, type: nil, image: nil)
uiActivities.append(activity)
}
return uiActivities
}
public func safariViewController(_ controller: SFSafariViewController, excludedActivityTypesFor URL: URL, title: String?) -> [UIActivity.ActivityType] {
//
// public func safariViewController(_ controller: SFSafariViewController, excludedActivityTypesFor URL: URL, title: String?) -> [UIActivity.ActivityType] {
// print("excludedActivityTypesFor")
// print(URL)
// print(title)
return []
}
public func safariViewController(_ controller: SFSafariViewController, initialLoadDidRedirectTo URL: URL) {
// return []
// }
//
// public func safariViewController(_ controller: SFSafariViewController, initialLoadDidRedirectTo URL: URL) {
// print("initialLoadDidRedirectTo")
// print(URL)
}
// }
public func onChromeSafariBrowserOpened() {
channel!.invokeMethod("onChromeSafariBrowserOpened", arguments: [])
......@@ -146,3 +158,54 @@ public class SafariViewController: SFSafariViewController, FlutterPlugin, SFSafa
return hexInt
}
}
class CustomUIActivity : UIActivity {
var uuid: String
var id: Int64
var url: URL
var title: String?
var type: UIActivity.ActivityType?
var label: String?
var image: UIImage?
init(uuid: String, id: Int64, url: URL, title: String?, label: String?, type: UIActivity.ActivityType?, image: UIImage?) {
self.uuid = uuid
self.id = id
self.url = url
self.title = title
self.label = label
self.type = type
self.image = image
}
override class var activityCategory: UIActivity.Category {
return .action
}
override var activityType: UIActivity.ActivityType? {
return type
}
override var activityTitle: String? {
return label
}
override var activityImage: UIImage? {
return image
}
override func canPerform(withActivityItems activityItems: [Any]) -> Bool {
return true
}
override func perform() {
let channel = FlutterMethodChannel(name: "com.pichillilorenzo/flutter_chromesafaribrowser_" + uuid, binaryMessenger: SwiftFlutterPlugin.instance!.registrar!.messenger())
let arguments: [String: Any?] = [
"url": url.absoluteString,
"title": title,
"id": id,
]
channel.invokeMethod("onChromeSafariBrowserMenuItemActionPerform", arguments: arguments)
}
}
......@@ -31,6 +31,7 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin {
var myWebStorageManager: Any?
var credentialDatabase: CredentialDatabase?
var inAppBrowserManager: InAppBrowserManager?
var headlessInAppWebViewManager: HeadlessInAppWebViewManager?
var chromeSafariBrowserManager: ChromeSafariBrowserManager?
var webViewControllers: [String: InAppBrowserWebViewController?] = [:]
......@@ -46,6 +47,7 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin {
registrar.register(FlutterWebViewFactory(registrar: registrar) as FlutterPlatformViewFactory, withId: "com.pichillilorenzo/flutter_inappwebview")
inAppBrowserManager = InAppBrowserManager(registrar: registrar)
headlessInAppWebViewManager = HeadlessInAppWebViewManager(registrar: registrar)
chromeSafariBrowserManager = ChromeSafariBrowserManager(registrar: registrar)
inAppWebViewStatic = InAppWebViewStatic(registrar: registrar)
if #available(iOS 11.0, *) {
......
......@@ -22,6 +22,9 @@
library flutter_inappwebview;
export 'src/types.dart';
export 'src/webview.dart';
export 'src/in_app_webview_controller.dart';
export 'src/headless_in_app_webview.dart';
export 'src/in_app_webview.dart';
export 'src/in_app_browser.dart';
export 'src/cookie_manager.dart';
......
import 'dart:async';
import 'dart:io';
import 'dart:collection';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
......@@ -7,8 +7,6 @@ import 'package:flutter/services.dart';
import 'types.dart';
import 'in_app_browser.dart';
///ChromeSafariBrowser class.
///
///This class uses native [Chrome Custom Tabs](https://developer.android.com/reference/android/support/customtabs/package-summary) on Android
///and [SFSafariViewController](https://developer.apple.com/documentation/safariservices/sfsafariviewcontroller) on iOS.
///
......@@ -16,6 +14,7 @@ import 'in_app_browser.dart';
class ChromeSafariBrowser {
String uuid;
InAppBrowser browserFallback;
Map<int, ChromeSafariBrowserMenuItem> _menuItems = new HashMap();
bool _isOpened = false;
MethodChannel _channel;
static const MethodChannel _sharedChannel = const MethodChannel('com.pichillilorenzo/flutter_chromesafaribrowser');
......@@ -42,6 +41,12 @@ class ChromeSafariBrowser {
onClosed();
this._isOpened = false;
break;
case "onChromeSafariBrowserMenuItemActionPerform":
String url = call.arguments["url"];
String title = call.arguments["title"];
int id = call.arguments["id"].toInt();
this._menuItems[id].action(url, title);
break;
default:
throw UnimplementedError("Unimplemented ${call.method} method");
}
......@@ -64,49 +69,45 @@ class ChromeSafariBrowser {
assert(url != null && url.isNotEmpty);
this.throwIsAlreadyOpened(message: 'Cannot open $url!');
Map<String, dynamic> optionsMap = {};
if (Platform.isAndroid)
optionsMap.addAll(options.android?.toMap() ?? {});
else if (Platform.isIOS)
optionsMap.addAll(options.ios?.toMap() ?? {});
Map<String, dynamic> optionsFallbackMap = {};
if (optionsFallback != null) {
optionsFallbackMap
.addAll(optionsFallback.crossPlatform?.toMap() ?? {});
optionsFallbackMap.addAll(optionsFallback
.inAppWebViewWidgetOptions?.crossPlatform
?.toMap() ??
{});
if (Platform.isAndroid) {
optionsFallbackMap
.addAll(optionsFallback.android?.toMap() ?? {});
optionsFallbackMap.addAll(optionsFallback
.inAppWebViewWidgetOptions?.android
?.toMap() ??
{});
} else if (Platform.isIOS) {
optionsFallbackMap
.addAll(optionsFallback.ios?.toMap() ?? {});
optionsFallbackMap.addAll(optionsFallback
.inAppWebViewWidgetOptions?.ios
?.toMap() ??
{});
}
}
List<Map<String, dynamic>> menuItemList = new List();
_menuItems.forEach((key, value) {
menuItemList.add({
"id": value.id,
"label": value.label
});
});
Map<String, dynamic> args = <String, dynamic>{};
args.putIfAbsent('uuid', () => uuid);
args.putIfAbsent('url', () => url);
args.putIfAbsent('options', () => optionsMap);
args.putIfAbsent('options', () => options?.toMap() ?? {});
args.putIfAbsent('uuidFallback',
() => (browserFallback != null) ? browserFallback.uuid : '');
args.putIfAbsent('headersFallback', () => headersFallback);
args.putIfAbsent('optionsFallback', () => optionsFallbackMap);
args.putIfAbsent('optionsFallback', () => optionsFallback?.toMap() ?? {});
args.putIfAbsent('menuItemList', () => menuItemList);
await _sharedChannel.invokeMethod('open', args);
this._isOpened = true;
}
///Closes the [ChromeSafariBrowser] instance.
Future<void> close() async {
Map<String, dynamic> args = <String, dynamic>{};
await _channel.invokeMethod("close", args);
}
///Adds a [ChromeSafariBrowserMenuItem] to the menu.
void addMenuItem(ChromeSafariBrowserMenuItem menuItem) {
this._menuItems[menuItem.id] = menuItem;
}
///Adds a list of [ChromeSafariBrowserMenuItem] to the menu.
void addMenuItems(List<ChromeSafariBrowserMenuItem> menuItems) {
menuItems.forEach((menuItem) {
this._menuItems[menuItem.id] = menuItem;
});
}
///Event fires when the [ChromeSafariBrowser] is opened.
void onOpened() {}
......@@ -137,3 +138,11 @@ class ChromeSafariBrowser {
}
}
}
class ChromeSafariBrowserMenuItem {
int id;
String label;
final void Function(String url, String title) action;
ChromeSafariBrowserMenuItem({@required this.id, @required this.label, @required this.action});
}
\ No newline at end of file
import 'package:flutter/foundation.dart';
import 'types.dart';
///ContentBlocker class represents a set of rules to use block content in the browser window.
///Class that represents a set of rules to use block content in the browser window.
///
///On iOS, it uses [WKContentRuleListStore](https://developer.apple.com/documentation/webkit/wkcontentruleliststore).
///On Android, it uses a custom implementation because such functionality doesn't exist.
......
......@@ -5,7 +5,7 @@ import 'package:flutter/services.dart';
import 'types.dart';
///CookieManager class implements a singleton object (shared instance) which manages the cookies used by WebView instances.
///Class that implements a singleton object (shared instance) which manages the cookies used by WebView instances.
///
///**NOTE for iOS**: available from iOS 11.0+.
class CookieManager {
......
import 'package:flutter/services.dart';
import 'types.dart';
import 'webview.dart';
import 'in_app_webview_controller.dart';
///Class that represents a WebView in headless mode.
///It can be used to run a WebView in background without attaching an `InAppWebView` to the widget tree.
///
///Remember to dispose it when you don't need it anymore.
class HeadlessInAppWebView implements WebView {
String uuid;
bool _isDisposed = true;
static const MethodChannel _sharedChannel = const MethodChannel('com.pichillilorenzo/flutter_headless_inappwebview');
///WebView Controller that can be used to access the [InAppWebViewController] API.
InAppWebViewController webViewController;
HeadlessInAppWebView(
{this.onWebViewCreated,
this.onLoadStart,
this.onLoadStop,
this.onLoadError,
this.onLoadHttpError,
this.onProgressChanged,
this.onConsoleMessage,
this.shouldOverrideUrlLoading,
this.onLoadResource,
this.onScrollChanged,
this.onDownloadStart,
this.onLoadResourceCustomScheme,
this.onCreateWindow,
this.onJsAlert,
this.onJsConfirm,
this.onJsPrompt,
this.onReceivedHttpAuthRequest,
this.onReceivedServerTrustAuthRequest,
this.onReceivedClientCertRequest,
this.onFindResultReceived,
this.shouldInterceptAjaxRequest,
this.onAjaxReadyStateChange,
this.onAjaxProgress,
this.shouldInterceptFetchRequest,
this.onUpdateVisitedHistory,
this.onPrint,
this.onLongPressHitTestResult,
this.androidOnSafeBrowsingHit,
this.androidOnPermissionRequest,
this.androidOnGeolocationPermissionsShowPrompt,
this.androidOnGeolocationPermissionsHidePrompt,
this.iosOnWebContentProcessDidTerminate,
this.iosOnDidCommit,
this.iosOnDidReceiveServerRedirectForProvisionalNavigation,
this.initialUrl,
this.initialFile,
this.initialData,
this.initialHeaders,
this.initialOptions}) {
uuid = uuidGenerator.v4();
webViewController = new InAppWebViewController(uuid, this);
}
Future<dynamic> handleMethod(MethodCall call) async {
switch (call.method) {
case "onHeadlessWebViewCreated":
onWebViewCreated(webViewController);
break;
default:
return webViewController.handleMethod(call);
}
}
///Runs the headless WebView.
Future<void> run() async {
if (!_isDisposed) {
return;
}
_isDisposed = false;
Map<String, dynamic> args = <String, dynamic>{};
args.putIfAbsent('uuid', () => uuid);
args.putIfAbsent('params', () => <String, dynamic>{
'initialUrl': '${Uri.parse(this.initialUrl)}',
'initialFile': this.initialFile,
'initialData': this.initialData?.toMap(),
'initialHeaders': this.initialHeaders,
'initialOptions': this.initialOptions?.toMap()
});
await _sharedChannel.invokeMethod('createHeadlessWebView', args);
}
///Disposes the headless WebView.
Future<void> dispose() async {
if (_isDisposed) {
return;
}
Map<String, dynamic> args = <String, dynamic>{};
args.putIfAbsent('uuid', () => uuid);
await _sharedChannel.invokeMethod('disposeHeadlessWebView', args);
_isDisposed = true;
}
@override
final Future<void> Function(InAppWebViewController controller)
androidOnGeolocationPermissionsHidePrompt;
@override
final Future<GeolocationPermissionShowPromptResponse> Function(
InAppWebViewController controller, String origin)
androidOnGeolocationPermissionsShowPrompt;
@override
final Future<PermissionRequestResponse> Function(
InAppWebViewController controller,
String origin,
List<String> resources) androidOnPermissionRequest;
@override
final Future<SafeBrowsingResponse> Function(InAppWebViewController controller,
String url, SafeBrowsingThreat threatType) androidOnSafeBrowsingHit;
@override
final InAppWebViewInitialData initialData;
@override
final String initialFile;
@override
final Map<String, String> initialHeaders;
@override
final InAppWebViewGroupOptions initialOptions;
@override
final String initialUrl;
@override
final Future<void> Function(InAppWebViewController controller) iosOnDidCommit;
@override
final Future<void> Function(InAppWebViewController controller)
iosOnDidReceiveServerRedirectForProvisionalNavigation;
@override
final Future<void> Function(InAppWebViewController controller)
iosOnWebContentProcessDidTerminate;
@override
final Future<AjaxRequestAction> Function(
InAppWebViewController controller, AjaxRequest ajaxRequest)
onAjaxProgress;
@override
final Future<AjaxRequestAction> Function(
InAppWebViewController controller, AjaxRequest ajaxRequest)
onAjaxReadyStateChange;
@override
final void Function(
InAppWebViewController controller, ConsoleMessage consoleMessage)
onConsoleMessage;
@override
final void Function(InAppWebViewController controller,
OnCreateWindowRequest onCreateWindowRequest) onCreateWindow;
@override
final void Function(InAppWebViewController controller, String url)
onDownloadStart;
@override
final void Function(InAppWebViewController controller, int activeMatchOrdinal,
int numberOfMatches, bool isDoneCounting) onFindResultReceived;
@override
final Future<JsAlertResponse> Function(
InAppWebViewController controller, String message) onJsAlert;
@override
final Future<JsConfirmResponse> Function(
InAppWebViewController controller, String message) onJsConfirm;
@override
final Future<JsPromptResponse> Function(InAppWebViewController controller,
String message, String defaultValue) onJsPrompt;
@override
final void Function(InAppWebViewController controller, String url, int code,
String message) onLoadError;
@override
final void Function(InAppWebViewController controller, String url,
int statusCode, String description) onLoadHttpError;
@override
final void Function(
InAppWebViewController controller, LoadedResource resource)
onLoadResource;
@override
final Future<CustomSchemeResponse> Function(
InAppWebViewController controller, String scheme, String url)
onLoadResourceCustomScheme;
@override
final void Function(InAppWebViewController controller, String url)
onLoadStart;
@override
final void Function(InAppWebViewController controller, String url) onLoadStop;
@override
final void Function(InAppWebViewController controller,
LongPressHitTestResult hitTestResult) onLongPressHitTestResult;
@override
final void Function(InAppWebViewController controller, String url) onPrint;
@override
final void Function(InAppWebViewController controller, int progress)
onProgressChanged;
@override
final Future<ClientCertResponse> Function(
InAppWebViewController controller, ClientCertChallenge challenge)
onReceivedClientCertRequest;
@override
final Future<HttpAuthResponse> Function(
InAppWebViewController controller, HttpAuthChallenge challenge)
onReceivedHttpAuthRequest;
@override
final Future<ServerTrustAuthResponse> Function(
InAppWebViewController controller, ServerTrustChallenge challenge)
onReceivedServerTrustAuthRequest;
@override
final void Function(InAppWebViewController controller, int x, int y)
onScrollChanged;
@override
final void Function(
InAppWebViewController controller, String url, bool androidIsReload)
onUpdateVisitedHistory;
@override
final void Function(InAppWebViewController controller) onWebViewCreated;
@override
final Future<AjaxRequest> Function(
InAppWebViewController controller, AjaxRequest ajaxRequest)
shouldInterceptAjaxRequest;
@override
final Future<FetchRequest> Function(
InAppWebViewController controller, FetchRequest fetchRequest)
shouldInterceptFetchRequest;
@override
final Future<ShouldOverrideUrlLoadingAction> Function(
InAppWebViewController controller,
ShouldOverrideUrlLoadingRequest shouldOverrideUrlLoadingRequest)
shouldOverrideUrlLoading;
}
\ No newline at end of file
......@@ -5,7 +5,7 @@ import 'package:flutter/foundation.dart';
import 'types.dart';
import 'package:flutter/services.dart';
///HttpAuthCredentialDatabase class implements a singleton object (shared instance) which manages the shared HTTP auth credentials cache.
///Class that implements a singleton object (shared instance) which manages the shared HTTP auth credentials cache.
///On iOS, this class uses the [URLCredentialStorage](https://developer.apple.com/documentation/foundation/urlcredentialstorage) class.
///On Android, this class has a custom implementation using `android.database.sqlite.SQLiteDatabase` because [WebViewDatabase](https://developer.android.com/reference/android/webkit/WebViewDatabase)
///doesn't offer the same functionalities as iOS `URLCredentialStorage`.
......
......@@ -4,14 +4,13 @@ import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'in_app_webview_controller.dart';
import 'webview_options.dart';
import 'types.dart';
import 'in_app_webview.dart' show InAppWebViewController;
///InAppBrowser class. [webViewController] can be used to access the [InAppWebView] API.
///
///This class uses the native WebView of the platform.
///The [webViewController] field can be used to access the [InAppWebViewController] API.
class InAppBrowser {
String uuid;
Map<String, JavaScriptHandlerCallback> javaScriptHandlersMap =
......@@ -20,7 +19,7 @@ class InAppBrowser {
MethodChannel _channel;
static const MethodChannel _sharedChannel = const MethodChannel('com.pichillilorenzo/flutter_inappbrowser');
/// WebView Controller that can be used to access the [InAppWebView] API.
/// WebView Controller that can be used to access the [InAppWebViewController] API.
InAppWebViewController webViewController;
///
......@@ -63,29 +62,11 @@ class InAppBrowser {
assert(url != null && url.isNotEmpty);
this.throwIsAlreadyOpened(message: 'Cannot open $url!');
Map<String, dynamic> optionsMap = {};
optionsMap.addAll(options.crossPlatform?.toMap() ?? {});
optionsMap.addAll(
options.inAppWebViewWidgetOptions?.crossPlatform?.toMap() ?? {});
if (Platform.isAndroid) {
optionsMap.addAll(options.android?.toMap() ?? {});
optionsMap.addAll(options
.inAppWebViewWidgetOptions?.android
?.toMap() ??
{});
} else if (Platform.isIOS) {
optionsMap.addAll(options.ios?.toMap() ?? {});
optionsMap.addAll(
options.inAppWebViewWidgetOptions?.ios?.toMap() ??
{});
}
Map<String, dynamic> args = <String, dynamic>{};
args.putIfAbsent('uuid', () => uuid);
args.putIfAbsent('url', () => url);
args.putIfAbsent('headers', () => headers);
args.putIfAbsent('options', () => optionsMap);
args.putIfAbsent('options', () => options?.toMap() ?? {});
await _sharedChannel.invokeMethod('openUrl', args);
}
......@@ -129,29 +110,13 @@ class InAppBrowser {
assert(assetFilePath != null && assetFilePath.isNotEmpty);
this.throwIsAlreadyOpened(message: 'Cannot open $assetFilePath!');
Map<String, dynamic> optionsMap = {};
optionsMap.addAll(options.crossPlatform?.toMap() ?? {});
optionsMap.addAll(
options.inAppWebViewWidgetOptions?.crossPlatform?.toMap() ?? {});
if (Platform.isAndroid) {
optionsMap.addAll(options.android?.toMap() ?? {});
optionsMap.addAll(options
.inAppWebViewWidgetOptions?.android
?.toMap() ??
{});
} else if (Platform.isIOS) {
optionsMap.addAll(options.ios?.toMap() ?? {});
optionsMap.addAll(
options.inAppWebViewWidgetOptions?.ios?.toMap() ??
{});
}
Map<String, dynamic> args = <String, dynamic>{};
args.putIfAbsent('uuid', () => uuid);
args.putIfAbsent('url', () => assetFilePath);
args.putIfAbsent('headers', () => headers);
args.putIfAbsent('options', () => optionsMap);
args.putIfAbsent('options', () => options?.toMap() ?? {});
await _sharedChannel.invokeMethod('openFile', args);
}
......@@ -173,27 +138,9 @@ class InAppBrowser {
InAppBrowserClassOptions options}) async {
assert(data != null);
Map<String, dynamic> optionsMap = {};
optionsMap.addAll(options.crossPlatform?.toMap() ?? {});
optionsMap.addAll(
options.inAppWebViewWidgetOptions?.crossPlatform?.toMap() ?? {});
if (Platform.isAndroid) {
optionsMap.addAll(options.android?.toMap() ?? {});
optionsMap.addAll(options
.inAppWebViewWidgetOptions?.android
?.toMap() ??
{});
} else if (Platform.isIOS) {
optionsMap.addAll(options.ios?.toMap() ?? {});
optionsMap.addAll(
options.inAppWebViewWidgetOptions?.ios?.toMap() ??
{});
}
Map<String, dynamic> args = <String, dynamic>{};
args.putIfAbsent('uuid', () => uuid);
args.putIfAbsent('options', () => optionsMap);
args.putIfAbsent('options', () => options?.toMap() ?? {});
args.putIfAbsent('data', () => data);
args.putIfAbsent('mimeType', () => mimeType);
args.putIfAbsent('encoding', () => encoding);
......@@ -243,26 +190,8 @@ class InAppBrowser {
Future<void> setOptions({@required InAppBrowserClassOptions options}) async {
this.throwIsNotOpened();
Map<String, dynamic> optionsMap = {};
optionsMap.addAll(options.crossPlatform?.toMap() ?? {});
optionsMap.addAll(
options.inAppWebViewWidgetOptions?.crossPlatform?.toMap() ?? {});
if (Platform.isAndroid) {
optionsMap.addAll(options.android?.toMap() ?? {});
optionsMap.addAll(options
.inAppWebViewWidgetOptions?.android
?.toMap() ??
{});
} else if (Platform.isIOS) {
optionsMap.addAll(options.ios?.toMap() ?? {});
optionsMap.addAll(
options.inAppWebViewWidgetOptions?.ios?.toMap() ??
{});
}
Map<String, dynamic> args = <String, dynamic>{};
args.putIfAbsent('options', () => optionsMap);
args.putIfAbsent('options', () => options?.toMap() ?? {});
await _channel.invokeMethod('setOptions', args);
}
......@@ -279,19 +208,19 @@ class InAppBrowser {
options = options.cast<String, dynamic>();
inAppBrowserClassOptions.crossPlatform =
InAppBrowserOptions.fromMap(options);
inAppBrowserClassOptions.inAppWebViewWidgetOptions = InAppWebViewWidgetOptions();
inAppBrowserClassOptions.inAppWebViewWidgetOptions.crossPlatform =
inAppBrowserClassOptions.inAppWebViewGroupOptions = InAppWebViewGroupOptions();
inAppBrowserClassOptions.inAppWebViewGroupOptions.crossPlatform =
InAppWebViewOptions.fromMap(options);
if (Platform.isAndroid) {
inAppBrowserClassOptions.android =
AndroidInAppBrowserOptions.fromMap(options);
inAppBrowserClassOptions
.inAppWebViewWidgetOptions.android =
.inAppWebViewGroupOptions.android =
AndroidInAppWebViewOptions.fromMap(options);
} else if (Platform.isIOS) {
inAppBrowserClassOptions.ios =
IOSInAppBrowserOptions.fromMap(options);
inAppBrowserClassOptions.inAppWebViewWidgetOptions
inAppBrowserClassOptions.inAppWebViewGroupOptions
.ios = IOSInAppWebViewOptions.fromMap(options);
}
}
......
......@@ -4,8 +4,6 @@ import 'dart:async';
import 'package:flutter/services.dart' show rootBundle;
import 'package:mime/mime.dart';
///InAppLocalhostServer class.
///
///This class allows you to create a simple server on `http://localhost:[port]/` in order to be able to load your assets file on a server. The default [port] value is `8080`.
class InAppLocalhostServer {
HttpServer _server;
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -5,7 +5,7 @@ import 'package:flutter/services.dart';
import 'types.dart';
///WebStorageManager class implements a singleton object (shared instance) which manages the web storage used by WebView instances.
///Class that implements a singleton object (shared instance) which manages the web storage used by WebView instances.
///
///**NOTE for iOS**: available from iOS 9.0+.
class WebStorageManager {
......@@ -30,7 +30,7 @@ class WebStorageManager {
static Future<dynamic> _handleMethod(MethodCall call) async {}
}
///AndroidWebStorageManager class is used to manage the JavaScript storage APIs provided by the WebView.
///Class that is used to manage the JavaScript storage APIs provided by the WebView.
///It manages the Application Cache API, the Web SQL Database API and the HTML5 Web Storage API.
class AndroidWebStorageManager {
///Gets the origins currently using either the Application Cache or Web SQL Database APIs.
......@@ -83,7 +83,7 @@ class AndroidWebStorageManager {
}
}
///IOSWebStorageManager class represents various types of data that a website might make use of.
///Class that represents various types of data that a website might make use of.
///This includes cookies, disk and memory caches, and persistent data such as WebSQL, IndexedDB databases, and local storage.
///
///**NOTE**: available on iOS 9.0+.
......
This diff is collapsed.
name: flutter_inappwebview
description: A Flutter plugin that allows you to add an inline webview or open an in-app browser window.
version: 3.0.0
version: 3.1.0
homepage: https://github.com/pichillilorenzo/flutter_inappwebview
environment:
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment