Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improved window.postMessage implementation #11304

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions IntegrationTests/IntegrationTestsApp.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ var TESTS = [
require('./ImageCachePolicyTest'),
require('./ImageSnapshotTest'),
require('./PromiseTest'),
require('./WebViewTest'),
require('./SyncMethodTest'),
require('./WebSocketTest'),
require('./AccessibilityManagerTest'),
Expand Down
59 changes: 59 additions & 0 deletions IntegrationTests/WebViewTest.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
'use strict';

var React = require('react');
var ReactNative = require('react-native');
var {
WebView,
} = ReactNative;

var { TestModule } = ReactNative.NativeModules;

class WebViewTest extends React.Component {

render() {
var firstMessageReceived = false;
var secondMessageReceived = false;
function processMessage(e) {
var message = e.nativeEvent.data;
if (message === 'First') {firstMessageReceived = true;}
if (message === 'Second') {secondMessageReceived = true;}

// got both messages
if (firstMessageReceived && secondMessageReceived) {TestModule.markTestPassed(true);}
// wait for next message
else if (firstMessageReceived && !secondMessageReceived) {return;}
// first message got lost
else if (!firstMessageReceived && secondMessageReceived) {throw new Error('First message got lost');}
}
var html = 'Hello world'
+ '<script>'
+ "window.setTimeout(function(){window.postMessage('First'); window.postMessage('Second')}, 0)"
+ '</script>';

// fail if messages didn't get through;
window.setTimeout(function() { throw new Error(firstMessageReceived ? 'Both messages got lost' : 'Second message got lost');}, 10000);

var source = {
html: html,
};

return (
<WebView
source={source}
onMessage = {processMessage}
/>
);
}
}

WebViewTest.displayName = 'WebViewTest';

module.exports = WebViewTest;
4 changes: 4 additions & 0 deletions RNTester/RNTesterIntegrationTests/RNTesterIntegrationTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -76,5 +76,9 @@ - (void)testTheTester_ExpectError
RCT_TEST_ONLY_WITH_PACKAGER(WebSocketTest)
RCT_TEST(AccessibilityManagerTest)

#if !TARGET_OS_TV // tvOS does not fully support WebView
RCT_TEST(WebViewTest)
#endif


@end
31 changes: 27 additions & 4 deletions React/Views/RCTWebView.m
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,11 @@ - (BOOL)webView:(__unused UIWebView *)webView shouldStartLoadWithRequest:(NSURLR
[event addEntriesFromDictionary: @{
@"data": data,
}];

NSString *source = @"document.dispatchEvent(new MessageEvent('message:received'));";

[_webView stringByEvaluatingJavaScriptFromString:source];

_onMessage(event);
}

Expand Down Expand Up @@ -301,10 +306,28 @@ - (void)webViewDidFinishLoad:(UIWebView *)webView
}
#endif
NSString *source = [NSString stringWithFormat:
@"window.originalPostMessage = window.postMessage;"
"window.postMessage = function(data) {"
"window.location = '%@://%@?' + encodeURIComponent(String(data));"
"};", RCTJSNavigationScheme, kPostMessageHost
@"(function() {"
"window.originalPostMessage = window.postMessage;"

"var messageQueue = [];"
"var messagePending = false;"

"function processQueue() {"
"if (!messageQueue.length || messagePending) return;"
"messagePending = true;"
"window.location = '%@://%@?' + encodeURIComponent(messageQueue.shift());"
"}"

"window.postMessage = function(data) {"
"messageQueue.push(String(data));"
"processQueue();"
"};"

"document.addEventListener('message:received', function(e) {"
"messagePending = false;"
"processQueue();"
"});"
"})();", RCTJSNavigationScheme, kPostMessageHost
];
[webView stringByEvaluatingJavaScriptFromString:source];
}
Expand Down