Commit b9fb01f1 authored by Lorenzo Pichilli's avatar Lorenzo Pichilli

fix #225, merged #228, updated ios options naming, updated default value for...

fix #225, merged #228, updated ios options naming, updated default value for databaseEnabled android option, added new methods and events
parent 5e272c46
This diff is collapsed.
## 3.0.0 ## 3.0.0
- Updated for Flutter 1.12 new Java Embedding API (Android)
- Updated `clearCache` for Android
- Added `Promise` javascript [polyfill](https://github.com/taylorhakes/promise-polyfill/blob/master/src/index.js) for webviews that doesn't support it for `window.flutter_inappwebview.callHandler` - Added `Promise` javascript [polyfill](https://github.com/taylorhakes/promise-polyfill/blob/master/src/index.js) for webviews that doesn't support it for `window.flutter_inappwebview.callHandler`
- Added `getDefaultUserAgent` static method to `InAppWebViewController` - Added `getDefaultUserAgent` static method to `InAppWebViewController`
- Added `printCurrentPage` method to `InAppWebViewController` - Added `onUpdateVisitedHistory`, `onPrint` event
- Added `onPrint` event - Added `onGeolocationPermissionsHidePrompt` event for Android
- Added `supportMultipleWindows` webview option for Android - Added `supportMultipleWindows` webview option for Android
- Added `regexToCancelSubFramesLoading` webview option for Android to cancel subframe requests on `shouldOverrideUrlLoading` event based on a Regular Expression - Added `regexToCancelSubFramesLoading` webview option for Android to cancel subframe requests on `shouldOverrideUrlLoading` event based on a Regular Expression
- Updated default value for `domStorageEnabled` option to `true` for Android - Added `getContentHeight`, `zoomBy`, `printCurrentPage`, `getScale` methods
- Fix for Android `InAppBrowser` for some controller methods not exposed. - Added `getOriginalUrl` webview method for Android
- Added `reloadFromOrigin` webview method for iOS
- Added `automaticallyAdjustsScrollIndicatorInsets` webview options for iOS
- Added `WebStorageManager` class which manages the web storage used by WebView instances
- Updated for Flutter 1.12 new Java Embedding API (Android)
- Updated `clearCache` for Android
- Updated default value for `domStorageEnabled` and `databaseEnabled` options to `true` for Android
- Merge "Fixes null error when calling getOptions for InAppBrowser class" [#214](https://github.com/pichillilorenzo/flutter_inappwebview/pull/214) (thanks to [panndoraBoo](https://github.com/panndoraBoo)) - Merge "Fixes null error when calling getOptions for InAppBrowser class" [#214](https://github.com/pichillilorenzo/flutter_inappwebview/pull/214) (thanks to [panndoraBoo](https://github.com/panndoraBoo))
- Added `dropDownWorkaroundEnabled` webview option for Android to enable a temporary workaround for html dropdowns (issue [#182](https://github.com/pichillilorenzo/flutter_inappwebview/issues/182)) - Merge "Fixes crash onConsoleMessage iOS forced unwrapping" [#228](https://github.com/pichillilorenzo/flutter_inappwebview/pull/228) (thanks to [tokonu](https://github.com/tokonu))
- Fix for Android and iOS `InAppBrowser` for some controller methods not exposed.
- Fixed "App Crashes after clicking on dropdown (Using inappwebview)" [#182](https://github.com/pichillilorenzo/flutter_inappwebview/issues/182) - Fixed "App Crashes after clicking on dropdown (Using inappwebview)" [#182](https://github.com/pichillilorenzo/flutter_inappwebview/issues/182)
- Fixed "webview can not be released when in ios" [#225](https://github.com/pichillilorenzo/flutter_inappwebview/issues/225). Now the iOS WebView is released from memory when it is disposed from Flutter.
### BREAKING CHANGES ### BREAKING CHANGES
...@@ -21,6 +27,14 @@ ...@@ -21,6 +27,14 @@
- it has a return type `ShouldOverrideUrlLoadingAction` to allow or cancel navigation instead of cancel every time the request - it has a return type `ShouldOverrideUrlLoadingAction` to allow or cancel navigation instead of cancel every time the request
- Renamed `onTargetBlank` to `onCreateWindow` - Renamed `onTargetBlank` to `onCreateWindow`
- Deleted `useOnTargetBlank` webview option - Deleted `useOnTargetBlank` webview option
- Making methods available only for the specific platform more explicit: moved all the webview's controller methods for Android inside `controller.android` and all the webview's controller methods for iOS inside `controller.ios`
- Making events available only for the specific platform more explicit:
- Renamed `onSafeBrowsingHit` to `androidOnSafeBrowsingHit`
- Renamed `onGeolocationPermissionsShowPrompt` to `androidOnGeolocationPermissionsShowPrompt`
- Renamed `onPermissionRequest` to `androidOnPermissionRequest`
- Updated attribute names for `InAppWebViewWidgetOptions`, `InAppBrowserClassOptions` and `ChromeSafariBrowserClassOptions` classes
- Renamed and updated `onNavigationStateChange` to `onUpdateVisitedHistory`
- Renamed all iOS options prefix from `Ios` to `IOS`
## 2.1.0+1 ## 2.1.0+1
......
This diff is collapsed.
...@@ -354,6 +354,24 @@ public class FlutterWebView implements PlatformView, MethodCallHandler { ...@@ -354,6 +354,24 @@ public class FlutterWebView implements PlatformView, MethodCallHandler {
result.success(false); result.success(false);
} }
break; break;
case "getContentHeight":
result.success((webView != null) ? webView.getContentHeight() : null);
break;
case "zoomBy":
if (webView != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
Float zoomFactor = (Float) call.argument("zoomFactor");
webView.zoomBy(zoomFactor);
result.success(true);
} else {
result.success(false);
}
break;
case "getOriginalUrl":
result.success((webView != null) ? webView.getOriginalUrl() : null);
break;
case "getScale":
result.success((webView != null) ? webView.getUpdatedScale() : null);
break;
default: default:
result.notImplemented(); result.notImplemented();
} }
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
package com.pichillilorenzo.flutter_inappwebview; package com.pichillilorenzo.flutter_inappwebview;
import android.app.Activity; import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
...@@ -133,7 +134,7 @@ public class InAppBrowser implements MethodChannel.MethodCallHandler { ...@@ -133,7 +134,7 @@ public class InAppBrowser implements MethodChannel.MethodCallHandler {
Intent intent = new Intent(Intent.ACTION_DIAL); Intent intent = new Intent(Intent.ACTION_DIAL);
intent.setData(Uri.parse(url)); intent.setData(Uri.parse(url));
activity.startActivity(intent); activity.startActivity(intent);
} catch (android.content.ActivityNotFoundException e) { } catch (ActivityNotFoundException e) {
Log.e(LOG_TAG, "Error dialing " + url + ": " + e.toString()); Log.e(LOG_TAG, "Error dialing " + url + ": " + e.toString());
} }
} }
...@@ -348,6 +349,22 @@ public class InAppBrowser implements MethodChannel.MethodCallHandler { ...@@ -348,6 +349,22 @@ public class InAppBrowser implements MethodChannel.MethodCallHandler {
} }
result.success(true); result.success(true);
break; break;
case "getContentHeight":
result.success(getContentHeight(uuid));
break;
case "zoomBy":
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
Float zoomFactor = (Float) call.argument("zoomFactor");
zoomBy(uuid, zoomFactor);
}
result.success(true);
break;
case "getOriginalUrl":
result.success(getOriginalUrl(uuid));
break;
case "getScale":
result.success(getScale(uuid));
break;
default: default:
result.notImplemented(); result.notImplemented();
} }
...@@ -814,6 +831,34 @@ public class InAppBrowser implements MethodChannel.MethodCallHandler { ...@@ -814,6 +831,34 @@ public class InAppBrowser implements MethodChannel.MethodCallHandler {
inAppBrowserActivity.printCurrentPage(); inAppBrowserActivity.printCurrentPage();
} }
public Integer getContentHeight(String uuid) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
return inAppBrowserActivity.getContentHeight();
return null;
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public void zoomBy(String uuid, Float zoomFactor) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
inAppBrowserActivity.zoomBy(zoomFactor);
}
public String getOriginalUrl(String uuid) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
return inAppBrowserActivity.getOriginalUrl();
return null;
}
public Float getScale(String uuid) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
return inAppBrowserActivity.getScale();
return null;
}
public void dispose() { public void dispose() {
channel.setMethodCallHandler(null); channel.setMethodCallHandler(null);
for ( InAppBrowserActivity activity : webViewActivities.values()) { for ( InAppBrowserActivity activity : webViewActivities.values()) {
......
...@@ -575,4 +575,27 @@ public class InAppBrowserActivity extends AppCompatActivity { ...@@ -575,4 +575,27 @@ public class InAppBrowserActivity extends AppCompatActivity {
webView.printCurrentPage(); webView.printCurrentPage();
} }
public Integer getContentHeight() {
if (webView != null)
return webView.getContentHeight();
return null;
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public void zoomBy(Float zoomFactor) {
if (webView != null)
webView.zoomBy(zoomFactor);
}
public String getOriginalUrl() {
if (webView != null)
return webView.getOriginalUrl();
return null;
}
public Float getScale() {
if (webView != null)
return webView.getUpdatedScale();
return null;
}
} }
...@@ -1342,69 +1342,8 @@ final public class InAppWebView extends InputAwareWebView { ...@@ -1342,69 +1342,8 @@ final public class InAppWebView extends InputAwareWebView {
new PrintAttributes.Builder().build()); new PrintAttributes.Builder().build());
} }
public void showDropDownWorkaround(final List<Integer> selectedValues, final List<List<String>> values, final boolean isMultiSelect, final DropDownWorkaroundCallback callback) { public Float getUpdatedScale() {
FrameLayout layout = new FrameLayout(Shared.activity); return scale;
final List<String> listViewValues = new ArrayList<String>();
for(List<String> value : values) {
listViewValues.add(value.get(0));
}
ListView listView = new ListView(Shared.activity);
ArrayAdapter<String> spinnerArrayAdapter = new ArrayAdapter<String>(Shared.activity, (!isMultiSelect) ? android.R.layout.simple_list_item_1 : android.R.layout.simple_list_item_multiple_choice, listViewValues);
spinnerArrayAdapter.setDropDownViewResource(android.R.layout.simple_list_item_multiple_choice);
listView.setAdapter(spinnerArrayAdapter);
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(Shared.activity, R.style.Theme_AppCompat_Dialog_Alert);
final AlertDialog alertDialog = alertDialogBuilder.create();
final List<String> result = new ArrayList<>();
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
String value = values.get(position).get(1);
if (!isMultiSelect) {
result.add(value);
alertDialog.dismiss();
} else {
if (!result.contains(value)) {
result.add(value);
} else {
result.remove(value);
}
}
}
});
if (isMultiSelect) {
listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
listView.setItemsCanFocus(false);
for(Integer selectedValueIndex : selectedValues) {
listView.setItemChecked(selectedValueIndex, true);
String value = values.get(selectedValueIndex).get(1);
result.add(value);
}
}
alertDialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialog) {
callback.result(result);
}
});
layout.addView(listView);
alertDialog.setView(layout);
alertDialog.show();
}
public static class DropDownWorkaroundCallback {
public void result(List<String> value) {
}
} }
@Override @Override
......
...@@ -411,10 +411,13 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR ...@@ -411,10 +411,13 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
} }
@Override @Override
public boolean onCreateWindow(WebView view, boolean isDialog, boolean userGesture, final Message resultMsg) { public boolean onCreateWindow(WebView view, boolean isDialog, boolean isUserGesture, final Message resultMsg) {
final Map<String, Object> obj = new HashMap<>(); final Map<String, Object> obj = new HashMap<>();
if (inAppBrowserActivity != null) if (inAppBrowserActivity != null)
obj.put("uuid", inAppBrowserActivity.uuid); obj.put("uuid", inAppBrowserActivity.uuid);
obj.put("androidIsDialog", isDialog);
obj.put("androidIsUserGesture", isUserGesture);
obj.put("iosWKNavigationType", null);
WebView.HitTestResult result = view.getHitTestResult(); WebView.HitTestResult result = view.getHitTestResult();
String data = result.getExtra(); String data = result.getExtra();
...@@ -478,6 +481,14 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR ...@@ -478,6 +481,14 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
}); });
} }
@Override
public void onGeolocationPermissionsHidePrompt() {
Map<String, Object> obj = new HashMap<>();
if (inAppBrowserActivity != null)
obj.put("uuid", inAppBrowserActivity.uuid);
getChannel().invokeMethod("onGeolocationPermissionsHidePrompt", obj);
}
@Override @Override
public boolean onConsoleMessage(ConsoleMessage consoleMessage) { public boolean onConsoleMessage(ConsoleMessage consoleMessage) {
Map<String, Object> obj = new HashMap<>(); Map<String, Object> obj = new HashMap<>();
......
...@@ -17,6 +17,7 @@ import android.webkit.SslErrorHandler; ...@@ -17,6 +17,7 @@ import android.webkit.SslErrorHandler;
import android.webkit.ValueCallback; import android.webkit.ValueCallback;
import android.webkit.WebResourceRequest; import android.webkit.WebResourceRequest;
import android.webkit.WebResourceResponse; import android.webkit.WebResourceResponse;
import android.webkit.WebStorage;
import android.webkit.WebView; import android.webkit.WebView;
import android.webkit.WebViewClient; import android.webkit.WebViewClient;
...@@ -54,7 +55,6 @@ public class InAppWebViewClient extends WebViewClient { ...@@ -54,7 +55,6 @@ public class InAppWebViewClient extends WebViewClient {
private InAppBrowserActivity inAppBrowserActivity; private InAppBrowserActivity inAppBrowserActivity;
private static int previousAuthRequestFailureCount = 0; private static int previousAuthRequestFailureCount = 0;
private static List<Credential> credentialsProposed = null; private static List<Credential> credentialsProposed = null;
private String onPageStartedURL = "";
public InAppWebViewClient(Object obj) { public InAppWebViewClient(Object obj) {
super(); super();
...@@ -188,7 +188,6 @@ public class InAppWebViewClient extends WebViewClient { ...@@ -188,7 +188,6 @@ public class InAppWebViewClient extends WebViewClient {
webView.loadUrl("javascript:" + js); webView.loadUrl("javascript:" + js);
} }
onPageStartedURL = url;
super.onPageStarted(view, url, favicon); super.onPageStarted(view, url, favicon);
webView.isLoading = true; webView.isLoading = true;
...@@ -241,16 +240,14 @@ public class InAppWebViewClient extends WebViewClient { ...@@ -241,16 +240,14 @@ public class InAppWebViewClient extends WebViewClient {
@Override @Override
public void doUpdateVisitedHistory (WebView view, String url, boolean isReload) { public void doUpdateVisitedHistory (WebView view, String url, boolean isReload) {
super.doUpdateVisitedHistory(view, url, isReload); Map<String, Object> obj = new HashMap<>();
if (inAppBrowserActivity != null)
obj.put("uuid", inAppBrowserActivity.uuid);
obj.put("url", url);
obj.put("androidIsReload", isReload);
getChannel().invokeMethod("onUpdateVisitedHistory", obj);
if (!isReload && !url.equals(onPageStartedURL)) { super.doUpdateVisitedHistory(view, url, isReload);
onPageStartedURL = "";
Map<String, Object> obj = new HashMap<>();
if (inAppBrowserActivity != null)
obj.put("uuid", inAppBrowserActivity.uuid);
obj.put("url", url);
getChannel().invokeMethod("onNavigationStateChange", obj);
}
} }
@Override @Override
......
...@@ -23,6 +23,7 @@ public class InAppWebViewFlutterPlugin implements FlutterPlugin, ActivityAware { ...@@ -23,6 +23,7 @@ public class InAppWebViewFlutterPlugin implements FlutterPlugin, ActivityAware {
public static InAppWebViewStatic inAppWebViewStatic; public static InAppWebViewStatic inAppWebViewStatic;
public static MyCookieManager myCookieManager; public static MyCookieManager myCookieManager;
public static CredentialDatabaseHandler credentialDatabaseHandler; public static CredentialDatabaseHandler credentialDatabaseHandler;
public static MyWebStorage myWebStorage;
public static ValueCallback<Uri[]> uploadMessageArray; public static ValueCallback<Uri[]> uploadMessageArray;
public InAppWebViewFlutterPlugin() {} public InAppWebViewFlutterPlugin() {}
...@@ -52,6 +53,7 @@ public class InAppWebViewFlutterPlugin implements FlutterPlugin, ActivityAware { ...@@ -52,6 +53,7 @@ public class InAppWebViewFlutterPlugin implements FlutterPlugin, ActivityAware {
"com.pichillilorenzo/flutter_inappwebview", new FlutterWebViewFactory(messenger, flutterView)); "com.pichillilorenzo/flutter_inappwebview", new FlutterWebViewFactory(messenger, flutterView));
inAppWebViewStatic = new InAppWebViewStatic(messenger); inAppWebViewStatic = new InAppWebViewStatic(messenger);
myCookieManager = new MyCookieManager(messenger); myCookieManager = new MyCookieManager(messenger);
myWebStorage = new MyWebStorage(messenger);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
credentialDatabaseHandler = new CredentialDatabaseHandler(messenger); credentialDatabaseHandler = new CredentialDatabaseHandler(messenger);
} }
...@@ -67,6 +69,10 @@ public class InAppWebViewFlutterPlugin implements FlutterPlugin, ActivityAware { ...@@ -67,6 +69,10 @@ public class InAppWebViewFlutterPlugin implements FlutterPlugin, ActivityAware {
myCookieManager.dispose(); myCookieManager.dispose();
myCookieManager = null; myCookieManager = null;
} }
if (myWebStorage != null) {
myWebStorage.dispose();
myWebStorage = null;
}
if (credentialDatabaseHandler != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { if (credentialDatabaseHandler != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
credentialDatabaseHandler.dispose(); credentialDatabaseHandler.dispose();
credentialDatabaseHandler = null; credentialDatabaseHandler = null;
......
...@@ -273,51 +273,6 @@ public class JavaScriptBridgeInterface { ...@@ -273,51 +273,6 @@ public class JavaScriptBridgeInterface {
@Override @Override
public void run() { public void run() {
// workaround for https://github.com/pichillilorenzo/flutter_inappwebview/issues/182
if (handlerName.equals("flutterInAppWebViewDropDownWorkaround")) {
try {
JSONArray jsonArray = new JSONArray(args);
List<Integer> selectedValues = new ArrayList<>();
JSONArray jsonSelectedValues = jsonArray.getJSONArray(0);
for(int i = 0; i < jsonSelectedValues.length(); i++) {
Integer selectedValue = jsonSelectedValues.getInt(i);
selectedValues.add(selectedValue);
}
boolean isMultiSelect = jsonArray.getBoolean(1);
List<List<String>> values = new ArrayList<>();
JSONArray options = jsonArray.getJSONArray(2);
for(int i = 0; i < options.length(); i++) {
JSONObject option = options.getJSONObject(i);
List<String> value = new ArrayList<>();
value.add(option.getString("key"));
value.add(option.getString("value"));
values.add(value);
}
webView.showDropDownWorkaround(selectedValues, values, isMultiSelect, new InAppWebView.DropDownWorkaroundCallback() {
@Override
public void result(List<String> values) {
String value = "{values: " + (new JSONArray(values)) + "}";
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
webView.evaluateJavascript("if(window." + name + "[" + _callHandlerID + "] != null) {window." + name + "[" + _callHandlerID + "](" + value + "); delete window." + name + "[" + _callHandlerID + "];}", (ValueCallback<String>) null);
}
else {
webView.loadUrl("javascript:if(window." + name + "[" + _callHandlerID + "] != null) {window." + name + "[" + _callHandlerID + "](" + value + "); delete window." + name + "[" + _callHandlerID + "];}");
}
}
});
} catch (JSONException e) {
e.printStackTrace();
}
return;
}
if (handlerName.equals("onPrint") && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { if (handlerName.equals("onPrint") && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
webView.printCurrentPage(); webView.printCurrentPage();
} }
......
package com.pichillilorenzo.flutter_inappwebview;
import android.util.Log;
import android.webkit.ValueCallback;
import android.webkit.WebStorage;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
public class MyWebStorage implements MethodChannel.MethodCallHandler {
static final String LOG_TAG = "MyWebStorage";
public static MethodChannel channel;
public static WebStorage webStorageManager;
public MyWebStorage(BinaryMessenger messenger) {
channel = new MethodChannel(messenger, "com.pichillilorenzo/flutter_inappwebview_webstoragemanager");
channel.setMethodCallHandler(this);
webStorageManager = WebStorage.getInstance();
}
@Override
public void onMethodCall(MethodCall call, MethodChannel.Result result) {
switch (call.method) {
case "getOrigins":
getOrigins(result);
break;
case "deleteAllData":
webStorageManager.deleteAllData();
result.success(true);
break;
case "deleteOrigin":
{
String origin = (String) call.argument("origin");
webStorageManager.deleteOrigin(origin);
}
result.success(true);
break;
case "getQuotaForOrigin":
{
String origin = (String) call.argument("origin");
getQuotaForOrigin(origin, result);
}
break;
case "getUsageForOrigin":
{
String origin = (String) call.argument("origin");
getUsageForOrigin(origin, result);
}
break;
default:
result.notImplemented();
}
}
public void getOrigins(final MethodChannel.Result result) {
webStorageManager.getOrigins(new ValueCallback<Map>() {
@Override
public void onReceiveValue(Map value) {
List<Map<String, Object>> origins = new ArrayList<>();
for(Object key : value.keySet()) {
WebStorage.Origin originObj = (WebStorage.Origin) value.get(key);
Map<String, Object> originInfo = new HashMap<>();
originInfo.put("origin", originObj.getOrigin());
originInfo.put("quota", originObj.getQuota());
originInfo.put("usage", originObj.getUsage());
origins.add(originInfo);
}
result.success(origins);
}
});
}
public void getQuotaForOrigin(String origin, final MethodChannel.Result result) {
webStorageManager.getQuotaForOrigin(origin, new ValueCallback<Long>() {
@Override
public void onReceiveValue(Long value) {
result.success(value);
}
});
}
public void getUsageForOrigin(String origin, final MethodChannel.Result result) {
webStorageManager.getUsageForOrigin(origin, new ValueCallback<Long>() {
@Override
public void onReceiveValue(Long value) {
result.success(value);
}
});
}
public void dispose() {
channel.setMethodCallHandler(null);
}
}
#
# NOTE: This podspec is NOT to be published. It is only used as a local source!
#
Pod::Spec.new do |s|
s.name = 'Flutter'
s.version = '1.0.0'
s.summary = 'High-performance, high-fidelity mobile apps.'
s.description = <<-DESC
Flutter provides an easy and productive way to build and deploy high-performance mobile apps for Android and iOS.
DESC
s.homepage = 'https://flutter.io'
s.license = { :type => 'MIT' }
s.author = { 'Flutter Dev Team' => 'flutter-dev@googlegroups.com' }
s.source = { :git => 'https://github.com/flutter/engine', :tag => s.version.to_s }
s.ios.deployment_target = '8.0'
s.vendored_frameworks = 'Flutter.framework'
end
...@@ -52,8 +52,8 @@ class _ChromeSafariBrowserExampleScreenState ...@@ -52,8 +52,8 @@ class _ChromeSafariBrowserExampleScreenState
await widget.browser.open( await widget.browser.open(
url: "https://flutter.dev/", url: "https://flutter.dev/",
options: ChromeSafariBrowserClassOptions( options: ChromeSafariBrowserClassOptions(
androidChromeCustomTabsOptions: AndroidChromeCustomTabsOptions(addShareButton: false), android: AndroidChromeCustomTabsOptions(addShareButton: false),
iosSafariOptions: IosSafariOptions(barCollapsingEnabled: true))); ios: IOSSafariOptions(barCollapsingEnabled: true)));
}, },
child: Text("Open Chrome Safari Browser")), child: Text("Open Chrome Safari Browser")),
)); ));
......
...@@ -92,7 +92,7 @@ class _InAppBrowserExampleScreenState extends State<InAppBrowserExampleScreen> { ...@@ -92,7 +92,7 @@ class _InAppBrowserExampleScreenState extends State<InAppBrowserExampleScreen> {
assetFilePath: "assets/index.html", assetFilePath: "assets/index.html",
options: InAppBrowserClassOptions( options: InAppBrowserClassOptions(
inAppWebViewWidgetOptions: InAppWebViewWidgetOptions( inAppWebViewWidgetOptions: InAppWebViewWidgetOptions(
inAppWebViewOptions: InAppWebViewOptions( crossPlatform: InAppWebViewOptions(
useShouldOverrideUrlLoading: true, useShouldOverrideUrlLoading: true,
useOnLoadResource: true, useOnLoadResource: true,
)))); ))));
......
...@@ -50,9 +50,10 @@ class _InAppWebViewExampleScreenState extends State<InAppWebViewExampleScreen> { ...@@ -50,9 +50,10 @@ class _InAppWebViewExampleScreenState extends State<InAppWebViewExampleScreen> {
BoxDecoration(border: Border.all(color: Colors.blueAccent)), BoxDecoration(border: Border.all(color: Colors.blueAccent)),
child: InAppWebView( child: InAppWebView(
initialUrl: "https://flutter.dev/", initialUrl: "https://flutter.dev/",
//initialFile: "assets/index.html",
initialHeaders: {}, initialHeaders: {},
initialOptions: InAppWebViewWidgetOptions( initialOptions: InAppWebViewWidgetOptions(
inAppWebViewOptions: InAppWebViewOptions( crossPlatform: InAppWebViewOptions(
debuggingEnabled: true, debuggingEnabled: true,
) )
), ),
...@@ -60,23 +61,49 @@ class _InAppWebViewExampleScreenState extends State<InAppWebViewExampleScreen> { ...@@ -60,23 +61,49 @@ class _InAppWebViewExampleScreenState extends State<InAppWebViewExampleScreen> {
webView = controller; webView = controller;
}, },
onLoadStart: (InAppWebViewController controller, String url) { onLoadStart: (InAppWebViewController controller, String url) {
print("onLoadStart $url");
setState(() { setState(() {
this.url = url; this.url = url;
}); });
}, },
onLoadStop: (InAppWebViewController controller, String url) async { onLoadStop: (InAppWebViewController controller, String url) async {
print("onLoadStop $url");
setState(() { setState(() {
this.url = url; this.url = url;
}); });
/*var origins = await WebStorageManager.instance().android.getOrigins();
for (var origin in origins) {
print(origin);
print(await WebStorageManager.instance().android.getQuotaForOrigin(origin: origin.origin));
print(await WebStorageManager.instance().android.getUsageForOrigin(origin: origin.origin));
}
await WebStorageManager.instance().android.deleteAllData();
print("\n\nDELETED\n\n");
origins = await WebStorageManager.instance().android.getOrigins();
for (var origin in origins) {
print(origin);
await WebStorageManager.instance().android.deleteOrigin(origin: origin.origin);
}*/
/*var records = await WebStorageManager.instance().ios.fetchDataRecords(dataTypes: IOSWKWebsiteDataType.ALL);
for(var record in records) {
print(record);
}
await WebStorageManager.instance().ios.removeDataModifiedSince(dataTypes: IOSWKWebsiteDataType.ALL, date: DateTime(0));
print("\n\nDELETED\n\n");
records = await WebStorageManager.instance().ios.fetchDataRecords(dataTypes: IOSWKWebsiteDataType.ALL);
for(var record in records) {
print(record);
}*/
}, },
onNavigationStateChange: (InAppWebViewController controller, String url) async { onProgressChanged: (InAppWebViewController controller, int progress) {
setState(() { setState(() {
this.url = url; this.progress = progress / 100;
}); });
}, },
onProgressChanged: (InAppWebViewController controller, int progress) { onUpdateVisitedHistory: (InAppWebViewController controller, String url, bool androidIsReload) {
print("onUpdateVisitedHistory $url");
setState(() { setState(() {
this.progress = progress / 100; this.url = url;
}); });
}, },
), ),
......
...@@ -57,7 +57,7 @@ class InAppWebViewAjaxTestState extends WidgetTestState { ...@@ -57,7 +57,7 @@ class InAppWebViewAjaxTestState extends WidgetTestState {
"""), """),
initialHeaders: {}, initialHeaders: {},
initialOptions: InAppWebViewWidgetOptions( initialOptions: InAppWebViewWidgetOptions(
inAppWebViewOptions: InAppWebViewOptions( crossPlatform: InAppWebViewOptions(
clearCache: true, clearCache: true,
debuggingEnabled: true, debuggingEnabled: true,
useShouldInterceptAjaxRequest: true, useShouldInterceptAjaxRequest: true,
......
...@@ -30,7 +30,7 @@ class InAppWebViewContentBlockerTestState extends WidgetTestState { ...@@ -30,7 +30,7 @@ class InAppWebViewContentBlockerTestState extends WidgetTestState {
initialUrl: "https://flutter.dev/", initialUrl: "https://flutter.dev/",
initialHeaders: {}, initialHeaders: {},
initialOptions: InAppWebViewWidgetOptions( initialOptions: InAppWebViewWidgetOptions(
inAppWebViewOptions: InAppWebViewOptions( crossPlatform: InAppWebViewOptions(
clearCache: true, clearCache: true,
debuggingEnabled: true, debuggingEnabled: true,
contentBlockers: [ contentBlockers: [
......
...@@ -31,7 +31,7 @@ class InAppWebViewCookieManagerTestState extends WidgetTestState { ...@@ -31,7 +31,7 @@ class InAppWebViewCookieManagerTestState extends WidgetTestState {
initialUrl: "https://flutter.dev/", initialUrl: "https://flutter.dev/",
initialHeaders: {}, initialHeaders: {},
initialOptions: InAppWebViewWidgetOptions( initialOptions: InAppWebViewWidgetOptions(
inAppWebViewOptions: InAppWebViewOptions( crossPlatform: InAppWebViewOptions(
clearCache: true, clearCache: true,
debuggingEnabled: true debuggingEnabled: true
) )
......
...@@ -75,7 +75,7 @@ class InAppWebViewFetchTestState extends WidgetTestState { ...@@ -75,7 +75,7 @@ class InAppWebViewFetchTestState extends WidgetTestState {
"""), """),
initialHeaders: {}, initialHeaders: {},
initialOptions: InAppWebViewWidgetOptions( initialOptions: InAppWebViewWidgetOptions(
inAppWebViewOptions: InAppWebViewOptions( crossPlatform: InAppWebViewOptions(
clearCache: true, clearCache: true,
debuggingEnabled: true, debuggingEnabled: true,
useShouldInterceptFetchRequest: true, useShouldInterceptFetchRequest: true,
......
...@@ -38,7 +38,7 @@ class InAppWebViewHttpAuthCredentialDatabaseTestState extends WidgetTestState { ...@@ -38,7 +38,7 @@ class InAppWebViewHttpAuthCredentialDatabaseTestState extends WidgetTestState {
initialUrl: "http://${environment["NODE_SERVER_IP"]}:8081/", initialUrl: "http://${environment["NODE_SERVER_IP"]}:8081/",
initialHeaders: {}, initialHeaders: {},
initialOptions: InAppWebViewWidgetOptions( initialOptions: InAppWebViewWidgetOptions(
inAppWebViewOptions: InAppWebViewOptions( crossPlatform: InAppWebViewOptions(
clearCache: true, clearCache: true,
debuggingEnabled: true debuggingEnabled: true
) )
......
...@@ -66,7 +66,7 @@ class InAppWebViewInitialDataTestState extends WidgetTestState { ...@@ -66,7 +66,7 @@ class InAppWebViewInitialDataTestState extends WidgetTestState {
"""), """),
initialHeaders: {}, initialHeaders: {},
initialOptions: InAppWebViewWidgetOptions( initialOptions: InAppWebViewWidgetOptions(
inAppWebViewOptions: InAppWebViewOptions( crossPlatform: InAppWebViewOptions(
clearCache: true, clearCache: true,
debuggingEnabled: true debuggingEnabled: true
) )
......
...@@ -29,7 +29,7 @@ class InAppWebViewInitialFileTestState extends WidgetTestState { ...@@ -29,7 +29,7 @@ class InAppWebViewInitialFileTestState extends WidgetTestState {
initialFile: "test_assets/in_app_webview_initial_file_test.html", initialFile: "test_assets/in_app_webview_initial_file_test.html",
initialHeaders: {}, initialHeaders: {},
initialOptions: InAppWebViewWidgetOptions( initialOptions: InAppWebViewWidgetOptions(
inAppWebViewOptions: InAppWebViewOptions( crossPlatform: InAppWebViewOptions(
clearCache: true, clearCache: true,
debuggingEnabled: true debuggingEnabled: true
) )
......
...@@ -30,7 +30,7 @@ class InAppWebViewInitialUrlTestState extends WidgetTestState { ...@@ -30,7 +30,7 @@ class InAppWebViewInitialUrlTestState extends WidgetTestState {
initialUrl: "https://flutter.dev/", initialUrl: "https://flutter.dev/",
initialHeaders: {}, initialHeaders: {},
initialOptions: InAppWebViewWidgetOptions( initialOptions: InAppWebViewWidgetOptions(
inAppWebViewOptions: InAppWebViewOptions( crossPlatform: InAppWebViewOptions(
clearCache: true, clearCache: true,
debuggingEnabled: true debuggingEnabled: true
) )
......
...@@ -44,7 +44,7 @@ class InAppWebViewJavaScriptHandlerTestState extends WidgetTestState { ...@@ -44,7 +44,7 @@ class InAppWebViewJavaScriptHandlerTestState extends WidgetTestState {
initialFile: "test_assets/in_app_webview_javascript_handler_test.html", initialFile: "test_assets/in_app_webview_javascript_handler_test.html",
initialHeaders: {}, initialHeaders: {},
initialOptions: InAppWebViewWidgetOptions( initialOptions: InAppWebViewWidgetOptions(
inAppWebViewOptions: InAppWebViewOptions( crossPlatform: InAppWebViewOptions(
clearCache: true, clearCache: true,
debuggingEnabled: true debuggingEnabled: true
) )
......
...@@ -29,7 +29,7 @@ class InAppWebViewOnConsoleMessageTestState extends WidgetTestState { ...@@ -29,7 +29,7 @@ class InAppWebViewOnConsoleMessageTestState extends WidgetTestState {
initialFile: "test_assets/in_app_webview_on_console_message_test.html", initialFile: "test_assets/in_app_webview_on_console_message_test.html",
initialHeaders: {}, initialHeaders: {},
initialOptions: InAppWebViewWidgetOptions( initialOptions: InAppWebViewWidgetOptions(
inAppWebViewOptions: InAppWebViewOptions( crossPlatform: InAppWebViewOptions(
clearCache: true, clearCache: true,
debuggingEnabled: true debuggingEnabled: true
) )
......
...@@ -29,7 +29,7 @@ class InAppWebViewOnCreateWindowTestState extends WidgetTestState { ...@@ -29,7 +29,7 @@ class InAppWebViewOnCreateWindowTestState extends WidgetTestState {
initialFile: "test_assets/in_app_webview_on_create_window_test.html", initialFile: "test_assets/in_app_webview_on_create_window_test.html",
initialHeaders: {}, initialHeaders: {},
initialOptions: InAppWebViewWidgetOptions( initialOptions: InAppWebViewWidgetOptions(
inAppWebViewOptions: InAppWebViewOptions( crossPlatform: InAppWebViewOptions(
clearCache: true, clearCache: true,
debuggingEnabled: true, debuggingEnabled: true,
javaScriptCanOpenWindowsAutomatically: true, javaScriptCanOpenWindowsAutomatically: true,
...@@ -48,8 +48,8 @@ class InAppWebViewOnCreateWindowTestState extends WidgetTestState { ...@@ -48,8 +48,8 @@ class InAppWebViewOnCreateWindowTestState extends WidgetTestState {
}); });
} }
}, },
onCreateWindow: (InAppWebViewController controller, String url) { onCreateWindow: (InAppWebViewController controller, OnCreateWindowRequest onCreateWindowRequest) {
controller.loadUrl(url: url); controller.loadUrl(url: onCreateWindowRequest.url);
}, },
), ),
), ),
......
...@@ -49,7 +49,7 @@ class InAppWebViewOnDownloadStartTestState extends WidgetTestState { ...@@ -49,7 +49,7 @@ class InAppWebViewOnDownloadStartTestState extends WidgetTestState {
"""), """),
initialHeaders: {}, initialHeaders: {},
initialOptions: InAppWebViewWidgetOptions( initialOptions: InAppWebViewWidgetOptions(
inAppWebViewOptions: InAppWebViewOptions( crossPlatform: InAppWebViewOptions(
clearCache: true, clearCache: true,
debuggingEnabled: true, debuggingEnabled: true,
useOnDownloadStart: true useOnDownloadStart: true
......
...@@ -29,7 +29,7 @@ class InAppWebViewOnFindResultReceivedTestState extends WidgetTestState { ...@@ -29,7 +29,7 @@ class InAppWebViewOnFindResultReceivedTestState extends WidgetTestState {
initialFile: "test_assets/in_app_webview_initial_file_test.html", initialFile: "test_assets/in_app_webview_initial_file_test.html",
initialHeaders: {}, initialHeaders: {},
initialOptions: InAppWebViewWidgetOptions( initialOptions: InAppWebViewWidgetOptions(
inAppWebViewOptions: InAppWebViewOptions( crossPlatform: InAppWebViewOptions(
clearCache: true, clearCache: true,
debuggingEnabled: true debuggingEnabled: true
) )
......
...@@ -37,7 +37,7 @@ class InAppWebViewOnJsDialogTestState extends WidgetTestState { ...@@ -37,7 +37,7 @@ class InAppWebViewOnJsDialogTestState extends WidgetTestState {
initialFile: "test_assets/in_app_webview_on_js_dialog_test.html", initialFile: "test_assets/in_app_webview_on_js_dialog_test.html",
initialHeaders: {}, initialHeaders: {},
initialOptions: InAppWebViewWidgetOptions( initialOptions: InAppWebViewWidgetOptions(
inAppWebViewOptions: InAppWebViewOptions( crossPlatform: InAppWebViewOptions(
clearCache: true, clearCache: true,
debuggingEnabled: true debuggingEnabled: true
) )
......
...@@ -30,7 +30,7 @@ class InAppWebViewOnLoadErrorTestState extends WidgetTestState { ...@@ -30,7 +30,7 @@ class InAppWebViewOnLoadErrorTestState extends WidgetTestState {
initialUrl: "https://not-existing-domain.org/", initialUrl: "https://not-existing-domain.org/",
initialHeaders: {}, initialHeaders: {},
initialOptions: InAppWebViewWidgetOptions( initialOptions: InAppWebViewWidgetOptions(
inAppWebViewOptions: InAppWebViewOptions( crossPlatform: InAppWebViewOptions(
clearCache: true, clearCache: true,
debuggingEnabled: true debuggingEnabled: true
) )
......
...@@ -30,7 +30,7 @@ class InAppWebViewOnLoadHttpErrorTestState extends WidgetTestState { ...@@ -30,7 +30,7 @@ class InAppWebViewOnLoadHttpErrorTestState extends WidgetTestState {
initialUrl: "https://google.com/404", initialUrl: "https://google.com/404",
initialHeaders: {}, initialHeaders: {},
initialOptions: InAppWebViewWidgetOptions( initialOptions: InAppWebViewWidgetOptions(
inAppWebViewOptions: InAppWebViewOptions( crossPlatform: InAppWebViewOptions(
clearCache: true, clearCache: true,
debuggingEnabled: true debuggingEnabled: true
) )
......
...@@ -30,7 +30,7 @@ class InAppWebViewOnLoadResourceCustomSchemeTestState extends WidgetTestState { ...@@ -30,7 +30,7 @@ class InAppWebViewOnLoadResourceCustomSchemeTestState extends WidgetTestState {
initialFile: "test_assets/in_app_webview_on_load_resource_custom_scheme_test.html", initialFile: "test_assets/in_app_webview_on_load_resource_custom_scheme_test.html",
initialHeaders: {}, initialHeaders: {},
initialOptions: InAppWebViewWidgetOptions( initialOptions: InAppWebViewWidgetOptions(
inAppWebViewOptions: InAppWebViewOptions( crossPlatform: InAppWebViewOptions(
clearCache: true, clearCache: true,
debuggingEnabled: true, debuggingEnabled: true,
resourceCustomSchemes: ["my-special-custom-scheme"] resourceCustomSchemes: ["my-special-custom-scheme"]
......
...@@ -35,7 +35,7 @@ class InAppWebViewOnLoadResourceTestState extends WidgetTestState { ...@@ -35,7 +35,7 @@ class InAppWebViewOnLoadResourceTestState extends WidgetTestState {
initialFile: "test_assets/in_app_webview_on_load_resource_test.html", initialFile: "test_assets/in_app_webview_on_load_resource_test.html",
initialHeaders: {}, initialHeaders: {},
initialOptions: InAppWebViewWidgetOptions( initialOptions: InAppWebViewWidgetOptions(
inAppWebViewOptions: InAppWebViewOptions( crossPlatform: InAppWebViewOptions(
clearCache: true, clearCache: true,
debuggingEnabled: true, debuggingEnabled: true,
useOnLoadResource: true useOnLoadResource: true
......
...@@ -29,7 +29,7 @@ class InAppWebViewOnNavigationStateChangeTestState extends WidgetTestState { ...@@ -29,7 +29,7 @@ class InAppWebViewOnNavigationStateChangeTestState extends WidgetTestState {
initialUrl: "https://flutter.dev/", initialUrl: "https://flutter.dev/",
initialHeaders: {}, initialHeaders: {},
initialOptions: InAppWebViewWidgetOptions( initialOptions: InAppWebViewWidgetOptions(
inAppWebViewOptions: InAppWebViewOptions( crossPlatform: InAppWebViewOptions(
clearCache: true, clearCache: true,
debuggingEnabled: true debuggingEnabled: true
) )
......
...@@ -30,7 +30,7 @@ class InAppWebViewOnProgressChangedTestState extends WidgetTestState { ...@@ -30,7 +30,7 @@ class InAppWebViewOnProgressChangedTestState extends WidgetTestState {
initialUrl: "https://flutter.dev/", initialUrl: "https://flutter.dev/",
initialHeaders: {}, initialHeaders: {},
initialOptions: InAppWebViewWidgetOptions( initialOptions: InAppWebViewWidgetOptions(
inAppWebViewOptions: InAppWebViewOptions( crossPlatform: InAppWebViewOptions(
clearCache: true, clearCache: true,
debuggingEnabled: true debuggingEnabled: true
) )
......
...@@ -31,7 +31,7 @@ class InAppWebViewOnReceivedHttpAuthRequestTestState extends WidgetTestState { ...@@ -31,7 +31,7 @@ class InAppWebViewOnReceivedHttpAuthRequestTestState extends WidgetTestState {
initialUrl: "http://${environment["NODE_SERVER_IP"]}:8081/", initialUrl: "http://${environment["NODE_SERVER_IP"]}:8081/",
initialHeaders: {}, initialHeaders: {},
initialOptions: InAppWebViewWidgetOptions( initialOptions: InAppWebViewWidgetOptions(
inAppWebViewOptions: InAppWebViewOptions( crossPlatform: InAppWebViewOptions(
clearCache: true, clearCache: true,
debuggingEnabled: true debuggingEnabled: true
) )
......
...@@ -32,20 +32,20 @@ class InAppWebViewOnSafeBrowsingHitTestState extends WidgetTestState { ...@@ -32,20 +32,20 @@ class InAppWebViewOnSafeBrowsingHitTestState extends WidgetTestState {
initialUrl: (Platform.isAndroid) ? "chrome://safe-browsing/match?type=malware" : "https://flutter.dev/", initialUrl: (Platform.isAndroid) ? "chrome://safe-browsing/match?type=malware" : "https://flutter.dev/",
initialHeaders: {}, initialHeaders: {},
initialOptions: InAppWebViewWidgetOptions( initialOptions: InAppWebViewWidgetOptions(
inAppWebViewOptions: InAppWebViewOptions( crossPlatform: InAppWebViewOptions(
// if I set javaScriptEnabled to true, it will crash! // if I set javaScriptEnabled to true, it will crash!
javaScriptEnabled: false, javaScriptEnabled: false,
clearCache: true, clearCache: true,
debuggingEnabled: true debuggingEnabled: true
), ),
androidInAppWebViewOptions: AndroidInAppWebViewOptions( android: AndroidInAppWebViewOptions(
safeBrowsingEnabled: true, safeBrowsingEnabled: true,
), ),
), ),
onWebViewCreated: (InAppWebViewController controller) { onWebViewCreated: (InAppWebViewController controller) {
webView = controller; webView = controller;
if(Platform.isAndroid) if(Platform.isAndroid)
controller.startSafeBrowsing(); controller.android.startSafeBrowsing();
}, },
onLoadStart: (InAppWebViewController controller, String url) { onLoadStart: (InAppWebViewController controller, String url) {
...@@ -55,7 +55,7 @@ class InAppWebViewOnSafeBrowsingHitTestState extends WidgetTestState { ...@@ -55,7 +55,7 @@ class InAppWebViewOnSafeBrowsingHitTestState extends WidgetTestState {
appBarTitle = url; appBarTitle = url;
}); });
}, },
onSafeBrowsingHit: (InAppWebViewController controller, String url, SafeBrowsingThreat threatType) async { androidOnSafeBrowsingHit: (InAppWebViewController controller, String url, SafeBrowsingThreat threatType) async {
return SafeBrowsingResponse(report: true, action: SafeBrowsingResponseAction.PROCEED); return SafeBrowsingResponse(report: true, action: SafeBrowsingResponseAction.PROCEED);
}, },
), ),
......
...@@ -31,7 +31,7 @@ class InAppWebViewOnScrollChangedTestState extends WidgetTestState { ...@@ -31,7 +31,7 @@ class InAppWebViewOnScrollChangedTestState extends WidgetTestState {
initialUrl: "https://flutter.dev/", initialUrl: "https://flutter.dev/",
initialHeaders: {}, initialHeaders: {},
initialOptions: InAppWebViewWidgetOptions( initialOptions: InAppWebViewWidgetOptions(
inAppWebViewOptions: InAppWebViewOptions( crossPlatform: InAppWebViewOptions(
clearCache: true, clearCache: true,
debuggingEnabled: true debuggingEnabled: true
) )
......
...@@ -29,7 +29,7 @@ class InAppWebViewShouldOverrideUrlLoadingTestState extends WidgetTestState { ...@@ -29,7 +29,7 @@ class InAppWebViewShouldOverrideUrlLoadingTestState extends WidgetTestState {
initialFile: "test_assets/in_app_webview_initial_file_test.html", initialFile: "test_assets/in_app_webview_initial_file_test.html",
initialHeaders: {}, initialHeaders: {},
initialOptions: InAppWebViewWidgetOptions( initialOptions: InAppWebViewWidgetOptions(
inAppWebViewOptions: InAppWebViewOptions( crossPlatform: InAppWebViewOptions(
clearCache: true, clearCache: true,
debuggingEnabled: true, debuggingEnabled: true,
useShouldOverrideUrlLoading: true useShouldOverrideUrlLoading: true
......
...@@ -31,7 +31,7 @@ class InAppWebViewSslRequestTestState extends WidgetTestState { ...@@ -31,7 +31,7 @@ class InAppWebViewSslRequestTestState extends WidgetTestState {
initialUrl: "https://${environment["NODE_SERVER_IP"]}:4433/", initialUrl: "https://${environment["NODE_SERVER_IP"]}:4433/",
initialHeaders: {}, initialHeaders: {},
initialOptions: InAppWebViewWidgetOptions( initialOptions: InAppWebViewWidgetOptions(
inAppWebViewOptions: InAppWebViewOptions( crossPlatform: InAppWebViewOptions(
clearCache: true, clearCache: true,
debuggingEnabled: true debuggingEnabled: true
) )
......
...@@ -26,6 +26,7 @@ ...@@ -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/.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/.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/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$/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/.dart_tool" />
<excludeFolder url="file://$MODULE_DIR$/flutter_inappbrowser_tests/.pub" /> <excludeFolder url="file://$MODULE_DIR$/flutter_inappbrowser_tests/.pub" />
......
//
// FlutterMethodCallDelegate.swift
// flutter_inappwebview
//
// Created by Lorenzo Pichilli on 15/12/2019.
//
import Foundation
public class FlutterMethodCallDelegate: NSObject {
public override init() {
super.init()
}
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
}
}
...@@ -8,12 +8,13 @@ ...@@ -8,12 +8,13 @@
import Foundation import Foundation
import WebKit import WebKit
public class FlutterWebViewController: NSObject, FlutterPlatformView { public class FlutterWebViewController: FlutterMethodCallDelegate, FlutterPlatformView {
private weak var registrar: FlutterPluginRegistrar? private weak var registrar: FlutterPluginRegistrar?
var webView: InAppWebView? var webView: InAppWebView?
var viewId: Int64 = 0 var viewId: Int64 = 0
var channel: FlutterMethodChannel? 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: Int64, arguments args: NSDictionary) {
super.init() super.init()
...@@ -21,24 +22,29 @@ public class FlutterWebViewController: NSObject, FlutterPlatformView { ...@@ -21,24 +22,29 @@ public class FlutterWebViewController: NSObject, FlutterPlatformView {
self.registrar = registrar self.registrar = registrar
self.viewId = viewId self.viewId = viewId
myView = UIView(frame: frame)
let channelName = "com.pichillilorenzo/flutter_inappwebview_" + String(viewId)
self.channel = FlutterMethodChannel(name: channelName, binaryMessenger: registrar.messenger())
self.channel?.setMethodCallHandler(LeakAvoider(delegate: self).handle)
let initialUrl = (args["initialUrl"] as? String)! let initialUrl = (args["initialUrl"] as? String)!
let initialFile = args["initialFile"] as? String let initialFile = args["initialFile"] as? String
let initialData = args["initialData"] as? [String: String] let initialData = args["initialData"] as? [String: String]
let initialHeaders = (args["initialHeaders"] as? [String: String])! let initialHeaders = (args["initialHeaders"] as? [String: String])!
let initialOptions = (args["initialOptions"] as? [String: Any])! let initialOptions = (args["initialOptions"] as? [String: Any])!
let options = InAppWebViewOptions() let options = InAppWebViewOptions()
options.parse(options: initialOptions) options.parse(options: initialOptions)
let preWebviewConfiguration = InAppWebView.preWKWebViewConfiguration(options: options) let preWebviewConfiguration = InAppWebView.preWKWebViewConfiguration(options: options)
webView = InAppWebView(frame: frame, configuration: preWebviewConfiguration, IABController: nil, IAWController: self) webView = InAppWebView(frame: myView!.bounds, configuration: preWebviewConfiguration, IABController: nil, channel: self.channel)
let channelName = "com.pichillilorenzo/flutter_inappwebview_" + String(viewId) webView!.autoresizingMask = [.flexibleWidth, .flexibleHeight]
self.channel = FlutterMethodChannel(name: channelName, binaryMessenger: registrar.messenger()) myView!.addSubview(webView!)
self.channel?.setMethodCallHandler(self.handle)
webView!.options = options webView!.options = options
webView!.prepare() webView!.prepare()
if #available(iOS 11.0, *) { if #available(iOS 11.0, *) {
self.webView!.configuration.userContentController.removeAllContentRuleLists() self.webView!.configuration.userContentController.removeAllContentRuleLists()
if let contentBlockers = webView!.options?.contentBlockers, contentBlockers.count > 0 { if let contentBlockers = webView!.options?.contentBlockers, contentBlockers.count > 0 {
...@@ -48,15 +54,15 @@ public class FlutterWebViewController: NSObject, FlutterPlatformView { ...@@ -48,15 +54,15 @@ public class FlutterWebViewController: NSObject, FlutterPlatformView {
WKContentRuleListStore.default().compileContentRuleList( WKContentRuleListStore.default().compileContentRuleList(
forIdentifier: "ContentBlockingRules", forIdentifier: "ContentBlockingRules",
encodedContentRuleList: blockRules) { (contentRuleList, error) in encodedContentRuleList: blockRules) { (contentRuleList, error) in
if let error = error { if let error = error {
print(error.localizedDescription) print(error.localizedDescription)
return return
} }
let configuration = self.webView!.configuration let configuration = self.webView!.configuration
configuration.userContentController.add(contentRuleList!) configuration.userContentController.add(contentRuleList!)
self.load(initialUrl: initialUrl, initialFile: initialFile, initialData: initialData, initialHeaders: initialHeaders) self.load(initialUrl: initialUrl, initialFile: initialFile, initialData: initialData, initialHeaders: initialHeaders)
} }
return return
...@@ -68,8 +74,16 @@ public class FlutterWebViewController: NSObject, FlutterPlatformView { ...@@ -68,8 +74,16 @@ public class FlutterWebViewController: NSObject, FlutterPlatformView {
load(initialUrl: initialUrl, initialFile: initialFile, initialData: initialData, initialHeaders: initialHeaders) load(initialUrl: initialUrl, initialFile: initialFile, initialData: initialData, initialHeaders: initialHeaders)
} }
deinit {
print("FlutterWebViewController - dealloc")
self.channel?.setMethodCallHandler(nil)
webView!.dispose()
webView = nil
myView = nil
}
public func view() -> UIView { public func view() -> UIView {
return webView! return myView!
} }
public func load(initialUrl: String, initialFile: String?, initialData: [String: String]?, initialHeaders: [String: String]) { public func load(initialUrl: String, initialFile: String?, initialData: [String: String]?, initialHeaders: [String: String]) {
...@@ -95,7 +109,7 @@ public class FlutterWebViewController: NSObject, FlutterPlatformView { ...@@ -95,7 +109,7 @@ public class FlutterWebViewController: NSObject, FlutterPlatformView {
} }
} }
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
let arguments = call.arguments as? NSDictionary let arguments = call.arguments as? NSDictionary
switch call.method { switch call.method {
case "getUrl": case "getUrl":
...@@ -344,10 +358,18 @@ public class FlutterWebViewController: NSObject, FlutterPlatformView { ...@@ -344,10 +358,18 @@ public class FlutterWebViewController: NSObject, FlutterPlatformView {
result(false) result(false)
} }
break break
case "removeFromSuperview": case "getContentHeight":
webView!.removeFromSuperview() result( (webView != nil) ? webView!.getContentHeight() : nil )
break
case "reloadFromOrigin":
if webView != nil {
webView!.reloadFromOrigin()
}
result(true) result(true)
break break
case "getScale":
result( (webView != nil) ? webView!.getScale() : nil )
break
default: default:
result(FlutterMethodNotImplemented) result(FlutterMethodNotImplemented)
break break
......
...@@ -65,7 +65,7 @@ typealias NewerClosureType = @convention(c) (Any, Selector, UnsafeRawPointer, B ...@@ -65,7 +65,7 @@ typealias NewerClosureType = @convention(c) (Any, Selector, UnsafeRawPointer, B
class InAppWebView_IBWrapper: InAppWebView { class InAppWebView_IBWrapper: InAppWebView {
required init(coder: NSCoder) { required init(coder: NSCoder) {
let config = WKWebViewConfiguration() let config = WKWebViewConfiguration()
super.init(frame: .zero, configuration: config, IABController: nil, IAWController: nil) super.init(frame: .zero, configuration: config, IABController: nil, channel: nil)
self.translatesAutoresizingMaskIntoConstraints = false self.translatesAutoresizingMaskIntoConstraints = false
} }
} }
...@@ -114,7 +114,7 @@ class InAppBrowserWebViewController: UIViewController, UIScrollViewDelegate, WKU ...@@ -114,7 +114,7 @@ class InAppBrowserWebViewController: UIViewController, UIScrollViewDelegate, WKU
override func viewWillAppear(_ animated: Bool) { override func viewWillAppear(_ animated: Bool) {
if !viewPrepared { if !viewPrepared {
let preWebviewConfiguration = InAppWebView.preWKWebViewConfiguration(options: webViewOptions) let preWebviewConfiguration = InAppWebView.preWKWebViewConfiguration(options: webViewOptions)
self.webView = InAppWebView(frame: .zero, configuration: preWebviewConfiguration, IABController: self, IAWController: nil) self.webView = InAppWebView(frame: .zero, configuration: preWebviewConfiguration, IABController: self, channel: nil)
self.containerWebView.addSubview(self.webView) self.containerWebView.addSubview(self.webView)
prepareConstraints() prepareConstraints()
prepareWebView() prepareWebView()
...@@ -194,12 +194,21 @@ class InAppBrowserWebViewController: UIViewController, UIScrollViewDelegate, WKU ...@@ -194,12 +194,21 @@ class InAppBrowserWebViewController: UIViewController, UIScrollViewDelegate, WKU
// Prevent crashes on closing windows // Prevent crashes on closing windows
deinit { deinit {
webView.removeObserver(self, forKeyPath: "estimatedProgress") print("InAppBrowserWebViewController - dealloc")
webView.uiDelegate = nil
} }
override func viewWillDisappear (_ animated: Bool) { override func viewWillDisappear (_ animated: Bool) {
super.viewWillDisappear(animated) super.viewWillDisappear(animated)
webView.dispose()
navigationDelegate = nil
transitioningDelegate = nil
urlField.delegate = nil
closeButton.removeTarget(self, action: #selector(self.close), for: .touchUpInside)
forwardButton.target = nil
forwardButton.target = nil
backButton.target = nil
reloadButton.target = nil
shareButton.target = nil
} }
func prepareConstraints () { func prepareConstraints () {
......
This diff is collapsed.
...@@ -48,6 +48,7 @@ public class InAppWebViewOptions: Options { ...@@ -48,6 +48,7 @@ public class InAppWebViewOptions: Options {
var dataDetectorTypes: [String] = ["NONE"] // WKDataDetectorTypeNone var dataDetectorTypes: [String] = ["NONE"] // WKDataDetectorTypeNone
var preferredContentMode = 0 var preferredContentMode = 0
var sharedCookiesEnabled = false var sharedCookiesEnabled = false
var automaticallyAdjustsScrollIndicatorInsets = false
override init(){ override init(){
super.init() super.init()
......
//
// LeakAvoider.swift
// flutter_inappwebview
//
// Created by Lorenzo Pichilli on 15/12/2019.
//
import Foundation
public class LeakAvoider: NSObject {
weak var delegate : FlutterMethodCallDelegate?
init(delegate: FlutterMethodCallDelegate) {
self.delegate = delegate
super.init()
}
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
self.delegate?.handle(call, result: result)
}
deinit {
print("LeakAvoider - dealloc")
}
}
//
// MyWebStorageManager.swift
// connectivity
//
// Created by Lorenzo Pichilli on 16/12/2019.
//
import Foundation
import WebKit
@available(iOS 9.0, *)
class MyWebStorageManager: NSObject, FlutterPlugin {
static var registrar: FlutterPluginRegistrar?
static var channel: FlutterMethodChannel?
static var websiteDataStore: WKWebsiteDataStore?
static func register(with registrar: FlutterPluginRegistrar) {
}
init(registrar: FlutterPluginRegistrar) {
super.init()
MyWebStorageManager.registrar = registrar
MyWebStorageManager.websiteDataStore = WKWebsiteDataStore.default()
MyWebStorageManager.channel = FlutterMethodChannel(name: "com.pichillilorenzo/flutter_inappwebview_webstoragemanager", binaryMessenger: registrar.messenger())
registrar.addMethodCallDelegate(self, channel: MyWebStorageManager.channel!)
}
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
let arguments = call.arguments as? NSDictionary
switch call.method {
case "fetchDataRecords":
let dataTypes = Set(arguments!["dataTypes"] as! [String])
MyWebStorageManager.fetchDataRecords(dataTypes: dataTypes, result: result)
break
case "removeDataFor":
let dataTypes = Set(arguments!["dataTypes"] as! [String])
let recordList = arguments!["recordList"] as! [[String: Any?]]
MyWebStorageManager.removeDataFor(dataTypes: dataTypes, recordList: recordList, result: result)
break
case "removeDataModifiedSince":
let dataTypes = Set(arguments!["dataTypes"] as! [String])
let timestamp = arguments!["timestamp"] as! Int64
MyWebStorageManager.removeDataModifiedSince(dataTypes: dataTypes, timestamp: timestamp, result: result)
break
default:
result(FlutterMethodNotImplemented)
break
}
}
public static func fetchDataRecords(dataTypes: Set<String>, result: @escaping FlutterResult) {
var recordList: [[String: Any?]] = []
MyWebStorageManager.websiteDataStore!.fetchDataRecords(ofTypes: dataTypes) { (data) in
for record in data {
recordList.append([
"displayName": record.displayName,
"dataTypes": record.dataTypes.map({ (dataType) -> String in
return dataType
})
])
}
result(recordList)
}
}
public static func removeDataFor(dataTypes: Set<String>, recordList: [[String: Any?]], result: @escaping FlutterResult) {
var records: [WKWebsiteDataRecord] = []
MyWebStorageManager.websiteDataStore!.fetchDataRecords(ofTypes: dataTypes) { (data) in
for record in data {
for r in recordList {
let displayName = r["displayName"] as! String
if (record.displayName == displayName) {
records.append(record)
break
}
}
}
MyWebStorageManager.websiteDataStore!.removeData(ofTypes: dataTypes, for: records) {
result(true)
}
}
}
public static func removeDataModifiedSince(dataTypes: Set<String>, timestamp: Int64, result: @escaping FlutterResult) {
let date = NSDate(timeIntervalSince1970: TimeInterval(timestamp))
MyWebStorageManager.websiteDataStore!.removeData(ofTypes: dataTypes, modifiedSince: date as Date) {
result(true)
}
}
}
...@@ -61,6 +61,9 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin { ...@@ -61,6 +61,9 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin {
if #available(iOS 11.0, *) { if #available(iOS 11.0, *) {
MyCookieManager(registrar: registrar) MyCookieManager(registrar: registrar)
} }
if #available(iOS 9.0, *) {
MyWebStorageManager(registrar: registrar)
}
CredentialDatabase(registrar: registrar) CredentialDatabase(registrar: registrar)
} }
...@@ -254,6 +257,39 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin { ...@@ -254,6 +257,39 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin {
self.clearCache(uuid: uuid) self.clearCache(uuid: uuid)
result(true) result(true)
break break
case "scrollTo":
let x = arguments!["x"] as! Int
let y = arguments!["y"] as! Int
self.scrollTo(uuid: uuid, x: x, y: y)
result(true)
break
case "scrollBy":
let x = arguments!["x"] as! Int
let y = arguments!["y"] as! Int
self.scrollTo(uuid: uuid, x: x, y: y)
result(true)
break
case "pauseTimers":
self.pauseTimers(uuid: uuid)
result(true)
break
case "resumeTimers":
self.resumeTimers(uuid: uuid)
result(true)
break
case "printCurrentPage":
self.printCurrentPage(uuid: uuid, result: result)
break
case "getContentHeight":
result(self.getContentHeight(uuid: uuid))
break
case "reloadFromOrigin":
self.reloadFromOrigin(uuid: uuid)
result(true)
break
case "getScale":
result(self.getScale(uuid: uuid))
break
default: default:
result(FlutterMethodNotImplemented) result(FlutterMethodNotImplemented)
break break
...@@ -690,33 +726,33 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin { ...@@ -690,33 +726,33 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin {
} }
} }
func onBrowserCreated(uuid: String, webView: WKWebView) { public func onBrowserCreated(uuid: String, webView: WKWebView) {
if let webViewController = self.webViewControllers[uuid] { if let webViewController = self.webViewControllers[uuid] {
self.channel!.invokeMethod("onBrowserCreated", arguments: ["uuid": uuid]) self.channel!.invokeMethod("onBrowserCreated", arguments: ["uuid": uuid])
} }
} }
func onExit(uuid: String) { public func onExit(uuid: String) {
self.channel!.invokeMethod("onExit", arguments: ["uuid": uuid]) self.channel!.invokeMethod("onExit", arguments: ["uuid": uuid])
} }
func onChromeSafariBrowserOpened(uuid: String) { public func onChromeSafariBrowserOpened(uuid: String) {
if self.safariViewControllers[uuid] != nil { if self.safariViewControllers[uuid] != nil {
self.channel!.invokeMethod("onChromeSafariBrowserOpened", arguments: ["uuid": uuid]) self.channel!.invokeMethod("onChromeSafariBrowserOpened", arguments: ["uuid": uuid])
} }
} }
func onChromeSafariBrowserLoaded(uuid: String) { public func onChromeSafariBrowserLoaded(uuid: String) {
if self.safariViewControllers[uuid] != nil { if self.safariViewControllers[uuid] != nil {
self.channel!.invokeMethod("onChromeSafariBrowserLoaded", arguments: ["uuid": uuid]) self.channel!.invokeMethod("onChromeSafariBrowserLoaded", arguments: ["uuid": uuid])
} }
} }
func onChromeSafariBrowserClosed(uuid: String) { public func onChromeSafariBrowserClosed(uuid: String) {
self.channel!.invokeMethod("onChromeSafariBrowserClosed", arguments: ["uuid": uuid]) self.channel!.invokeMethod("onChromeSafariBrowserClosed", arguments: ["uuid": uuid])
} }
func safariExit(uuid: String) { public func safariExit(uuid: String) {
if let safariViewController = self.safariViewControllers[uuid] { if let safariViewController = self.safariViewControllers[uuid] {
if #available(iOS 9.0, *) { if #available(iOS 9.0, *) {
(safariViewController as! SafariViewController).statusDelegate = nil (safariViewController as! SafariViewController).statusDelegate = nil
...@@ -727,7 +763,7 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin { ...@@ -727,7 +763,7 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin {
} }
} }
func browserExit(uuid: String) { public func browserExit(uuid: String) {
if let webViewController = self.webViewControllers[uuid] { if let webViewController = self.webViewControllers[uuid] {
// Set navigationDelegate to nil to ensure no callbacks are received from it. // Set navigationDelegate to nil to ensure no callbacks are received from it.
webViewController?.navigationDelegate = nil webViewController?.navigationDelegate = nil
...@@ -743,33 +779,33 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin { ...@@ -743,33 +779,33 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin {
} }
} }
func setOptions(uuid: String, options: InAppBrowserOptions, optionsMap: [String: Any]) { public func setOptions(uuid: String, options: InAppBrowserOptions, optionsMap: [String: Any]) {
if let webViewController = self.webViewControllers[uuid] { if let webViewController = self.webViewControllers[uuid] {
webViewController!.setOptions(newOptions: options, newOptionsMap: optionsMap) webViewController!.setOptions(newOptions: options, newOptionsMap: optionsMap)
} }
} }
func getOptions(uuid: String) -> [String: Any]? { public func getOptions(uuid: String) -> [String: Any]? {
if let webViewController = self.webViewControllers[uuid] { if let webViewController = self.webViewControllers[uuid] {
return webViewController!.getOptions() return webViewController!.getOptions()
} }
return nil return nil
} }
func getCopyBackForwardList(uuid: String) -> [String: Any]? { public func getCopyBackForwardList(uuid: String) -> [String: Any]? {
if let webViewController = self.webViewControllers[uuid] { if let webViewController = self.webViewControllers[uuid] {
return webViewController!.webView.getCopyBackForwardList() return webViewController!.webView.getCopyBackForwardList()
} }
return nil return nil
} }
func findAllAsync(uuid: String, find: String) { public func findAllAsync(uuid: String, find: String) {
if let webViewController = self.webViewControllers[uuid] { if let webViewController = self.webViewControllers[uuid] {
webViewController!.webView.findAllAsync(find: find, completionHandler: nil) webViewController!.webView.findAllAsync(find: find, completionHandler: nil)
} }
} }
func findNext(uuid: String, forward: Bool, result: @escaping FlutterResult) { public func findNext(uuid: String, forward: Bool, result: @escaping FlutterResult) {
if let webViewController = self.webViewControllers[uuid] { if let webViewController = self.webViewControllers[uuid] {
webViewController!.webView.findNext(forward: forward, completionHandler: {(value, error) in webViewController!.webView.findNext(forward: forward, completionHandler: {(value, error) in
if error != nil { if error != nil {
...@@ -783,7 +819,7 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin { ...@@ -783,7 +819,7 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin {
} }
} }
func clearMatches(uuid: String, result: @escaping FlutterResult) { public func clearMatches(uuid: String, result: @escaping FlutterResult) {
if let webViewController = self.webViewControllers[uuid] { if let webViewController = self.webViewControllers[uuid] {
webViewController!.webView.clearMatches(completionHandler: {(value, error) in webViewController!.webView.clearMatches(completionHandler: {(value, error) in
if error != nil { if error != nil {
...@@ -797,12 +833,69 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin { ...@@ -797,12 +833,69 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin {
} }
} }
func clearCache(uuid: String) { public func clearCache(uuid: String) {
if let webViewController = self.webViewControllers[uuid] { if let webViewController = self.webViewControllers[uuid] {
webViewController!.webView.clearCache() webViewController!.webView.clearCache()
} }
} }
public func scrollTo(uuid: String, x: Int, y: Int) {
if let webViewController = self.webViewControllers[uuid] {
webViewController!.webView.scrollTo(x: x, y: y)
}
}
public func scrollBy(uuid: String, x: Int, y: Int) {
if let webViewController = self.webViewControllers[uuid] {
webViewController!.webView.scrollBy(x: x, y: y)
}
}
public func pauseTimers(uuid: String) {
if let webViewController = self.webViewControllers[uuid] {
webViewController!.webView.pauseTimers()
}
}
public func resumeTimers(uuid: String) {
if let webViewController = self.webViewControllers[uuid] {
webViewController!.webView.resumeTimers()
}
}
public func printCurrentPage(uuid: String, result: @escaping FlutterResult) {
if let webViewController = self.webViewControllers[uuid] {
webViewController!.webView.printCurrentPage(printCompletionHandler: {(completed, error) in
if !completed, let e = error {
result(false)
return
}
result(true)
})
} else {
result(false)
}
}
public func getContentHeight(uuid: String) -> Int64? {
if let webViewController = self.webViewControllers[uuid] {
return webViewController!.webView.getContentHeight()
}
return nil
}
public func reloadFromOrigin(uuid: String) {
if let webViewController = self.webViewControllers[uuid] {
webViewController!.webView.reloadFromOrigin()
}
}
public func getScale(uuid: String) -> Float? {
if let webViewController = self.webViewControllers[uuid] {
return webViewController!.webView.getScale()
}
return nil
}
} }
// Helper function inserted by Swift 4.2 migrator. // Helper function inserted by Swift 4.2 migrator.
......
//
// TestWebView.swift
// flutter_inappwebview
//
// Created by Lorenzo Pichilli on 14/12/2019.
//
import Flutter
import Foundation
import WebKit
public class TestWebView: WKWebView {
override init(frame: CGRect, configuration: WKWebViewConfiguration) {
super.init(frame: frame, configuration: configuration)
}
required public init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)!
}
public override func removeFromSuperview() {
configuration.userContentController.removeAllUserScripts()
super.removeFromSuperview()
print("\n\n DISPOSE \n\n")
}
deinit {
print("dealloc") // never called
}
}
...@@ -32,3 +32,4 @@ export 'src/in_app_localhost_server.dart'; ...@@ -32,3 +32,4 @@ export 'src/in_app_localhost_server.dart';
export 'src/webview_options.dart'; export 'src/webview_options.dart';
export 'src/content_blocker.dart'; export 'src/content_blocker.dart';
export 'src/http_auth_credentials_database.dart'; export 'src/http_auth_credentials_database.dart';
export 'src/web_storage_manager.dart';
...@@ -63,30 +63,30 @@ class ChromeSafariBrowser { ...@@ -63,30 +63,30 @@ class ChromeSafariBrowser {
Map<String, dynamic> optionsMap = {}; Map<String, dynamic> optionsMap = {};
if (Platform.isAndroid) if (Platform.isAndroid)
optionsMap.addAll(options.androidChromeCustomTabsOptions?.toMap() ?? {}); optionsMap.addAll(options.android?.toMap() ?? {});
else if (Platform.isIOS) else if (Platform.isIOS)
optionsMap.addAll(options.iosSafariOptions?.toMap() ?? {}); optionsMap.addAll(options.ios?.toMap() ?? {});
Map<String, dynamic> optionsFallbackMap = {}; Map<String, dynamic> optionsFallbackMap = {};
if (optionsFallback != null) { if (optionsFallback != null) {
optionsFallbackMap optionsFallbackMap
.addAll(optionsFallback.inAppBrowserOptions?.toMap() ?? {}); .addAll(optionsFallback.crossPlatform?.toMap() ?? {});
optionsFallbackMap.addAll(optionsFallback optionsFallbackMap.addAll(optionsFallback
.inAppWebViewWidgetOptions?.inAppWebViewOptions .inAppWebViewWidgetOptions?.crossPlatform
?.toMap() ?? ?.toMap() ??
{}); {});
if (Platform.isAndroid) { if (Platform.isAndroid) {
optionsFallbackMap optionsFallbackMap
.addAll(optionsFallback.androidInAppBrowserOptions?.toMap() ?? {}); .addAll(optionsFallback.android?.toMap() ?? {});
optionsFallbackMap.addAll(optionsFallback optionsFallbackMap.addAll(optionsFallback
.inAppWebViewWidgetOptions?.androidInAppWebViewOptions .inAppWebViewWidgetOptions?.android
?.toMap() ?? ?.toMap() ??
{}); {});
} else if (Platform.isIOS) { } else if (Platform.isIOS) {
optionsFallbackMap optionsFallbackMap
.addAll(optionsFallback.iosInAppBrowserOptions?.toMap() ?? {}); .addAll(optionsFallback.ios?.toMap() ?? {});
optionsFallbackMap.addAll(optionsFallback optionsFallbackMap.addAll(optionsFallback
.inAppWebViewWidgetOptions?.iosInAppWebViewOptions .inAppWebViewWidgetOptions?.ios
?.toMap() ?? ?.toMap() ??
{}); {});
} }
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
import 'dart:async';
import 'package:flutter/foundation.dart';
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.
///
///**NOTE for iOS**: available from iOS 9.0+.
class WebStorageManager {
static WebStorageManager _instance;
static const MethodChannel _channel = const MethodChannel(
'com.pichillilorenzo/flutter_inappwebview_webstoragemanager');
AndroidWebStorageManager android = AndroidWebStorageManager();
IOSWebStorageManager ios = IOSWebStorageManager();
///Gets the WebStorage manager shared instance.
static WebStorageManager instance() {
return (_instance != null) ? _instance : _init();
}
static WebStorageManager _init() {
_channel.setMethodCallHandler(_handleMethod);
_instance = new WebStorageManager();
return _instance;
}
static Future<dynamic> _handleMethod(MethodCall call) async {}
}
///AndroidWebStorageManager class 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.
Future<List<AndroidWebStorageOrigin>> getOrigins() async {
List<AndroidWebStorageOrigin> originsList = [];
Map<String, dynamic> args = <String, dynamic>{};
List<Map<dynamic, dynamic>> origins = (await WebStorageManager._channel.invokeMethod('getOrigins', args)).cast<Map<dynamic, dynamic>>();
for(var origin in origins) {
originsList.add(AndroidWebStorageOrigin(origin: origin["origin"], quota: origin["quota"], usage: origin["usage"]));
}
return originsList;
}
///Clears all storage currently being used by the JavaScript storage APIs.
///This includes the Application Cache, Web SQL Database and the HTML5 Web Storage APIs.
Future<void> deleteAllData() async {
Map<String, dynamic> args = <String, dynamic>{};
await WebStorageManager._channel.invokeMethod('deleteAllData', args);
}
///Clears the storage currently being used by both the Application Cache and Web SQL Database APIs by the given [origin].
///The origin is specified using its string representation.
Future<void> deleteOrigin({@required String origin}) async {
assert(origin != null);
Map<String, dynamic> args = <String, dynamic>{};
args.putIfAbsent("origin", () => origin);
await WebStorageManager._channel.invokeMethod('deleteOrigin', args);
}
///Gets the storage quota for the Web SQL Database API for the given [origin].
///The quota is given in bytes and the origin is specified using its string representation.
///Note that a quota is not enforced on a per-origin basis for the Application Cache API.
Future<int> getQuotaForOrigin({@required String origin}) async {
assert(origin != null);
Map<String, dynamic> args = <String, dynamic>{};
args.putIfAbsent("origin", () => origin);
return await WebStorageManager._channel.invokeMethod('getQuotaForOrigin', args);
}
///Gets the amount of storage currently being used by both the Application Cache and Web SQL Database APIs by the given [origin].
///The amount is given in bytes and the origin is specified using its string representation.
Future<int> getUsageForOrigin({@required String origin}) async {
assert(origin != null);
Map<String, dynamic> args = <String, dynamic>{};
args.putIfAbsent("origin", () => origin);
return await WebStorageManager._channel.invokeMethod('getUsageForOrigin', args);
}
}
///IOSWebStorageManager class 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+.
class IOSWebStorageManager {
///Fetches data records containing the given website data types.
///
///[dataTypes] represents the website data types to fetch records for.
Future<List<IOSWKWebsiteDataRecord>> fetchDataRecords({@required Set<IOSWKWebsiteDataType> dataTypes}) async {
assert(dataTypes != null);
List<IOSWKWebsiteDataRecord> recordList = [];
List<String> dataTypesList = [];
for (var dataType in dataTypes) {
dataTypesList.add(dataType.toValue());
}
Map<String, dynamic> args = <String, dynamic>{};
args.putIfAbsent("dataTypes", () => dataTypesList);
List<Map<dynamic, dynamic>> records = (await WebStorageManager._channel.invokeMethod('fetchDataRecords', args)).cast<Map<dynamic, dynamic>>();
for(var record in records) {
List<String> dataTypesString = record["dataTypes"].cast<String>();
Set<IOSWKWebsiteDataType> dataTypes = Set();
for(var dataType in dataTypesString) {
dataTypes.add(IOSWKWebsiteDataType.fromValue(dataType));
}
recordList.add(IOSWKWebsiteDataRecord(displayName: record["displayName"], dataTypes: dataTypes));
}
return recordList;
}
///Removes website data of the given types for the given data records.
///
///[dataTypes] represents the website data types that should be removed.
///
///[dataRecords] represents the website data records to delete website data for.
Future<void> removeDataFor({@required Set<IOSWKWebsiteDataType> dataTypes, @required List<IOSWKWebsiteDataRecord> dataRecords}) async {
assert(dataTypes != null && dataRecords != null);
List<String> dataTypesList = [];
for (var dataType in dataTypes) {
dataTypesList.add(dataType.toValue());
}
List<Map<String, dynamic>> recordList = [];
for (var record in dataRecords) {
recordList.add(record.toMap());
}
Map<String, dynamic> args = <String, dynamic>{};
args.putIfAbsent("dataTypes", () => dataTypesList);
args.putIfAbsent("recordList", () => recordList);
await WebStorageManager._channel.invokeMethod('removeDataFor', args);
}
///Removes all website data of the given types that has been modified since the given date.
///
///[dataTypes] represents the website data types that should be removed.
///
///[date] represents a date. All website data modified after this date will be removed.
Future<void> removeDataModifiedSince({@required Set<IOSWKWebsiteDataType> dataTypes, @required DateTime date}) async {
assert(dataTypes != null && date != null);
List<String> dataTypesList = [];
for (var dataType in dataTypes) {
dataTypesList.add(dataType.toValue());
}
var timestamp = date.millisecondsSinceEpoch;
Map<String, dynamic> args = <String, dynamic>{};
args.putIfAbsent("dataTypes", () => dataTypesList);
args.putIfAbsent("timestamp", () => timestamp);
await WebStorageManager._channel.invokeMethod('removeDataModifiedSince', args);
}
}
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