소스 검색

Merge branch 'master' into update-ssl-error-to-top-level-only

Alesandro Ortiz 4 년 전
부모
커밋
2592e5e538
No account linked to committer's email address

+ 5
- 11
.github/workflows/windows-ci.yml 파일 보기

@@ -15,17 +15,10 @@ jobs:
15 15
       with:
16 16
         node-version: '12.9.1'
17 17
 
18
-    - name: Install Visual Studio components
19
-      shell: powershell
20
-      run: .\.github\workflows\scripts\install-vs-features.ps1 Microsoft.VisualStudio.Component.VC.v141.x86.x64,Microsoft.VisualStudio.ComponentGroup.UWP.VC.v141
21
-
22 18
     - name: Setup MSBuild
23 19
       uses: microsoft/setup-msbuild@v1.0.0
24 20
       with:
25 21
         vs-version: 16.5
26
-       
27
-    - name: Setup NuGet
28
-      uses: NuGet/setup-nuget@v1.0.2
29 22
 
30 23
     - name: Check node modules cache
31 24
       uses: actions/cache@v1
@@ -45,13 +38,14 @@ jobs:
45 38
       run: |
46 39
         yarn build
47 40
         yarn tsc
48
- 
49
-    - name: NuGet restore
50
-      run: nuget restore example\windows\WebViewWindows.sln
51 41
 
52 42
     - name: Build x64 release
53
-      run: msbuild example\windows\WebViewWindows.sln /p:Configuration=Release /p:Platform=x64 -m
43
+      shell: powershell
44
+      run: npx react-native run-windows --root example --arch x64 --release --no-packager --no-deploy --logging
54 45
 
46
+    # Workaround for a bug in package searching during deploy.
47
+    # The deploy script only searches windows/{*/bin/x64/Release,Release/*}, but the build step above placed the pakcages at windows/x64/Release.
48
+    # Copy the packages to Windows/Release before deploying.
55 49
     - name: Deploy
56 50
       shell: powershell
57 51
       run: |

+ 127
- 26
android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManager.java 파일 보기

@@ -4,7 +4,6 @@ import android.annotation.SuppressLint;
4 4
 import android.annotation.TargetApi;
5 5
 import android.app.DownloadManager;
6 6
 import android.content.Context;
7
-import android.content.Intent;
8 7
 import android.content.pm.ActivityInfo;
9 8
 import android.content.pm.PackageManager;
10 9
 import android.graphics.Bitmap;
@@ -14,8 +13,7 @@ import android.net.http.SslError;
14 13
 import android.net.Uri;
15 14
 import android.os.Build;
16 15
 import android.os.Environment;
17
-import androidx.annotation.RequiresApi;
18
-import androidx.core.content.ContextCompat;
16
+import android.os.SystemClock;
19 17
 import android.text.TextUtils;
20 18
 import android.util.Log;
21 19
 import android.view.Gravity;
@@ -28,6 +26,7 @@ import android.webkit.CookieManager;
28 26
 import android.webkit.DownloadListener;
29 27
 import android.webkit.GeolocationPermissions;
30 28
 import android.webkit.JavascriptInterface;
29
+import android.webkit.RenderProcessGoneDetail;
31 30
 import android.webkit.SslErrorHandler;
32 31
 import android.webkit.PermissionRequest;
33 32
 import android.webkit.URLUtil;
@@ -40,6 +39,12 @@ import android.webkit.WebView;
40 39
 import android.webkit.WebViewClient;
41 40
 import android.widget.FrameLayout;
42 41
 
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;
43 48
 import com.facebook.react.views.scroll.ScrollEvent;
44 49
 import com.facebook.react.views.scroll.ScrollEventType;
45 50
 import com.facebook.react.views.scroll.OnScrollDispatchHelper;
@@ -63,6 +68,7 @@ import com.facebook.react.uimanager.annotations.ReactProp;
63 68
 import com.facebook.react.uimanager.events.ContentSizeChangeEvent;
64 69
 import com.facebook.react.uimanager.events.Event;
65 70
 import com.facebook.react.uimanager.events.EventDispatcher;
71
+import com.reactnativecommunity.webview.RNCWebViewModule.ShouldOverrideUrlLoadingLock.ShouldOverrideCallbackState;
66 72
 import com.reactnativecommunity.webview.events.TopLoadingErrorEvent;
67 73
 import com.reactnativecommunity.webview.events.TopHttpErrorEvent;
68 74
 import com.reactnativecommunity.webview.events.TopLoadingFinishEvent;
@@ -70,6 +76,7 @@ import com.reactnativecommunity.webview.events.TopLoadingProgressEvent;
70 76
 import com.reactnativecommunity.webview.events.TopLoadingStartEvent;
71 77
 import com.reactnativecommunity.webview.events.TopMessageEvent;
72 78
 import com.reactnativecommunity.webview.events.TopShouldStartLoadWithRequestEvent;
79
+import com.reactnativecommunity.webview.events.TopRenderProcessGoneEvent;
73 80
 
74 81
 import org.json.JSONException;
75 82
 import org.json.JSONObject;
@@ -82,8 +89,7 @@ import java.util.ArrayList;
82 89
 import java.util.HashMap;
83 90
 import java.util.Locale;
84 91
 import java.util.Map;
85
-
86
-import javax.annotation.Nullable;
92
+import java.util.concurrent.atomic.AtomicReference;
87 93
 
88 94
 /**
89 95
  * Manages instances of {@link WebView}
@@ -111,6 +117,7 @@ import javax.annotation.Nullable;
111 117
  */
112 118
 @ReactModule(name = RNCWebViewManager.REACT_CLASS)
