浏览代码

Merge pull request #1 from romkor/add_http_error_stream

Add http error stream
Roman Rodych 7 年之前
父节点
当前提交
018b740b5c

+ 5 - 0
.gitignore

@@ -9,3 +9,8 @@ packages
 pubspec.lock
 
 example/ios/Podfile.lock
+**/Flutter/App.framework/
+**/Flutter/Flutter.framework/
+**/Flutter/Generated.xcconfig/
+**/Flutter/flutter_assets/
+

+ 9 - 0
CHANGELOG.md

@@ -1,3 +1,12 @@
+# 0.1.6
+
+- fix onStateChanged
+- Taking safe areas into account for bottom bars
+- iOS
+    + withLocalUrl option for iOS > 9.0
+- Android
+    + add reload, goBack and foForward function
+
 # 0.1.5
 
 - iOS use WKWebView instead of UIWebView

+ 9 - 0
README.md

@@ -103,3 +103,12 @@ Future<Map<String, dynamic>> getCookies();
 ```dart
 Future<Null> resize(Rect rect);
 ```
+```dart
+Future<Null> show();
+```
+```dart
+Future<Null> hide();
+```
+```dart
+Future<Null> reloadUrl(String url);
+```

+ 3 - 2
android/build.gradle

@@ -3,11 +3,12 @@ version '1.0-SNAPSHOT'
 
 buildscript {
     repositories {
+        google()
         jcenter()
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.3.0'
+        classpath 'com.android.tools.build:gradle:3.1.2'
     }
 }
 
@@ -21,7 +22,7 @@ apply plugin: 'com.android.library'
 
 android {
     compileSdkVersion 25
-    buildToolsVersion '25.0.0'
+    buildToolsVersion '27.0.3'
 
     defaultConfig {
         testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"

+ 3 - 4
android/src/main/AndroidManifest.xml

@@ -1,7 +1,6 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="com.flutter_webview_plugin"
-          android:versionCode="1"
-          android:versionName="0.0.1">
+          package="com.flutter_webview_plugin">
+
+    <uses-sdk android:minSdkVersion="23" android:targetSdkVersion="23"/>
 
-    <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="21"/>
 </manifest>

+ 11 - 0
android/src/main/java/com/flutter_webview_plugin/BrowserClient.java

@@ -1,6 +1,8 @@
 package com.flutter_webview_plugin;
 
 import android.graphics.Bitmap;
+import android.webkit.WebResourceRequest;
+import android.webkit.WebResourceResponse;
 import android.webkit.WebView;
 import android.webkit.WebViewClient;
 
@@ -37,4 +39,13 @@ public class BrowserClient extends WebViewClient {
         FlutterWebviewPlugin.channel.invokeMethod("onState", data);
 
     }
+
+    @Override
+    public void onReceivedHttpError(WebView view, WebResourceRequest request, WebResourceResponse errorResponse) {
+        super.onReceivedHttpError(view, request, errorResponse);
+        Map<String, Object> data = new HashMap<>();
+        data.put("url", request.getUrl().toString());
+        data.put("code", Integer.toString(errorResponse.getStatusCode()));
+        FlutterWebviewPlugin.channel.invokeMethod("onError", data);
+    }
 }

+ 67 - 0
android/src/main/java/com/flutter_webview_plugin/FlutterWebviewPlugin.java

@@ -48,6 +48,24 @@ public class FlutterWebviewPlugin implements MethodCallHandler {
             case "resize":
                 resize(call, result);
                 break;
+            case "reload":
+                reload(call, result);
+                break;
+            case "back":
+                back(call, result);
+                break;
+            case "forward":
+                forward(call, result);
+                break;
+            case "hide":
+                hide(call, result);
+                break;
+            case "show":
+                show(call, result);
+                break;
+            case "reloadUrl":
+                reloadUrl(call, result);
+                break;				
             default:
                 result.notImplemented();
                 break;
@@ -111,6 +129,45 @@ public class FlutterWebviewPlugin implements MethodCallHandler {
         }
     }
 
+    /** 
+    * Navigates back on the Webview.
+    */
+    private void back(MethodCall call, MethodChannel.Result result) {
+        if (webViewManager != null) {
+            webViewManager.back(call, result);
+        }
+    }
+    /** 
+    * Navigates forward on the Webview.
+    */
+    private void forward(MethodCall call, MethodChannel.Result result) {
+        if (webViewManager != null) {
+            webViewManager.forward(call, result);
+        }
+    }
+
+    /** 
+    * Reloads the Webview.
+    */
+    private void reload(MethodCall call, MethodChannel.Result result) {
+        if (webViewManager != null) {
+            webViewManager.reload(call, result);
+        }
+    }
+    private void reloadUrl(MethodCall call, MethodChannel.Result result) {
+        if (webViewManager != null) {
+            String url = call.argument("url");
+            webViewManager.openUrl(false,
+                    false,
+                    false,
+                    false,
+                    "",
+                    url,
+                    false,
+                    false
+            );
+        }
+    }
     private void eval(MethodCall call, final MethodChannel.Result result) {
         if (webViewManager != null) {
             webViewManager.eval(call, result);
@@ -124,6 +181,16 @@ public class FlutterWebviewPlugin implements MethodCallHandler {
         }
         result.success(null);
     }
+    private void hide(MethodCall call, final MethodChannel.Result result) {
+        if (webViewManager != null) {
+            webViewManager.hide(call, result);
+        }
+    }
+    private void show(MethodCall call, final MethodChannel.Result result) {
+        if (webViewManager != null) {
+            webViewManager.show(call, result);
+        }
+    }
 
     private int dp2px(Context context, float dp) {
         final float scale = context.getResources().getDisplayMetrics().density;

+ 46 - 0
android/src/main/java/com/flutter_webview_plugin/WebviewManager.java

@@ -122,8 +122,54 @@ class WebviewManager {
             }
         });
     }
+    /** 
+    * Reloads the Webview.
+    */
+    void reload(MethodCall call, MethodChannel.Result result) {
+        if (webView != null) {
+            webView.reload();
+        }
+    }
+    /** 
+    * Navigates back on the Webview.
+    */
+    void back(MethodCall call, MethodChannel.Result result) {
+        if (webView != null && webView.canGoBack()) {
+            webView.goBack();
+        }
+    }
+    /** 
+    * Navigates forward on the Webview.
+    */
+    void forward(MethodCall call, MethodChannel.Result result) {
+        if (webView != null && webView.canGoForward()) {
+            webView.goForward();
+        }
+    }
 
     void resize(FrameLayout.LayoutParams params) {
         webView.setLayoutParams(params);
     }
+    /** 
+    * Checks if going back on the Webview is possible.
+    */
+    boolean canGoBack() {
+        return webView.canGoBack();
+    }
+    /** 
+    * Checks if going forward on the Webview is possible.
+    */
+    boolean canGoForward() {
+        return webView.canGoForward();
+    }
+    void hide(MethodCall call, MethodChannel.Result result) {
+        if (webView != null) {
+            webView.setVisibility(View.INVISIBLE);
+        }
+    }
+    void show(MethodCall call, MethodChannel.Result result) {
+        if (webView != null) {
+            webView.setVisibility(View.VISIBLE);
+        }
+    }
 }

+ 2 - 2
example/android/app/build.gradle

@@ -15,8 +15,8 @@ apply plugin: 'com.android.application'
 apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion '25.0.2'
+    compileSdkVersion 27
+    buildToolsVersion '27.0.3'
 
     lintOptions {
         disable 'InvalidPackage'

+ 1 - 1
example/android/app/src/main/AndroidManifest.xml

@@ -3,7 +3,7 @@
     android:versionCode="1"
     android:versionName="0.0.1">
 
-    <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="21" />
+    <uses-sdk android:minSdkVersion="23" android:targetSdkVersion="23" />
 
     <!-- The INTERNET permission is required for development. Specifically,
          flutter needs it to communicate with the running application

+ 9 - 1
example/android/build.gradle

@@ -1,16 +1,24 @@
 buildscript {
     repositories {
+        google()
         jcenter()
+        maven {
+            url 'https://maven.google.com/'
+        }
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.3'
+        classpath 'com.android.tools.build:gradle:3.1.1'
     }
 }
 
 allprojects {
     repositories {
+        google()
         jcenter()
+        maven {
+            url 'https://maven.google.com/'
+        }
     }
 }
 

文件差异内容过多而无法显示
+ 354 - 467
example/ios/Flutter/flutter_assets/LICENSE


二进制
example/ios/Flutter/flutter_assets/snapshot_blob.bin


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

@@ -160,7 +160,6 @@
 				97C146EC1CF9000F007C117D /* Resources */,
 				9705A1C41CF9048500538489 /* Embed Frameworks */,
 				95BB15E9E1769C0D146AA592 /* [CP] Embed Pods Frameworks */,
-				532EA9D341340B1DCD08293D /* [CP] Copy Pods Resources */,
 				3B06AD1E1E4923F5004D2608 /* Thin Binary */,
 			);
 			buildRules = (
@@ -236,21 +235,6 @@
 			shellPath = /bin/sh;
 			shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin";
 		};
