Skip to content

Commit

Permalink
fix(android): Prevent libhwui crash when WebView is in ScrollView (#2874
Browse files Browse the repository at this point in the history
)

* fix(android): Prevent libhwui crash when WebView is in ScrollView

* fix incorrect reactTag for event passing

* fix regression from Background example test case

* fix getParent NPE

* Apply suggestions from code review

* Fix rebase conflict
  • Loading branch information
Kudo committed Oct 6, 2023
1 parent 663f256 commit 886664d
Show file tree
Hide file tree
Showing 7 changed files with 317 additions and 258 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ public boolean shouldOverrideUrlLoading (WebView subview, String url) {

((RNCWebView) view).dispatchEvent(
view,
new TopOpenWindowEvent(view.getId(), event)
new TopOpenWindowEvent(RNCWebViewWrapper.getReactTagFromWebView(view), event)
);

return true;
Expand Down Expand Up @@ -130,15 +130,15 @@ public void onProgressChanged(WebView webView, int newProgress) {
if (progressChangedFilter.isWaitingForCommandLoadUrl()) {
return;
}
int reactTag = RNCWebViewWrapper.getReactTagFromWebView(webView);
WritableMap event = Arguments.createMap();
event.putDouble("target", webView.getId());
event.putDouble("target", reactTag);
event.putString("title", webView.getTitle());
event.putString("url", url);
event.putBoolean("canGoBack", webView.canGoBack());
event.putBoolean("canGoForward", webView.canGoForward());
event.putDouble("progress", (float) newProgress / 100);

int reactTag = webView.getId();
UIManagerHelper.getEventDispatcherForReactTag(this.mWebView.getThemedReactContext(), reactTag).dispatchEvent(new TopLoadingProgressEvent(reactTag, event));
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,8 @@
package com.reactnativecommunity.webview;

import androidx.annotation.Nullable;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Rect;
import android.os.Build;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;

import android.view.ActionMode;
import android.view.Menu;
import android.view.MenuItem;
Expand All @@ -21,33 +14,28 @@
import android.webkit.WebView;
import android.webkit.WebViewClient;

import androidx.annotation.Nullable;

import com.facebook.common.logging.FLog;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.CatalystInstance;
import com.facebook.react.bridge.LifecycleEventListener;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.bridge.WritableNativeArray;
import com.facebook.react.bridge.WritableNativeMap;
import com.facebook.react.uimanager.ThemedReactContext;
import com.facebook.react.uimanager.UIManagerHelper;
import com.facebook.react.uimanager.UIManagerModule;
import com.facebook.react.uimanager.events.ContentSizeChangeEvent;
import com.facebook.react.uimanager.events.Event;
import com.facebook.react.uimanager.events.EventDispatcher;
import com.facebook.react.uimanager.events.RCTEventEmitter;
import com.facebook.react.views.scroll.OnScrollDispatchHelper;
import com.facebook.react.views.scroll.ScrollEvent;
import com.facebook.react.views.scroll.ScrollEventType;
import com.reactnativecommunity.webview.events.TopCustomMenuSelectionEvent;
import com.reactnativecommunity.webview.events.TopLoadingProgressEvent;
import com.reactnativecommunity.webview.events.TopMessageEvent;

import org.json.JSONException;
import org.json.JSONObject;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.List;
import java.util.Map;

Expand Down Expand Up @@ -143,7 +131,7 @@ protected void onSizeChanged(int w, int h, int ow, int oh) {
dispatchEvent(
this,
new ContentSizeChangeEvent(
this.getId(),
RNCWebViewWrapper.getReactTagFromWebView(this),
w,
h
)
Expand Down Expand Up @@ -194,7 +182,7 @@ public void onReceiveValue(String selectionJson) {
selectionText = new JSONObject(selectionJson).getString("selection");
} catch (JSONException ignored) {}
wMap.putString("selectedText", selectionText);
dispatchEvent(RNCWebView.this, new TopCustomMenuSelectionEvent(RNCWebView.this.getId(), wMap));
dispatchEvent(RNCWebView.this, new TopCustomMenuSelectionEvent(RNCWebViewWrapper.getReactTagFromWebView(RNCWebView.this), wMap));
mode.finish();
}
}
Expand Down Expand Up @@ -326,7 +314,7 @@ public void run() {
if (mCatalystInstance != null) {
mWebView.sendDirectMessage("onMessage", data);
} else {
dispatchEvent(webView, new TopMessageEvent(webView.getId(), data));
dispatchEvent(webView, new TopMessageEvent(RNCWebViewWrapper.getReactTagFromWebView(webView), data));
}
}
});
Expand All @@ -337,7 +325,7 @@ public void run() {
if (mCatalystInstance != null) {
this.sendDirectMessage("onMessage", eventData);
} else {
dispatchEvent(this, new TopMessageEvent(this.getId(), eventData));
dispatchEvent(this, new TopMessageEvent(RNCWebViewWrapper.getReactTagFromWebView(this), eventData));
}
}
}
Expand Down Expand Up @@ -365,7 +353,7 @@ protected void onScrollChanged(int x, int y, int oldX, int oldY) {

if (mOnScrollDispatchHelper.onScrollChanged(x, y)) {
ScrollEvent event = ScrollEvent.obtain(
this.getId(),
RNCWebViewWrapper.getReactTagFromWebView(this),
ScrollEventType.SCROLL,
x,
y,
Expand All @@ -382,7 +370,7 @@ protected void onScrollChanged(int x, int y, int oldX, int oldY) {

protected void dispatchEvent(WebView webView, Event event) {
ThemedReactContext reactContext = getThemedReactContext();
int reactTag = webView.getId();
int reactTag = RNCWebViewWrapper.getReactTagFromWebView(webView);
UIManagerHelper.getEventDispatcherForReactTag(reactContext, reactTag).dispatchEvent(event);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ public void doUpdateVisitedHistory (WebView webView, String url, boolean isReloa
((RNCWebView) webView).dispatchEvent(
webView,
new TopLoadingStartEvent(
webView.getId(),
RNCWebViewWrapper.getReactTagFromWebView(webView),
createWebViewEvent(webView, url)));
}

Expand Down Expand Up @@ -125,7 +125,7 @@ public boolean shouldOverrideUrlLoading(WebView view, String url) {
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.");
progressChangedFilter.setWaitingForCommandLoadUrl(true);

int reactTag = view.getId();
int reactTag = RNCWebViewWrapper.getReactTagFromWebView(view);
UIManagerHelper.getEventDispatcherForReactTag((ReactContext) view.getContext(), reactTag).dispatchEvent(new TopShouldStartLoadWithRequestEvent(
reactTag,
createWebViewEvent(view, url)));
Expand Down Expand Up @@ -240,8 +240,8 @@ public void onReceivedError(
eventData.putDouble("code", errorCode);
eventData.putString("description", description);

int reactTag = webView.getId();
UIManagerHelper.getEventDispatcherForReactTag((ReactContext) webView.getContext(), reactTag).dispatchEvent(new TopLoadingErrorEvent(webView.getId(), eventData));
int reactTag = RNCWebViewWrapper.getReactTagFromWebView(webView);
UIManagerHelper.getEventDispatcherForReactTag((ReactContext) webView.getContext(), reactTag).dispatchEvent(new TopLoadingErrorEvent(reactTag, eventData));
}

@RequiresApi(api = Build.VERSION_CODES.M)
Expand All @@ -257,8 +257,8 @@ public void onReceivedHttpError(
eventData.putInt("statusCode", errorResponse.getStatusCode());
eventData.putString("description", errorResponse.getReasonPhrase());

int reactTag = webView.getId();
UIManagerHelper.getEventDispatcherForReactTag((ReactContext) webView.getContext(), reactTag).dispatchEvent(new TopHttpErrorEvent(webView.getId(), eventData));
int reactTag = RNCWebViewWrapper.getReactTagFromWebView(webView);
UIManagerHelper.getEventDispatcherForReactTag((ReactContext) webView.getContext(), reactTag).dispatchEvent(new TopHttpErrorEvent(reactTag, eventData));
}
}

Expand Down Expand Up @@ -287,21 +287,21 @@ public boolean onRenderProcessGone(WebView webView, RenderProcessGoneDetail deta

WritableMap event = createWebViewEvent(webView, webView.getUrl());
event.putBoolean("didCrash", detail.didCrash());
int reactTag = webView.getId();
UIManagerHelper.getEventDispatcherForReactTag((ReactContext) webView.getContext(), reactTag).dispatchEvent(new TopRenderProcessGoneEvent(webView.getId(), event));
int reactTag = RNCWebViewWrapper.getReactTagFromWebView(webView);
UIManagerHelper.getEventDispatcherForReactTag((ReactContext) webView.getContext(), reactTag).dispatchEvent(new TopRenderProcessGoneEvent(reactTag, event));

// returning false would crash the app.
return true;
}

protected void emitFinishEvent(WebView webView, String url) {
int reactTag = webView.getId();
UIManagerHelper.getEventDispatcherForReactTag((ReactContext) webView.getContext(), reactTag).dispatchEvent(new TopLoadingFinishEvent(webView.getId(), createWebViewEvent(webView, url)));
int reactTag = RNCWebViewWrapper.getReactTagFromWebView(webView);
UIManagerHelper.getEventDispatcherForReactTag((ReactContext) webView.getContext(), reactTag).dispatchEvent(new TopLoadingFinishEvent(reactTag, createWebViewEvent(webView, url)));
}

protected WritableMap createWebViewEvent(WebView webView, String url) {
WritableMap event = Arguments.createMap();
event.putDouble("target", webView.getId());
event.putDouble("target", RNCWebViewWrapper.getReactTagFromWebView(webView));
// Don't use webView.getUrl() here, the URL isn't updated to the new value yet in callbacks
// like onPageFinished
event.putString("url", url);
Expand Down
Loading

0 comments on commit 886664d

Please sign in to comment.