113 119
 public class RNCWebViewManager extends SimpleViewManager<WebView> {
120
+  private static final String TAG = "RNCWebViewManager";
114 121
 
115 122
   public static final int COMMAND_GO_BACK = 1;
116 123
   public static final int COMMAND_GO_FORWARD = 2;
@@ -134,6 +141,7 @@ public class RNCWebViewManager extends SimpleViewManager<WebView> {
134 141
   // Use `webView.loadUrl("about:blank")` to reliably reset the view
135 142
   // state and release page resources (including any running JavaScript).
136 143
   protected static final String BLANK_URL = "about:blank";
144
+  protected static final int SHOULD_OVERRIDE_URL_LOADING_TIMEOUT = 250;
137 145
   protected WebViewConfig mWebViewConfig;
138 146
 
139 147
   protected RNCWebChromeClient mWebChromeClient = null;
@@ -297,6 +305,21 @@ public class RNCWebViewManager extends SimpleViewManager<WebView> {
297 305
     }
298 306
   }
299 307
 
308
+  @ReactProp(name = "androidLayerType")
309
+  public void setLayerType(WebView view, String layerTypeString) {
310
+    int layerType = View.LAYER_TYPE_NONE;
311
+    switch (layerTypeString) {
312
+        case "hardware":
313
+          layerType = View.LAYER_TYPE_HARDWARE;
314
+          break;
315
+        case "software":
316
+          layerType = View.LAYER_TYPE_SOFTWARE;
317
+          break;
318
+    }
319
+    view.setLayerType(layerType, null);
320
+  }
321
+
322
+
300 323
   @ReactProp(name = "overScrollMode")
301 324
   public void setOverScrollMode(WebView view, String overScrollModeString) {
302 325
     Integer overScrollMode;
@@ -430,6 +453,11 @@ public class RNCWebViewManager extends SimpleViewManager<WebView> {
430 453
 
431 454
   @ReactProp(name = "incognito")
432 455
   public void setIncognito(WebView view, boolean enabled) {
456
+    // Don't do anything when incognito is disabled
457
+    if (!enabled) {
458
+      return;
459
+    }
460
+
433 461
     // Remove all previous cookies
434 462
     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
435 463
       CookieManager.getInstance().removeAllCookies(null);
@@ -439,14 +467,14 @@ public class RNCWebViewManager extends SimpleViewManager<WebView> {
439 467
 
440 468
     // Disable caching
441 469
     view.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);
442
-    view.getSettings().setAppCacheEnabled(!enabled);
470
+    view.getSettings().setAppCacheEnabled(false);
443 471
     view.clearHistory();
444
-    view.clearCache(enabled);
472
+    view.clearCache(true);
445 473
 
446 474
     // No form data or autofill enabled
447 475
     view.clearFormData();
448
-    view.getSettings().setSavePassword(!enabled);
449
-    view.getSettings().setSaveFormData(!enabled);
476
+    view.getSettings().setSavePassword(false);
477
+    view.getSettings().setSaveFormData(false);
450 478
   }
451 479
 
452 480
   @ReactProp(name = "source")
@@ -576,6 +604,7 @@ public class RNCWebViewManager extends SimpleViewManager<WebView> {
576 604
     export.put(TopShouldStartLoadWithRequestEvent.EVENT_NAME, MapBuilder.of("registrationName", "onShouldStartLoadWithRequest"));
577 605
     export.put(ScrollEventType.getJSEventName(ScrollEventType.SCROLL), MapBuilder.of("registrationName", "onScroll"));
578 606
     export.put(TopHttpErrorEvent.EVENT_NAME, MapBuilder.of("registrationName", "onHttpError"));
607
+    export.put(TopRenderProcessGoneEvent.EVENT_NAME, MapBuilder.of("registrationName", "onRenderProcessGone"));
579 608
     return export;
580 609
   }
581 610
 
@@ -772,7 +801,7 @@ public class RNCWebViewManager extends SimpleViewManager<WebView> {
772 801
       mLastLoadFailed = false;
773 802
 
774 803
       RNCWebView reactWebView = (RNCWebView) webView;
775
-      reactWebView.callInjectedJavaScriptBeforeContentLoaded();       
804
+      reactWebView.callInjectedJavaScriptBeforeContentLoaded();
776 805
 
777 806
       dispatchEvent(
778 807
         webView,
@@ -783,15 +812,52 @@ public class RNCWebViewManager extends SimpleViewManager<WebView> {
783 812
 
784 813
     @Override
785 814
     public boolean shouldOverrideUrlLoading(WebView view, String url) {
786
-      progressChangedFilter.setWaitingForCommandLoadUrl(true);
787
-      dispatchEvent(
788
-        view,
789
-        new TopShouldStartLoadWithRequestEvent(
790
-          view.getId(),
791
-          createWebViewEvent(view, url)));
792
-      return true;
793
-    }
815
+      final RNCWebView rncWebView = (RNCWebView) view;
816
+      final boolean isJsDebugging = ((ReactContext) view.getContext()).getJavaScriptContextHolder().get() == 0;
817
+
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;
794 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
+    }
795 861
 
796 862
     @TargetApi(Build.VERSION_CODES.N)
797 863
     @Override
@@ -844,11 +910,11 @@ public class RNCWebViewManager extends SimpleViewManager<WebView> {
844 910
           case SslError.SSL_UNTRUSTED:
845 911
             description = "The certificate authority is not trusted";
846 912
             break;
847
-          default: 
913
+          default:
848 914
             description = "Unknown SSL Error";
849 915
             break;
850 916
         }
851
-        
917
+
852 918
         description = descriptionPrefix + description;
853 919
 
854 920
         this.onReceivedError(
@@ -858,7 +924,7 @@ public class RNCWebViewManager extends SimpleViewManager<WebView> {
858 924
           failingUrl
859 925
         );
860 926
     }
861
-    
927
+
862 928
     @Override
863 929
     public void onReceivedError(
864 930
       WebView webView,
@@ -915,6 +981,41 @@ public class RNCWebViewManager extends SimpleViewManager<WebView> {
915 981
       }
916 982
     }
917 983
 
984
+    @TargetApi(Build.VERSION_CODES.O)
985
+    @Override
986
+    public boolean onRenderProcessGone(WebView webView, RenderProcessGoneDetail detail) {
987
+        // WebViewClient.onRenderProcessGone was added in O.
988
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
989
+            return false;
990
+        }
991
+        super.onRenderProcessGone(webView, detail);
992
+
993
+        if(detail.didCrash()){
994
+          Log.e("RNCWebViewManager", "The WebView rendering process crashed.");
995
+        }
996
+        else{
997
+          Log.w("RNCWebViewManager", "The WebView rendering process was killed by the system.");
998
+        }
999
+
1000
+        // if webView is null, we cannot return any event
1001
+        // since the view is already dead/disposed
1002
+        // still prevent the app crash by returning true.
1003
+        if(webView == null){
1004
+          return true;
1005
+        }
1006
+
1007
+        WritableMap event = createWebViewEvent(webView, webView.getUrl());
1008
+        event.putBoolean("didCrash", detail.didCrash());
1009
+
1010
+        dispatchEvent(
1011
+          webView,
1012
+          new TopRenderProcessGoneEvent(webView.getId(), event)
1013
+        );
1014
+
1015
+        // returning false would crash the app.
1016
+        return true;
1017
+    }
1018
+
918 1019
     protected void emitFinishEvent(WebView webView, String url) {
919 1020
       dispatchEvent(
920 1021
         webView,
@@ -1121,6 +1222,7 @@ public class RNCWebViewManager extends SimpleViewManager<WebView> {
1121 1222
      */
1122 1223
     public RNCWebView(ThemedReactContext reactContext) {
1123 1224
       super(reactContext);
1225
+      this.createCatalystInstance();
1124 1226
       progressChangedFilter = new ProgressChangedFilter();
1125 1227
     }
1126 1228
 
@@ -1229,7 +1331,6 @@ public class RNCWebViewManager extends SimpleViewManager<WebView> {
1229 1331
 
1230 1332
       if (enabled) {
1231 1333
         addJavascriptInterface(createRNCWebViewBridge(this), JAVASCRIPT_INTERFACE);
1232
-        this.createCatalystInstance();
1233 1334
       } else {
1234 1335
         removeJavascriptInterface(JAVASCRIPT_INTERFACE);
1235 1336
       }
@@ -1285,7 +1386,7 @@ public class RNCWebViewManager extends SimpleViewManager<WebView> {
1285 1386
             data.putString("data", message);
1286 1387
 
1287 1388
             if (mCatalystInstance != null) {
1288
-              mContext.sendDirectMessage(data);
1389
+              mContext.sendDirectMessage("onMessage", data);
1289 1390
             } else {
1290 1391
               dispatchEvent(webView, new TopMessageEvent(webView.getId(), data));
1291 1392
             }
@@ -1296,21 +1397,21 @@ public class RNCWebViewManager extends SimpleViewManager<WebView> {
1296 1397
         eventData.putString("data", message);
1297 1398
 
1298 1399
         if (mCatalystInstance != null) {
1299
-          this.sendDirectMessage(eventData);
1400
+          this.sendDirectMessage("onMessage", eventData);
1300 1401
         } else {
1301 1402
           dispatchEvent(this, new TopMessageEvent(this.getId(), eventData));
1302 1403
         }
1303 1404
       }
1304 1405
     }
1305 1406
 
1306
-    protected void sendDirectMessage(WritableMap data) {
1407
+    protected void sendDirectMessage(final String method, WritableMap data) {
1307 1408
       WritableNativeMap event = new WritableNativeMap();
1308 1409
       event.putMap("nativeEvent", data);
1309 1410
 
1310 1411
       WritableNativeArray params = new WritableNativeArray();
1311 1412
       params.pushMap(event);
1312 1413
 
1313
-      mCatalystInstance.callFunction(messagingModuleName, "onMessage", params);
1414
+      mCatalystInstance.callFunction(messagingModuleName, method, params);
1314 1415
     }
1315 1416
 
1316 1417
     protected void onScrollChanged(int x, int y, int oldX, int oldY) {

+ 45
- 1
android/src/main/java/com/reactnativecommunity/webview/RNCWebViewModule.java 파일 보기

@@ -12,9 +12,11 @@ import android.os.Environment;
12 12
 import android.os.Parcelable;
13 13
 import android.provider.MediaStore;
14 14
 
15
+import androidx.annotation.Nullable;
15 16
 import androidx.annotation.RequiresApi;
16 17
 import androidx.core.content.ContextCompat;
17 18
 import androidx.core.content.FileProvider;
19
+import androidx.core.util.Pair;
18 20
 
19 21
 import android.util.Log;
20 22
 import android.webkit.MimeTypeMap;
@@ -35,6 +37,8 @@ import java.io.File;
35 37
 import java.io.IOException;
36 38
 import java.util.ArrayList;
37 39
 import java.util.Arrays;
40
+import java.util.HashMap;
41
+import java.util.concurrent.atomic.AtomicReference;
38 42
 
39 43
 import static android.app.Activity.RESULT_OK;
40 44
 
@@ -50,6 +54,35 @@ public class RNCWebViewModule extends ReactContextBaseJavaModule implements Acti
50 54
   private File outputVideo;
51 55
   private DownloadManager.Request downloadRequest;
52 56
 
57
+  protected static class ShouldOverrideUrlLoadingLock {
58
+    protected enum ShouldOverrideCallbackState {
59
+      UNDECIDED,
60
+      SHOULD_OVERRIDE,
61
+      DO_NOT_OVERRIDE,
62
+    }
63
+
64
+    private int nextLockIdentifier = 0;
65
+    private final HashMap<Integer, AtomicReference<ShouldOverrideCallbackState>> shouldOverrideLocks = new HashMap<>();
66
+
67
+    public synchronized Pair<Integer, AtomicReference<ShouldOverrideCallbackState>> getNewLock() {
68
+      final int lockIdentifier = nextLockIdentifier++;
69
+      final AtomicReference<ShouldOverrideCallbackState> shouldOverride = new AtomicReference<>(ShouldOverrideCallbackState.UNDECIDED);
70
+      shouldOverrideLocks.put(lockIdentifier, shouldOverride);
71
+      return new Pair<>(lockIdentifier, shouldOverride);
72
+    }
73
+
74
+    @Nullable
75
+    public synchronized AtomicReference<ShouldOverrideCallbackState> getLock(Integer lockIdentifier) {
76
+      return shouldOverrideLocks.get(lockIdentifier);
77
+    }
78
+
79
+    public synchronized void removeLock(Integer lockIdentifier) {
80
+      shouldOverrideLocks.remove(lockIdentifier);
81
+    }
82
+  }
83
+
84
+  protected static final ShouldOverrideUrlLoadingLock shouldOverrideUrlLoadingLock = new ShouldOverrideUrlLoadingLock();
85
+
53 86
   private enum MimeType {
54 87
     DEFAULT("*/*"),
55 88
     IMAGE("image"),
@@ -105,6 +138,17 @@ public class RNCWebViewModule extends ReactContextBaseJavaModule implements Acti
105 138
     promise.resolve(result);
106 139
   }
107 140
 
141
+  @ReactMethod(isBlockingSynchronousMethod = true)
142
+  public void onShouldStartLoadWithRequestCallback(final boolean shouldStart, final int lockIdentifier) {
143
+    final AtomicReference<ShouldOverrideUrlLoadingLock.ShouldOverrideCallbackState> lockObject = shouldOverrideUrlLoadingLock.getLock(lockIdentifier);
144
+    if (lockObject != null) {
145
+      synchronized (lockObject) {
146
+        lockObject.set(shouldStart ? ShouldOverrideUrlLoadingLock.ShouldOverrideCallbackState.DO_NOT_OVERRIDE : ShouldOverrideUrlLoadingLock.ShouldOverrideCallbackState.SHOULD_OVERRIDE);
147
+        lockObject.notify();
148
+      }
149
+    }
150
+  }
151
+
108 152
   public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) {
109 153
 
110 154
     if (filePathCallback == null && filePathCallbackLegacy == null) {
@@ -273,7 +317,7 @@ public class RNCWebViewModule extends ReactContextBaseJavaModule implements Acti
273 317
 
274 318
   public boolean grantFileDownloaderPermissions() {
275 319
     // Permission not required for Android Q and above
276
-    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
320
+    if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {
277 321
       return true;
278 322
     }
279 323
 

+ 26
- 0
android/src/main/java/com/reactnativecommunity/webview/events/TopRenderProcessGoneEvent.kt 파일 보기

@@ -0,0 +1,26 @@
1
+package com.reactnativecommunity.webview.events
2
+
3
+import com.facebook.react.bridge.WritableMap
4
+import com.facebook.react.uimanager.events.Event
5
+import com.facebook.react.uimanager.events.RCTEventEmitter
6
+
7
+/**
8
+ * Event emitted when the WebView's process has crashed or
9
+   was killed by the OS.
10
+ */
11
+class TopRenderProcessGoneEvent(viewId: Int, private val mEventData: WritableMap) :
12
+  Event<TopRenderProcessGoneEvent>(viewId) {
13
+  companion object {
14
+    const val EVENT_NAME = "topRenderProcessGone"
15
+  }
16
+
17
+  override fun getEventName(): String = EVENT_NAME
18
+
19
+  override fun canCoalesce(): Boolean = false
20
+
21
+  override fun getCoalescingKey(): Short = 0
22
+
23
+  override fun dispatch(rctEventEmitter: RCTEventEmitter) =
24
+    rctEventEmitter.receiveEvent(viewTag, eventName, mEventData)
25
+
26
+}

+ 2
- 0
android/src/main/java/com/reactnativecommunity/webview/events/TopShouldStartLoadWithRequestEvent.kt 파일 보기

@@ -14,6 +14,8 @@ class TopShouldStartLoadWithRequestEvent(viewId: Int, private val mData: Writabl
14 14
 
15 15
   init {
16 16
     mData.putString("navigationType", "other")
17
+    // Android does not raise shouldOverrideUrlLoading for inner frames
18
+    mData.putBoolean("isTopFrame", true)
17 19
   }
18 20
 
19 21
   override fun getEventName(): String = EVENT_NAME

+ 8
- 0
apple/RNCWebView.h 파일 보기

@@ -62,6 +62,12 @@
62 62
 @property (nonatomic, assign) BOOL directionalLockEnabled;
63 63
 @property (nonatomic, assign) BOOL ignoreSilentHardwareSwitch;
64 64
 @property (nonatomic, copy) NSString * _Nullable allowingReadAccessToURL;
65
+@property (nonatomic, assign) BOOL pullToRefreshEnabled;
66
+@property (nonatomic, weak) UIRefreshControl * refreshControl;
67
+
68
+#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 /* iOS 13 */
69
+@property (nonatomic, assign) WKContentMode contentMode;
70
+#endif
65 71
 
66 72
 + (void)setClientAuthenticationCredential:(nullable NSURLCredential*)credential;
67 73
 + (void)setCustomCertificatesForHost:(nullable NSDictionary *)certificates;
@@ -71,5 +77,7 @@
71 77
 - (void)goBack;
72 78
 - (void)reload;
73 79
 - (void)stopLoading;
80
+- (void)addPullToRefreshControl;
81
+- (void)pullToRefresh:(UIRefreshControl *)refreshControl;
74 82
 
75 83
 @end

+ 48
- 38
apple/RNCWebView.m 파일 보기

@@ -226,6 +226,14 @@ static NSDictionary* customCertificatesForHost;
226 226
   }
227 227
   wkWebViewConfig.userContentController = [WKUserContentController new];
228 228
 
229
+#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 /* iOS 13 */
230
+  if (@available(iOS 13.0, *)) {
231
+    WKWebpagePreferences *pagePrefs = [[WKWebpagePreferences alloc]init];
232
+    pagePrefs.preferredContentMode = _contentMode;
233
+    wkWebViewConfig.defaultWebpagePreferences = pagePrefs;
234
+  }
235
+#endif
236
+
229 237
   // Shim the HTML5 history API:
230 238
   [wkWebViewConfig.userContentController addScriptMessageHandler:[[RNCWeakScriptMessageDelegate alloc] initWithDelegate:self]
231 239
                                                             name:HistoryShimName];
@@ -267,9 +275,13 @@ static NSDictionary* customCertificatesForHost;
267 275
     _webView.UIDelegate = self;
268 276
     _webView.navigationDelegate = self;
269 277
 #if !TARGET_OS_OSX
278
+    if (_pullToRefreshEnabled) {
279
+        [self addPullToRefreshControl];
280
+    }
270 281
     _webView.scrollView.scrollEnabled = _scrollEnabled;
271 282
     _webView.scrollView.pagingEnabled = _pagingEnabled;
272
-    _webView.scrollView.bounces = _bounces;
283
+      //For UIRefreshControl to work correctly, the bounces should always be true
284
+    _webView.scrollView.bounces = _pullToRefreshEnabled || _bounces; 
273 285
     _webView.scrollView.showsHorizontalScrollIndicator = _showsHorizontalScrollIndicator;
274 286
     _webView.scrollView.showsVerticalScrollIndicator = _showsVerticalScrollIndicator;
275 287
     _webView.scrollView.directionalLockEnabled = _directionalLockEnabled;
@@ -300,7 +312,6 @@ static NSDictionary* customCertificatesForHost;
300 312
   _webView.allowsBackForwardNavigationGestures = _allowsBackForwardNavigationGestures;
301 313
 }
302 314
 
303
-
304 315
 - (void)removeFromSuperview
305 316
 {
306 317
     if (_webView) {
@@ -869,40 +880,9 @@ static NSDictionary* customCertificatesForHost;
869 880
  * topViewController
870 881
  */
871 882
 -(UIViewController *)topViewController{
872
-    UIViewController *controller = [self topViewControllerWithRootViewController:[self getCurrentWindow].rootViewController];
873
-    return controller;
883
+    return RCTPresentedViewController();
874 884
 }
875 885
 
876
-/**
877
- * topViewControllerWithRootViewController
878
- */
879
--(UIViewController *)topViewControllerWithRootViewController:(UIViewController *)viewController{
880
-  if (viewController==nil) return nil;
881
-  if (viewController.presentedViewController!=nil) {
882
-    return [self topViewControllerWithRootViewController:viewController.presentedViewController];
883
-  } else if ([viewController isKindOfClass:[UITabBarController class]]){
884
-    return [self topViewControllerWithRootViewController:[(UITabBarController *)viewController selectedViewController]];
885
-  } else if ([viewController isKindOfClass:[UINavigationController class]]){
886
-    return [self topViewControllerWithRootViewController:[(UINavigationController *)viewController visibleViewController]];
887
-  } else {
888
-    return viewController;
889
-  }
890
-}
891
-/**
892
- * getCurrentWindow
893
- */
894
--(UIWindow *)getCurrentWindow{
895
-  UIWindow *window = [UIApplication sharedApplication].keyWindow;
896
-  if (window.windowLevel!=UIWindowLevelNormal) {
897
-    for (UIWindow *wid in [UIApplication sharedApplication].windows) {
898
-      if (window.windowLevel==UIWindowLevelNormal) {
899
-        window = wid;
900
-        break;
901
-      }
902
-    }
903
-  }
904
-  return window;
905
-}
906 886
 #endif // !TARGET_OS_OSX
907 887
 
908 888
 /**
@@ -929,13 +909,15 @@ static NSDictionary* customCertificatesForHost;
929 909
 
930 910
   WKNavigationType navigationType = navigationAction.navigationType;
931 911
   NSURLRequest *request = navigationAction.request;
912
+  BOOL isTopFrame = [request.URL isEqual:request.mainDocumentURL];
932 913
 
933 914
   if (_onShouldStartLoadWithRequest) {
934 915
     NSMutableDictionary<NSString *, id> *event = [self baseEvent];
935 916
     [event addEntriesFromDictionary: @{
936 917
       @"url": (request.URL).absoluteString,
937 918
       @"mainDocumentURL": (request.mainDocumentURL).absoluteString,
938
-      @"navigationType": navigationTypes[@(navigationType)]
919
+      @"navigationType": navigationTypes[@(navigationType)],
920
+      @"isTopFrame": @(isTopFrame)
939 921
     }];
940 922
     if (![self.delegate webView:self
941 923
       shouldStartLoadForRequest:event
@@ -947,7 +929,6 @@ static NSDictionary* customCertificatesForHost;
947 929
 
948 930
   if (_onLoadingStart) {
949 931
     // We have this check to filter out iframe requests and whatnot
950
-    BOOL isTopFrame = [request.URL isEqual:request.mainDocumentURL];
951 932
     if (isTopFrame) {
952 933
       NSMutableDictionary<NSString *, id> *event = [self baseEvent];
953 934
       [event addEntriesFromDictionary: @{
@@ -1147,6 +1128,35 @@ static NSDictionary* customCertificatesForHost;
1147 1128
   }
1148 1129
 }
1149 1130
 
1131
+- (void)addPullToRefreshControl
1132
+{
1133
+    UIRefreshControl *refreshControl = [[UIRefreshControl alloc] init];
1134
+    _refreshControl = refreshControl;
1135
+    [_webView.scrollView addSubview: refreshControl];
1136
+    [refreshControl addTarget:self action:@selector(pullToRefresh:) forControlEvents: UIControlEventValueChanged];
1137
+}
1138
+
1139
+- (void)pullToRefresh:(UIRefreshControl *)refreshControl
1140
+{
1141
+    [self reload];
1142
+    [refreshControl endRefreshing];
1143
+}
1144
+
1145
+#if !TARGET_OS_OSX
1146
+- (void)setPullToRefreshEnabled:(BOOL)pullToRefreshEnabled
1147
+{
1148
+    _pullToRefreshEnabled = pullToRefreshEnabled;
1149
+    
1150
+    if (pullToRefreshEnabled) {
1151
+        [self addPullToRefreshControl];
1152
+    } else {
1153
+        [_refreshControl removeFromSuperview];
1154
+    }
1155
+
1156
+    [self setBounces:_bounces];
1157
+}
1158
+#endif // !TARGET_OS_OSX
1159
+
1150 1160
 - (void)stopLoading
1151 1161
 {
1152 1162
   [_webView stopLoading];
@@ -1156,11 +1166,11 @@ static NSDictionary* customCertificatesForHost;
1156 1166
 - (void)setBounces:(BOOL)bounces
1157 1167
 {
1158 1168
   _bounces = bounces;
1159
-  _webView.scrollView.bounces = bounces;
1169
+    //For UIRefreshControl to work correctly, the bounces should always be true
1170
+  _webView.scrollView.bounces = _pullToRefreshEnabled || bounces;
1160 1171
 }
1161 1172
 #endif // !TARGET_OS_OSX
1162 1173
 
1163
-
1164 1174
 - (void)setInjectedJavaScript:(NSString *)source {
1165 1175
   _injectedJavaScript = source;
1166 1176
 

+ 18
- 0
apple/RNCWebViewManager.m 파일 보기

@@ -14,6 +14,16 @@
14 14
 @interface RNCWebViewManager () <RNCWebViewDelegate>
15 15
 @end
16 16
 
17
+@implementation RCTConvert (WKWebView)
18
+#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 /* iOS 13 */
19
+RCT_ENUM_CONVERTER(WKContentMode, (@{
20
+    @"recommended": @(WKContentModeRecommended),
21
+    @"mobile": @(WKContentModeMobile),
22
+    @"desktop": @(WKContentModeDesktop),
23
+}), WKContentModeRecommended, integerValue)
24
+#endif
25
+@end
26
+
17 27
 @implementation RNCWebViewManager
18 28
 {
19 29
   NSConditionLock *_shouldStartLoadLock;
@@ -70,6 +80,10 @@ RCT_EXPORT_VIEW_PROPERTY(allowingReadAccessToURL, NSString)
70 80
 RCT_EXPORT_VIEW_PROPERTY(contentInsetAdjustmentBehavior, UIScrollViewContentInsetAdjustmentBehavior)
71 81
 #endif
72 82
 
83
+#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 /* iOS 13 */
84
+RCT_EXPORT_VIEW_PROPERTY(contentMode, WKContentMode)
85
+#endif
86
+
73 87
 /**
74 88
  * Expose methods to enable messaging the webview.
75 89
  */
@@ -89,6 +103,10 @@ RCT_EXPORT_METHOD(postMessage:(nonnull NSNumber *)reactTag message:(NSString *)m
89 103
   }];
90 104
 }
91 105
 
106
+RCT_CUSTOM_VIEW_PROPERTY(pullToRefreshEnabled, BOOL, RNCWebView) {
107
+    view.pullToRefreshEnabled = json == nil ? false : [RCTConvert BOOL: json];
108
+}
109
+
92 110
 RCT_CUSTOM_VIEW_PROPERTY(bounces, BOOL, RNCWebView) {
93 111
   view.bounces = json == nil ? true : [RCTConvert BOOL: json];
94 112
 }

+ 3
- 1
docs/Debugging.md 파일 보기

@@ -15,12 +15,14 @@ It's possible to debug WebView contents in the iOS simulator or on a device usin
15 15
 3. Safari -> Develop -> [device name] -> [app name] -> [url - title]
16 16
 4. You can now debug the WebView contents just as you would on the web
17 17
 
18
-##### Note:
18
+##### Notes:
19 19
 
20 20
 When debugging on device you must enable Web Inspector in your device settings:
21 21
 
22 22
 Settings -> Safari -> Advanced -> Web Inspector
23 23
 
24
+Also, if you don't see your device in the Develop menu, and you started Safari before you started your simulator, try restarting Safari.
25
+
24 26
 ### Android & Chrome
25 27
 
26 28
 It's possible to debug WebView contents in the Android emulator or on a device using Chrome DevTools.

+ 2
- 1
docs/Guide.md 파일 보기

@@ -305,6 +305,7 @@ export default class App extends Component {
305 305
             uri:
306 306
               'https://github.com/react-native-community/react-native-webview',
307 307
           }}
308
+          onMessage={(event) => {}}
308 309
           injectedJavaScript={runFirst}
309 310
         />
310 311
       </View>
@@ -313,7 +314,7 @@ export default class App extends Component {
313 314
 }
314 315
 ```
315 316
 
316
-This runs the JavaScript in the `runFirst` string once the page is loaded. In this case, you can see that both the body style was changed to red and the alert showed up after 2 seconds.
317
+This runs the JavaScript in the `runFirst` string once the page is loaded. In this case, you can see that both the body style was changed to red and the alert showed up after 2 seconds. An `onMessage` event is required as well to inject the JavaScript code into the WebView.
317 318
 
318 319
 By setting `injectedJavaScriptForMainFrameOnly: false`, the JavaScript injection will occur on all frames (not just the main frame) if supported for the given platform. For example, if a page contains an iframe, the javascript will be injected into that iframe as well with this set to `false`. (Note this is not supported on Android.) There is also `injectedJavaScriptBeforeContentLoadedForMainFrameOnly` for injecting prior to content loading. Read more about this in the [Reference](./Reference.md#injectedjavascriptformainframeonly).
319 320
 

+ 161
- 77
docs/Reference.md 파일 보기

@@ -13,6 +13,7 @@ This document lays out the current public properties and methods for the React N
13 13
 - [`mediaPlaybackRequiresUserAction`](Reference.md#mediaplaybackrequiresuseraction)
14 14
 - [`nativeConfig`](Reference.md#nativeconfig)
15 15
 - [`onError`](Reference.md#onerror)
16
+- [`onRenderProcessGone`](Reference.md#onRenderProcessGone)
16 17
 - [`onLoad`](Reference.md#onload)
17 18
 - [`onLoadEnd`](Reference.md#onloadend)
18 19
 - [`onLoadStart`](Reference.md#onloadstart)
@@ -34,6 +35,7 @@ This document lays out the current public properties and methods for the React N
34 35
 - [`javaScriptEnabled`](Reference.md#javascriptenabled)
35 36
 - [`javaScriptCanOpenWindowsAutomatically`](Reference.md#javascriptcanopenwindowsautomatically)
36 37
 - [`androidHardwareAccelerationDisabled`](Reference.md#androidHardwareAccelerationDisabled)
38
+- [`androidLayerType`](Reference.md#androidLayerType)
37 39
 - [`mixedContentMode`](Reference.md#mixedcontentmode)
38 40
 - [`thirdPartyCookiesEnabled`](Reference.md#thirdpartycookiesenabled)
39 41
 - [`userAgent`](Reference.md#useragent)
@@ -44,6 +46,7 @@ This document lays out the current public properties and methods for the React N
44 46
 - [`overScrollMode`](Reference.md#overscrollmode)
45 47
 - [`contentInset`](Reference.md#contentinset)
46 48
 - [`contentInsetAdjustmentBehavior`](Reference.md#contentInsetAdjustmentBehavior)
49
+- [`contentMode`](Reference.md#contentMode)
47 50
 - [`dataDetectorTypes`](Reference.md#datadetectortypes)
48 51
 - [`scrollEnabled`](Reference.md#scrollenabled)
49 52
 - [`directionalLockEnabled`](Reference.md#directionalLockEnabled)
@@ -65,6 +68,7 @@ This document lays out the current public properties and methods for the React N
65 68
 - [`allowsLinkPreview`](Reference.md#allowsLinkPreview)
66 69
 - [`sharedCookiesEnabled`](Reference.md#sharedCookiesEnabled)
67 70
 - [`textZoom`](Reference.md#textZoom)
71
+- [`pullToRefreshEnabled`](Reference.md#pullToRefreshEnabled)
68 72
 - [`ignoreSilentHardwareSwitch`](Reference.md#ignoreSilentHardwareSwitch)
69 73
 - [`onFileDownload`](Reference.md#onFileDownload)
70 74
 
@@ -88,7 +92,7 @@ This document lays out the current public properties and methods for the React N
88 92
 
89 93
 ## Props
90 94
 
91
-### `source`
95
+### `source`[⬆](#props-index)<!-- Link generated with jump2header -->
92 96
 
93 97
 Loads static HTML or a URI (with optional headers) in the WebView. Note that static HTML will require setting [`originWhitelist`](Reference.md#originwhitelist) to `["*"]`.
94 98
 
@@ -114,7 +118,7 @@ _Note that using static HTML requires the WebView property [originWhiteList](Ref
114 118
 
115 119
 ---
116 120
 
117
-### `automaticallyAdjustContentInsets`
121
+### `automaticallyAdjustContentInsets`[⬆](#props-index)<!-- Link generated with jump2header -->
118 122
 
119 123
 Controls whether to adjust the content inset for web views that are placed behind a navigation bar, tab bar, or toolbar. The default value is `true`.
120 124
 
@@ -124,7 +128,7 @@ Controls whether to adjust the content inset for web views that are placed behin
124 128
 
125 129
 ---
126 130
 
127
-### `injectedJavaScript`
131
+### `injectedJavaScript`[⬆](#props-index)<!-- Link generated with jump2header -->
128 132
 
129 133
 Set this to provide JavaScript that will be injected into the web page after the document finishes loading, but before other subresources finish loading.
130 134
 
@@ -156,7 +160,7 @@ const INJECTED_JAVASCRIPT = `(function() {
156 160
 
157 161
 ---
158 162
 
159
-### `injectedJavaScriptBeforeContentLoaded`
163
+### `injectedJavaScriptBeforeContentLoaded`[⬆](#props-index)<!-- Link generated with jump2header -->
160 164
 
161 165
 Set this to provide JavaScript that will be injected into the web page after the document element is created, but before other subresources finish loading.
162 166
 
@@ -188,7 +192,7 @@ const INJECTED_JAVASCRIPT = `(function() {
188 192
 
189 193
 ---
190 194
 
191
-### `injectedJavaScriptForMainFrameOnly`
195
+### `injectedJavaScriptForMainFrameOnly`[⬆](#props-index)<!-- Link generated with jump2header -->
192 196
 
193 197
 If `true` (default; mandatory for Android), loads the `injectedJavaScript` only into the main frame.
194 198
 
@@ -200,7 +204,7 @@ If `false`, (only supported on iOS and macOS), loads it into all frames (e.g. if
200 204
 
201 205
 ---
202 206
 
203
-### `injectedJavaScriptBeforeContentLoadedForMainFrameOnly`
207
+### `injectedJavaScriptBeforeContentLoadedForMainFrameOnly`[⬆](#props-index)<!-- Link generated with jump2header -->
204 208
 
205 209
 If `true` (default; mandatory for Android), loads the `injectedJavaScriptBeforeContentLoaded` only into the main frame.
206 210
 
@@ -212,7 +216,7 @@ If `false`, (only supported on iOS and macOS), loads it into all frames (e.g. if
212 216
 
213 217
 ---
214 218
 
215
-### `mediaPlaybackRequiresUserAction`
219
+### `mediaPlaybackRequiresUserAction`[⬆](#props-index)<!-- Link generated with jump2header -->
216 220
 
217 221
 Boolean that determines whether HTML5 audio and video requires the user to tap them before they start playing. The default value is `true`. (Android API minimum version 17).
218 222
 
@@ -224,7 +228,7 @@ NOTE: the default `true` value might cause some videos to hang loading on iOS. S
224 228
 
225 229
 ---
226 230
 
227
-### `nativeConfig`
231
+### `nativeConfig`[⬆](#props-index)<!-- Link generated with jump2header -->
228 232
 
229 233
 Override the native component used to render the WebView. Enables a custom native WebView which uses the same JavaScript as the original WebView.
230 234
 
@@ -240,7 +244,7 @@ The `nativeConfig` prop expects an object with the following keys:
240 244
 
241 245
 ---
242 246
 
243
-### `onError`
247
+### `onError`[⬆](#props-index)<!-- Link generated with jump2header -->
244 248
 
245 249
 Function that is invoked when the `WebView` load fails.
246 250
 
@@ -280,7 +284,7 @@ url
280 284
 
281 285
 ---
282 286
 
283
-### `onLoad`
287
+### `onLoad`[⬆](#props-index)<!-- Link generated with jump2header -->
284 288
 
285 289
 Function that is invoked when the `WebView` has finished loading.
286 290
 
@@ -313,7 +317,7 @@ url
313 317
 
314 318
 ---
315 319
 
316
-### `onLoadEnd`
320
+### `onLoadEnd`[⬆](#props-index)<!-- Link generated with jump2header -->
317 321
 
318 322
 Function that is invoked when the `WebView` load succeeds or fails.
319 323
 
@@ -347,7 +351,7 @@ url
347 351
 
348 352
 ---
349 353
 
350
-### `onLoadStart`
354
+### `onLoadStart`[⬆](#props-index)<!-- Link generated with jump2header -->
351 355
 
352 356
 Function that is invoked when the `WebView` starts loading.
353 357
 
@@ -381,7 +385,7 @@ url
381 385
 
382 386
 ---
383 387
 
384
-### `onLoadProgress`
388
+### `onLoadProgress`[⬆](#props-index)<!-- Link generated with jump2header -->
385 389
 
386 390
 Function that is invoked when the `WebView` is loading.
387 391
 
@@ -414,7 +418,7 @@ url
414 418
 
415 419
 ---
416 420
 
417
-### `onHttpError`
421
+### `onHttpError`[⬆](#props-index)<!-- Link generated with jump2header -->
418 422
 
419 423
 Function that is invoked when the `WebView` receives an http error.
420 424
 
@@ -458,7 +462,40 @@ url
458 462
 
459 463
 ---
460 464
 
461
-### `onMessage`
465
+### `onRenderProcessGone`[⬆](#props-index)<!-- Link generated with jump2header -->
466
+
467
+Function that is invoked when the `WebView` process crashes or is killed by the OS on Android.
468
+
469
+> **_Note_**
470
+> Android API minimum level 26. Android Only
471
+
472
+| Type     | Required |
473
+| -------- | -------- |
474
+| function | No       |
475
+
476
+Example:
477
+
478
+```jsx
479
+<WebView
480
+  source={{ uri: 'https://reactnative.dev' }}
481
+  onRenderProcessGone={syntheticEvent => {
482
+    const { nativeEvent } = syntheticEvent;
483
+    console.warn(
484
+      'WebView Crashed: ',
485
+      nativeEvent.didCrash,
486
+    );
487
+  }}
488
+/>
489
+```
490
+
491
+Function passed to `onRenderProcessGone` is called with a SyntheticEvent wrapping a nativeEvent with these properties:
492
+
493
+```
494
+didCrash
495
+```
496
+---
497
+
498
+### `onMessage`[⬆](#props-index)<!-- Link generated with jump2header -->
462 499
 
463 500
 Function that is invoked when the webview calls `window.ReactNativeWebView.postMessage`. Setting this property will inject this global into your webview.
464 501
 
@@ -472,7 +509,7 @@ To learn more, read the [Communicating between JS and Native](Guide.md#communica
472 509
 
473 510
 ---
474 511
 
475
-### `onNavigationStateChange`
512
+### `onNavigationStateChange`[⬆](#props-index)<!-- Link generated with jump2header -->
476 513
 
477 514
 Function that is invoked when the `WebView` loading starts or ends.
478 515
 
@@ -508,7 +545,7 @@ Note that this method will not be invoked on hash URL changes (e.g. from `https:
508 545
 
509 546
 ---
510 547
 
511
-### `onContentProcessDidTerminate`
548
+### `onContentProcessDidTerminate`[⬆](#props-index)<!-- Link generated with jump2header -->
512 549
 
513 550
 Function that is invoked when the `WebView` content process is terminated.
514 551
 
@@ -542,7 +579,7 @@ url
542 579
 
543 580
 ---
544 581
 
545
-### `originWhitelist`
582
+### `originWhitelist`[⬆](#props-index)<!-- Link generated with jump2header -->
546 583
 
547 584
 List of origin strings to allow being navigated to. The strings allow wildcards and get matched against _just_ the origin (not the full URL). If the user taps to navigate to a new page but the new page is not in this whitelist, the URL will be handled by the OS. The default whitelisted origins are "http://*" and "https://*".
548 585
 
@@ -562,7 +599,7 @@ Example:
562 599
 
563 600
 ---
564 601
 
565
-### `renderError`
602
+### `renderError`[⬆](#props-index)<!-- Link generated with jump2header -->
566 603
 
567 604
 Function that returns a view to show if there's an error.
568 605
 
@@ -583,7 +620,7 @@ The function passed to `renderError` will be called with the name of the error
583 620
 
584 621
 ---
585 622
 
586
-### `renderLoading`
623
+### `renderLoading`[⬆](#props-index)<!-- Link generated with jump2header -->
587 624
 
588 625
 Function that returns a loading indicator. The startInLoadingState prop must be set to true in order to use this prop.
589 626
 
@@ -603,7 +640,7 @@ Example:
603 640
 
604 641
 ---
605 642
 
606
-### `scalesPageToFit`
643
+### `scalesPageToFit`[⬆](#props-index)<!-- Link generated with jump2header -->
607 644
 
608 645
 Boolean that controls whether the web content is scaled to fit the view and enables the user to change the scale. The default value is `true`.
609 646
 
@@ -613,7 +650,7 @@ Boolean that controls whether the web content is scaled to fit the view and enab
613 650
 
614 651
 ---
615 652
 
616
-### `onShouldStartLoadWithRequest`
653
+### `onShouldStartLoadWithRequest`[⬆](#props-index)<!-- Link generated with jump2header -->
617 654
 
618 655
 Function that allows custom handling of any web view requests. Return `true` from the function to continue loading the request and `false` to stop loading.
619 656
 
@@ -647,11 +684,12 @@ canGoForward
647 684
 lockIdentifier
648 685
 mainDocumentURL (iOS only)
649 686
 navigationType
687
+isTopFrame
650 688
 ```
651 689
 
652 690
 ---
653 691
 
654
-### `startInLoadingState`
692
+### `startInLoadingState`[⬆](#props-index)<!-- Link generated with jump2header -->
655 693
 
656 694
 Boolean value that forces the `WebView` to show the loading view on the first load. This prop must be set to `true` in order for the `renderLoading` prop to work.
657 695
 
@@ -661,7 +699,7 @@ Boolean value that forces the `WebView` to show the loading view on the first lo
661 699
 
662 700
 ---
663 701
 
664
-### `style`
702
+### `style`[⬆](#props-index)<!-- Link generated with jump2header -->
665 703
 
666 704
 A style object that allow you to customize the `WebView` style. Please note that there are default styles (example: you need to add `flex: 0` to the style if you want to use `height` property).
667 705
 
@@ -680,7 +718,7 @@ Example:
680 718
 
681 719
 ---
682 720
 
683
-### `containerStyle`
721
+### `containerStyle`[⬆](#props-index)<!-- Link generated with jump2header -->
684 722
 
685 723
 A style object that allow you to customize the `WebView` container style. Please note that there are default styles (example: you need to add `flex: 0` to the style if you want to use `height` property).
686 724
 
@@ -699,7 +737,7 @@ Example:
699 737
 
700 738
 ---
701 739
 
702
-### `decelerationRate`
740
+### `decelerationRate`[⬆](#props-index)<!-- Link generated with jump2header -->
703 741
 
704 742
 A floating-point number that determines how quickly the scroll view decelerates after the user lifts their finger. You may also use the string shortcuts `"normal"` and `"fast"` which match the underlying iOS settings for `UIScrollViewDecelerationRateNormal` and `UIScrollViewDecelerationRateFast` respectively:
705 743
 
@@ -712,7 +750,7 @@ A floating-point number that determines how quickly the scroll view decelerates
712 750
 
713 751
 ---
714 752
 
715
-### `domStorageEnabled`
753
+### `domStorageEnabled`[⬆](#props-index)<!-- Link generated with jump2header -->
716 754
 
717 755
 Boolean value to control whether DOM Storage is enabled. Used only in Android.
718 756
 
@@ -722,7 +760,7 @@ Boolean value to control whether DOM Storage is enabled. Used only in Android.
722 760
 
723 761
 ---
724 762
 
725
-### `javaScriptEnabled`
763
+### `javaScriptEnabled`[⬆](#props-index)<!-- Link generated with jump2header -->
726 764
 
727 765
 Boolean value to enable JavaScript in the `WebView`. The default value is `true`.
728 766
 
@@ -732,7 +770,7 @@ Boolean value to enable JavaScript in the `WebView`. The default value is `true`
732 770
 
733 771
 ---
734 772
 
735
-### `javaScriptCanOpenWindowsAutomatically`
773
+### `javaScriptCanOpenWindowsAutomatically`[⬆](#props-index)<!-- Link generated with jump2header -->
736 774
 
737 775
 A Boolean value indicating whether JavaScript can open windows without user interaction. The default value is `false`.
738 776
 
@@ -742,9 +780,9 @@ A Boolean value indicating whether JavaScript can open windows without user inte
742 780
 
743 781
 ---
744 782
 
745
-### `androidHardwareAccelerationDisabled`
783
+### `androidHardwareAccelerationDisabled`[⬆](#props-index)<!-- Link generated with jump2header -->
746 784
 
747
-Boolean value to disable Hardware Acceleration in the `WebView`. Used on Android only as Hardware Acceleration is a feature only for Android. The default value is `false`.
785
+**Deprecated.** Use the `androidLayerType` prop instead. 
748 786
 
749 787
 | Type | Required | Platform |
750 788
 | ---- | -------- | -------- |
@@ -752,7 +790,25 @@ Boolean value to disable Hardware Acceleration in the `WebView`. Used on Android
752 790
 
753 791
 ---
754 792
 
755
-### `mixedContentMode`
793
+### `androidLayerType`[⬆](#props-index)<!-- Link generated with jump2header -->
794
+
795
+Specifies the layer type. 
796
+
797
+Possible values for `androidLayerType` are:
798
+
799
+- `none` (default) - The view does not have a layer.
800
+- `software` - The view has a software layer. A software layer is backed by a bitmap and causes the view to be rendered using Android's software rendering pipeline, even if hardware acceleration is enabled.
801
+- `hardware` - The view has a hardware layer. A hardware layer is backed by a hardware specific texture and causes the view to be rendered using Android's hardware rendering pipeline, but only if hardware acceleration is turned on for the view hierarchy.
802
+
803
+Avoid setting both `androidLayerType` and `androidHardwareAccelerationDisabled` props at the same time, as this may cause undefined behaviour.
804
+
805
+| Type   | Required | Platform |
806
+| ------ | -------- | -------- |
807
+| string | No       | Android  |
808
+
809
+---
810
+
811
+### `mixedContentMode`[⬆](#props-index)<!-- Link generated with jump2header -->
756 812
 
757 813
 Specifies the mixed content mode. i.e WebView will allow a secure origin to load content from any other origin.
758 814
 
@@ -768,7 +824,7 @@ Possible values for `mixedContentMode` are:
768 824
 
769 825
 ---
770 826
 
771
-### `thirdPartyCookiesEnabled`
827
+### `thirdPartyCookiesEnabled`[⬆](#props-index)<!-- Link generated with jump2header -->
772 828
 
773 829
 Boolean value to enable third party cookies in the `WebView`. Used on Android Lollipop and above only as third party cookies are enabled by default on Android Kitkat and below and on iOS. The default value is `true`. For more on cookies, read the [Guide](Guide.md#Managing-Cookies)
774 830
 
@@ -778,7 +834,7 @@ Boolean value to enable third party cookies in the `WebView`. Used on Android Lo
778 834
 
779 835
 ---
780 836
 
781
-### `userAgent`
837
+### `userAgent`[⬆](#props-index)<!-- Link generated with jump2header -->
782 838
 
783 839
 Sets the user-agent for the `WebView`.
784 840
 
@@ -788,7 +844,7 @@ Sets the user-agent for the `WebView`.
788 844
 
789 845
 ---
790 846
 
791
-### `applicationNameForUserAgent`
847
+### `applicationNameForUserAgent`[⬆](#props-index)<!-- Link generated with jump2header -->
792 848
 
793 849
 Append to the existing user-agent. Setting `userAgent` will override this.
794 850
 
@@ -806,7 +862,7 @@ Append to the existing user-agent. Setting `userAgent` will override this.
806 862
 // Mozilla/5.0 (iPhone; CPU iPhone OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 DemoApp/1.1.0
807 863
 ```
808 864
 
809
-### `allowsFullscreenVideo`
865
+### `allowsFullscreenVideo`[⬆](#props-index)<!-- Link generated with jump2header -->
810 866
 
811 867
 Boolean that determines whether videos are allowed to be played in fullscreen. The default value is `false`.
812 868
 
@@ -816,7 +872,7 @@ Boolean that determines whether videos are allowed to be played in fullscreen. T
816 872
 
817 873
 ---
818 874
 
819
-### `allowsInlineMediaPlayback`
875
+### `allowsInlineMediaPlayback`[⬆](#props-index)<!-- Link generated with jump2header -->
820 876
 
821 877
 Boolean that determines whether HTML5 videos play inline or use the native full-screen controller. The default value is `false`.
822 878
 
@@ -830,7 +886,7 @@ Boolean that determines whether HTML5 videos play inline or use the native full-
830 886
 
831 887
 ---
832 888
 
833
-### `bounces`
889
+### `bounces`[⬆](#props-index)<!-- Link generated with jump2header -->
834 890
 
835 891
 Boolean value that determines whether the web view bounces when it reaches the edge of the content. The default value is `true`.
836 892
 
@@ -840,7 +896,7 @@ Boolean value that determines whether the web view bounces when it reaches the e
840 896
 
841 897
 ---
842 898
 
843
-### `overScrollMode`
899
+### `overScrollMode`[⬆](#props-index)<!-- Link generated with jump2header -->
844 900
 
845 901
 Specifies the over scroll mode.
846 902
 
@@ -856,7 +912,7 @@ Possible values for `overScrollMode` are:
856 912
 
857 913
 ---
858 914
 
859
-### `contentInset`
915
+### `contentInset`[⬆](#props-index)<!-- Link generated with jump2header -->
860 916
 
861 917
 The amount by which the web view content is inset from the edges of the scroll view. Defaults to {top: 0, left: 0, bottom: 0, right: 0}.
862 918
 
@@ -866,7 +922,7 @@ The amount by which the web view content is inset from the edges of the scroll v
866 922
 
867 923
 ---
868 924
 
869
-### `contentInsetAdjustmentBehavior`
925
+### `contentInsetAdjustmentBehavior`[⬆](#props-index)<!-- Link generated with jump2header -->
870 926
 
871 927
 This property specifies how the safe area insets are used to modify the content area of the scroll view. The default value of this property is "never". Available on iOS 11 and later. Defaults to `never`.
872 928
 
@@ -883,7 +939,25 @@ Possible values:
883 939
 
884 940
 ---
885 941
 
886
-### `dataDetectorTypes`
942
+### `contentMode`[⬆](#props-index)<!-- Link generated with jump2header -->
943
+
944
+Controls the type of content to load. Available on iOS 13 and later. Defaults to `recommended`, which loads mobile content on iPhone & iPad Mini but desktop content on larger iPads.
945
+
946
+See [Introducing Desktop-class Browsing on iPad](https://developer.apple.com/videos/play/wwdc2019/203/) for more.
947
+
948
+Possible values:
949
+
950
+- `recommended`
951
+- `mobile`
952
+- `desktop`
953
+
954
+| Type   | Required | Platform |
955
+| ------ | -------- | -------- |
956
+| string | No       | iOS      |
957
+
958
+---
959
+
960
+### `dataDetectorTypes`[⬆](#props-index)<!-- Link generated with jump2header -->
887 961
 
888 962
 Determines the types of data converted to clickable URLs in the web view's content. By default only phone numbers are detected.
889 963
 
@@ -907,7 +981,7 @@ Possible values for `dataDetectorTypes` are:
907 981
 
908 982
 ---
909 983
 
910
-### `scrollEnabled`
984
+### `scrollEnabled`[⬆](#props-index)<!-- Link generated with jump2header -->
911 985
 
912 986
 Boolean value that determines whether scrolling is enabled in the `WebView`. The default value is `true`. Setting this to `false` will prevent the webview from moving the document body when the keyboard appears over an input.
913 987
 
@@ -917,7 +991,7 @@ Boolean value that determines whether scrolling is enabled in the `WebView`. The
917 991
 
918 992
 ---
919 993
 
920
-### `directionalLockEnabled`
994
+### `directionalLockEnabled`[⬆](#props-index)<!-- Link generated with jump2header -->
921 995
 
922 996
 A Boolean value that determines whether scrolling is disabled in a particular direction.
923 997
 The default value is `true`.
@@ -928,7 +1002,7 @@ The default value is `true`.
928 1002
 
929 1003
 ---
930 1004
 
931
-### `showsHorizontalScrollIndicator`
1005
+### `showsHorizontalScrollIndicator`[⬆](#props-index)<!-- Link generated with jump2header -->
932 1006
 
933 1007
 Boolean value that determines whether a horizontal scroll indicator is shown in the `WebView`. The default value is `true`.
934 1008
 
@@ -938,7 +1012,7 @@ Boolean value that determines whether a horizontal scroll indicator is shown in
938 1012
 
939 1013
 ---
940 1014
 
941
-### `showsVerticalScrollIndicator`
1015
+### `showsVerticalScrollIndicator`[⬆](#props-index)<!-- Link generated with jump2header -->
942 1016
 
943 1017
 Boolean value that determines whether a vertical scroll indicator is shown in the `WebView`. The default value is `true`.
944 1018
 
@@ -948,7 +1022,7 @@ Boolean value that determines whether a vertical scroll indicator is shown in th
948 1022
 
949 1023
 ---
950 1024
 
951
-### `geolocationEnabled`
1025
+### `geolocationEnabled`[⬆](#props-index)<!-- Link generated with jump2header -->
952 1026
 
953 1027
 Set whether Geolocation is enabled in the `WebView`. The default value is `false`. Used only in Android.
954 1028
 
@@ -958,7 +1032,7 @@ Set whether Geolocation is enabled in the `WebView`. The default value is `false
958 1032
 
959 1033
 ---
960 1034
 
961
-### `allowFileAccessFromFileURLs`
1035
+### `allowFileAccessFromFileURLs`[⬆](#props-index)<!-- Link generated with jump2header -->
962 1036
 
963 1037
 Boolean that sets whether JavaScript running in the context of a file scheme URL should be allowed to access content from other file scheme URLs. The default value is `false`.
964 1038
 
@@ -968,7 +1042,7 @@ Boolean that sets whether JavaScript running in the context of a file scheme URL
968 1042
 
969 1043
 ---
970 1044
 
971
-### `allowUniversalAccessFromFileURLs`
1045
+### `allowUniversalAccessFromFileURLs`[⬆](#props-index)<!-- Link generated with jump2header -->
972 1046
 
973 1047
 Boolean that sets whether JavaScript running in the context of a file scheme URL should be allowed to access content from any origin. Including accessing content from other file scheme URLs. The default value is `false`.
974 1048
 
@@ -978,7 +1052,7 @@ Boolean that sets whether JavaScript running in the context of a file scheme URL
978 1052
 
979 1053
 ---
980 1054
 
981
-### `allowingReadAccessToURL`
1055
+### `allowingReadAccessToURL`[⬆](#props-index)<!-- Link generated with jump2header -->
982 1056
 
983 1057
 A String value that indicates which URLs the WebView's file can then reference in scripts, AJAX requests, and CSS imports. This is only used in for WebViews that are loaded with a source.uri set to a `'file://'` URL. If not provided, the default is to only allow read access to the URL provided in source.uri itself.
984 1058
 
@@ -988,7 +1062,7 @@ A String value that indicates which URLs the WebView's file can then reference i
988 1062
 
989 1063
 ---
990 1064
 
991
-### `url`
1065
+### `url`[⬆](#props-index)<!-- Link generated with jump2header -->
992 1066
 
993 1067
 **Deprecated.** Use the `source` prop instead.
994 1068
 
@@ -998,7 +1072,7 @@ A String value that indicates which URLs the WebView's file can then reference i
998 1072
 
999 1073
 ---
1000 1074
 
1001
-### `html`
1075
+### `html`[⬆](#props-index)<!-- Link generated with jump2header -->
1002 1076
 
1003 1077
 **Deprecated.** Use the `source` prop instead.
1004 1078
 
@@ -1008,7 +1082,7 @@ A String value that indicates which URLs the WebView's file can then reference i
1008 1082
 
1009 1083
 ---
1010 1084
 
1011
-### `keyboardDisplayRequiresUserAction`
1085
+### `keyboardDisplayRequiresUserAction`[⬆](#props-index)<!-- Link generated with jump2header -->
1012 1086
 
1013 1087
 If false, web content can programmatically display the keyboard. The default value is `true`.
1014 1088
 
@@ -1018,7 +1092,7 @@ If false, web content can programmatically display the keyboard. The default val
1018 1092
 
1019 1093
 ---
1020 1094
 
1021
-### `hideKeyboardAccessoryView`
1095
+### `hideKeyboardAccessoryView`[⬆](#props-index)<!-- Link generated with jump2header -->
1022 1096
 
1023 1097
 If true, this will hide the keyboard accessory view (< > and Done).
1024 1098
 
@@ -1028,7 +1102,7 @@ If true, this will hide the keyboard accessory view (< > and Done).
1028 1102
 
1029 1103
 ---
1030 1104
 
1031
-### `allowsBackForwardNavigationGestures`
1105
+### `allowsBackForwardNavigationGestures`[⬆](#props-index)<!-- Link generated with jump2header -->
1032 1106
 
1033 1107
 If true, this will be able horizontal swipe gestures. The default value is `false`.
1034 1108
 
@@ -1038,7 +1112,7 @@ If true, this will be able horizontal swipe gestures. The default value is `fals
1038 1112
 
1039 1113
 ---
1040 1114
 
1041
-### `incognito`
1115
+### `incognito`[⬆](#props-index)<!-- Link generated with jump2header -->
1042 1116
 
1043 1117
 Does not store any data within the lifetime of the WebView.
1044 1118
 
@@ -1048,7 +1122,7 @@ Does not store any data within the lifetime of the WebView.
1048 1122
 
1049 1123
 ---
1050 1124
 
1051
-### `allowFileAccess`
1125
+### `allowFileAccess`[⬆](#props-index)<!-- Link generated with jump2header -->
1052 1126
 
1053 1127
 If true, this will allow access to the file system via `file://` URI's. The default value is `false`.
1054 1128
 
@@ -1058,7 +1132,7 @@ If true, this will allow access to the file system via `file://` URI's. The defa
1058 1132
 
1059 1133
 ---
1060 1134
 
1061
-### `saveFormDataDisabled`
1135
+### `saveFormDataDisabled`[⬆](#props-index)<!-- Link generated with jump2header -->
1062 1136
 
1063 1137
 Sets whether the WebView should disable saving form data. The default value is `false`. This function does not have any effect from Android API level 26 onwards as there is an Autofill feature which stores form data.
1064 1138
 
@@ -1068,7 +1142,7 @@ Sets whether the WebView should disable saving form data. The default value is `
1068 1142
 
1069 1143
 ---
1070 1144
 
1071
-### `cacheEnabled`
1145
+### `cacheEnabled`[⬆](#props-index)<!-- Link generated with jump2header -->
1072 1146
 
1073 1147
 Sets whether WebView should use browser caching.
1074 1148
 
@@ -1078,7 +1152,7 @@ Sets whether WebView should use browser caching.
1078 1152
 
1079 1153
 ---
1080 1154
 
1081
-### `cacheMode`
1155
+### `cacheMode`[⬆](#props-index)<!-- Link generated with jump2header -->
1082 1156
 
1083 1157
 Overrides the way the cache is used. The way the cache is used is based on the navigation type. For a normal page load, the cache is checked and content is re-validated as needed. When navigating back, content is not revalidated, instead the content is just retrieved from the cache. This property allows the client to override this behavior.
1084 1158
 
@@ -1095,7 +1169,7 @@ Possible values are:
1095 1169
 
1096 1170
 ---
1097 1171
 
1098
-### `pagingEnabled`
1172
+### `pagingEnabled`[⬆](#props-index)<!-- Link generated with jump2header -->
1099 1173
 
1100 1174
 If the value of this property is true, the scroll view stops on multiples of the scroll view’s bounds when the user scrolls. The default value is false.
1101 1175
 
@@ -1105,7 +1179,7 @@ If the value of this property is true, the scroll view stops on multiples of the
1105 1179
 
1106 1180
 ---
1107 1181
 
1108
-### `allowsLinkPreview`
1182
+### `allowsLinkPreview`[⬆](#props-index)<!-- Link generated with jump2header -->
1109 1183
 
1110 1184
 A Boolean value that determines whether pressing on a link displays a preview of the destination for the link. In iOS this property is available on devices that support 3D Touch. In iOS 10 and later, the default value is true; before that, the default value is false.
1111 1185
 
@@ -1115,7 +1189,7 @@ A Boolean value that determines whether pressing on a link displays a preview of
1115 1189
 
1116 1190
 ---
1117 1191
 
1118
-### `sharedCookiesEnabled`
1192
+### `sharedCookiesEnabled`[⬆](#props-index)<!-- Link generated with jump2header -->
1119 1193
 
1120 1194
 Set `true` if shared cookies from `[NSHTTPCookieStorage sharedHTTPCookieStorage]` should used for every load request in the WebView. The default value is `false`. For more on cookies, read the [Guide](Guide.md#Managing-Cookies)
1121 1195
 
@@ -1125,7 +1199,7 @@ Set `true` if shared cookies from `[NSHTTPCookieStorage sharedHTTPCookieStorage]
1125 1199
 
1126 1200
 ---
1127 1201
 
1128
-### `textZoom`
1202
+### `textZoom`[⬆](#props-index)<!-- Link generated with jump2header -->
1129 1203
 
1130 1204
 If the user has set a custom font size in the Android system, an undesirable scale of the site interface in WebView occurs.
1131 1205
 
@@ -1139,7 +1213,17 @@ Example:
1139 1213
 
1140 1214
 `<WebView textZoom={100} />`
1141 1215
 
1142
-### `ignoreSilentHardwareSwitch`
1216
+---
1217
+
1218
+### `pullToRefreshEnabled`[⬆](#props-index)<!-- Link generated with jump2header -->
1219
+
1220
+Boolean value that determines whether a pull to refresh gesture is available in the `WebView`. The default value is `false`. If `true`, sets `bounces` automatically to `true`.
1221
+
1222
+| Type    | Required | Platform |
1223
+| ------- | -------- | -------- |
1224
+| boolean | No       | iOS      |
1225
+
1226
+### `ignoreSilentHardwareSwitch`[⬆](#props-index)<!-- Link generated with jump2header -->
1143 1227
 
1144 1228
 (ios only)
1145 1229
 
@@ -1149,7 +1233,7 @@ When set to true the hardware silent switch is ignored. Default: `false`
1149 1233
 | ------- | -------- | -------- |
1150 1234
 | boolean | No       | iOS      |
1151 1235
 
1152
-### `onFileDownload`
1236
+### `onFileDownload`[⬆](#props-index)<!-- Link generated with jump2header -->
1153 1237
 This property is iOS-only.
1154 1238
 
1155 1239
 Function that is invoked when the client needs to download a file.
@@ -1183,13 +1267,13 @@ Example:
1183 1267
 
1184 1268
 ## Methods
1185 1269
 
1186
-### `extraNativeComponentConfig()`
1270
+### `extraNativeComponentConfig()`[⬆](#methods-index)<!-- Link generated with jump2header -->
1187 1271
 
1188 1272
 ```javascript
1189 1273
 static extraNativeComponentConfig()
1190 1274
 ```
1191 1275
 
1192
-### `goForward()`
1276
+### `goForward()`[⬆](#methods-index)<!-- Link generated with jump2header -->
1193 1277
 
1194 1278
 ```javascript
1195 1279
 goForward();
@@ -1197,7 +1281,7 @@ goForward();
1197 1281
 
1198 1282
 Go forward one page in the web view's history.
1199 1283
 
1200
-### `goBack()`
1284
+### `goBack()`[⬆](#methods-index)<!-- Link generated with jump2header -->
1201 1285
 
1202 1286
 ```javascript
1203 1287
 goBack();
@@ -1205,7 +1289,7 @@ goBack();
1205 1289
 
1206 1290
 Go back one page in the web view's history.
1207 1291
 
1208
-### `reload()`
1292
+### `reload()`[⬆](#methods-index)<!-- Link generated with jump2header -->
1209 1293
 
1210 1294
 ```javascript
1211 1295
 reload();
@@ -1213,7 +1297,7 @@ reload();
1213 1297
 
1214 1298
 Reloads the current page.
1215 1299
 
1216
-### `stopLoading()`
1300
+### `stopLoading()`[⬆](#methods-index)<!-- Link generated with jump2header -->
1217 1301
 
1218 1302
 ```javascript
1219 1303
 stopLoading();
@@ -1221,7 +1305,7 @@ stopLoading();
1221 1305
 
1222 1306
 Stop loading the current page.
1223 1307
 
1224
-### `injectJavaScript(str)`
1308
+### `injectJavaScript(str)`[⬆](#methods-index)<!-- Link generated with jump2header -->
1225 1309
 
1226 1310
 ```javascript
1227 1311
 injectJavaScript('... javascript string ...');
@@ -1231,7 +1315,7 @@ Executes the JavaScript string.
1231 1315
 
1232 1316
 To learn more, read the [Communicating between JS and Native](Guide.md#communicating-between-js-and-native) guide.
1233 1317
 
1234
-### `requestFocus()`
1318
+### `requestFocus()`[⬆](#methods-index)<!-- Link generated with jump2header -->
1235 1319
 
1236 1320
 ```javascript
1237 1321
 requestFocus();
@@ -1239,14 +1323,14 @@ requestFocus();
1239 1323
 
1240 1324
 Request the webView to ask for focus. (People working on TV apps might want having a look at this!)
1241 1325
 
1242
-### `postMessage(str)`
1326
+### `postMessage(str)`[⬆](#methods-index)<!-- Link generated with jump2header -->
1243 1327
 
1244 1328
 ```javascript
1245 1329
 postMessage('message');
1246 1330
 ```
1247 1331
 Post a message to WebView, handled by [`onMessage`](Reference.md#onmessage).
1248 1332
 
1249
-### `clearFormData()`
1333
+### `clearFormData()`[⬆](#methods-index)<!-- Link generated with jump2header -->
1250 1334
 
1251 1335
 (android only)
1252 1336
 
@@ -1256,7 +1340,7 @@ clearFormData();
1256 1340
 
1257 1341
 Removes the autocomplete popup from the currently focused form field, if present. [developer.android.com reference](<https://developer.android.com/reference/android/webkit/WebView.html#clearFormData()>)
1258 1342
 
1259
-### `clearCache(bool)`
1343
+### `clearCache(bool)`[⬆](#methods-index)<!-- Link generated with jump2header -->
1260 1344
 
1261 1345
 (android only)
1262 1346
 
@@ -1266,7 +1350,7 @@ clearCache(true);
1266 1350
 
1267 1351
 Clears the resource cache. Note that the cache is per-application, so this will clear the cache for all WebViews used. [developer.android.com reference](<https://developer.android.com/reference/android/webkit/WebView.html#clearCache(boolean)>)
1268 1352
 
1269
-### `clearHistory()`
1353
+### `clearHistory()`[⬆](#methods-index)<!-- Link generated with jump2header -->
1270 1354
 
1271 1355
 (android only)
1272 1356
 

+ 23
- 0
index.d.ts 파일 보기

@@ -41,6 +41,29 @@ declare class WebView extends Component<WebViewProps> {
41 41
      * Focuses on WebView redered page.
42 42
      */
43 43
     requestFocus: () => void;
44
+    
45
+     /**
46
+     * Posts a message to WebView.
47
+     */
48
+    postMessage: (message: string) => void;
49
+    
50
+     /**
51
+     * (Android only)
52
+     * Removes the autocomplete popup from the currently focused form field, if present.
53
+     */
54
+    clearFormData: () => void;
55
+
56
+     /**
57
+     * (Android only)
58
+     * Clears the resource cache. Note that the cache is per-application, so this will clear the cache for all WebViews used.
59
+     */
60
+    clearCache: (clear: boolean) => void;
61
+
62
+     /**
63
+     * (Android only)
64
+     * Tells this WebView to clear its internal back/forward list.
65
+     */
66
+    clearHistory: () => void;
44 67
 }
45 68
 
46 69
 export {WebView};

+ 2
- 0
metro.config.windows.js 파일 보기

@@ -35,6 +35,8 @@ module.exports = {
35 35
       new RegExp(
36 36
         `${path.resolve(__dirname, 'windows').replace(/[/\\]/g, '/')}.*`,
37 37
       ),
38
+      // Avoid error EBUSY: resource busy or locked, open '...\vnext\msbuild.ProjectImports.zip' when building 'vnext\Microsoft.ReactNative.sln' with '/bl'
39
+      /.*\.ProjectImports\.zip/,
38 40
     ]),
39 41
   },
40 42
   transformer: {

+ 2
- 3
package.json 파일 보기

@@ -8,7 +8,7 @@
8 8
     "Thibault Malbranche <malbranche.thibault@gmail.com>"
9 9
   ],
10 10
   "license": "MIT",
11
-  "version": "10.3.1",
11
+  "version": "10.8.3",
12 12
   "homepage": "https://github.com/react-native-community/react-native-webview#readme",
13 13
   "scripts": {
14 14
     "start": "node node_modules/react-native/local-cli/cli.js start",
@@ -29,8 +29,7 @@
29 29
     "type": "Component"
30 30
   },
31 31
   "peerDependencies": {
32
-    "react": "16.11.0",
33
-    "react-native": ">=0.60 <0.63"
32
+    "react-native": ">=0.60 <0.64"
34 33
   },
35 34
   "dependencies": {
36 35
     "escape-string-regexp": "2.0.0",

+ 17
- 3
src/WebView.android.tsx 파일 보기

@@ -21,6 +21,7 @@ import {
21 21
   defaultRenderLoading,
22 22
 } from './WebViewShared';
23 23
 import {
24
+  WebViewRenderProcessGoneEvent,
24 25
   WebViewErrorEvent,
25 26
   WebViewHttpErrorEvent,
26 27
   WebViewMessageEvent,
@@ -60,6 +61,7 @@ class WebView extends React.Component<AndroidWebViewProps, State> {
60 61
     saveFormDataDisabled: false,
61 62
     cacheEnabled: true,
62 63
     androidHardwareAccelerationDisabled: false,
64
+    androidLayerType: 'none',
63 65
     originWhitelist: defaultOriginWhitelist,
64 66
   };
65 67
 
@@ -75,6 +77,7 @@ class WebView extends React.Component<AndroidWebViewProps, State> {
75 77
     lastErrorEvent: null,
76 78
   };
77 79
 
80
+  onShouldStartLoadWithRequest: ReturnType<typeof createOnShouldStartLoadWithRequest> | null = null;
78 81
 
79 82
   webViewRef = React.createRef<NativeWebViewAndroid>();
80 83
 
@@ -228,6 +231,13 @@ class WebView extends React.Component<AndroidWebViewProps, State> {
228 231
     }
229 232
   }
230 233
 
234
+  onRenderProcessGone = (event: WebViewRenderProcessGoneEvent) => {
235
+    const { onRenderProcessGone } = this.props;
236
+    if (onRenderProcessGone) {
237
+      onRenderProcessGone(event);
238
+    }
239
+  }
240
+
231 241
   onLoadingFinish = (event: WebViewNavigationEvent) => {
232 242
     const { onLoad, onLoadEnd } = this.props;
233 243
     const { nativeEvent: { url } } = event;
@@ -271,8 +281,11 @@ class WebView extends React.Component<AndroidWebViewProps, State> {
271 281
   onShouldStartLoadWithRequestCallback = (
272 282
     shouldStart: boolean,
273 283
     url: string,
284
+    lockIdentifier?: number,
274 285
   ) => {
275
-    if (shouldStart) {
286
+    if (lockIdentifier) {
287
+      NativeModules.RNCWebView.onShouldStartLoadWithRequestCallback(shouldStart, lockIdentifier);
288
+    } else if (shouldStart) {
276 289
       UIManager.dispatchViewManagerCommand(
277 290
         this.getWebViewHandle(),
278 291
         this.getCommands().loadUrl,
@@ -329,7 +342,7 @@ class WebView extends React.Component<AndroidWebViewProps, State> {
329 342
     const NativeWebView
330 343
       = (nativeConfig.component as typeof NativeWebViewAndroid) || RNCWebView;
331 344
 
332
-    const onShouldStartLoadWithRequest = createOnShouldStartLoadWithRequest(
345
+    this.onShouldStartLoadWithRequest = createOnShouldStartLoadWithRequest(
333 346
       this.onShouldStartLoadWithRequestCallback,
334 347
       // casting cause it's in the default props
335 348
       originWhitelist as readonly string[],
@@ -347,8 +360,9 @@ class WebView extends React.Component<AndroidWebViewProps, State> {
347 360
         onLoadingProgress={this.onLoadingProgress}
348 361
         onLoadingStart={this.onLoadingStart}
349 362
         onHttpError={this.onHttpError}
363
+        onRenderProcessGone={this.onRenderProcessGone}
350 364
         onMessage={this.onMessage}
351
-        onShouldStartLoadWithRequest={onShouldStartLoadWithRequest}
365
+        onShouldStartLoadWithRequest={this.onShouldStartLoadWithRequest}
352 366
         ref={this.webViewRef}
353 367
         // TODO: find a better way to type this.
354 368
         source={resolveAssetSource(source as ImageSourcePropType)}

+ 2
- 2
src/WebViewShared.tsx 파일 보기

@@ -2,8 +2,8 @@ import escapeStringRegexp from 'escape-string-regexp';
2 2
 import React from 'react';
3 3
 import { Linking, View, ActivityIndicator, Text } from 'react-native';
4 4
 import {
5
-  WebViewNavigationEvent,
6 5
   OnShouldStartLoadWithRequest,
6
+  ShouldStartLoadRequestEvent,
7 7
 } from './WebViewTypes';
8 8
 import styles from './WebView.styles';
9 9
 
@@ -39,7 +39,7 @@ const createOnShouldStartLoadWithRequest = (
39 39
   originWhitelist: readonly string[],
40 40
   onShouldStartLoadWithRequest?: OnShouldStartLoadWithRequest,
41 41
 ) => {
42
-  return ({ nativeEvent }: WebViewNavigationEvent) => {
42
+  return ({ nativeEvent }: ShouldStartLoadRequestEvent) => {
43 43
     let shouldStart = true;
44 44
     const { url, lockIdentifier } = nativeEvent;
45 45
 

+ 68
- 10
src/WebViewTypes.ts 파일 보기

@@ -113,6 +113,10 @@ export interface WebViewNavigation extends WebViewNativeEvent {
113 113
   mainDocumentURL?: string;
114 114
 }
115 115
 
116
+export interface ShouldStartLoadRequest extends WebViewNavigation {
117
+  isTopFrame: boolean;
118
+}
119
+
116 120
 export interface FileDownload {
117 121
   downloadUrl: string;
118 122
 }
@@ -137,6 +141,10 @@ export interface WebViewHttpError extends WebViewNativeEvent {
137 141
   statusCode: number;
138 142
 }
139 143
 
144
+export interface WebViewRenderProcessGoneDetail {
145
+  didCrash: boolean;
146
+}
147
+
140 148
 export type WebViewEvent = NativeSyntheticEvent<WebViewNativeEvent>;
141 149
 
142 150
 export type WebViewProgressEvent = NativeSyntheticEvent<
@@ -145,6 +153,8 @@ export type WebViewProgressEvent = NativeSyntheticEvent<
145 153
 
146 154
 export type WebViewNavigationEvent = NativeSyntheticEvent<WebViewNavigation>;
147 155
 
156
+export type ShouldStartLoadRequestEvent = NativeSyntheticEvent<ShouldStartLoadRequest>;
157
+
148 158
 export type FileDownloadEvent = NativeSyntheticEvent<FileDownload>;
149 159
 
150 160
 export type WebViewMessageEvent = NativeSyntheticEvent<WebViewMessage>;
@@ -155,6 +165,8 @@ export type WebViewTerminatedEvent = NativeSyntheticEvent<WebViewNativeEvent>;
155 165
 
156 166
 export type WebViewHttpErrorEvent = NativeSyntheticEvent<WebViewHttpError>;
157 167
 
168
+export type WebViewRenderProcessGoneEvent = NativeSyntheticEvent<WebViewRenderProcessGoneDetail>;
169
+
158 170
 export type DataDetectorTypes =
159 171
   | 'phoneNumber'
160 172
   | 'link'
@@ -170,6 +182,8 @@ export type OverScrollModeType = 'always' | 'content' | 'never';
170 182
 
171 183
 export type CacheMode = 'LOAD_DEFAULT' | 'LOAD_CACHE_ONLY' | 'LOAD_CACHE_ELSE_NETWORK' | 'LOAD_NO_CACHE';
172 184
 
185
+export type AndroidLayerType = 'none' | 'software' | 'hardware';
186
+
173 187
 export interface WebViewSourceUri {
174 188
   /**
175 189
    * The URI to load in the `WebView`. Can be a local or remote file.
@@ -232,7 +246,7 @@ export interface WebViewNativeConfig {
232 246
 }
233 247
 
234 248
 export type OnShouldStartLoadWithRequest = (
235
-  event: WebViewNavigation,
249
+  event: ShouldStartLoadRequest,
236 250
 ) => boolean;
237 251
 
238 252
 export interface CommonNativeWebViewProps extends ViewProps {
@@ -252,7 +266,7 @@ export interface CommonNativeWebViewProps extends ViewProps {
252 266
   onLoadingStart: (event: WebViewNavigationEvent) => void;
253 267
   onHttpError: (event: WebViewHttpErrorEvent) => void;
254 268
   onMessage: (event: WebViewMessageEvent) => void;
255
-  onShouldStartLoadWithRequest: (event: WebViewNavigationEvent) => void;
269
+  onShouldStartLoadWithRequest: (event: ShouldStartLoadRequestEvent) => void;
256 270
   showsHorizontalScrollIndicator?: boolean;
257 271
   showsVerticalScrollIndicator?: boolean;
258 272
   // TODO: find a better way to type this.
@@ -260,7 +274,7 @@ export interface CommonNativeWebViewProps extends ViewProps {
260 274
   source: any;
261 275
   userAgent?: string;
262 276
   /**
263
-   * Append to the existing user-agent. Overriden if `userAgent` is set.
277
+   * Append to the existing user-agent. Overridden if `userAgent` is set.
264 278
    */
265 279
   applicationNameForUserAgent?: string;
266 280
 }
@@ -272,11 +286,13 @@ export interface AndroidNativeWebViewProps extends CommonNativeWebViewProps {
272 286
   allowFileAccessFromFileURLs?: boolean;
273 287
   allowUniversalAccessFromFileURLs?: boolean;
274 288
   androidHardwareAccelerationDisabled?: boolean;
289
+  androidLayerType?: AndroidLayerType;
275 290
   domStorageEnabled?: boolean;
276 291
   geolocationEnabled?: boolean;
277 292
   javaScriptEnabled?: boolean;
278 293
   mixedContentMode?: 'never' | 'always' | 'compatibility';
279 294
   onContentSizeChange?: (event: WebViewEvent) => void;
295
+  onRenderProcessGone?: (event: WebViewRenderProcessGoneEvent) => void;
280 296
   overScrollMode?: OverScrollModeType;
281 297
   saveFormDataDisabled?: boolean;
282 298
   textZoom?: number;
@@ -285,12 +301,9 @@ export interface AndroidNativeWebViewProps extends CommonNativeWebViewProps {
285 301
   readonly urlPrefixesForDefaultIntent?: string[];
286 302
 }
287 303
 
288
-export enum ContentInsetAdjustmentBehavior {
289
-  automatic = 'automatic',
290
-  scrollableAxes = 'scrollableAxes',
291
-  never = 'never',
292
-  always = 'always'
293
-};
304
+export declare type ContentInsetAdjustmentBehavior = 'automatic' | 'scrollableAxes' | 'never' | 'always';
305
+
306
+export declare type ContentMode = 'recommended' | 'mobile' | 'desktop';
294 307
 
295 308
 export interface IOSNativeWebViewProps extends CommonNativeWebViewProps {
296 309
   allowingReadAccessToURL?: string;
@@ -301,6 +314,7 @@ export interface IOSNativeWebViewProps extends CommonNativeWebViewProps {
301 314
   bounces?: boolean;
302 315
   contentInset?: ContentInsetProp;
303 316
   contentInsetAdjustmentBehavior?: ContentInsetAdjustmentBehavior;
317
+  contentMode?: ContentMode;
304 318
   readonly dataDetectorTypes?: DataDetectorTypes | DataDetectorTypes[];
305 319
   decelerationRate?: number;
306 320
   directionalLockEnabled?: boolean;
@@ -398,6 +412,18 @@ export interface IOSWebViewProps extends WebViewSharedProps {
398 412
    */
399 413
   contentInset?: ContentInsetProp;
400 414
 
415
+  /**
416
+   * Defaults to `recommended`, which loads mobile content on iPhone
417
+   * and iPad Mini but desktop content on other iPads.
418
+   *
419
+   * Possible values are:
420
+   * - `'recommended'`
421
+   * - `'mobile'`
422
+   * - `'desktop'`
423
+   * @platform ios
424
+   */
425
+  contentMode?: ContentMode;
426
+
401 427
   /**
402 428
    * Determines the types of data converted to clickable URLs in the web view's content.
403 429
    * By default only phone numbers are detected.
@@ -523,6 +549,15 @@ export interface IOSWebViewProps extends WebViewSharedProps {
523 549
   */
524 550
   injectedJavaScriptBeforeContentLoadedForMainFrameOnly?: boolean;
525 551
 
552
+  /**
553
+   * Boolean value that determines whether a pull to refresh gesture is
554
+   * available in the `WebView`. The default value is `false`.
555
+   * If `true`, sets `bounces` automatically to `true`
556
+   * @platform ios
557
+   *
558
+  */
559
+  pullToRefreshEnabled?: boolean;
560
+
526 561
   /**
527 562
    * Function that is invoked when the client needs to download a file.
528 563
    *
@@ -683,6 +718,12 @@ export interface AndroidWebViewProps extends WebViewSharedProps {
683 718
   onNavigationStateChange?: (event: WebViewNavigation) => void;
684 719
   onContentSizeChange?: (event: WebViewEvent) => void;
685 720
 
721
+  /**
722
+   * Function that is invoked when the `WebView` process crashes or is killed by the OS.
723
+   * Works only on Android (minimum API level 26).
724
+   */
725
+  onRenderProcessGone?: (event: WebViewRenderProcessGoneEvent) => void;
726
+
686 727
   /**
687 728
    * https://developer.android.com/reference/android/webkit/WebSettings.html#setCacheMode(int)
688 729
    * Set the cacheMode. Possible values are:
@@ -721,7 +762,7 @@ export interface AndroidWebViewProps extends WebViewSharedProps {
721 762
    */
722 763
   geolocationEnabled?: boolean;
723 764
 
724
-  
765
+
725 766
   /**
726 767
    * Boolean that sets whether JavaScript running in the context of a file
727 768
    * scheme URL should be allowed to access content from other file scheme URLs.
@@ -766,6 +807,18 @@ export interface AndroidWebViewProps extends WebViewSharedProps {
766 807
    */
767 808
   androidHardwareAccelerationDisabled?: boolean;
768 809
 
810
+    /**
811
+   * https://developer.android.com/reference/android/webkit/WebView#setLayerType(int,%20android.graphics.Paint)
812
+   * Sets the layerType. Possible values are:
813
+   *
814
+   * - `'none'` (default)
815
+   * - `'software'`
816
+   * - `'hardware'`
817
+   *
818
+   * @platform android
819
+   */
820
+  androidLayerType?: AndroidLayerType;
821
+
769 822
   /**
770 823
    * Boolean value to enable third party cookies in the `WebView`. Used on
771 824
    * Android Lollipop and above only as third party cookies are enabled by
@@ -973,4 +1026,9 @@ export interface WebViewSharedProps extends ViewProps {
973 1026
    * Should caching be enabled. Default is true.
974 1027
    */
975 1028
   cacheEnabled?: boolean;
1029
+
1030
+  /**
1031
+   * Append to the existing user-agent. Overridden if `userAgent` is set.
1032
+   */
1033
+  applicationNameForUserAgent?: string;
976 1034
 }