Skip to content

Commit

Permalink
Merge pull request #20 from pedia/master
Browse files Browse the repository at this point in the history
iOS delegate and some features
  • Loading branch information
lejard-h authored Dec 20, 2017
2 parents 39225b2 + 0bdb71a commit 0e62672
Show file tree
Hide file tree
Showing 9 changed files with 445 additions and 86 deletions.
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
# 0.0.10

- iOS: add Delegate, same as the event of android.

- iOS && Android:

- eval javascript
- user agent setting
- state change event
- embed in rectangle(not fullscreen)
- hidden webview

# 0.0.9

- Android: remove the need to use FlutterActivity as base activity
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,21 @@
package com.flutter_webview_plugin;

import android.content.Intent;

import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.os.Build;
import android.view.ViewGroup;
import android.view.View;
import android.webkit.CookieManager;
import android.webkit.ValueCallback;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.FrameLayout;

import java.util.HashMap;
import java.util.Map;

import io.flutter.app.FlutterActivity;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
Expand All @@ -15,13 +26,13 @@
*/
public class FlutterWebviewPlugin implements MethodCallHandler {
private Activity activity;
private WebView webView;
public static MethodChannel channel;
private final int WEBVIEW_ACTIVITY_CODE = 1;
private static final String CHANNEL_NAME = "flutter_webview_plugin";

public static void registerWith(PluginRegistry.Registrar registrar) {
channel = new MethodChannel(registrar.messenger(), CHANNEL_NAME);
FlutterWebviewPlugin instance = new FlutterWebviewPlugin((Activity) registrar.activity());
FlutterWebviewPlugin instance = new FlutterWebviewPlugin((Activity)registrar.activity());
channel.setMethodCallHandler(instance);
}

Expand All @@ -38,27 +49,165 @@ public void onMethodCall(MethodCall call, MethodChannel.Result result) {
case "close":
close(call, result);
break;
case "eval":
eval(call, result);
break;
default:
result.notImplemented();
break;
}
}

private void clearCookies() {
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();
}
}

private void clearCache() {
webView.clearCache(true);
webView.clearFormData();
}

private WebViewClient setWebViewClient() {
WebViewClient webViewClient = new BrowserClient();
webView.setWebViewClient(webViewClient);
return webViewClient;
}

private void eval(String code, final MethodChannel.Result result) {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
webView.evaluateJavascript(code, new ValueCallback<String>() {
@Override
public void onReceiveValue(String value) {
result.success(value);
}
});
} else {
webView.loadUrl(code);
}
}

// @Override
protected void onDestroy() {
FlutterWebviewPlugin.channel.invokeMethod("onDestroy", null);
}

// @Override
public void onBackPressed() {
if(webView.canGoBack()){
webView.goBack();
return;
}
FlutterWebviewPlugin.channel.invokeMethod("onBackPressed", null);
}

private static int dp2px(Context context, float dp) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dp * scale +0.5f);
}

private void openUrl(MethodCall call, MethodChannel.Result result) {
Intent intent = new Intent(activity, WebviewActivity.class);
if (webView == null) {
webView = new WebView(activity);

Map<String, Number> rc = call.argument("rect");
if (rc != null) {
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
dp2px(activity, rc.get("width").intValue()), dp2px(activity, rc.get("height").intValue()));
params.setMargins(dp2px(activity, rc.get("left").intValue()), dp2px(activity, rc.get("top").intValue()),
0, 0);
activity.addContentView(webView, params);
}
else if (!(boolean) call.argument("hidden")) {
activity.setContentView(webView);
}

setWebViewClient();
}

webView.getSettings().setJavaScriptEnabled((boolean) call.argument("withJavascript"));

if ((boolean) call.argument("clearCache")) {
clearCache();
}

if ((boolean) call.argument("hidden")) {
webView.setVisibility(View.INVISIBLE);
}

intent.putExtra(WebviewActivity.URL_KEY, (String) call.argument("url"));
intent.putExtra(WebviewActivity.WITH_JAVASCRIPT_KEY, (boolean) call.argument("withJavascript"));
intent.putExtra(WebviewActivity.CLEAR_CACHE_KEY, (boolean) call.argument("clearCache"));
intent.putExtra(WebviewActivity.CLEAR_COOKIES_KEY, (boolean) call.argument("clearCookies"));
if ((boolean) call.argument("clearCookies")) {
clearCookies();
}

activity.startActivityForResult(intent, WEBVIEW_ACTIVITY_CODE);
String userAgent = call.argument("userAgent");
if (userAgent != null) {
webView.getSettings().setUserAgentString(userAgent);
}

String url = (String) call.argument("url");
webView.loadUrl(url);
result.success(null);
}

private void close(MethodCall call, MethodChannel.Result result) {
activity.finishActivity(WEBVIEW_ACTIVITY_CODE);
if (View.VISIBLE == webView.getVisibility()) {
ViewGroup vg = (ViewGroup) (webView.getParent());
vg.removeView(webView);
}
webView = null;
result.success(null);

FlutterWebviewPlugin.channel.invokeMethod("onDestroy", null);
}

