Просмотр исходного кода

Merge pull request #1 from fluttercommunity/master

Synchronize my fork to original repository
HungHD 7 лет назад
Родитель
Сommit
d86ac7ee23

+ 1 - 0
.gitignore

@@ -1,6 +1,7 @@
 .DS_Store
 .DS_Store
 .atom/
 .atom/
 .idea
 .idea
+.vscode
 .packages
 .packages
 .pub/
 .pub/
 build/
 build/

+ 17 - 2
CHANGELOG.md

@@ -1,3 +1,18 @@
+# 0.3.0
+
+- Fixes rect capture issue. Ensures WebView remains in the correct place on screen even when keyboard appears.
+- Fixed iOS crash issue with Flutter `>= 0.10.2`.
+- Added new `clearCookies` feature.
+- Added support for `hidden` and `initialChild` feature to show page loading view.
+- Added supportMultipleWindows: enables Multiple Window Support on Android.
+- Added appCacheEnabled: enables Application Caches API on Android.
+- Added allowFileURLs: allows `file://` local file URLs.
+- iOS Now supports: `reload`, `goBack`, and `goForward`.
+- iOS Bug fix `didFailNavigation` #77
+- Updated Android `compileSdkVersion` to `27` matching offical Flutter plugins.
+- Fixed Android `reloadUrl` so settings are not cleared.
+- Enabled compatible `Mixed Content Mode` on Android.
+
 # 0.2.1
 # 0.2.1
 
 
 - Added webview scrolling listener
 - Added webview scrolling listener
@@ -57,10 +72,10 @@
     - state change event
     - state change event
     - embed in rectangle or fullscreen if null
     - embed in rectangle or fullscreen if null
     - hidden webview
     - hidden webview
-    
+
 - Android
 - Android
     - adding Activity in manifest is not needed anymore
     - adding Activity in manifest is not needed anymore
-    
+
 - Add `WebviewScaffold`
 - Add `WebviewScaffold`
 
 
 # 0.0.9
 # 0.0.9

Разница между файлами не показана из-за своего большого размера
+ 0 - 1
README.md


+ 5 - 4
android/build.gradle

@@ -1,4 +1,4 @@
-group 'com.yourcompany.flutter_webview_plugin'
+group 'com.flutter_webview_plugin'
 version '1.0-SNAPSHOT'
 version '1.0-SNAPSHOT'
 
 
 buildscript {
 buildscript {
@@ -8,7 +8,7 @@ buildscript {
     }
     }
 
 
     dependencies {
     dependencies {
-        classpath 'com.android.tools.build:gradle:3.1.2'
+        classpath 'com.android.tools.build:gradle:3.2.1'
     }
     }
 }
 }
 
 
@@ -21,11 +21,12 @@ allprojects {
 apply plugin: 'com.android.library'
 apply plugin: 'com.android.library'
 
 
 android {
 android {
-    compileSdkVersion 25
-    buildToolsVersion '27.0.3'
+    compileSdkVersion 27
 
 
     defaultConfig {
     defaultConfig {
         testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
         testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+        // NOTE(jeffmikels): When targetSdkVersion or minSdkVersion is not set or < 4, gradle adds 
+        // additional scary permissions such as WRITE_EXTERNAL_STORAGE and READ_PHONE_STATE.
         minSdkVersion 16
         minSdkVersion 16
     }
     }
     lintOptions {
     lintOptions {

+ 0 - 1
android/src/main/AndroidManifest.xml

@@ -1,4 +1,3 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="com.flutter_webview_plugin">
           package="com.flutter_webview_plugin">
-
 </manifest>
 </manifest>

+ 45 - 24
android/src/main/java/com/flutter_webview_plugin/FlutterWebviewPlugin.java

@@ -7,6 +7,9 @@ import android.content.Intent;
 import android.graphics.Point;
 import android.graphics.Point;
 import android.view.Display;
 import android.view.Display;
 import android.widget.FrameLayout;
 import android.widget.FrameLayout;
+import android.webkit.CookieManager;
+import android.webkit.ValueCallback;
+import android.os.Build;
 
 
 import java.util.Map;
 import java.util.Map;
 
 
@@ -70,7 +73,10 @@ public class FlutterWebviewPlugin implements MethodCallHandler, PluginRegistry.A
                 break;
                 break;
             case "stopLoading":
             case "stopLoading":
                 stopLoading(call, result);
                 stopLoading(call, result);
-                break;				
+                break;
+            case "cleanCookies":
+                cleanCookies(call, result);
+                break;
             default:
             default:
                 result.notImplemented();
                 result.notImplemented();
                 break;
                 break;
@@ -86,8 +92,11 @@ public class FlutterWebviewPlugin implements MethodCallHandler, PluginRegistry.A
         boolean clearCookies = call.argument("clearCookies");
         boolean clearCookies = call.argument("clearCookies");
         boolean withZoom = call.argument("withZoom");
         boolean withZoom = call.argument("withZoom");
         boolean withLocalStorage = call.argument("withLocalStorage");
         boolean withLocalStorage = call.argument("withLocalStorage");
+        boolean supportMultipleWindows = call.argument("supportMultipleWindows");
+        boolean appCacheEnabled = call.argument("appCacheEnabled");
         Map<String, String> headers = call.argument("headers");
         Map<String, String> headers = call.argument("headers");
         boolean scrollBar = call.argument("scrollBar");
         boolean scrollBar = call.argument("scrollBar");
+        boolean allowFileURLs = call.argument("allowFileURLs");
 
 
         if (webViewManager == null || webViewManager.closed == true) {
         if (webViewManager == null || webViewManager.closed == true) {
             webViewManager = new WebviewManager(activity);
             webViewManager = new WebviewManager(activity);
@@ -106,7 +115,10 @@ public class FlutterWebviewPlugin implements MethodCallHandler, PluginRegistry.A
                 headers,
                 headers,
                 withZoom,
                 withZoom,
                 withLocalStorage,
                 withLocalStorage,
-                scrollBar
+                scrollBar,
+                supportMultipleWindows,
+                appCacheEnabled,
+                allowFileURLs
         );
         );
         result.success(null);
         result.success(null);
     }
     }
@@ -132,7 +144,7 @@ public class FlutterWebviewPlugin implements MethodCallHandler, PluginRegistry.A
     }
     }
 
 
     private void stopLoading(MethodCall call, MethodChannel.Result result) {
     private void stopLoading(MethodCall call, MethodChannel.Result result) {
-        if (webViewManager != null){
+        if (webViewManager != null) {
             webViewManager.stopLoading(call, result);
             webViewManager.stopLoading(call, result);
         }
         }
     }
     }
@@ -144,47 +156,40 @@ public class FlutterWebviewPlugin implements MethodCallHandler, PluginRegistry.A
         }
         }
     }
     }
 
 
-    /** 
-    * Navigates back on the Webview.
-    */
+    /**
+     * Navigates back on the Webview.
+     */
     private void back(MethodCall call, MethodChannel.Result result) {
     private void back(MethodCall call, MethodChannel.Result result) {
         if (webViewManager != null) {
         if (webViewManager != null) {
             webViewManager.back(call, result);
             webViewManager.back(call, result);
         }
         }
     }
     }
-    /** 
-    * Navigates forward on the Webview.
-    */
+
+    /**
+     * Navigates forward on the Webview.
+     */
     private void forward(MethodCall call, MethodChannel.Result result) {
     private void forward(MethodCall call, MethodChannel.Result result) {
         if (webViewManager != null) {
         if (webViewManager != null) {
             webViewManager.forward(call, result);
             webViewManager.forward(call, result);
         }
         }
     }
     }
 
 
-    /** 
-    * Reloads the Webview.
-    */
+    /**
+     * Reloads the Webview.
+     */
     private void reload(MethodCall call, MethodChannel.Result result) {
     private void reload(MethodCall call, MethodChannel.Result result) {
         if (webViewManager != null) {
         if (webViewManager != null) {
             webViewManager.reload(call, result);
             webViewManager.reload(call, result);
         }
         }
     }
     }
+
     private void reloadUrl(MethodCall call, MethodChannel.Result result) {
     private void reloadUrl(MethodCall call, MethodChannel.Result result) {
         if (webViewManager != null) {
         if (webViewManager != null) {
             String url = call.argument("url");
             String url = call.argument("url");
-            webViewManager.openUrl(false,
-                    false,
-                    false,
-                    false,
-                    "",
-                    url,
-                    null,
-                    false,
-                    false,
-                    false
-            );
+            webViewManager.reloadUrl(url);
         }
         }
     }
     }
+
     private void eval(MethodCall call, final MethodChannel.Result result) {
     private void eval(MethodCall call, final MethodChannel.Result result) {
         if (webViewManager != null) {
         if (webViewManager != null) {
             webViewManager.eval(call, result);
             webViewManager.eval(call, result);
@@ -198,17 +203,33 @@ public class FlutterWebviewPlugin implements MethodCallHandler, PluginRegistry.A
         }
         }
         result.success(null);
         result.success(null);
     }
     }
+
     private void hide(MethodCall call, final MethodChannel.Result result) {
     private void hide(MethodCall call, final MethodChannel.Result result) {
         if (webViewManager != null) {
         if (webViewManager != null) {
             webViewManager.hide(call, result);
             webViewManager.hide(call, result);
         }
         }
     }
     }
+
     private void show(MethodCall call, final MethodChannel.Result result) {
     private void show(MethodCall call, final MethodChannel.Result result) {
         if (webViewManager != null) {
         if (webViewManager != null) {
             webViewManager.show(call, result);
             webViewManager.show(call, result);
         }
         }
     }
     }
 
 
+    private void cleanCookies(MethodCall call, final MethodChannel.Result result) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+            CookieManager.getInstance().removeAllCookies(new ValueCallback<Boolean>() {
+                @Override
+                public void onReceiveValue(Boolean aBoolean) {
+
+                }
+            });
+        } else {
+            CookieManager.getInstance().removeAllCookie();
+        }
+        result.success(null);
+    }
+
     private int dp2px(Context context, float dp) {
     private int dp2px(Context context, float dp) {
         final float scale = context.getResources().getDisplayMetrics().density;
         final float scale = context.getResources().getDisplayMetrics().density;
         return (int) (dp * scale + 0.5f);
         return (int) (dp * scale + 0.5f);
@@ -216,7 +237,7 @@ public class FlutterWebviewPlugin implements MethodCallHandler, PluginRegistry.A
 
 
     @Override
     @Override
     public boolean onActivityResult(int i, int i1, Intent intent) {
     public boolean onActivityResult(int i, int i1, Intent intent) {
-        if(webViewManager != null && webViewManager.resultHandler != null){
+        if (webViewManager != null && webViewManager.resultHandler != null) {
             return webViewManager.resultHandler.handleResult(i, i1, intent);
             return webViewManager.resultHandler.handleResult(i, i1, intent);
         }
         }
         return false;
         return false;

+ 54 - 22
android/src/main/java/com/flutter_webview_plugin/WebviewManager.java

@@ -12,6 +12,7 @@ import android.view.ViewGroup;
 import android.webkit.CookieManager;
 import android.webkit.CookieManager;
 import android.webkit.ValueCallback;
 import android.webkit.ValueCallback;
 import android.webkit.WebChromeClient;
 import android.webkit.WebChromeClient;
+import android.webkit.WebSettings;
 import android.webkit.WebView;
 import android.webkit.WebView;
 import android.webkit.WebViewClient;
 import android.webkit.WebViewClient;
 import android.widget.FrameLayout;
 import android.widget.FrameLayout;
@@ -39,26 +40,27 @@ class WebviewManager {
         public boolean handleResult(int requestCode, int resultCode, Intent intent){
         public boolean handleResult(int requestCode, int resultCode, Intent intent){
             boolean handled = false;
             boolean handled = false;
             if(Build.VERSION.SDK_INT >= 21){
             if(Build.VERSION.SDK_INT >= 21){
-                Uri[] results = null;
-                // check result
-                if(resultCode == Activity.RESULT_OK){
-                    if(requestCode == FILECHOOSER_RESULTCODE){
-                        if(mUploadMessageArray != null){
-                            String dataString = intent.getDataString();
-                            if(dataString != null){
-                                results = new Uri[]{Uri.parse(dataString)};
-                            }
+                if(requestCode == FILECHOOSER_RESULTCODE){
+                    Uri[] results = null;
+                    if(resultCode == Activity.RESULT_OK && intent != null){
+                        String dataString = intent.getDataString();
+                        if(dataString != null){
+                            results = new Uri[]{ Uri.parse(dataString) };
                         }
                         }
-                        handled = true;
                     }
                     }
+                    if(mUploadMessageArray != null){
+                        mUploadMessageArray.onReceiveValue(results);
+                        mUploadMessageArray = null;
+                    }
+                    handled = true;
                 }
                 }
-                mUploadMessageArray.onReceiveValue(results);
-                mUploadMessageArray = null;
             }else {
             }else {
                 if (requestCode == FILECHOOSER_RESULTCODE) {
                 if (requestCode == FILECHOOSER_RESULTCODE) {
-                    if (null != mUploadMessage) {
-                        Uri result = intent == null || resultCode != RESULT_OK ? null
-                                : intent.getData();
+                	Uri result = null;
+                    if (resultCode == RESULT_OK && intent != null) {
+                        result = intent.getData();
+                    }
+                    if (mUploadMessage != null) {
                         mUploadMessage.onReceiveValue(result);
                         mUploadMessage.onReceiveValue(result);
                         mUploadMessage = null;
                         mUploadMessage = null;
                     }
                     }
@@ -189,11 +191,37 @@ class WebviewManager {
         webView.clearFormData();
         webView.clearFormData();
     }
     }
 
 
-    void openUrl(boolean withJavascript, boolean clearCache, boolean hidden, boolean clearCookies, String userAgent, String url, Map<String, String> headers, boolean withZoom, boolean withLocalStorage, boolean scrollBar) {
+    void openUrl(
+            boolean withJavascript,
+            boolean clearCache,
+            boolean hidden,
+            boolean clearCookies,
+            String userAgent,
+            String url,
+            Map<String, String> headers,
+            boolean withZoom,
+            boolean withLocalStorage,
+            boolean scrollBar,
+            boolean supportMultipleWindows,
+            boolean appCacheEnabled,
+            boolean allowFileURLs
+    ) {
         webView.getSettings().setJavaScriptEnabled(withJavascript);
         webView.getSettings().setJavaScriptEnabled(withJavascript);
         webView.getSettings().setBuiltInZoomControls(withZoom);
         webView.getSettings().setBuiltInZoomControls(withZoom);
         webView.getSettings().setSupportZoom(withZoom);
         webView.getSettings().setSupportZoom(withZoom);
         webView.getSettings().setDomStorageEnabled(withLocalStorage);
         webView.getSettings().setDomStorageEnabled(withLocalStorage);
+        webView.getSettings().setJavaScriptCanOpenWindowsAutomatically(supportMultipleWindows);
+
+        webView.getSettings().setSupportMultipleWindows(supportMultipleWindows);
+
+        webView.getSettings().setAppCacheEnabled(appCacheEnabled);
+
+        webView.getSettings().setAllowFileAccessFromFileURLs(allowFileURLs);
+        webView.getSettings().setAllowUniversalAccessFromFileURLs(allowFileURLs);
+
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+            webView.getSettings().setMixedContentMode(WebSettings.MIXED_CONTENT_COMPATIBILITY_MODE);
+        }
 
 
         if (clearCache) {
         if (clearCache) {
             clearCache();
             clearCache();
@@ -210,7 +238,7 @@ class WebviewManager {
         if (userAgent != null) {
         if (userAgent != null) {
             webView.getSettings().setUserAgentString(userAgent);
             webView.getSettings().setUserAgentString(userAgent);
         }
         }
-      
+
         if(!scrollBar){
         if(!scrollBar){
             webView.setVerticalScrollBarEnabled(false);
             webView.setVerticalScrollBarEnabled(false);
         }
         }
@@ -222,6 +250,10 @@ class WebviewManager {
         }
         }
     }
     }
 
 
+    void reloadUrl(String url) {
+        webView.loadUrl(url);
+    }
+
     void close(MethodCall call, MethodChannel.Result result) {
     void close(MethodCall call, MethodChannel.Result result) {
         if (webView != null) {
         if (webView != null) {
             ViewGroup vg = (ViewGroup) (webView.getParent());
             ViewGroup vg = (ViewGroup) (webView.getParent());
@@ -251,7 +283,7 @@ class WebviewManager {
             }
             }
         });
         });
     }
     }
-    /** 
+    /**
     * Reloads the Webview.
     * Reloads the Webview.
     */
     */
     void reload(MethodCall call, MethodChannel.Result result) {
     void reload(MethodCall call, MethodChannel.Result result) {
@@ -259,7 +291,7 @@ class WebviewManager {
             webView.reload();
             webView.reload();
         }
         }
     }
     }
-    /** 
+    /**
     * Navigates back on the Webview.
     * Navigates back on the Webview.
     */
     */
     void back(MethodCall call, MethodChannel.Result result) {
     void back(MethodCall call, MethodChannel.Result result) {
@@ -267,7 +299,7 @@ class WebviewManager {
             webView.goBack();
             webView.goBack();
         }
         }
     }
     }
-    /** 
+    /**
     * Navigates forward on the Webview.
     * Navigates forward on the Webview.
     */
     */
     void forward(MethodCall call, MethodChannel.Result result) {
     void forward(MethodCall call, MethodChannel.Result result) {
@@ -279,13 +311,13 @@ class WebviewManager {
     void resize(FrameLayout.LayoutParams params) {
     void resize(FrameLayout.LayoutParams params) {
         webView.setLayoutParams(params);
         webView.setLayoutParams(params);
     }
     }
-    /** 
+    /**
     * Checks if going back on the Webview is possible.
     * Checks if going back on the Webview is possible.
     */
     */
     boolean canGoBack() {
     boolean canGoBack() {
         return webView.canGoBack();
         return webView.canGoBack();
     }
     }
-    /** 
+    /**
     * Checks if going forward on the Webview is possible.
     * Checks if going forward on the Webview is possible.
     */
     */
     boolean canGoForward() {
     boolean canGoForward() {

+ 3 - 5
example/android/app/build.gradle

@@ -16,7 +16,6 @@ apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
 
 
 android {
 android {
     compileSdkVersion 27
     compileSdkVersion 27
-    buildToolsVersion '27.0.3'
 
 
     lintOptions {
     lintOptions {
         disable 'InvalidPackage'
         disable 'InvalidPackage'
@@ -24,7 +23,6 @@ android {
 
 
     defaultConfig {
     defaultConfig {
         testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
         testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
-        
         // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
         // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
         applicationId "com.yourcompany.flutter_webview_plugin_example"
         applicationId "com.yourcompany.flutter_webview_plugin_example"
     }
     }
@@ -43,7 +41,7 @@ flutter {
 }
 }
 
 
 dependencies {
 dependencies {
-    androidTestCompile 'com.android.support:support-annotations:25.0.0'
-    androidTestCompile 'com.android.support.test:runner:0.5'
-    androidTestCompile 'com.android.support.test:rules:0.5'
+    androidTestImplementation 'com.android.support:support-annotations:27.0.0'
+    androidTestImplementation 'com.android.support.test:runner:1.0.2'
+    androidTestImplementation 'com.android.support.test:rules:1.0.2'
 }
 }

+ 0 - 2
example/android/app/src/main/AndroidManifest.xml

@@ -3,8 +3,6 @@
     android:versionCode="1"
     android:versionCode="1"
     android:versionName="0.0.1">
     android:versionName="0.0.1">
 
 
-    <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="21" />
-
     <!-- The INTERNET permission is required for development. Specifically,
     <!-- The INTERNET permission is required for development. Specifically,
          flutter needs it to communicate with the running application
          flutter needs it to communicate with the running application
          to allow setting breakpoints, to provide hot reload, etc.
          to allow setting breakpoints, to provide hot reload, etc.

+ 1 - 1
example/android/build.gradle

@@ -8,7 +8,7 @@ buildscript {
     }
     }
 
 
     dependencies {
     dependencies {
-        classpath 'com.android.tools.build:gradle:3.1.1'
+        classpath 'com.android.tools.build:gradle:3.2.1'
     }
     }
 }
 }
 
 

Разница между файлами не показана из-за своего большого размера
+ 432 - 314
example/ios/Flutter/flutter_assets/LICENSE


+ 1 - 1
example/ios/Runner.xcodeproj/project.pbxproj

@@ -242,7 +242,7 @@
 			);
 			);
 			inputPaths = (
 			inputPaths = (
 				"${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh",
 				"${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh",
-				"${PODS_ROOT}/../../../../../development/flutter/bin/cache/artifacts/engine/ios/Flutter.framework",
+				"${PODS_ROOT}/../../../../../flutter/bin/cache/artifacts/engine/ios/Flutter.framework",
 				"${BUILT_PRODUCTS_DIR}/flutter_webview_plugin/flutter_webview_plugin.framework",
 				"${BUILT_PRODUCTS_DIR}/flutter_webview_plugin/flutter_webview_plugin.framework",
 			);
 			);
 			name = "[CP] Embed Pods Frameworks";
 			name = "[CP] Embed Pods Frameworks";

+ 133 - 104
example/lib/main.dart

@@ -9,28 +9,61 @@ const kAndroidUserAgent =
 
 
 String selectedUrl = 'https://flutter.io';
 String selectedUrl = 'https://flutter.io';
 
 
-void main() {
-  runApp(new MyApp());
-}
+void main() => runApp(MyApp());
 
 
 class MyApp extends StatelessWidget {
 class MyApp extends StatelessWidget {
+  final flutterWebViewPlugin = FlutterWebviewPlugin();
+
   @override
   @override
   Widget build(BuildContext context) {
   Widget build(BuildContext context) {
-    return new MaterialApp(
+    return MaterialApp(
       title: 'Flutter WebView Demo',
       title: 'Flutter WebView Demo',
-      theme: new ThemeData(
+      theme: ThemeData(
         primarySwatch: Colors.blue,
         primarySwatch: Colors.blue,
       ),
       ),
       routes: {
       routes: {
         '/': (_) => const MyHomePage(title: 'Flutter WebView Demo'),
         '/': (_) => const MyHomePage(title: 'Flutter WebView Demo'),
-        '/widget': (_) => new WebviewScaffold(
-              url: selectedUrl,
-              appBar: new AppBar(
-                title: const Text('Widget webview'),
+        '/widget': (_) {
+          return WebviewScaffold(
+            url: selectedUrl,
+            appBar: AppBar(
+              title: const Text('Widget WebView'),
+            ),
+            withZoom: true,
+            withLocalStorage: true,
+            hidden: true,
+            initialChild: Container(
+              color: Colors.redAccent,
+              child: const Center(
+                child: Text('Waiting.....'),
+              ),
+            ),
+            bottomNavigationBar: BottomAppBar(
+              child: Row(
+                children: <Widget>[
+                  IconButton(
+                    icon: const Icon(Icons.arrow_back_ios),
+                    onPressed: () {
+                      flutterWebViewPlugin.goBack();
+                    },
+                  ),
+                  IconButton(
+                    icon: const Icon(Icons.arrow_forward_ios),
+                    onPressed: () {
+                      flutterWebViewPlugin.goForward();
+                    },
+                  ),
+                  IconButton(
+                    icon: const Icon(Icons.autorenew),
+                    onPressed: () {
+                      flutterWebViewPlugin.reload();
+                    },
+                  ),
+                ],
               ),
               ),
-              withZoom: true,
-              withLocalStorage: true,
-            )
+            ),
+          );
+        },
       },
       },
     );
     );
   }
   }
@@ -42,12 +75,12 @@ class MyHomePage extends StatefulWidget {
   final String title;
   final String title;
 
 
   @override
   @override
-  _MyHomePageState createState() => new _MyHomePageState();
+  _MyHomePageState createState() => _MyHomePageState();
 }
 }
 
 
 class _MyHomePageState extends State<MyHomePage> {
 class _MyHomePageState extends State<MyHomePage> {
   // Instance of WebView plugin
   // Instance of WebView plugin
-  final flutterWebviewPlugin = new FlutterWebviewPlugin();
+  final flutterWebViewPlugin = FlutterWebviewPlugin();
 
 
   // On destroy stream
   // On destroy stream
   StreamSubscription _onDestroy;
   StreamSubscription _onDestroy;
@@ -64,12 +97,11 @@ class _MyHomePageState extends State<MyHomePage> {
 
 
   StreamSubscription<double> _onScrollXChanged;
   StreamSubscription<double> _onScrollXChanged;
 
 
-  final _urlCtrl = new TextEditingController(text: selectedUrl);
+  final _urlCtrl = TextEditingController(text: selectedUrl);
 
 
-  final _codeCtrl =
-      new TextEditingController(text: 'window.navigator.userAgent');
+  final _codeCtrl = TextEditingController(text: 'window.navigator.userAgent');
 
 
-  final _scaffoldKey = new GlobalKey<ScaffoldState>();
+  final _scaffoldKey = GlobalKey<ScaffoldState>();
 
 
   final _history = [];
   final _history = [];
 
 
@@ -77,23 +109,22 @@ class _MyHomePageState extends State<MyHomePage> {
   void initState() {
   void initState() {
     super.initState();
     super.initState();
 
 
-    flutterWebviewPlugin.close();
+    flutterWebViewPlugin.close();
 
 
     _urlCtrl.addListener(() {
     _urlCtrl.addListener(() {
       selectedUrl = _urlCtrl.text;
       selectedUrl = _urlCtrl.text;
     });
     });
 
 
     // Add a listener to on destroy WebView, so you can make came actions.
     // Add a listener to on destroy WebView, so you can make came actions.
-    _onDestroy = flutterWebviewPlugin.onDestroy.listen((_) {
+    _onDestroy = flutterWebViewPlugin.onDestroy.listen((_) {
       if (mounted) {
       if (mounted) {
         // Actions like show a info toast.
         // Actions like show a info toast.
-        _scaffoldKey.currentState.showSnackBar(
-            const SnackBar(content: const Text('Webview Destroyed')));
+        _scaffoldKey.currentState.showSnackBar(const SnackBar(content: const Text('Webview Destroyed')));
       }
       }
     });
     });
 
 
     // Add a listener to on url changed
     // Add a listener to on url changed
-    _onUrlChanged = flutterWebviewPlugin.onUrlChanged.listen((String url) {
+    _onUrlChanged = flutterWebViewPlugin.onUrlChanged.listen((String url) {
       if (mounted) {
       if (mounted) {
         setState(() {
         setState(() {
           _history.add('onUrlChanged: $url');
           _history.add('onUrlChanged: $url');
@@ -101,26 +132,23 @@ class _MyHomePageState extends State<MyHomePage> {
       }
       }
     });
     });
 
 
-    _onScrollYChanged =
-        flutterWebviewPlugin.onScrollYChanged.listen((double y) {
+    _onScrollYChanged = flutterWebViewPlugin.onScrollYChanged.listen((double y) {
       if (mounted) {
       if (mounted) {
         setState(() {
         setState(() {
-          _history.add("Scroll in  Y Direction: $y");
+          _history.add('Scroll in Y Direction: $y');
         });
         });
       }
       }
     });
     });
 
 
-    _onScrollXChanged =
-        flutterWebviewPlugin.onScrollXChanged.listen((double x) {
+    _onScrollXChanged = flutterWebViewPlugin.onScrollXChanged.listen((double x) {
       if (mounted) {
       if (mounted) {
         setState(() {
         setState(() {
-          _history.add("Scroll in  X Direction: $x");
+          _history.add('Scroll in X Direction: $x');
         });
         });
       }
       }
     });
     });
 
 
-    _onStateChanged =
-        flutterWebviewPlugin.onStateChanged.listen((WebViewStateChanged state) {
+    _onStateChanged = flutterWebViewPlugin.onStateChanged.listen((WebViewStateChanged state) {
       if (mounted) {
       if (mounted) {
         setState(() {
         setState(() {
           _history.add('onStateChanged: ${state.type} ${state.url}');
           _history.add('onStateChanged: ${state.type} ${state.url}');
@@ -128,8 +156,7 @@ class _MyHomePageState extends State<MyHomePage> {
       }
       }
     });
     });
 
 
-    _onHttpError =
-        flutterWebviewPlugin.onHttpError.listen((WebViewHttpError error) {
+    _onHttpError = flutterWebViewPlugin.onHttpError.listen((WebViewHttpError error) {
       if (mounted) {
       if (mounted) {
         setState(() {
         setState(() {
           _history.add('onHttpError: ${error.code} ${error.url}');
           _history.add('onHttpError: ${error.code} ${error.url}');
@@ -148,89 +175,91 @@ class _MyHomePageState extends State<MyHomePage> {
     _onScrollXChanged.cancel();
     _onScrollXChanged.cancel();
     _onScrollYChanged.cancel();
     _onScrollYChanged.cancel();
 
 
-    flutterWebviewPlugin.dispose();
+    flutterWebViewPlugin.dispose();
 
 
     super.dispose();
     super.dispose();
   }
   }
 
 
   @override
   @override
   Widget build(BuildContext context) {
   Widget build(BuildContext context) {
-    return new Scaffold(
+    return Scaffold(
       key: _scaffoldKey,
       key: _scaffoldKey,
-      appBar: new AppBar(
+      appBar: AppBar(
         title: const Text('Plugin example app'),
         title: const Text('Plugin example app'),
       ),
       ),
-      body: new Column(
-        mainAxisAlignment: MainAxisAlignment.center,
-        children: [
-          new Container(
-            padding: const EdgeInsets.all(24.0),
-            child: new TextField(controller: _urlCtrl),
-          ),
-          new RaisedButton(
-            onPressed: () {
-              flutterWebviewPlugin.launch(selectedUrl,
-                  rect: new Rect.fromLTWH(
-                      0.0, 0.0, MediaQuery.of(context).size.width, 300.0),
-                  userAgent: kAndroidUserAgent);
-            },
-            child: const Text('Open Webview (rect)'),
-          ),
-          new RaisedButton(
-            onPressed: () {
-              flutterWebviewPlugin.launch(selectedUrl, hidden: true);
-            },
-            child: const Text('Open "hidden" Webview'),
-          ),
-          new RaisedButton(
-            onPressed: () {
-              flutterWebviewPlugin.launch(selectedUrl);
-            },
-            child: const Text('Open Fullscreen Webview'),
-          ),
-          new RaisedButton(
-            onPressed: () {
-              Navigator.of(context).pushNamed('/widget');
-            },
-            child: const Text('Open widget webview'),
-          ),
-          new Container(
-            padding: const EdgeInsets.all(24.0),
-            child: new TextField(controller: _codeCtrl),
-          ),
-          new RaisedButton(
-            onPressed: () {
-              final future =
-                  flutterWebviewPlugin.evalJavascript(_codeCtrl.text);
-              future.then((String result) {
-                setState(() {
-                  _history.add('eval: $result');
+      body: SingleChildScrollView(
+        child: Column(
+          mainAxisAlignment: MainAxisAlignment.center,
+          children: [
+            Container(
+              padding: const EdgeInsets.all(24.0),
+              child: TextField(controller: _urlCtrl),
+            ),
+            RaisedButton(
+              onPressed: () {
+                flutterWebViewPlugin.launch(
+                  selectedUrl,
+                  rect: Rect.fromLTWH(0.0, 0.0, MediaQuery.of(context).size.width, 300.0),
+                  userAgent: kAndroidUserAgent,
+                );
+              },
+              child: const Text('Open Webview (rect)'),
+            ),
+            RaisedButton(
+              onPressed: () {
+                flutterWebViewPlugin.launch(selectedUrl, hidden: true);
+              },
+              child: const Text('Open "hidden" Webview'),
+            ),
+            RaisedButton(
+              onPressed: () {
+                flutterWebViewPlugin.launch(selectedUrl);
+              },
+              child: const Text('Open Fullscreen Webview'),
+            ),
+            RaisedButton(
+              onPressed: () {
+                Navigator.of(context).pushNamed('/widget');
+              },
+              child: const Text('Open widget webview'),
+            ),
+            Container(
+              padding: const EdgeInsets.all(24.0),
+              child: TextField(controller: _codeCtrl),
+            ),
+            RaisedButton(
+              onPressed: () {
+                final future = flutterWebViewPlugin.evalJavascript(_codeCtrl.text);
+                future.then((String result) {
+                  setState(() {
+                    _history.add('eval: $result');
+                  });
                 });
                 });
-              });
-            },
-            child: const Text('Eval some javascript'),
-          ),
-          new RaisedButton(
-            onPressed: () {
-              setState(() {
-                _history.clear();
-              });
-              flutterWebviewPlugin.close();
-            },
-            child: const Text('Close'),
-          ),
-          new RaisedButton(
-            onPressed: () {
-              flutterWebviewPlugin.getCookies().then((m) {
+              },
+              child: const Text('Eval some javascript'),
+            ),
+            RaisedButton(
+              onPressed: () {
                 setState(() {
                 setState(() {
-                  _history.add('cookies: $m');
+                  _history.clear();
+                });
+                flutterWebViewPlugin.close();
+              },
+              child: const Text('Close'),
+            ),
+            RaisedButton(
+              onPressed: () {
+                flutterWebViewPlugin.getCookies().then((m) {
+                  setState(() {
+                    _history.add('cookies: $m');
+                  });
                 });
                 });
-              });
-            },
-            child: const Text('Cookies'),
-          ),
-          new Text(_history.join('\n'))
-        ],
+              },
+              child: const Text('Cookies'),
+            ),
+            Text(_history.join('\n'))
+          ],
+        ),
       ),
       ),
     );
     );
   }
   }

+ 44 - 18
ios/Classes/FlutterWebviewPlugin.m

@@ -14,10 +14,10 @@ static NSString *const CHANNEL_NAME = @"flutter_webview_plugin";
     channel = [FlutterMethodChannel
     channel = [FlutterMethodChannel
                methodChannelWithName:CHANNEL_NAME
                methodChannelWithName:CHANNEL_NAME
                binaryMessenger:[registrar messenger]];
                binaryMessenger:[registrar messenger]];
-    
-    UIViewController *viewController = (UIViewController *)registrar.messenger;
+
+    UIViewController *viewController = [UIApplication sharedApplication].delegate.window.rootViewController;
     FlutterWebviewPlugin* instance = [[FlutterWebviewPlugin alloc] initWithViewController:viewController];
     FlutterWebviewPlugin* instance = [[FlutterWebviewPlugin alloc] initWithViewController:viewController];
-    
+
     [registrar addMethodCallDelegate:instance channel:channel];
     [registrar addMethodCallDelegate:instance channel:channel];
 }
 }
 
 
@@ -48,7 +48,7 @@ static NSString *const CHANNEL_NAME = @"flutter_webview_plugin";
         result(nil);
         result(nil);
     } else if ([@"reloadUrl" isEqualToString:call.method]) {
     } else if ([@"reloadUrl" isEqualToString:call.method]) {
         [self reloadUrl:call];
         [self reloadUrl:call];
-        result(nil);	
+        result(nil);
     } else if ([@"show" isEqualToString:call.method]) {
     } else if ([@"show" isEqualToString:call.method]) {
         [self show];
         [self show];
         result(nil);
         result(nil);
@@ -58,6 +58,17 @@ static NSString *const CHANNEL_NAME = @"flutter_webview_plugin";
     } else if ([@"stopLoading" isEqualToString:call.method]) {
     } else if ([@"stopLoading" isEqualToString:call.method]) {
         [self stopLoading];
         [self stopLoading];
         result(nil);
         result(nil);
+    } else if ([@"cleanCookies" isEqualToString:call.method]) {
+        [self cleanCookies];
+    } else if ([@"back" isEqualToString:call.method]) {
+        [self back];
+        result(nil);
+    } else if ([@"forward" isEqualToString:call.method]) {
+        [self forward];
+        result(nil);
+    } else if ([@"reload" isEqualToString:call.method]) {
+        [self reload];
+        result(nil);
     } else {
     } else {
         result(FlutterMethodNotImplemented);
         result(FlutterMethodNotImplemented);
     }
     }
@@ -72,27 +83,27 @@ static NSString *const CHANNEL_NAME = @"flutter_webview_plugin";
     NSString *userAgent = call.arguments[@"userAgent"];
     NSString *userAgent = call.arguments[@"userAgent"];
     NSNumber *withZoom = call.arguments[@"withZoom"];
     NSNumber *withZoom = call.arguments[@"withZoom"];
     NSNumber *scrollBar = call.arguments[@"scrollBar"];
     NSNumber *scrollBar = call.arguments[@"scrollBar"];
-    
+
     if (clearCache != (id)[NSNull null] && [clearCache boolValue]) {
     if (clearCache != (id)[NSNull null] && [clearCache boolValue]) {
         [[NSURLCache sharedURLCache] removeAllCachedResponses];
         [[NSURLCache sharedURLCache] removeAllCachedResponses];
     }
     }
-    
+
     if (clearCookies != (id)[NSNull null] && [clearCookies boolValue]) {
     if (clearCookies != (id)[NSNull null] && [clearCookies boolValue]) {
         [[NSURLSession sharedSession] resetWithCompletionHandler:^{
         [[NSURLSession sharedSession] resetWithCompletionHandler:^{
         }];
         }];
     }
     }
-    
+
     if (userAgent != (id)[NSNull null]) {
     if (userAgent != (id)[NSNull null]) {
         [[NSUserDefaults standardUserDefaults] registerDefaults:@{@"UserAgent": userAgent}];
         [[NSUserDefaults standardUserDefaults] registerDefaults:@{@"UserAgent": userAgent}];
     }
     }
-    
+
     CGRect rc;
     CGRect rc;
-    if (rect != nil) {
+    if (rect != (id)[NSNull null]) {
         rc = [self parseRect:rect];
         rc = [self parseRect:rect];
     } else {
     } else {
         rc = self.viewController.view.bounds;
         rc = self.viewController.view.bounds;
     }
     }
-    
+
     self.webview = [[WKWebView alloc] initWithFrame:rc];
     self.webview = [[WKWebView alloc] initWithFrame:rc];
     self.webview.navigationDelegate = self;
     self.webview.navigationDelegate = self;
     self.webview.scrollView.delegate = self;
     self.webview.scrollView.delegate = self;
@@ -100,8 +111,6 @@ static NSString *const CHANNEL_NAME = @"flutter_webview_plugin";
     self.webview.scrollView.showsHorizontalScrollIndicator = [scrollBar boolValue];
     self.webview.scrollView.showsHorizontalScrollIndicator = [scrollBar boolValue];
     self.webview.scrollView.showsVerticalScrollIndicator = [scrollBar boolValue];
     self.webview.scrollView.showsVerticalScrollIndicator = [scrollBar boolValue];
 
 
-
-
     _enableZoom = [withZoom boolValue];
     _enableZoom = [withZoom boolValue];
 
 
     [self.viewController.view addSubview:self.webview];
     [self.viewController.view addSubview:self.webview];
@@ -138,11 +147,11 @@ static NSString *const CHANNEL_NAME = @"flutter_webview_plugin";
             } else {
             } else {
                 NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]];
                 NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]];
                 NSDictionary *headers = call.arguments[@"headers"];
                 NSDictionary *headers = call.arguments[@"headers"];
-                
+
                 if (headers != nil) {
                 if (headers != nil) {
                     [request setAllHTTPHeaderFields:headers];
                     [request setAllHTTPHeaderFields:headers];
                 }
                 }
-                
+
                 [self.webview loadRequest:request];
                 [self.webview loadRequest:request];
             }
             }
         }
         }
@@ -204,6 +213,26 @@ static NSString *const CHANNEL_NAME = @"flutter_webview_plugin";
         [self.webview stopLoading];
         [self.webview stopLoading];
     }
     }
 }
 }
+- (void)back {
+    if (self.webview != nil) {
+        [self.webview goBack];
+    }
+}
+- (void)forward {
+    if (self.webview != nil) {
+        [self.webview goForward];
+    }
+}
+- (void)reload {
+    if (self.webview != nil) {
+        [self.webview reload];
+    }
+}
+
+- (void)cleanCookies {
+    [[NSURLSession sharedSession] resetWithCompletionHandler:^{
+        }];
+}
 
 
 #pragma mark -- WkWebView Delegate
 #pragma mark -- WkWebView Delegate
 - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction
 - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction
@@ -241,10 +270,7 @@ static NSString *const CHANNEL_NAME = @"flutter_webview_plugin";
 }
 }
 
 
 - (void)webView:(WKWebView *)webView didFailNavigation:(WKNavigation *)navigation withError:(NSError *)error {
 - (void)webView:(WKWebView *)webView didFailNavigation:(WKNavigation *)navigation withError:(NSError *)error {
-    id data = [FlutterError errorWithCode:[NSString stringWithFormat:@"%ld", error.code]
-                                  message:error.localizedDescription
-                                  details:error.localizedFailureReason];
-    [channel invokeMethod:@"onError" arguments:data];
+    [channel invokeMethod:@"onError" arguments:@{@"code": [NSString stringWithFormat:@"%ld", error.code], @"error": error.localizedDescription}];
 }
 }
 
 
 - (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler {
 - (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler {

+ 65 - 69
lib/src/base.dart

@@ -11,25 +11,24 @@ enum WebViewState { shouldStart, startLoad, finishLoad }
 
 
 // TODO: use an id by webview to be able to manage multiple webview
 // TODO: use an id by webview to be able to manage multiple webview
 
 
-/// Singleton Class that communicate with a Webview Instance
-/// Have to be instanciate after `runApp` called.
+/// Singleton class that communicate with a Webview Instance
 class FlutterWebviewPlugin {
 class FlutterWebviewPlugin {
-  final _channel = const MethodChannel(_kChannel);
+  factory FlutterWebviewPlugin() => _instance ??= FlutterWebviewPlugin._();
 
 
-  final _onDestroy = new StreamController<Null>.broadcast();
-  final _onUrlChanged = new StreamController<String>.broadcast();
-  final _onStateChanged = new StreamController<WebViewStateChanged>.broadcast();
-  final _onScrollXChanged = new StreamController<double>.broadcast();
-  final _onScrollYChanged = new StreamController<double>.broadcast();
-  final _onHttpError = new StreamController<WebViewHttpError>.broadcast();
+  FlutterWebviewPlugin._() {
+    _channel.setMethodCallHandler(_handleMessages);
+  }
 
 
   static FlutterWebviewPlugin _instance;
   static FlutterWebviewPlugin _instance;
 
 
-  factory FlutterWebviewPlugin() => _instance ??= new FlutterWebviewPlugin._();
+  final _channel = const MethodChannel(_kChannel);
 
 
-  FlutterWebviewPlugin._() {
-    _channel.setMethodCallHandler(_handleMessages);
-  }
+  final _onDestroy = StreamController<Null>.broadcast();
+  final _onUrlChanged = StreamController<String>.broadcast();
+  final _onStateChanged = StreamController<WebViewStateChanged>.broadcast();
+  final _onScrollXChanged = StreamController<double>.broadcast();
+  final _onScrollYChanged = StreamController<double>.broadcast();
+  final _onHttpError = StreamController<WebViewHttpError>.broadcast();
 
 
   Future<Null> _handleMessages(MethodCall call) async {
   Future<Null> _handleMessages(MethodCall call) async {
     switch (call.method) {
     switch (call.method) {
@@ -39,21 +38,21 @@ class FlutterWebviewPlugin {
       case 'onUrlChanged':
       case 'onUrlChanged':
         _onUrlChanged.add(call.arguments['url']);
         _onUrlChanged.add(call.arguments['url']);
         break;
         break;
-      case "onScrollXChanged":
-        _onScrollXChanged.add(call.arguments["xDirection"]);
+      case 'onScrollXChanged':
+        _onScrollXChanged.add(call.arguments['xDirection']);
         break;
         break;
-      case "onScrollYChanged":
-        _onScrollYChanged.add(call.arguments["yDirection"]);
+      case 'onScrollYChanged':
+        _onScrollYChanged.add(call.arguments['yDirection']);
         break;
         break;
-      case "onState":
+      case 'onState':
         _onStateChanged.add(
         _onStateChanged.add(
-          new WebViewStateChanged.fromMap(
-              new Map<String, dynamic>.from(call.arguments)),
+          WebViewStateChanged.fromMap(
+            Map<String, dynamic>.from(call.arguments),
+          ),
         );
         );
         break;
         break;
       case 'onHttpError':
       case 'onHttpError':
-        _onHttpError.add(
-            WebViewHttpError(call.arguments['code'], call.arguments['url']));
+        _onHttpError.add(WebViewHttpError(call.arguments['code'], call.arguments['url']));
         break;
         break;
     }
     }
   }
   }
@@ -95,19 +94,23 @@ class FlutterWebviewPlugin {
   /// - [withLocalUrl]: allow url as a local path
   /// - [withLocalUrl]: allow url as a local path
   ///     Allow local files on iOs > 9.0
   ///     Allow local files on iOs > 9.0
   /// - [scrollBar]: enable or disable scrollbar
   /// - [scrollBar]: enable or disable scrollbar
-  Future<Null> launch(String url,
-      {Map<String, String> headers,
-      bool withJavascript,
-      bool clearCache,
-      bool clearCookies,
-      bool hidden,
-      bool enableAppScheme,
-      Rect rect,
-      String userAgent,
-      bool withZoom,
-      bool withLocalStorage,
-      bool withLocalUrl,
-      bool scrollBar}) async {
+  Future<Null> launch(String url, {
+    Map<String, String> headers,
+    bool withJavascript,
+    bool clearCache,
+    bool clearCookies,
+    bool hidden,
+    bool enableAppScheme,
+    Rect rect,
+    String userAgent,
+    bool withZoom,
+    bool withLocalStorage,
+    bool withLocalUrl,
+    bool scrollBar,
+    bool supportMultipleWindows,
+    bool appCacheEnabled,
+    bool allowFileURLs,
+  }) async {
     final args = <String, dynamic>{
     final args = <String, dynamic>{
       'url': url,
       'url': url,
       'withJavascript': withJavascript ?? true,
       'withJavascript': withJavascript ?? true,
@@ -119,7 +122,10 @@ class FlutterWebviewPlugin {
       'withZoom': withZoom ?? false,
       'withZoom': withZoom ?? false,
       'withLocalStorage': withLocalStorage ?? true,
       'withLocalStorage': withLocalStorage ?? true,
       'withLocalUrl': withLocalUrl ?? false,
       'withLocalUrl': withLocalUrl ?? false,
-      'scrollBar': scrollBar ?? true
+      'scrollBar': scrollBar ?? true,
+      'supportMultipleWindows': supportMultipleWindows ?? false,
+      'appCacheEnabled': appCacheEnabled ?? false,
+      'allowFileURLs': allowFileURLs ?? false,
     };
     };
 
 
     if (headers != null) {
     if (headers != null) {
@@ -131,7 +137,7 @@ class FlutterWebviewPlugin {
         'left': rect.left,
         'left': rect.left,
         'top': rect.top,
         'top': rect.top,
         'width': rect.width,
         'width': rect.width,
-        'height': rect.height
+        'height': rect.height,
       };
       };
     }
     }
     await _channel.invokeMethod('launch', args);
     await _channel.invokeMethod('launch', args);
@@ -145,44 +151,34 @@ class FlutterWebviewPlugin {
 
 
   /// Close the Webview
   /// Close the Webview
   /// Will trigger the [onDestroy] event
   /// Will trigger the [onDestroy] event
-  Future close() => _channel.invokeMethod('close');
+  Future<Null> close() async => await _channel.invokeMethod('close');
 
 
   /// Reloads the WebView.
   /// Reloads the WebView.
-  /// This is only available on Android for now.
-  Future reload() => _channel.invokeMethod('reload');
+  Future<Null> reload() async => await _channel.invokeMethod('reload');
 
 
   /// Navigates back on the Webview.
   /// Navigates back on the Webview.
-  /// This is only available on Android for now.
-  Future goBack() => _channel.invokeMethod('back');
+  Future<Null> goBack() async => await _channel.invokeMethod('back');
 
 
   /// Navigates forward on the Webview.
   /// Navigates forward on the Webview.
-  /// This is only available on Android for now.
-  Future goForward() => _channel.invokeMethod('forward');
+  Future<Null> goForward() async => await _channel.invokeMethod('forward');
 
 
   // Hides the webview
   // Hides the webview
-  Future hide() => _channel.invokeMethod('hide');
+  Future<Null> hide() async => await _channel.invokeMethod('hide');
 
 
   // Shows the webview
   // Shows the webview
-  Future show() => _channel.invokeMethod('show');
+  Future<Null> show() async => await _channel.invokeMethod('show');
 
 
-  // Reload webview with a new url
-  Future reloadUrl(String url) async {
+  // Reload webview with a url
+  Future<Null> reloadUrl(String url) async {
     final args = <String, String>{'url': url};
     final args = <String, String>{'url': url};
     await _channel.invokeMethod('reloadUrl', args);
     await _channel.invokeMethod('reloadUrl', args);
   }
   }
 
 
-  // Stops current loading process
-  Future stopLoading() => _channel.invokeMethod("stopLoading");
-
-  /// adds the plugin as ActivityResultListener
-  /// Only needed and used on Android
-  Future registerAcitivityResultListener() =>
-      _channel.invokeMethod('registerAcitivityResultListener');
+  // Clean cookies on WebView
+  Future<Null> cleanCookies() async => await _channel.invokeMethod('cleanCookies');
 
 
-  /// removes the plugin as ActivityResultListener
-  /// Only needed and used on Android
-  Future removeAcitivityResultListener() =>
-      _channel.invokeMethod('removeAcitivityResultListener');
+  // Stops current loading process
+  Future<Null> stopLoading() async => await _channel.invokeMethod('stopLoading');
 
 
   /// Close all Streams
   /// Close all Streams
   void dispose() {
   void dispose() {
@@ -201,8 +197,8 @@ class FlutterWebviewPlugin {
 
 
     if (cookiesString?.isNotEmpty == true) {
     if (cookiesString?.isNotEmpty == true) {
       cookiesString.split(';').forEach((String cookie) {
       cookiesString.split(';').forEach((String cookie) {
-        final splited = cookie.split('=');
-        cookies[splited[0]] = splited[1];
+        final split = cookie.split('=');
+        cookies[split[0]] = split[1];
       });
       });
     }
     }
 
 
@@ -216,17 +212,13 @@ class FlutterWebviewPlugin {
       'left': rect.left,
       'left': rect.left,
       'top': rect.top,
       'top': rect.top,
       'width': rect.width,
       'width': rect.width,
-      'height': rect.height
+      'height': rect.height,
     };
     };
     await _channel.invokeMethod('resize', args);
     await _channel.invokeMethod('resize', args);
   }
   }
 }
 }
 
 
 class WebViewStateChanged {
 class WebViewStateChanged {
-  final WebViewState type;
-  final String url;
-  final int navigationType;
-
   WebViewStateChanged(this.type, this.url, this.navigationType);
   WebViewStateChanged(this.type, this.url, this.navigationType);
 
 
   factory WebViewStateChanged.fromMap(Map<String, dynamic> map) {
   factory WebViewStateChanged.fromMap(Map<String, dynamic> map) {
@@ -242,13 +234,17 @@ class WebViewStateChanged {
         t = WebViewState.finishLoad;
         t = WebViewState.finishLoad;
         break;
         break;
     }
     }
-    return new WebViewStateChanged(t, map['url'], map['navigationType']);
+    return WebViewStateChanged(t, map['url'], map['navigationType']);
   }
   }
+
+  final WebViewState type;
+  final String url;
+  final int navigationType;
 }
 }
 
 
 class WebViewHttpError {
 class WebViewHttpError {
+  WebViewHttpError(this.code, this.url);
+
   final String url;
   final String url;
   final String code;
   final String code;
-
-  WebViewHttpError(this.code, this.url);
 }
 }

+ 135 - 74
lib/src/webview_scaffold.dart

@@ -2,12 +2,39 @@ import 'dart:async';
 
 
 import 'package:flutter/foundation.dart';
 import 'package:flutter/foundation.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter/material.dart';
+import 'package:flutter/rendering.dart';
 
 
 import 'base.dart';
 import 'base.dart';
 
 
 class WebviewScaffold extends StatefulWidget {
 class WebviewScaffold extends StatefulWidget {
+
+  const WebviewScaffold({
+    Key key,
+    this.appBar,
+    @required this.url,
+    this.headers,
+    this.withJavascript,
+    this.clearCache,
+    this.clearCookies,
+    this.enableAppScheme,
+    this.userAgent,
+    this.primary = true,
+    this.persistentFooterButtons,
+    this.bottomNavigationBar,
+    this.withZoom,
+    this.withLocalStorage,
+    this.withLocalUrl,
+    this.scrollBar,
+    this.supportMultipleWindows,
+    this.appCacheEnabled,
+    this.hidden = false,
+    this.initialChild,
+    this.allowFileURLs,
+  }) : super(key: key);
+
   final PreferredSizeWidget appBar;
   final PreferredSizeWidget appBar;
   final String url;
   final String url;
+  final Map<String, String> headers;
   final bool withJavascript;
   final bool withJavascript;
   final bool clearCache;
   final bool clearCache;
   final bool clearCookies;
   final bool clearCookies;
@@ -20,112 +47,146 @@ class WebviewScaffold extends StatefulWidget {
   final bool withLocalStorage;
   final bool withLocalStorage;
   final bool withLocalUrl;
   final bool withLocalUrl;
   final bool scrollBar;
   final bool scrollBar;
-
-  final Map<String, String> headers;
-
-  const WebviewScaffold(
-      {Key key,
-      this.appBar,
-      @required this.url,
-      this.headers,
-      this.withJavascript,
-      this.clearCache,
-      this.clearCookies,
-      this.enableAppScheme,
-      this.userAgent,
-      this.primary = true,
-      this.persistentFooterButtons,
-      this.bottomNavigationBar,
-      this.withZoom,
-      this.withLocalStorage,
-      this.withLocalUrl,
-      this.scrollBar})
-      : super(key: key);
+  final bool supportMultipleWindows;
+  final bool appCacheEnabled;
+  final bool hidden;
+  final Widget initialChild;
+  final bool allowFileURLs;
 
 
   @override
   @override
-  _WebviewScaffoldState createState() => new _WebviewScaffoldState();
+  _WebviewScaffoldState createState() => _WebviewScaffoldState();
 }
 }
 
 
 class _WebviewScaffoldState extends State<WebviewScaffold> {
 class _WebviewScaffoldState extends State<WebviewScaffold> {
-  final webviewReference = new FlutterWebviewPlugin();
+  final webviewReference = FlutterWebviewPlugin();
   Rect _rect;
   Rect _rect;
   Timer _resizeTimer;
   Timer _resizeTimer;
+  StreamSubscription<WebViewStateChanged> _onStateChanged;
 
 
   @override
   @override
   void initState() {
   void initState() {
     super.initState();
     super.initState();
     webviewReference.close();
     webviewReference.close();
+
+    if (widget.hidden) {
+      _onStateChanged = webviewReference.onStateChanged.listen((WebViewStateChanged state) {
+        if (state.type == WebViewState.finishLoad) {
+          webviewReference.show();
+        }
+      });
+    }
   }
   }
 
 
   @override
   @override
   void dispose() {
   void dispose() {
     super.dispose();
     super.dispose();
+    _resizeTimer?.cancel();
     webviewReference.close();
     webviewReference.close();
+    if (widget.hidden) {
+      _onStateChanged.cancel();
+    }
     webviewReference.dispose();
     webviewReference.dispose();
   }
   }
 
 
   @override
   @override
   Widget build(BuildContext context) {
   Widget build(BuildContext context) {
-    if (_rect == null) {
-      _rect = _buildRect(context);
-      webviewReference.launch(widget.url,
-          headers: widget.headers,
-          withJavascript: widget.withJavascript,
-          clearCache: widget.clearCache,
-          clearCookies: widget.clearCookies,
-          enableAppScheme: widget.enableAppScheme,
-          userAgent: widget.userAgent,
-          rect: _rect,
-          withZoom: widget.withZoom,
-          withLocalStorage: widget.withLocalStorage,
-          withLocalUrl: widget.withLocalUrl,
-          scrollBar: widget.scrollBar);
-    } else {
-      final rect = _buildRect(context);
-      if (_rect != rect) {
-        _rect = rect;
-        _resizeTimer?.cancel();
-        _resizeTimer = new Timer(new Duration(milliseconds: 300), () {
-          // avoid resizing to fast when build is called multiple time
-          webviewReference.resize(_rect);
-        });
-      }
-    }
-    return new Scaffold(
-        appBar: widget.appBar,
-        persistentFooterButtons: widget.persistentFooterButtons,
-        bottomNavigationBar: widget.bottomNavigationBar,
-        body: const Center(child: const CircularProgressIndicator()));
+    return Scaffold(
+      appBar: widget.appBar,
+      persistentFooterButtons: widget.persistentFooterButtons,
+      bottomNavigationBar: widget.bottomNavigationBar,
+      body: _WebviewPlaceholder(
+        onRectChanged: (Rect value) {
+          if (_rect == null) {
+            _rect = value;
+            webviewReference.launch(
+              widget.url,
+              headers: widget.headers,
+              withJavascript: widget.withJavascript,
+              clearCache: widget.clearCache,
+              clearCookies: widget.clearCookies,
+              hidden: widget.hidden,
+              enableAppScheme: widget.enableAppScheme,
+              userAgent: widget.userAgent,
+              rect: _rect,
+              withZoom: widget.withZoom,
+              withLocalStorage: widget.withLocalStorage,
+              withLocalUrl: widget.withLocalUrl,
+              scrollBar: widget.scrollBar,
+              supportMultipleWindows: widget.supportMultipleWindows,
+              appCacheEnabled: widget.appCacheEnabled,
+              allowFileURLs: widget.allowFileURLs,
+            );
+          } else {
+            if (_rect != value) {
+              _rect = value;
+              _resizeTimer?.cancel();
+              _resizeTimer = Timer(const Duration(milliseconds: 250), () {
+                // avoid resizing to fast when build is called multiple time
+                webviewReference.resize(_rect);
+              });
+            }
+          }
+        },
+        child: widget.initialChild ?? const Center(child: const CircularProgressIndicator()),
+      ),
+    );
   }
   }
+}
 
 
-  Rect _buildRect(BuildContext context) {
-    final fullscreen = widget.appBar == null;
+class _WebviewPlaceholder extends SingleChildRenderObjectWidget {
+  const _WebviewPlaceholder({
+    Key key,
+    @required this.onRectChanged,
+    Widget child,
+  }) : super(key: key, child: child);
 
 
-    final mediaQuery = MediaQuery.of(context);
-    final topPadding = widget.primary ? mediaQuery.padding.top : 0.0;
-    final top =
-        fullscreen ? 0.0 : widget.appBar.preferredSize.height + topPadding;
+  final ValueChanged<Rect> onRectChanged;
 
 
-    var height = mediaQuery.size.height - top;
+  @override
+  RenderObject createRenderObject(BuildContext context) {
+    return _WebviewPlaceholderRender(
+      onRectChanged: onRectChanged,
+    );
+  }
 
 
-    if (widget.bottomNavigationBar != null) {
-      height -= 56.0 +
-          mediaQuery.padding
-              .bottom; // todo(lejard_h) find a way to determine bottomNavigationBar programmatically
-    }
+  @override
+  void updateRenderObject(BuildContext context, _WebviewPlaceholderRender renderObject) {
+    renderObject..onRectChanged = onRectChanged;
+  }
+}
+
+class _WebviewPlaceholderRender extends RenderProxyBox {
+  _WebviewPlaceholderRender({
+    RenderBox child,
+    ValueChanged<Rect> onRectChanged,
+  })  : _callback = onRectChanged,
+        super(child);
+
+  ValueChanged<Rect> _callback;
+  Rect _rect;
+
+  Rect get rect => _rect;
 
 
-    if (widget.persistentFooterButtons != null) {
-      height -=
-          53.0; // todo(lejard_h) find a way to determine persistentFooterButtons programmatically
-      if (widget.bottomNavigationBar == null) {
-        height -= mediaQuery.padding.bottom;
-      }
+  set onRectChanged(ValueChanged<Rect> callback) {
+    if (callback != _callback) {
+      _callback = callback;
+      notifyRect();
     }
     }
+  }
 
 
-    if (height < 0.0) {
-      height = 0.0;
+  void notifyRect() {
+    if (_callback != null && _rect != null) {
+      _callback(_rect);
     }
     }
+  }
 
 
-    return new Rect.fromLTWH(0.0, top, mediaQuery.size.width, height);
+  @override
+  void paint(PaintingContext context, Offset offset) {
+    super.paint(context, offset);
+    final rect = offset & size;
+    if (_rect != rect) {
+      _rect = rect;
+      notifyRect();
+    }
   }
   }
 }
 }

+ 5 - 2
pubspec.yaml

@@ -4,11 +4,14 @@ authors:
 - Hadrien Lejard <hadrien.lejard@gmail.com>
 - Hadrien Lejard <hadrien.lejard@gmail.com>
 - Toufik Zitouni <toufiksapps@gmail.com>
 - Toufik Zitouni <toufiksapps@gmail.com>
 - Pedia <kpedia@163.com>
 - Pedia <kpedia@163.com>
+- Simon Lightfoot <simon@devangels.london>
+- Rafal Wachol <gorudonu@gmail.com>
 homepage: https://github.com/dart-flitter/flutter_webview_plugin
 homepage: https://github.com/dart-flitter/flutter_webview_plugin
-version: 0.2.1+2
+version: 0.3.0+2
+maintainer: Simon Lightfoot (@slightfoot)
 
 
 environment:
 environment:
-  sdk: ">=2.0.0-dev <3.0.0"
+  sdk: ">=2.0.0 <3.0.0"
 
 
 flutter:
 flutter:
   plugin:
   plugin:

Некоторые файлы не были показаны из-за большого количества измененных файлов