Skip to content

Commit 5a55953

Browse files
committed
Add support for sending data from webview to native in iOS and Android
1 parent 90f1e5a commit 5a55953

File tree

7 files changed

+99
-10
lines changed

7 files changed

+99
-10
lines changed

android/src/main/java/com/flutter_webview_plugin/WebviewManager.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import android.view.View;
1111
import android.view.ViewGroup;
1212
import android.webkit.CookieManager;
13+
import android.webkit.JavascriptInterface;
1314
import android.webkit.GeolocationPermissions;
1415
import android.webkit.ValueCallback;
1516
import android.webkit.WebChromeClient;
@@ -244,6 +245,8 @@ public void onProgressChanged(WebView view, int progress) {
244245
FlutterWebviewPlugin.channel.invokeMethod("onProgressChanged", args);
245246
}
246247
});
248+
249+
webView.addJavascriptInterface(new WebAppInterface(), "Android");
247250
}
248251

249252
private Uri getOutputFilename(String intentType) {
@@ -495,4 +498,13 @@ void stopLoading(MethodCall call, MethodChannel.Result result){
495498
webView.stopLoading();
496499
}
497500
}
501+
502+
public class WebAppInterface {
503+
@JavascriptInterface
504+
public void postMessage(String value){
505+
Map<String, String> postMessageMap = new HashMap<>();
506+
postMessageMap.put("postMessage", value);
507+
FlutterWebviewPlugin.channel.invokeMethod("onPostMessage", postMessageMap);
508+
}
509+
}
498510
}

example/html/index.html

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
6+
<meta http-equiv="X-UA-Compatible" content="ie=edge">
7+
<title>Document</title>
8+
</head>
9+
<body>
10+
<button id="button" style="background-color:#158461;height:30px;">send to flutter</button>
11+
12+
<script>
13+
function sendData(data) {
14+
if (/(iPhone|iPad|iPod|iOS)/i.test(navigator.userAgent)){
15+
window.webkit.messageHandlers.Native.postMessage(data);
16+
}else{
17+
if (window.Android && window.Android.postMessage) {
18+
Android.postMessage(data);
19+
}
20+
}
21+
}
22+
23+
window.onload = function () {
24+
document.getElementById('button').onclick = function () {
25+
sendData(JSON.stringify({ action: 'log', data: '1234' }));
26+
}
27+
}
28+
</script>
29+
</body>
30+
</html>

example/ios/Runner.xcodeproj/project.pbxproj

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
objects = {
88

99
/* Begin PBXBuildFile section */
10-
2D5378261FAA1A9400D5DBA9 /* flutter_assets in Resources */ = {isa = PBXBuildFile; fileRef = 2D5378251FAA1A9400D5DBA9 /* flutter_assets */; };
1110
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
1211
3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; };
1312
3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
@@ -40,7 +39,8 @@
4039
/* End PBXCopyFilesBuildPhase section */
4140

4241
/* Begin PBXFileReference section */
43-
2D5378251FAA1A9400D5DBA9 /* flutter_assets */ = {isa = PBXFileReference; lastKnownFileType = folder; name = flutter_assets; path = Flutter/flutter_assets; sourceTree = SOURCE_ROOT; };
42+
0FF8E441CB3BD619650FCC75 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
43+
2BCC7A531667984C22F241E2 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
4444
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
4545
3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = "<group>"; };
4646
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
@@ -77,6 +77,8 @@
7777
840012C8B5EDBCF56B0E4AC1 /* Pods */ = {
7878
isa = PBXGroup;
7979
children = (
80+
2BCC7A531667984C22F241E2 /* Pods-Runner.debug.xcconfig */,
81+
0FF8E441CB3BD619650FCC75 /* Pods-Runner.release.xcconfig */,
8082
);
8183
name = Pods;
8284
sourceTree = "<group>";
@@ -86,7 +88,6 @@
8688
children = (
8789
3B80C3931E831B6300D905FE /* App.framework */,
8890
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
89-
2D5378251FAA1A9400D5DBA9 /* flutter_assets */,
9091
9740EEBA1CF902C7004384FC /* Flutter.framework */,
9192
9740EEB21CF90195004384FC /* Debug.xcconfig */,
9293
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
@@ -211,7 +212,6 @@
211212
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
212213
9740EEB51CF90195004384FC /* Generated.xcconfig in Resources */,
213214
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
214-
2D5378261FAA1A9400D5DBA9 /* flutter_assets in Resources */,
215215
9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */,
216216
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
217217
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
@@ -241,8 +241,8 @@
241241
files = (
242242
);
243243
inputPaths = (
244-
"${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh",
245-
"${PODS_ROOT}/../../../../../flutter/bin/cache/artifacts/engine/ios/Flutter.framework",
244+
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh",
245+
"${PODS_ROOT}/../../../../../../Documents/flutter/bin/cache/artifacts/engine/ios/Flutter.framework",
246246
"${BUILT_PRODUCTS_DIR}/flutter_webview_plugin/flutter_webview_plugin.framework",
247247
);
248248
name = "[CP] Embed Pods Frameworks";
@@ -252,7 +252,7 @@
252252
);
253253
runOnlyForDeploymentPostprocessing = 0;
254254
shellPath = /bin/sh;
255-
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
255+
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
256256
showEnvVarsInLog = 0;
257257
};
258258
9740EEB61CF901F6004384FC /* Run Script */ = {
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+
<plist version="1.0">
4+
<dict>
5+
<key>BuildSystemType</key>
6+
<string>Original</string>
7+
</dict>
8+
</plist>

example/lib/main.dart

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ const kAndroidUserAgent =
88
'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';
99

1010
String selectedUrl = 'https://flutter.io';
11+
String messageUrl = 'your_server/index.html';
1112

1213
void main() => runApp(MyApp());
1314

@@ -99,6 +100,8 @@ class _MyHomePageState extends State<MyHomePage> {
99100

100101
StreamSubscription<double> _onScrollXChanged;
101102

103+
StreamSubscription<String> _onMessage;
104+
102105
final _urlCtrl = TextEditingController(text: selectedUrl);
103106

104107
final _codeCtrl = TextEditingController(text: 'window.navigator.userAgent');
@@ -173,6 +176,14 @@ class _MyHomePageState extends State<MyHomePage> {
173176
});
174177
}
175178
});
179+
180+
_onMessage = flutterWebViewPlugin.onPostMessage.listen((msg) {
181+
if (mounted) {
182+
setState(() {
183+
_history.add('message: $msg');
184+
});
185+
}
186+
});
176187
}
177188

178189
@override
@@ -185,6 +196,7 @@ class _MyHomePageState extends State<MyHomePage> {
185196
_onProgressChanged.cancel();
186197
_onScrollXChanged.cancel();
187198
_onScrollYChanged.cancel();
199+
_onMessage.cancel();
188200

189201
flutterWebViewPlugin.dispose();
190202

@@ -217,6 +229,16 @@ class _MyHomePageState extends State<MyHomePage> {
217229
},
218230
child: const Text('Open Webview (rect)'),
219231
),
232+
RaisedButton(
233+
onPressed: () {
234+
flutterWebViewPlugin.launch(
235+
messageUrl,
236+
rect: Rect.fromLTWH(0.0, 0.0, MediaQuery.of(context).size.width, 300.0),
237+
invalidUrlRegex: r'^(https).+(twitter)', // prevent redirecting to twitter when user click on its icon in flutter website
238+
);
239+
},
240+
child: const Text('Open Webview (message demo)'),
241+
),
220242
RaisedButton(
221243
onPressed: () {
222244
flutterWebViewPlugin.launch(selectedUrl, hidden: true);

ios/Classes/FlutterWebviewPlugin.m

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,12 @@ - (void)initWebview:(FlutterMethodCall*)call {
107107
rc = self.viewController.view.bounds;
108108
}
109109

110-
self.webview = [[WKWebView alloc] initWithFrame:rc];
110+
WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
111+
config.userContentController = [[WKUserContentController alloc] init];
112+
113+
[config.userContentController addScriptMessageHandler:self name:@"Native"];
114+
115+
self.webview = [[WKWebView alloc] initWithFrame:rc configuration:config];
111116
self.webview.UIDelegate = self;
112117
self.webview.navigationDelegate = self;
113118
self.webview.scrollView.delegate = self;
@@ -338,6 +343,11 @@ - (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNaviga
338343
decisionHandler(WKNavigationResponsePolicyAllow);
339344
}
340345

346+
#pragma mark - WKScriptMessageHandler
347+
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
348+
[channel invokeMethod:@"onPostMessage" arguments: @{@"postMessage": message.body}];
349+
}
350+
341351
#pragma mark -- UIScrollViewDelegate
342352
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
343353
if (scrollView.pinchGestureRecognizer.isEnabled != _enableZoom) {

lib/src/base.dart

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ class FlutterWebviewPlugin {
3131
final _onScrollYChanged = StreamController<double>.broadcast();
3232
final _onProgressChanged = new StreamController<double>.broadcast();
3333
final _onHttpError = StreamController<WebViewHttpError>.broadcast();
34+
final _onPostMessage = StreamController<String>.broadcast();
3435

3536
Future<Null> _handleMessages(MethodCall call) async {
3637
switch (call.method) {
@@ -49,8 +50,8 @@ class FlutterWebviewPlugin {
4950
case 'onScrollYChanged':
5051
_onScrollYChanged.add(call.arguments['yDirection']);
5152
break;
52-
case "onProgressChanged":
53-
_onProgressChanged.add(call.arguments["progress"]);
53+
case 'onProgressChanged':
54+
_onProgressChanged.add(call.arguments['progress']);
5455
break;
5556
case 'onState':
5657
_onStateChanged.add(
@@ -62,6 +63,9 @@ class FlutterWebviewPlugin {
6263
case 'onHttpError':
6364
_onHttpError.add(WebViewHttpError(call.arguments['code'], call.arguments['url']));
6465
break;
66+
case 'onPostMessage':
67+
_onPostMessage.add(call.arguments['postMessage']);
68+
break;
6569
}
6670
}
6771

@@ -90,6 +94,8 @@ class FlutterWebviewPlugin {
9094

9195
Stream<WebViewHttpError> get onHttpError => _onHttpError.stream;
9296

97+
Stream<String> get onPostMessage => _onPostMessage.stream;
98+
9399
/// Start the Webview with [url]
94100
/// - [headers] specify additional HTTP headers
95101
/// - [withJavascript] enable Javascript or not for the Webview
@@ -212,6 +218,7 @@ class FlutterWebviewPlugin {
212218
_onScrollXChanged.close();
213219
_onScrollYChanged.close();
214220
_onHttpError.close();
221+
_onPostMessage.close();
215222
_instance = null;
216223
}
217224

0 commit comments

Comments
 (0)