private void eval(MethodCall call, final MethodChannel.Result result) {
String code = call.argument("code");

if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
webView.evaluateJavascript(code, new ValueCallback<String>() {
@Override
public void onReceiveValue(String value) {
result.success(value);
}
});
} else {
// TODO:
webView.loadUrl(code);
}
}


private class BrowserClient extends WebViewClient {
private BrowserClient() {
super();
}

@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
Map<String, Object> data = new HashMap<>();
data.put("url", url);
FlutterWebviewPlugin.channel.invokeMethod("onUrlChanged", data);

data.put("type", "startLoad");
FlutterWebviewPlugin.channel.invokeMethod("onState", data);
}

@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
Map<String, Object> data = new HashMap<>();
data.put("url", url);
data.put("type", "finishLoad");
FlutterWebviewPlugin.channel.invokeMethod("onState", data);
}
}
}

This file was deleted.

10 changes: 9 additions & 1 deletion example/ios/Runner.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -257,9 +257,14 @@
files = (
);
inputPaths = (
"${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh",
"${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";
outputPaths = (
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Flutter.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_webview_plugin.framework",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
Expand All @@ -286,13 +291,16 @@
files = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n";
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
Expand Down
75 changes: 58 additions & 17 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import 'package:flutter/material.dart';

import 'package:flutter_webview_plugin/flutter_webview_plugin.dart';

const kAndroidUserAgent =
"Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Mobile Safari/537.36";

void main() {
runApp(new MyApp());
}
Expand Down Expand Up @@ -32,16 +35,20 @@ class MyHomePage extends StatefulWidget {

class _MyHomePageState extends State<MyHomePage> {
// Instance of WebView plugin
final FlutterWebviewPlugin flutterWebviewPlugin = new FlutterWebviewPlugin();
final FlutterWebViewPlugin flutterWebviewPlugin = new FlutterWebViewPlugin();

// On destroy stream
StreamSubscription _onDestroy;

// On urlChanged stream
StreamSubscription<String> _onUrlChanged;

TextEditingController _ctrl =
new TextEditingController(text: "https://flutter.io");
TextEditingController _urlCtrl =
new TextEditingController(text: "http://github.com");

TextEditingController _codeCtrl =
new TextEditingController(text: "window.navigator.userAgent");

GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey();

final _history = [];
Expand All @@ -63,7 +70,7 @@ class _MyHomePageState extends State<MyHomePage> {
_onUrlChanged = flutterWebviewPlugin.onUrlChanged.listen((String url) {
if (mounted) {
setState(() {
_history.add(url);
_history.add("onUrlChanged: $url");
});
}
});
Expand All @@ -90,24 +97,58 @@ class _MyHomePageState extends State<MyHomePage> {
children: [
new Container(
padding: const EdgeInsets.all(24.0),
child: new TextField(controller: _ctrl),
child: new TextField(controller: _urlCtrl),
),
new RaisedButton(
onPressed: () {
flutterWebviewPlugin.launch(_urlCtrl.text,
fullScreen: false,
rect: new Rect.fromLTWH(
0.0, 0.0, MediaQuery.of(context).size.width, 300.0),
userAgent: kAndroidUserAgent);
},
child: new Text("Open Webview (rect)"),
),
new RaisedButton(
onPressed: () {
flutterWebviewPlugin.launch(_urlCtrl.text, hidden: true);
},
child: new Text("Open 'hidden' Webview"),
),
new RaisedButton(
onPressed: () {
flutterWebviewPlugin.launch(_urlCtrl.text, fullScreen: true);
},
child: new Text("Open Fullscreen Webview"),
),
new Container(
padding: const EdgeInsets.all(24.0),
child: new TextField(controller: _codeCtrl),
),
new RaisedButton(
onPressed: _onPressed,
child: new Text("Open Webview"),
onPressed: () {
Future<String> future =
flutterWebviewPlugin.evalJavascript(_codeCtrl.text);
future.then((String result) {
setState(() {
_history.add("eval: $result");
});
});
},
child: new Text("Eval some javascript"),
),
new Text(_history.join(", "))
new RaisedButton(
onPressed: () {
setState(() {
_history.clear();
});
flutterWebviewPlugin.close();
},
child: new Text("Close"),
),
new Text(_history.join("\n"))
],
),
);
}

void _onPressed() {
try {
// This way you launch WebView with an url as a parameter.
flutterWebviewPlugin.launch(_ctrl.text);
} catch (e) {
print(e);
}
}
}
2 changes: 1 addition & 1 deletion ios/Classes/FlutterWebviewPlugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ static FlutterMethodChannel *channel;

@interface FlutterWebviewPlugin : NSObject<FlutterPlugin>
@property (nonatomic, retain) UIViewController *viewController;
@property (nonatomic, retain) WebviewController *webviewController;
@property (nonatomic, retain) UIWebView *webview;
@end
Loading

0 comments on commit 0e62672

Please sign in to comment.