-		532EA9D341340B1DCD08293D /* [CP] Copy Pods Resources */ = {
-			isa = PBXShellScriptBuildPhase;
-			buildActionMask = 2147483647;
-			files = (
-			);
-			inputPaths = (
-			);
-			name = "[CP] Copy Pods Resources";
-			outputPaths = (
-			);
-			runOnlyForDeploymentPostprocessing = 0;
-			shellPath = /bin/sh;
-			shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
-			showEnvVarsInLog = 0;
-		};
 		95BB15E9E1769C0D146AA592 /* [CP] Embed Pods Frameworks */ = {
 			isa = PBXShellScriptBuildPhase;
 			buildActionMask = 2147483647;
@@ -258,7 +242,7 @@
 			);
 			inputPaths = (
 				"${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh",
-				"${PODS_ROOT}/../../../../../../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",
 			);
 			name = "[CP] Embed Pods Frameworks";

+ 11 - 0
example/lib/main.dart

@@ -58,6 +58,8 @@ class _MyHomePageState extends State<MyHomePage> {
   // On urlChanged stream
   StreamSubscription<WebViewStateChanged> _onStateChanged;
 
+  StreamSubscription<WebViewError> _onError;
+
   TextEditingController _urlCtrl = new TextEditingController(text: selectedUrl);
 
   TextEditingController _codeCtrl =
@@ -103,6 +105,14 @@ class _MyHomePageState extends State<MyHomePage> {
         });
       }
     });
+
+    _onError = flutterWebviewPlugin.onError.listen((WebViewError error) {
+      if (mounted) {
+        setState(() {
+          _history.add("onError: ${error.code} ${error.url}");
+        });
+      }
+    });
   }
 
   @override
@@ -111,6 +121,7 @@ class _MyHomePageState extends State<MyHomePage> {
     _onDestroy.cancel();
     _onUrlChanged.cancel();
     _onStateChanged.cancel();
+    _onError.cancel();
 
     flutterWebviewPlugin.dispose();
 

+ 51 - 4
ios/Classes/FlutterWebviewPlugin.m

@@ -46,6 +46,15 @@ static NSString *const CHANNEL_NAME = @"flutter_webview_plugin";
     } else if ([@"resize" isEqualToString:call.method]) {
         [self resize:call];
         result(nil);
+    } else if ([@"reloadUrl" isEqualToString:call.method]) {
+        [self reloadUrl:call];
+        result(nil);	
+    } else if ([@"show" isEqualToString:call.method]) {
+        [self show];
+        result(nil);
+    } else if ([@"hide" isEqualToString:call.method]) {
+        [self hide];
+        result(nil);
     } else {
         result(FlutterMethodNotImplemented);
     }
@@ -101,10 +110,20 @@ static NSString *const CHANNEL_NAME = @"flutter_webview_plugin";
 
 - (void)navigate:(FlutterMethodCall*)call {
     if (self.webview != nil) {
-        NSString *url = call.arguments[@"url"];
-        NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:url]];
-        [self.webview loadRequest:request];
-    }
+            NSString *url = call.arguments[@"url"];
+            NSNumber *withLocalUrl = call.arguments[@"withLocalUrl"];
+            if ( [withLocalUrl boolValue]) {
+                NSURL *htmlUrl = [NSURL fileURLWithPath:url isDirectory:false];
+                if (@available(iOS 9.0, *)) {
+                    [self.webview loadFileURL:htmlUrl allowingReadAccessToURL:htmlUrl];
+                } else {
+                    @throw @"not available on version earlier than ios 9.0";
+                }
+            } else {
+                NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:url]];
+                [self.webview loadRequest:request];
+            }
+        }
 }
 
 - (void)evalJavascript:(FlutterMethodCall*)call
