Improved window.postMessage implementation
Summary: Adds a queue to postMessage so that messages sent close together are not lost. Setting location="a";location="b" results in only "b" reaching shouldStartLoadWithRequest. Making the second update asynchronous with setTimeout does not fix the issue unless a delay is added. With this update, postMessage queues "b" until it gets a "message:received" event that confirms "a" has already been processed. The included test sends two messages from a webview and checks that both are received. It fails against the preexisting code with the first message being dropped. Closes https://github.com/facebook/react-native/pull/11304 Differential Revision: D5481385 Pulled By: hramos fbshipit-source-id: 9b6af195eeff8f20c820e2fcdac997c90763e840
This commit is contained in:
parent
bca825ee50
commit
42f7b9e717
|
@ -33,6 +33,7 @@ var TESTS = [
|
|||
require('./ImageCachePolicyTest'),
|
||||
require('./ImageSnapshotTest'),
|
||||
require('./PromiseTest'),
|
||||
require('./WebViewTest'),
|
||||
require('./SyncMethodTest'),
|
||||
require('./WebSocketTest'),
|
||||
require('./AccessibilityManagerTest'),
|
||||
|
|
|
@ -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;
|
|
@ -76,5 +76,9 @@ RCT_TEST(PromiseTest)
|
|||
RCT_TEST_ONLY_WITH_PACKAGER(WebSocketTest)
|
||||
RCT_TEST(AccessibilityManagerTest)
|
||||
|
||||
#if !TARGET_OS_TV // tvOS does not fully support WebView
|
||||
RCT_TEST(WebViewTest)
|
||||
#endif
|
||||
|
||||
|
||||
@end
|
||||
|
|
|
@ -250,6 +250,11 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder)
|
|||
[event addEntriesFromDictionary: @{
|
||||
@"data": data,
|
||||
}];
|
||||
|
||||
NSString *source = @"document.dispatchEvent(new MessageEvent('message:received'));";
|
||||
|
||||
[_webView stringByEvaluatingJavaScriptFromString:source];
|
||||
|
||||
_onMessage(event);
|
||||
}
|
||||
|
||||
|
@ -301,10 +306,28 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder)
|
|||
}
|
||||
#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];
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue