44import android .annotation .TargetApi ;
55import android .app .DownloadManager ;
66import android .content .Context ;
7- import android .content .Intent ;
87import android .content .pm .ActivityInfo ;
98import android .content .pm .PackageManager ;
109import android .graphics .Bitmap ;
1413import android .net .Uri ;
1514import android .os .Build ;
1615import android .os .Environment ;
17- import androidx .annotation .RequiresApi ;
18- import androidx .core .content .ContextCompat ;
16+ import android .os .SystemClock ;
1917import android .text .TextUtils ;
2018import android .util .Log ;
2119import android .view .Gravity ;
4139import android .webkit .WebViewClient ;
4240import android .widget .FrameLayout ;
4341
42+ import androidx .annotation .Nullable ;
43+ import androidx .annotation .RequiresApi ;
44+ import androidx .core .content .ContextCompat ;
45+ import androidx .core .util .Pair ;
46+
47+ import com .facebook .common .logging .FLog ;
4448import com .facebook .react .views .scroll .ScrollEvent ;
4549import com .facebook .react .views .scroll .ScrollEventType ;
4650import com .facebook .react .views .scroll .OnScrollDispatchHelper ;
6468import com .facebook .react .uimanager .events .ContentSizeChangeEvent ;
6569import com .facebook .react .uimanager .events .Event ;
6670import com .facebook .react .uimanager .events .EventDispatcher ;
71+ import com .reactnativecommunity .webview .RNCWebViewModule .ShouldOverrideUrlLoadingLock .ShouldOverrideCallbackState ;
6772import com .reactnativecommunity .webview .events .TopLoadingErrorEvent ;
6873import com .reactnativecommunity .webview .events .TopHttpErrorEvent ;
6974import com .reactnativecommunity .webview .events .TopLoadingFinishEvent ;
8489import java .util .HashMap ;
8590import java .util .Locale ;
8691import java .util .Map ;
87-
88- import javax .annotation .Nullable ;
92+ import java .util .concurrent .atomic .AtomicReference ;
8993
9094/**
9195 * Manages instances of {@link WebView}
113117 */
114118@ ReactModule (name = RNCWebViewManager .REACT_CLASS )
115119public class RNCWebViewManager extends SimpleViewManager <WebView > {
120+ private static final String TAG = "RNCWebViewManager" ;
116121
117122 public static final int COMMAND_GO_BACK = 1 ;
118123 public static final int COMMAND_GO_FORWARD = 2 ;
@@ -136,6 +141,7 @@ public class RNCWebViewManager extends SimpleViewManager<WebView> {
136141 // Use `webView.loadUrl("about:blank")` to reliably reset the view
137142 // state and release page resources (including any running JavaScript).
138143 protected static final String BLANK_URL = "about:blank" ;
144+ protected static final int SHOULD_OVERRIDE_URL_LOADING_TIMEOUT = 250 ;
139145 protected WebViewConfig mWebViewConfig ;
140146
141147 protected RNCWebChromeClient mWebChromeClient = null ;
@@ -806,15 +812,52 @@ public void onPageStarted(WebView webView, String url, Bitmap favicon) {
806812
807813 @ Override
808814 public boolean shouldOverrideUrlLoading (WebView view , String url ) {
809- progressChangedFilter .setWaitingForCommandLoadUrl (true );
810- dispatchEvent (
811- view ,
812- new TopShouldStartLoadWithRequestEvent (
813- view .getId (),
814- createWebViewEvent (view , url )));
815- return true ;
816- }
815+ final RNCWebView rncWebView = (RNCWebView ) view ;
816+ final boolean isJsDebugging = ((ReactContext ) view .getContext ()).getJavaScriptContextHolder ().get () == 0 ;
817817
818+ if (!isJsDebugging && rncWebView .mCatalystInstance != null ) {
819+ final Pair <Integer , AtomicReference <ShouldOverrideCallbackState >> lock = RNCWebViewModule .shouldOverrideUrlLoadingLock .getNewLock ();
820+ final int lockIdentifier = lock .first ;
821+ final AtomicReference <ShouldOverrideCallbackState > lockObject = lock .second ;
822+
823+ final WritableMap event = createWebViewEvent (view , url );
824+ event .putInt ("lockIdentifier" , lockIdentifier );
825+ rncWebView .sendDirectMessage ("onShouldStartLoadWithRequest" , event );
826+
827+ try {
828+ assert lockObject != null ;
829+ synchronized (lockObject ) {
830+ final long startTime = SystemClock .elapsedRealtime ();
831+ while (lockObject .get () == ShouldOverrideCallbackState .UNDECIDED ) {
832+ if (SystemClock .elapsedRealtime () - startTime > SHOULD_OVERRIDE_URL_LOADING_TIMEOUT ) {
833+ FLog .w (TAG , "Did not receive response to shouldOverrideUrlLoading in time, defaulting to allow loading." );
834+ RNCWebViewModule .shouldOverrideUrlLoadingLock .removeLock (lockIdentifier );
835+ return false ;
836+ }
837+ lockObject .wait (SHOULD_OVERRIDE_URL_LOADING_TIMEOUT );
838+ }
839+ }
840+ } catch (InterruptedException e ) {
841+ FLog .e (TAG , "shouldOverrideUrlLoading was interrupted while waiting for result." , e );
842+ RNCWebViewModule .shouldOverrideUrlLoadingLock .removeLock (lockIdentifier );
843+ return false ;
844+ }
845+
846+ final boolean shouldOverride = lockObject .get () == ShouldOverrideCallbackState .SHOULD_OVERRIDE ;
847+ RNCWebViewModule .shouldOverrideUrlLoadingLock .removeLock (lockIdentifier );
848+
849+ return shouldOverride ;
850+ } else {
851+ FLog .w (TAG , "Couldn't use blocking synchronous call for onShouldStartLoadWithRequest due to debugging or missing Catalyst instance, falling back to old event-and-load." );
852+ progressChangedFilter .setWaitingForCommandLoadUrl (true );
853+ dispatchEvent (
854+ view ,
855+ new TopShouldStartLoadWithRequestEvent (
856+ view .getId (),
857+ createWebViewEvent (view , url )));
858+ return true ;
859+ }
860+ }
818861
819862 @ TargetApi (Build .VERSION_CODES .N )
820863 @ Override
@@ -1164,6 +1207,7 @@ protected static class RNCWebView extends WebView implements LifecycleEventListe
11641207 */
11651208 public RNCWebView (ThemedReactContext reactContext ) {
11661209 super (reactContext );
1210+ this .createCatalystInstance ();
11671211 progressChangedFilter = new ProgressChangedFilter ();
11681212 }
11691213
@@ -1272,7 +1316,6 @@ public void setMessagingEnabled(boolean enabled) {
12721316
12731317 if (enabled ) {
12741318 addJavascriptInterface (createRNCWebViewBridge (this ), JAVASCRIPT_INTERFACE );
1275- this .createCatalystInstance ();
12761319 } else {
12771320 removeJavascriptInterface (JAVASCRIPT_INTERFACE );
12781321 }
@@ -1328,7 +1371,7 @@ public void run() {
13281371 data .putString ("data" , message );
13291372
13301373 if (mCatalystInstance != null ) {
1331- mContext .sendDirectMessage (data );
1374+ mContext .sendDirectMessage ("onMessage" , data );
13321375 } else {
13331376 dispatchEvent (webView , new TopMessageEvent (webView .getId (), data ));
13341377 }
@@ -1339,21 +1382,21 @@ public void run() {
13391382 eventData .putString ("data" , message );
13401383
13411384 if (mCatalystInstance != null ) {
1342- this .sendDirectMessage (eventData );
1385+ this .sendDirectMessage ("onMessage" , eventData );
13431386 } else {
13441387 dispatchEvent (this , new TopMessageEvent (this .getId (), eventData ));
13451388 }
13461389 }
13471390 }
13481391
1349- protected void sendDirectMessage (WritableMap data ) {
1392+ protected void sendDirectMessage (final String method , WritableMap data ) {
13501393 WritableNativeMap event = new WritableNativeMap ();
13511394 event .putMap ("nativeEvent" , data );
13521395
13531396 WritableNativeArray params = new WritableNativeArray ();
13541397 params .pushMap (event );
13551398
1356- mCatalystInstance .callFunction (messagingModuleName , "onMessage" , params );
1399+ mCatalystInstance .callFunction (messagingModuleName , method , params );
13571400 }
13581401
13591402 protected void onScrollChanged (int x , int y , int oldX , int oldY ) {
0 commit comments