@@ -140,6 +159,25 @@ static NSString *const CHANNEL_NAME = @"flutter_webview_plugin";
     }
 }
 
+- (void)reloadUrl:(FlutterMethodCall*)call {
+    if (self.webview != nil) {
+		NSString *url = call.arguments[@"url"];
+		NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:url]];
+        [self.webview loadRequest:request];
+    }
+}
+- (void)show {
+    if (self.webview != nil) {
+        self.webview.hidden = false;
+    }
+}
+
+- (void)hide {
+    if (self.webview != nil) {
+        self.webview.hidden = true;
+    }
+}
+
 #pragma mark -- WkWebView Delegate
 - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction
     decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
@@ -181,6 +219,15 @@ static NSString *const CHANNEL_NAME = @"flutter_webview_plugin";
     [channel invokeMethod:@"onError" arguments:data];
 }
 
+- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler {
+    if ([navigationResponse.response isKindOfClass:[NSHTTPURLResponse class]]) {
+        NSHTTPURLResponse * response = (NSHTTPURLResponse *)navigationResponse.response;
+
+        [channel invokeMethod:@"onError" arguments:@{@"code": [NSString stringWithFormat:@"%ld", response.statusCode], @"url": webView.URL.absoluteString}];
+    }
+    decisionHandler(WKNavigationResponsePolicyAllow);
+}
+
 #pragma mark -- UIScrollViewDelegate
 - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
     if (scrollView.pinchGestureRecognizer.isEnabled != _enableZoom) {

+ 48 - 6
lib/src/base.dart

@@ -1,8 +1,8 @@
 import 'dart:async';
 import 'dart:ui';
 
-import 'package:flutter/services.dart';
 import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
 
 const _kChannel = 'flutter_webview_plugin';
 
@@ -19,7 +19,7 @@ class FlutterWebviewPlugin {
   final _onDestroy = new StreamController<Null>.broadcast();
   final _onUrlChanged = new StreamController<String>.broadcast();
   final _onStateChanged = new StreamController<WebViewStateChanged>.broadcast();
-  final _onError = new StreamController<String>.broadcast();
+  final _onError = new StreamController<WebViewError>.broadcast();
 
   static FlutterWebviewPlugin _instance;
 
@@ -38,10 +38,13 @@ class FlutterWebviewPlugin {
         _onUrlChanged.add(call.arguments["url"]);
         break;
       case "onState":
-        _onStateChanged.add(new WebViewStateChanged.fromMap(call.arguments));
+        _onStateChanged.add(
+          new WebViewStateChanged.fromMap(
+              new Map<String, dynamic>.from(call.arguments)),
+        );
         break;
       case "onError":
-        _onError.add(call.arguments);
+        _onError.add(WebViewError(call.arguments['code'], call.arguments['url']));
         break;
     }
   }
@@ -57,6 +60,8 @@ class FlutterWebviewPlugin {
   /// more detail than other events
   Stream<WebViewStateChanged> get onStateChanged => _onStateChanged.stream;
 
+  Stream<WebViewError> get onError => _onError.stream;
+
   /// Start the Webview with [url]
   /// - [withJavascript] enable Javascript or not for the Webview
   ///     iOS WebView: Not implemented yet
@@ -71,6 +76,8 @@ class FlutterWebviewPlugin {
   /// - [withLocalStorage] enable localStorage API on Webview
   ///     Currently Android only.
   ///     It is always enabled in UIWebView of iOS and  can not be disabled.
+  /// - [withLocalUrl]: allow url as a local path
+  ///     Allow local files on iOs > 9.0
   Future<Null> launch(String url,
       {bool withJavascript,
       bool clearCache,
@@ -80,7 +87,8 @@ class FlutterWebviewPlugin {
       Rect rect,
       String userAgent,
       bool withZoom,
-      bool withLocalStorage}) async {
+      bool withLocalStorage,
+      bool withLocalUrl}) async {
     Map<String, dynamic> args = {
       "url": url,
       "withJavascript": withJavascript ?? true,
@@ -90,7 +98,8 @@ class FlutterWebviewPlugin {
       "enableAppScheme": enableAppScheme ?? true,
       "userAgent": userAgent,
       "withZoom": withZoom ?? false,
-      "withLocalStorage": withLocalStorage ?? true
+      "withLocalStorage": withLocalStorage ?? true,
+      "withLocalUrl": withLocalUrl ?? false
     };
     if (rect != null) {
       args["rect"] = {
@@ -113,6 +122,32 @@ class FlutterWebviewPlugin {
   /// Will trigger the [onDestroy] event
   Future close() => _channel.invokeMethod("close");
 
+  /// Reloads the WebView.
+  /// This is only available on Android for now.
+  Future reload() => _channel.invokeMethod("reload");
+
+  /// Navigates back on the Webview.
+  /// This is only available on Android for now.
+  Future goBack() => _channel.invokeMethod("back");
+
+  /// Navigates forward on the Webview.
+  /// This is only available on Android for now.
+  Future goForward() => _channel.invokeMethod("forward");
+  
+  // Hides the webview
+  Future hide() => _channel.invokeMethod("hide");
+  
+  // Shows the webview
+  Future show() => _channel.invokeMethod("show");
+
+  // Reload webview with a new url
+  Future reloadUrl(String url) async {
+    Map<String, dynamic> args = {
+      "url": url
+    };
+    await _channel.invokeMethod("reloadUrl", args);
+  }
+
   /// Close all Streams
   void dispose() {
     _onDestroy.close();
@@ -172,3 +207,10 @@ class WebViewStateChanged {
     return new WebViewStateChanged(t, map["url"], map["navigationType"]);
   }
 }
+
+class WebViewError {
+  final String url;
+  final String code;
+
+  WebViewError(this.code, this.url);
+}

+ 9 - 3
lib/src/webview_scaffold.dart

@@ -18,6 +18,7 @@ class WebviewScaffold extends StatefulWidget {
   final Widget bottomNavigationBar;
   final bool withZoom;
   final bool withLocalStorage;
+  final bool withLocalUrl;
 
   WebviewScaffold(
       {Key key,
@@ -32,7 +33,8 @@ class WebviewScaffold extends StatefulWidget {
       this.persistentFooterButtons,
       this.bottomNavigationBar,
       this.withZoom,
-      this.withLocalStorage})
+      this.withLocalStorage,
+      this.withLocalUrl})
       : super(key: key);
 
   @override
@@ -67,7 +69,8 @@ class _WebviewScaffoldState extends State<WebviewScaffold> {
           userAgent: widget.userAgent,
           rect: _rect,
           withZoom: widget.withZoom,
-          withLocalStorage: widget.withLocalStorage);
+          withLocalStorage: widget.withLocalStorage,
+          withLocalUrl: widget.withLocalUrl);
     } else {
       Rect rect = _buildRect(context);
       if (_rect != rect) {
@@ -98,12 +101,15 @@ class _WebviewScaffoldState extends State<WebviewScaffold> {
 
     if (widget.bottomNavigationBar != null) {
       height -=
-          56.0; // todo(lejard_h) find a way to determine bottomNavigationBar programmatically
+          56.0 + mediaQuery.padding.bottom; // todo(lejard_h) find a way to determine bottomNavigationBar programmatically
     }
 
     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;
+      }
     }
 
     return new Rect.fromLTWH(0.0, top, mediaQuery.size.width, height);

+ 2 - 2
pubspec.yaml

@@ -5,10 +5,10 @@ authors:
 - Toufik Zitouni <toufiksapps@gmail.com>
 - Pedia <kpedia@163.com>
 homepage: https://github.com/dart-flitter/flutter_webview_plugin
-version: 0.1.5
+version: 0.1.6
 
 environment:
-  sdk: ">=1.8.0 <2.0.0"
+  sdk: ">=1.19.0 <2.0.0"
 
 flutter:
   plugin:

部分文件因为文件数量过多而无法显示