Skip to content

Conversation

@kbulgakov-exo
Copy link

@kbulgakov-exo kbulgakov-exo commented Jan 18, 2026

The existing approach with locking the main thread to make a synchronous call asking JS "can I proceed with this URL" isn't reliable. Even the recent timeout bump to 500ms #47 didn't help, we still experience the loading issues. Bumping the timeout even more (for example with #48) would inevitably lead to performance degradation because of the locked thread. We should come up with a more reliable solution

The bottleneck

I've put some logs to diagnose what exactly is the bottleneck. The JS callback works super fast, but the problem is that sometimes it seems to be called after Native already makes the decision after the 500ms default timeout:

 Timeline:
  0ms      Native dispatches event
           |
           |  (JS thread busy)
           |
  501ms    Native TIMEOUT → blocks navigation
           |
 >501ms   JS receives event, responds "allow"
           |
           ✗ Response ignored - decision already made 

The solution

Let's mirror the async architecture of the onShouldStartLoad calls from https://github.com/react-native-webview/react-native-webview. We can easily backport most of the code.

I recommend reviewing commit by commit

Notes:

  • the first commit cherry-picks WebViewDecisionManager from upstream with minor formatting changes
  • the other commits rely on the upstream code as well, but with a few minor changes to conform to our codebase. I’m going to leave the code references below.

Testing

  • WebView loads content normally when JS responds with true
  • WebView rejects loading when JS responds with false

@kbulgakov-exo kbulgakov-exo requested review from a team and 633kh4ck January 18, 2026 19:09
@kbulgakov-exo kbulgakov-exo self-assigned this Jan 18, 2026
Comment on lines +1126 to +1135
int lockIdentifier = [[RNCWebViewDecisionManager getInstance] setDecisionHandler:^(BOOL shouldStart) {
dispatch_async(dispatch_get_main_queue(), ^{
if (!shouldStart) {
decisionHandler(WKNavigationActionPolicyCancel);
return;
}
allowNavigation();
});
}];

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reference: https://github.com/react-native-webview/react-native-webview/blob/5bc526fce5b9d6225df183bdf3d8cf542007d90a/apple/RNCWebViewImpl.m#L1366-L1386

The allowing code is moved into the allowNavigation helper to be reused below to keep the old fallback behavior

RCTLogWarn(@"startLoadWithResult invoked with invalid lockIdentifier: "
"got %lld, expected %lld", (long long)lockIdentifier, (long long)_shouldStartLoadLock.condition);
}
[[RNCWebViewDecisionManager getInstance] setResult:result forLockIdentifier:(int)lockIdentifier];
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Author

@kbulgakov-exo kbulgakov-exo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tACK

  • WebView loads content normally when JS responds with true
  • WebView rejects loading when JS responds with false

Copy link

@guten-exodus guten-exodus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

utACK nice

@kbulgakov-exo
Copy link
Author

@guten-exodus Could you check whether this also addresses the pain points you had in Pay?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants