Procházet zdrojové kódy

Merge branch 'master' into master

Erik Haider Forsén před 4 roky
rodič
revize
4b56a6d95e
No account linked to committer's email address

+ 5
- 11
.github/workflows/windows-ci.yml Zobrazit soubor

15
       with:
15
       with:
16
         node-version: '12.9.1'
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
     - name: Setup MSBuild
18
     - name: Setup MSBuild
23
       uses: microsoft/setup-msbuild@v1.0.0
19
       uses: microsoft/setup-msbuild@v1.0.0
24
       with:
20
       with:
25
         vs-version: 16.5
21
         vs-version: 16.5
26
-       
27
-    - name: Setup NuGet
28
-      uses: NuGet/setup-nuget@v1.0.2
29
 
22
 
30
     - name: Check node modules cache
23
     - name: Check node modules cache
31
       uses: actions/cache@v1
24
       uses: actions/cache@v1
45
       run: |
38
       run: |
46
         yarn build
39
         yarn build
47
         yarn tsc
40
         yarn tsc
48
- 
49
-    - name: NuGet restore
50
-      run: nuget restore example\windows\WebViewWindows.sln
51
 
41
 
52
     - name: Build x64 release
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
     - name: Deploy
49
     - name: Deploy
56
       shell: powershell
50
       shell: powershell
57
       run: |
51
       run: |

+ 85
- 22
android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManager.java Zobrazit soubor

4
 import android.annotation.TargetApi;
4
 import android.annotation.TargetApi;
5
 import android.app.DownloadManager;
5
 import android.app.DownloadManager;
6
 import android.content.Context;
6
 import android.content.Context;
7
-import android.content.Intent;
8
 import android.content.pm.ActivityInfo;
7
 import android.content.pm.ActivityInfo;
9
 import android.content.pm.PackageManager;
8
 import android.content.pm.PackageManager;
10
 import android.graphics.Bitmap;
9
 import android.graphics.Bitmap;
14
 import android.net.Uri;
13
 import android.net.Uri;
15
 import android.os.Build;
14
 import android.os.Build;
16
 import android.os.Environment;
15
 import android.os.Environment;
17
-import androidx.annotation.RequiresApi;
18
-import androidx.core.content.ContextCompat;
16
+import android.os.SystemClock;
19
 import android.text.TextUtils;
17
 import android.text.TextUtils;
20
 import android.util.Log;
18
 import android.util.Log;
21
 import android.view.Gravity;
19
 import android.view.Gravity;
41
 import android.webkit.WebViewClient;
39
 import android.webkit.WebViewClient;
42
 import android.widget.FrameLayout;
40
 import android.widget.FrameLayout;
43
 
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;
44
 import com.facebook.react.views.scroll.ScrollEvent;
48
 import com.facebook.react.views.scroll.ScrollEvent;
45
 import com.facebook.react.views.scroll.ScrollEventType;
49
 import com.facebook.react.views.scroll.ScrollEventType;
46
 import com.facebook.react.views.scroll.OnScrollDispatchHelper;
50
 import com.facebook.react.views.scroll.OnScrollDispatchHelper;
64
 import com.facebook.react.uimanager.events.ContentSizeChangeEvent;
68
 import com.facebook.react.uimanager.events.ContentSizeChangeEvent;
65
 import com.facebook.react.uimanager.events.Event;
69
 import com.facebook.react.uimanager.events.Event;
66
 import com.facebook.react.uimanager.events.EventDispatcher;
70
 import com.facebook.react.uimanager.events.EventDispatcher;
71
+import com.reactnativecommunity.webview.RNCWebViewModule.ShouldOverrideUrlLoadingLock.ShouldOverrideCallbackState;
67
 import com.reactnativecommunity.webview.events.TopLoadingErrorEvent;
72
 import com.reactnativecommunity.webview.events.TopLoadingErrorEvent;
68
 import com.reactnativecommunity.webview.events.TopHttpErrorEvent;
73
 import com.reactnativecommunity.webview.events.TopHttpErrorEvent;
69
 import com.reactnativecommunity.webview.events.TopLoadingFinishEvent;
74
 import com.reactnativecommunity.webview.events.TopLoadingFinishEvent;
84
 import java.util.HashMap;
89
 import java.util.HashMap;
85
 import java.util.Locale;
90
 import java.util.Locale;
86
 import java.util.Map;
91
 import java.util.Map;
87
-
88
-import javax.annotation.Nullable;
92
+import java.util.concurrent.atomic.AtomicReference;
89
 
93
 
90
 /**
94
 /**
91
  * Manages instances of {@link WebView}
95
  * Manages instances of {@link WebView}
113
  */
117
  */
114
 @ReactModule(name = RNCWebViewManager.REACT_CLASS)
118
 @ReactModule(name = RNCWebViewManager.REACT_CLASS)
115
 public class RNCWebViewManager extends SimpleViewManager<WebView> {
119
 public class RNCWebViewManager extends SimpleViewManager<WebView> {
120
+  private static final String TAG = "RNCWebViewManager";
116
 
121
 
117
   public static final int COMMAND_GO_BACK = 1;
122
   public static final int COMMAND_GO_BACK = 1;
118
   public static final int COMMAND_GO_FORWARD = 2;
123
   public static final int COMMAND_GO_FORWARD = 2;
136
   // Use `webView.loadUrl("about:blank")` to reliably reset the view
141
   // Use `webView.loadUrl("about:blank")` to reliably reset the view
137
   // state and release page resources (including any running JavaScript).
142
   // state and release page resources (including any running JavaScript).
138
   protected static final String BLANK_URL = "about:blank";
143
   protected static final String BLANK_URL = "about:blank";
144
+  protected static final int SHOULD_OVERRIDE_URL_LOADING_TIMEOUT = 250;
139
   protected WebViewConfig mWebViewConfig;
145
   protected WebViewConfig mWebViewConfig;
140
 
146
 
141
   protected RNCWebChromeClient mWebChromeClient = null;
147
   protected RNCWebChromeClient mWebChromeClient = null;
299
     }
305
     }
300
   }
306
   }
301
 
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
+
302
   @ReactProp(name = "overScrollMode")
323
   @ReactProp(name = "overScrollMode")
303
   public void setOverScrollMode(WebView view, String overScrollModeString) {
324
   public void setOverScrollMode(WebView view, String overScrollModeString) {
304
     Integer overScrollMode;
325
     Integer overScrollMode;
432
 
453
 
433
   @ReactProp(name = "incognito")
454
   @ReactProp(name = "incognito")
434
   public void setIncognito(WebView view, boolean enabled) {
455
   public void setIncognito(WebView view, boolean enabled) {
456
+    // Don't do anything when incognito is disabled
457
+    if (!enabled) {
458
+      return;
459
+    }
460
+
435
     // Remove all previous cookies
461
     // Remove all previous cookies
436
     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
462
     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
437
       CookieManager.getInstance().removeAllCookies(null);
463
       CookieManager.getInstance().removeAllCookies(null);
441
 
467
 
442
     // Disable caching
468
     // Disable caching
443
     view.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);
469
     view.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);
444
-    view.getSettings().setAppCacheEnabled(!enabled);
470
+    view.getSettings().setAppCacheEnabled(false);
445
     view.clearHistory();
471
     view.clearHistory();
446
-    view.clearCache(enabled);
472
+    view.clearCache(true);
447
 
473
 
448
     // No form data or autofill enabled
474
     // No form data or autofill enabled
449
     view.clearFormData();
475
     view.clearFormData();
450
-    view.getSettings().setSavePassword(!enabled);
451
-    view.getSettings().setSaveFormData(!enabled);
476
+    view.getSettings().setSavePassword(false);
477
+    view.getSettings().setSaveFormData(false);
452
   }
478
   }
453
 
479
 
454
   @ReactProp(name = "source")
480
   @ReactProp(name = "source")
786
 
812
 
787
     @Override
813
     @Override
788
     public boolean shouldOverrideUrlLoading(WebView view, String url) {
814
     public boolean shouldOverrideUrlLoading(WebView view, String url) {
789
-      progressChangedFilter.setWaitingForCommandLoadUrl(true);
790
-      dispatchEvent(
791
-        view,
792
-        new TopShouldStartLoadWithRequestEvent(
793
-          view.getId(),
794
-          createWebViewEvent(view, url)));
795
-      return true;
796
-    }
815
+      final RNCWebView rncWebView = (RNCWebView) view;
816
+      final boolean isJsDebugging = ((ReactContext) view.getContext()).getJavaScriptContextHolder().get() == 0;
797
 
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;
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
+    }
798
 
861
 
799
     @TargetApi(Build.VERSION_CODES.N)
862
     @TargetApi(Build.VERSION_CODES.N)
800
     @Override
863
     @Override
1144
      */
1207
      */
1145
     public RNCWebView(ThemedReactContext reactContext) {
1208
     public RNCWebView(ThemedReactContext reactContext) {
1146
       super(reactContext);
1209
       super(reactContext);
1210
+      this.createCatalystInstance();
1147
       progressChangedFilter = new ProgressChangedFilter();
1211
       progressChangedFilter = new ProgressChangedFilter();
1148
     }
1212
     }
1149
 
1213
 
1252
 
1316
 
1253
       if (enabled) {
1317
       if (enabled) {
1254
         addJavascriptInterface(createRNCWebViewBridge(this), JAVASCRIPT_INTERFACE);
1318
         addJavascriptInterface(createRNCWebViewBridge(this), JAVASCRIPT_INTERFACE);
1255
-        this.createCatalystInstance();
1256
       } else {
1319
       } else {
1257
         removeJavascriptInterface(JAVASCRIPT_INTERFACE);
1320
         removeJavascriptInterface(JAVASCRIPT_INTERFACE);
1258
       }
1321
       }
1308
             data.putString("data", message);
1371
             data.putString("data", message);
1309
 
1372
 
1310
             if (mCatalystInstance != null) {
1373
             if (mCatalystInstance != null) {
1311
-              mContext.sendDirectMessage(data);
1374
+              mContext.sendDirectMessage("onMessage", data);
1312
             } else {
1375
             } else {
1313
               dispatchEvent(webView, new TopMessageEvent(webView.getId(), data));
1376
               dispatchEvent(webView, new TopMessageEvent(webView.getId(), data));
1314
             }
1377
             }
1319
         eventData.putString("data", message);
1382
         eventData.putString("data", message);
1320
 
1383
 
1321
         if (mCatalystInstance != null) {
1384
         if (mCatalystInstance != null) {
1322
-          this.sendDirectMessage(eventData);
1385
+          this.sendDirectMessage("onMessage", eventData);
1323
         } else {
1386
         } else {
1324
           dispatchEvent(this, new TopMessageEvent(this.getId(), eventData));
1387
           dispatchEvent(this, new TopMessageEvent(this.getId(), eventData));
1325
         }
1388
         }
1326
       }
1389
       }
1327
     }
1390
     }
1328
 
1391
 
1329
-    protected void sendDirectMessage(WritableMap data) {
1392
+    protected void sendDirectMessage(final String method, WritableMap data) {
1330
       WritableNativeMap event = new WritableNativeMap();
1393
       WritableNativeMap event = new WritableNativeMap();
1331
       event.putMap("nativeEvent", data);
1394
       event.putMap("nativeEvent", data);
1332
 
1395
 
1333
       WritableNativeArray params = new WritableNativeArray();
1396
       WritableNativeArray params = new WritableNativeArray();
1334
       params.pushMap(event);
1397
       params.pushMap(event);
1335
 
1398
 
1336
-      mCatalystInstance.callFunction(messagingModuleName, "onMessage", params);
1399
+      mCatalystInstance.callFunction(messagingModuleName, method, params);
1337
     }
1400
     }
1338
 
1401
 
1339
     protected void onScrollChanged(int x, int y, int oldX, int oldY) {
1402
     protected void onScrollChanged(int x, int y, int oldX, int oldY) {

+ 44
- 0
android/src/main/java/com/reactnativecommunity/webview/RNCWebViewModule.java Zobrazit soubor

12
 import android.os.Parcelable;
12
 import android.os.Parcelable;
13
 import android.provider.MediaStore;
13
 import android.provider.MediaStore;
14
 
14
 
15
+import androidx.annotation.Nullable;
15
 import androidx.annotation.RequiresApi;
16
 import androidx.annotation.RequiresApi;
16
 import androidx.core.content.ContextCompat;
17
 import androidx.core.content.ContextCompat;
17
 import androidx.core.content.FileProvider;
18
 import androidx.core.content.FileProvider;
19
+import androidx.core.util.Pair;
18
 
20
 
19
 import android.util.Log;
21
 import android.util.Log;
20
 import android.webkit.MimeTypeMap;
22
 import android.webkit.MimeTypeMap;
35
 import java.io.IOException;
37
 import java.io.IOException;
36
 import java.util.ArrayList;
38
 import java.util.ArrayList;
37
 import java.util.Arrays;
39
 import java.util.Arrays;
40
+import java.util.HashMap;
41
+import java.util.concurrent.atomic.AtomicReference;
38
 
42
 
39
 import static android.app.Activity.RESULT_OK;
43
 import static android.app.Activity.RESULT_OK;
40
 
44
 
50
   private File outputVideo;
54
   private File outputVideo;
51
   private DownloadManager.Request downloadRequest;
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
   private enum MimeType {
86
   private enum MimeType {
54
     DEFAULT("*/*"),
87
     DEFAULT("*/*"),
55
     IMAGE("image"),
88
     IMAGE("image"),
105
     promise.resolve(result);
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
   public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) {
152
   public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) {
109
 
153
 
110
     if (filePathCallback == null && filePathCallbackLegacy == null) {
154
     if (filePathCallback == null && filePathCallbackLegacy == null) {

+ 2
- 0
android/src/main/java/com/reactnativecommunity/webview/events/TopShouldStartLoadWithRequestEvent.kt Zobrazit soubor

14
 
14
 
15
   init {
15
   init {
16
     mData.putString("navigationType", "other")
16
     mData.putString("navigationType", "other")
17
+    // Android does not raise shouldOverrideUrlLoading for inner frames
18
+    mData.putBoolean("isTopFrame", true)
17
   }
19
   }
18
 
20
 
19
   override fun getEventName(): String = EVENT_NAME
21
   override fun getEventName(): String = EVENT_NAME

+ 9
- 0
apple/RNCWebView.h Zobrazit soubor

35
 @property (nonatomic, assign) BOOL injectedJavaScriptBeforeContentLoadedForMainFrameOnly;
35
 @property (nonatomic, assign) BOOL injectedJavaScriptBeforeContentLoadedForMainFrameOnly;
36
 @property (nonatomic, assign) BOOL scrollEnabled;
36
 @property (nonatomic, assign) BOOL scrollEnabled;
37
 @property (nonatomic, assign) BOOL sharedCookiesEnabled;
37
 @property (nonatomic, assign) BOOL sharedCookiesEnabled;
38
+@property (nonatomic, assign) BOOL autoManageStatusBarEnabled;
38
 @property (nonatomic, assign) BOOL pagingEnabled;
39
 @property (nonatomic, assign) BOOL pagingEnabled;
39
 @property (nonatomic, assign) CGFloat decelerationRate;
40
 @property (nonatomic, assign) CGFloat decelerationRate;
40
 @property (nonatomic, assign) BOOL allowsInlineMediaPlayback;
41
 @property (nonatomic, assign) BOOL allowsInlineMediaPlayback;
62
 @property (nonatomic, assign) BOOL directionalLockEnabled;
63
 @property (nonatomic, assign) BOOL directionalLockEnabled;
63
 @property (nonatomic, assign) BOOL ignoreSilentHardwareSwitch;
64
 @property (nonatomic, assign) BOOL ignoreSilentHardwareSwitch;
64
 @property (nonatomic, copy) NSString * _Nullable allowingReadAccessToURL;
65
 @property (nonatomic, copy) NSString * _Nullable allowingReadAccessToURL;
66
+@property (nonatomic, assign) BOOL pullToRefreshEnabled;
67
+@property (nonatomic, weak) UIRefreshControl * refreshControl;
68
+
69
+#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 /* iOS 13 */
70
+@property (nonatomic, assign) WKContentMode contentMode;
71
+#endif
65
 
72
 
66
 + (void)setClientAuthenticationCredential:(nullable NSURLCredential*)credential;
73
 + (void)setClientAuthenticationCredential:(nullable NSURLCredential*)credential;
67
 + (void)setCustomCertificatesForHost:(nullable NSDictionary *)certificates;
74
 + (void)setCustomCertificatesForHost:(nullable NSDictionary *)certificates;
71
 - (void)goBack;
78
 - (void)goBack;
72
 - (void)reload;
79
 - (void)reload;
73
 - (void)stopLoading;
80
 - (void)stopLoading;
81
+- (void)addPullToRefreshControl;
82
+- (void)pullToRefresh:(UIRefreshControl *)refreshControl;
74
 
83
 
75
 @end
84
 @end

+ 58
- 40
apple/RNCWebView.m Zobrazit soubor

125
     _showsVerticalScrollIndicator = YES;
125
     _showsVerticalScrollIndicator = YES;
126
     _directionalLockEnabled = YES;
126
     _directionalLockEnabled = YES;
127
     _automaticallyAdjustContentInsets = YES;
127
     _automaticallyAdjustContentInsets = YES;
128
+    _autoManageStatusBarEnabled = YES;
128
     _contentInset = UIEdgeInsetsZero;
129
     _contentInset = UIEdgeInsetsZero;
129
     _savedKeyboardDisplayRequiresUserAction = YES;
130
     _savedKeyboardDisplayRequiresUserAction = YES;
130
     #if !TARGET_OS_OSX
131
     #if !TARGET_OS_OSX
226
   }
227
   }
227
   wkWebViewConfig.userContentController = [WKUserContentController new];
228
   wkWebViewConfig.userContentController = [WKUserContentController new];
228
 
229
 
230
+#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 /* iOS 13 */
231
+  if (@available(iOS 13.0, *)) {
232
+    WKWebpagePreferences *pagePrefs = [[WKWebpagePreferences alloc]init];
233
+    pagePrefs.preferredContentMode = _contentMode;
234
+    wkWebViewConfig.defaultWebpagePreferences = pagePrefs;
235
+  }
236
+#endif
237
+
229
   // Shim the HTML5 history API:
238
   // Shim the HTML5 history API:
230
   [wkWebViewConfig.userContentController addScriptMessageHandler:[[RNCWeakScriptMessageDelegate alloc] initWithDelegate:self]
239
   [wkWebViewConfig.userContentController addScriptMessageHandler:[[RNCWeakScriptMessageDelegate alloc] initWithDelegate:self]
231
                                                             name:HistoryShimName];
240
                                                             name:HistoryShimName];
267
     _webView.UIDelegate = self;
276
     _webView.UIDelegate = self;
268
     _webView.navigationDelegate = self;
277
     _webView.navigationDelegate = self;
269
 #if !TARGET_OS_OSX
278
 #if !TARGET_OS_OSX
279
+    if (_pullToRefreshEnabled) {
280
+        [self addPullToRefreshControl];
281
+    }
270
     _webView.scrollView.scrollEnabled = _scrollEnabled;
282
     _webView.scrollView.scrollEnabled = _scrollEnabled;
271
     _webView.scrollView.pagingEnabled = _pagingEnabled;
283
     _webView.scrollView.pagingEnabled = _pagingEnabled;
272
-    _webView.scrollView.bounces = _bounces;
284
+      //For UIRefreshControl to work correctly, the bounces should always be true
285
+    _webView.scrollView.bounces = _pullToRefreshEnabled || _bounces; 
273
     _webView.scrollView.showsHorizontalScrollIndicator = _showsHorizontalScrollIndicator;
286
     _webView.scrollView.showsHorizontalScrollIndicator = _showsHorizontalScrollIndicator;
274
     _webView.scrollView.showsVerticalScrollIndicator = _showsVerticalScrollIndicator;
287
     _webView.scrollView.showsVerticalScrollIndicator = _showsVerticalScrollIndicator;
275
     _webView.scrollView.directionalLockEnabled = _directionalLockEnabled;
288
     _webView.scrollView.directionalLockEnabled = _directionalLockEnabled;
300
   _webView.allowsBackForwardNavigationGestures = _allowsBackForwardNavigationGestures;
313
   _webView.allowsBackForwardNavigationGestures = _allowsBackForwardNavigationGestures;
301
 }
314
 }
302
 
315
 
303
-
304
 - (void)removeFromSuperview
316
 - (void)removeFromSuperview
305
 {
317
 {
306
     if (_webView) {
318
     if (_webView) {
324
 -(void)showFullScreenVideoStatusBars
336
 -(void)showFullScreenVideoStatusBars
325
 {
337
 {
326
 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
338
 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
339
+    if (!_autoManageStatusBarEnabled) {
340
+      return;
341
+    }
342
+
327
     _isFullScreenVideoOpen = YES;
343
     _isFullScreenVideoOpen = YES;
328
     RCTUnsafeExecuteOnMainQueueSync(^{
344
     RCTUnsafeExecuteOnMainQueueSync(^{
329
-      [RCTSharedApplication() setStatusBarStyle:UIStatusBarStyleLightContent animated:YES];
345
+      [RCTSharedApplication() setStatusBarStyle:self->_savedStatusBarStyle animated:YES];
330
     });
346
     });
331
 #pragma clang diagnostic pop
347
 #pragma clang diagnostic pop
332
 }
348
 }
334
 -(void)hideFullScreenVideoStatusBars
350
 -(void)hideFullScreenVideoStatusBars
335
 {
351
 {
336
 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
352
 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
353
+    if (!_autoManageStatusBarEnabled) {
354
+      return;
355
+    }
356
+
337
     _isFullScreenVideoOpen = NO;
357
     _isFullScreenVideoOpen = NO;
338
     RCTUnsafeExecuteOnMainQueueSync(^{
358
     RCTUnsafeExecuteOnMainQueueSync(^{
339
       [RCTSharedApplication() setStatusBarHidden:self->_savedStatusBarHidden animated:YES];
359
       [RCTSharedApplication() setStatusBarHidden:self->_savedStatusBarHidden animated:YES];
869
  * topViewController
889
  * topViewController
870
  */
890
  */
871
 -(UIViewController *)topViewController{
891
 -(UIViewController *)topViewController{
872
-    UIViewController *controller = [self topViewControllerWithRootViewController:[self getCurrentWindow].rootViewController];
873
-    return controller;
892
+    return RCTPresentedViewController();
874
 }
893
 }
875
 
894
 
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
 #endif // !TARGET_OS_OSX
895
 #endif // !TARGET_OS_OSX
907
 
896
 
908
 /**
897
 /**
929
 
918
 
930
   WKNavigationType navigationType = navigationAction.navigationType;
919
   WKNavigationType navigationType = navigationAction.navigationType;
931
   NSURLRequest *request = navigationAction.request;
920
   NSURLRequest *request = navigationAction.request;
921
+  BOOL isTopFrame = [request.URL isEqual:request.mainDocumentURL];
932
 
922
 
933
   if (_onShouldStartLoadWithRequest) {
923
   if (_onShouldStartLoadWithRequest) {
934
     NSMutableDictionary<NSString *, id> *event = [self baseEvent];
924
     NSMutableDictionary<NSString *, id> *event = [self baseEvent];
935
     [event addEntriesFromDictionary: @{
925
     [event addEntriesFromDictionary: @{
936
       @"url": (request.URL).absoluteString,
926
       @"url": (request.URL).absoluteString,
937
       @"mainDocumentURL": (request.mainDocumentURL).absoluteString,
927
       @"mainDocumentURL": (request.mainDocumentURL).absoluteString,
938
-      @"navigationType": navigationTypes[@(navigationType)]
928
+      @"navigationType": navigationTypes[@(navigationType)],
929
+      @"isTopFrame": @(isTopFrame)
939
     }];
930
     }];
940
     if (![self.delegate webView:self
931
     if (![self.delegate webView:self
941
       shouldStartLoadForRequest:event
932
       shouldStartLoadForRequest:event
947
 
938
 
948
   if (_onLoadingStart) {
939
   if (_onLoadingStart) {
949
     // We have this check to filter out iframe requests and whatnot
940
     // We have this check to filter out iframe requests and whatnot
950
-    BOOL isTopFrame = [request.URL isEqual:request.mainDocumentURL];
951
     if (isTopFrame) {
941
     if (isTopFrame) {
952
       NSMutableDictionary<NSString *, id> *event = [self baseEvent];
942
       NSMutableDictionary<NSString *, id> *event = [self baseEvent];
953
       [event addEntriesFromDictionary: @{
943
       [event addEntriesFromDictionary: @{
1147
   }
1137
   }
1148
 }
1138
 }
1149
 
1139
 
1140
+- (void)addPullToRefreshControl
1141
+{
1142
+    UIRefreshControl *refreshControl = [[UIRefreshControl alloc] init];
1143
+    _refreshControl = refreshControl;
1144
+    [_webView.scrollView addSubview: refreshControl];
1145
+    [refreshControl addTarget:self action:@selector(pullToRefresh:) forControlEvents: UIControlEventValueChanged];
1146
+}
1147
+
1148
+- (void)pullToRefresh:(UIRefreshControl *)refreshControl
1149
+{
1150
+    [self reload];
1151
+    [refreshControl endRefreshing];
1152
+}
1153
+
1154
+#if !TARGET_OS_OSX
1155
+- (void)setPullToRefreshEnabled:(BOOL)pullToRefreshEnabled
1156
+{
1157
+    _pullToRefreshEnabled = pullToRefreshEnabled;
1158
+    
1159
+    if (pullToRefreshEnabled) {
1160
+        [self addPullToRefreshControl];
1161
+    } else {
1162
+        [_refreshControl removeFromSuperview];
1163
+    }
1164
+
1165
+    [self setBounces:_bounces];
1166
+}
1167
+#endif // !TARGET_OS_OSX
1168
+
1150
 - (void)stopLoading
1169
 - (void)stopLoading
1151
 {
1170
 {
1152
   [_webView stopLoading];
1171
   [_webView stopLoading];
1156
 - (void)setBounces:(BOOL)bounces
1175
 - (void)setBounces:(BOOL)bounces
1157
 {
1176
 {
1158
   _bounces = bounces;
1177
   _bounces = bounces;
1159
-  _webView.scrollView.bounces = bounces;
1178
+    //For UIRefreshControl to work correctly, the bounces should always be true
1179
+  _webView.scrollView.bounces = _pullToRefreshEnabled || bounces;
1160
 }
1180
 }
1161
 #endif // !TARGET_OS_OSX
1181
 #endif // !TARGET_OS_OSX
1162
 
1182
 
1163
-
1164
 - (void)setInjectedJavaScript:(NSString *)source {
1183
 - (void)setInjectedJavaScript:(NSString *)source {
1165
   _injectedJavaScript = source;
1184
   _injectedJavaScript = source;
1166
 
1185
 
1372
 }
1391
 }
1373
 
1392
 
1374
 @end
1393
 @end
1375
-

+ 19
- 0
apple/RNCWebViewManager.m Zobrazit soubor

14
 @interface RNCWebViewManager () <RNCWebViewDelegate>
14
 @interface RNCWebViewManager () <RNCWebViewDelegate>
15
 @end
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
 @implementation RNCWebViewManager
27
 @implementation RNCWebViewManager
18
 {
28
 {
19
   NSConditionLock *_shouldStartLoadLock;
29
   NSConditionLock *_shouldStartLoadLock;
56
 #endif
66
 #endif
57
 RCT_EXPORT_VIEW_PROPERTY(contentInset, UIEdgeInsets)
67
 RCT_EXPORT_VIEW_PROPERTY(contentInset, UIEdgeInsets)
58
 RCT_EXPORT_VIEW_PROPERTY(automaticallyAdjustContentInsets, BOOL)
68
 RCT_EXPORT_VIEW_PROPERTY(automaticallyAdjustContentInsets, BOOL)
69
+RCT_EXPORT_VIEW_PROPERTY(autoManageStatusBarEnabled, BOOL)
59
 RCT_EXPORT_VIEW_PROPERTY(hideKeyboardAccessoryView, BOOL)
70
 RCT_EXPORT_VIEW_PROPERTY(hideKeyboardAccessoryView, BOOL)
60
 RCT_EXPORT_VIEW_PROPERTY(allowsBackForwardNavigationGestures, BOOL)
71
 RCT_EXPORT_VIEW_PROPERTY(allowsBackForwardNavigationGestures, BOOL)
61
 RCT_EXPORT_VIEW_PROPERTY(incognito, BOOL)
72
 RCT_EXPORT_VIEW_PROPERTY(incognito, BOOL)
70
 RCT_EXPORT_VIEW_PROPERTY(contentInsetAdjustmentBehavior, UIScrollViewContentInsetAdjustmentBehavior)
81
 RCT_EXPORT_VIEW_PROPERTY(contentInsetAdjustmentBehavior, UIScrollViewContentInsetAdjustmentBehavior)
71
 #endif
82
 #endif
72
 
83
 
84
+#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 /* iOS 13 */
85
+RCT_EXPORT_VIEW_PROPERTY(contentMode, WKContentMode)
86
+#endif
87
+
73
 /**
88
 /**
74
  * Expose methods to enable messaging the webview.
89
  * Expose methods to enable messaging the webview.
75
  */
90
  */
89
   }];
104
   }];
90
 }
105
 }
91
 
106
 
107
+RCT_CUSTOM_VIEW_PROPERTY(pullToRefreshEnabled, BOOL, RNCWebView) {
108
+    view.pullToRefreshEnabled = json == nil ? false : [RCTConvert BOOL: json];
109
+}
110
+
92
 RCT_CUSTOM_VIEW_PROPERTY(bounces, BOOL, RNCWebView) {
111
 RCT_CUSTOM_VIEW_PROPERTY(bounces, BOOL, RNCWebView) {
93
   view.bounces = json == nil ? true : [RCTConvert BOOL: json];
112
   view.bounces = json == nil ? true : [RCTConvert BOOL: json];
94
 }
113
 }

+ 3
- 1
docs/Debugging.md Zobrazit soubor

15
 3. Safari -> Develop -> [device name] -> [app name] -> [url - title]
15
 3. Safari -> Develop -> [device name] -> [app name] -> [url - title]
16
 4. You can now debug the WebView contents just as you would on the web
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
 When debugging on device you must enable Web Inspector in your device settings:
20
 When debugging on device you must enable Web Inspector in your device settings:
21
 
21
 
22
 Settings -> Safari -> Advanced -> Web Inspector
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
 ### Android & Chrome
26
 ### Android & Chrome
25
 
27
 
26
 It's possible to debug WebView contents in the Android emulator or on a device using Chrome DevTools.
28
 It's possible to debug WebView contents in the Android emulator or on a device using Chrome DevTools.

+ 2
- 1
docs/Guide.md Zobrazit soubor

305
             uri:
305
             uri:
306
               'https://github.com/react-native-community/react-native-webview',
306
               'https://github.com/react-native-community/react-native-webview',
307
           }}
307
           }}
308
+          onMessage={(event) => {}}
308
           injectedJavaScript={runFirst}
309
           injectedJavaScript={runFirst}
309
         />
310
         />
310
       </View>
311
       </View>
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
 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
 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
 

+ 122
- 55
docs/Reference.md Zobrazit soubor

35
 - [`javaScriptEnabled`](Reference.md#javascriptenabled)
35
 - [`javaScriptEnabled`](Reference.md#javascriptenabled)
36
 - [`javaScriptCanOpenWindowsAutomatically`](Reference.md#javascriptcanopenwindowsautomatically)
36
 - [`javaScriptCanOpenWindowsAutomatically`](Reference.md#javascriptcanopenwindowsautomatically)
37
 - [`androidHardwareAccelerationDisabled`](Reference.md#androidHardwareAccelerationDisabled)
37
 - [`androidHardwareAccelerationDisabled`](Reference.md#androidHardwareAccelerationDisabled)
38
+- [`androidLayerType`](Reference.md#androidLayerType)
38
 - [`mixedContentMode`](Reference.md#mixedcontentmode)
39
 - [`mixedContentMode`](Reference.md#mixedcontentmode)
39
 - [`thirdPartyCookiesEnabled`](Reference.md#thirdpartycookiesenabled)
40
 - [`thirdPartyCookiesEnabled`](Reference.md#thirdpartycookiesenabled)
40
 - [`userAgent`](Reference.md#useragent)
41
 - [`userAgent`](Reference.md#useragent)
45
 - [`overScrollMode`](Reference.md#overscrollmode)
46
 - [`overScrollMode`](Reference.md#overscrollmode)
46
 - [`contentInset`](Reference.md#contentinset)
47
 - [`contentInset`](Reference.md#contentinset)
47
 - [`contentInsetAdjustmentBehavior`](Reference.md#contentInsetAdjustmentBehavior)
48
 - [`contentInsetAdjustmentBehavior`](Reference.md#contentInsetAdjustmentBehavior)
49
+- [`contentMode`](Reference.md#contentMode)
48
 - [`dataDetectorTypes`](Reference.md#datadetectortypes)
50
 - [`dataDetectorTypes`](Reference.md#datadetectortypes)
49
 - [`scrollEnabled`](Reference.md#scrollenabled)
51
 - [`scrollEnabled`](Reference.md#scrollenabled)
50
 - [`directionalLockEnabled`](Reference.md#directionalLockEnabled)
52
 - [`directionalLockEnabled`](Reference.md#directionalLockEnabled)
66
 - [`allowsLinkPreview`](Reference.md#allowsLinkPreview)
68
 - [`allowsLinkPreview`](Reference.md#allowsLinkPreview)
67
 - [`sharedCookiesEnabled`](Reference.md#sharedCookiesEnabled)
69
 - [`sharedCookiesEnabled`](Reference.md#sharedCookiesEnabled)
68
 - [`textZoom`](Reference.md#textZoom)
70
 - [`textZoom`](Reference.md#textZoom)
71
+- [`pullToRefreshEnabled`](Reference.md#pullToRefreshEnabled)
69
 - [`ignoreSilentHardwareSwitch`](Reference.md#ignoreSilentHardwareSwitch)
72
 - [`ignoreSilentHardwareSwitch`](Reference.md#ignoreSilentHardwareSwitch)
70
 - [`onFileDownload`](Reference.md#onFileDownload)
73
 - [`onFileDownload`](Reference.md#onFileDownload)
74
+- [`autoManageStatusBarEnabled`](Reference.md#autoManageStatusBarEnabled)
71
 
75
 
72
 ## Methods Index
76
 ## Methods Index
73
 
77
 
133
 
137
 
134
 On iOS, see [`WKUserScriptInjectionTimeAtDocumentEnd`](https://developer.apple.com/documentation/webkit/wkuserscriptinjectiontime/wkuserscriptinjectiontimeatdocumentend?language=objc)
138
 On iOS, see [`WKUserScriptInjectionTimeAtDocumentEnd`](https://developer.apple.com/documentation/webkit/wkuserscriptinjectiontime/wkuserscriptinjectiontimeatdocumentend?language=objc)
135
 
139
 
136
-| Type   | Required | Platform |
137
-| ------ | -------- | -------- |
138
-| string | No       | iOS, Android, macOS
140
+| Type   | Required | Platform            |
141
+| ------ | -------- | ------------------- |
142
+| string | No       | iOS, Android, macOS |
139
 
143
 
140
 To learn more, read the [Communicating between JS and Native](Guide.md#communicating-between-js-and-native) guide.
144
 To learn more, read the [Communicating between JS and Native](Guide.md#communicating-between-js-and-native) guide.
141
 
145
 
165
 
169
 
166
 On iOS, see [`WKUserScriptInjectionTimeAtDocumentStart`](https://developer.apple.com/documentation/webkit/wkuserscriptinjectiontime/wkuserscriptinjectiontimeatdocumentstart?language=objc)
170
 On iOS, see [`WKUserScriptInjectionTimeAtDocumentStart`](https://developer.apple.com/documentation/webkit/wkuserscriptinjectiontime/wkuserscriptinjectiontimeatdocumentstart?language=objc)
167
 
171
 
168
-| Type   | Required | Platform |
169
-| ------ | -------- | -------- |
172
+| Type   | Required | Platform   |
173
+| ------ | -------- | ---------- |
170
 | string | No       | iOS, macOS |
174
 | string | No       | iOS, macOS |
171
 
175
 
172
 To learn more, read the [Communicating between JS and Native](Guide.md#communicating-between-js-and-native) guide.
176
 To learn more, read the [Communicating between JS and Native](Guide.md#communicating-between-js-and-native) guide.
173
 
177
 
174
 Example:
178
 Example:
175
 
179
 
176
-Post message a JSON object of `window.location` to be handled by [`onMessage`](Reference.md#onmessage). `window.ReactNativeWebView.postMessage` *will* be available at this time.
180
+Post message a JSON object of `window.location` to be handled by [`onMessage`](Reference.md#onmessage). `window.ReactNativeWebView.postMessage` _will_ be available at this time.
177
 
181
 
178
 ```jsx
182
 ```jsx
179
 const INJECTED_JAVASCRIPT = `(function() {
183
 const INJECTED_JAVASCRIPT = `(function() {
195
 
199
 
196
 If `false`, (only supported on iOS and macOS), loads it into all frames (e.g. iframes).
200
 If `false`, (only supported on iOS and macOS), loads it into all frames (e.g. iframes).
197
 
201
 
198
-| Type   | Required | Platform |
199
-| ------ | -------- | -------- |
202
+| Type | Required | Platform                                          |
203
+| ---- | -------- | ------------------------------------------------- |
200
 | bool | No       | iOS and macOS (only `true` supported for Android) |
204
 | bool | No       | iOS and macOS (only `true` supported for Android) |
201
 
205
 
202
 ---
206
 ---
207
 
211
 
208
 If `false`, (only supported on iOS and macOS), loads it into all frames (e.g. iframes).
212
 If `false`, (only supported on iOS and macOS), loads it into all frames (e.g. iframes).
209
 
213
 
210
-| Type   | Required | Platform |
211
-| ------ | -------- | -------- |
214
+| Type | Required | Platform                                          |
215
+| ---- | -------- | ------------------------------------------------- |
212
 | bool | No       | iOS and macOS (only `true` supported for Android) |
216
 | bool | No       | iOS and macOS (only `true` supported for Android) |
213
 
217
 
214
 ---
218
 ---
219
 
223
 
220
 NOTE: the default `true` value might cause some videos to hang loading on iOS. Setting it to `false` could fix this issue.
224
 NOTE: the default `true` value might cause some videos to hang loading on iOS. Setting it to `false` could fix this issue.
221
 
225
 
222
-| Type | Required | Platform |
223
-| ---- | -------- | -------- |
226
+| Type | Required | Platform            |
227
+| ---- | -------- | ------------------- |
224
 | bool | No       | iOS, Android, macOS |
228
 | bool | No       | iOS, Android, macOS |
225
 
229
 
226
 ---
230
 ---
235
 - `props` (object)
239
 - `props` (object)
236
 - `viewManager` (object)
240
 - `viewManager` (object)
237
 
241
 
238
-| Type   | Required | Platform |
239
-| ------ | -------- | -------- |
242
+| Type   | Required | Platform            |
243
+| ------ | -------- | ------------------- |
240
 | object | No       | iOS, Android, macOS |
244
 | object | No       | iOS, Android, macOS |
241
 
245
 
242
 ---
246
 ---
254
 ```jsx
258
 ```jsx
255
 <WebView
259
 <WebView
256
   source={{ uri: 'https://reactnative.dev' }}
260
   source={{ uri: 'https://reactnative.dev' }}
257
-  onError={syntheticEvent => {
261
+  onError={(syntheticEvent) => {
258
     const { nativeEvent } = syntheticEvent;
262
     const { nativeEvent } = syntheticEvent;
259
     console.warn('WebView error: ', nativeEvent);
263
     console.warn('WebView error: ', nativeEvent);
260
   }}
264
   }}
294
 ```jsx
298
 ```jsx
295
 <WebView
299
 <WebView
296
   source={{ uri: 'https://reactnative.dev' }}
300
   source={{ uri: 'https://reactnative.dev' }}
297
-  onLoad={syntheticEvent => {
301
+  onLoad={(syntheticEvent) => {
298
     const { nativeEvent } = syntheticEvent;
302
     const { nativeEvent } = syntheticEvent;
299
     this.url = nativeEvent.url;
303
     this.url = nativeEvent.url;
300
   }}
304
   }}
327
 ```jsx
331
 ```jsx
328
 <WebView
332
 <WebView
329
   source={{ uri: 'https://reactnative.dev' }}
333
   source={{ uri: 'https://reactnative.dev' }}
330
-  onLoadEnd={syntheticEvent => {
334
+  onLoadEnd={(syntheticEvent) => {
331
     // update component to be aware of loading status
335
     // update component to be aware of loading status
332
     const { nativeEvent } = syntheticEvent;
336
     const { nativeEvent } = syntheticEvent;
333
     this.isLoading = nativeEvent.loading;
337
     this.isLoading = nativeEvent.loading;
361
 ```jsx
365
 ```jsx
362
 <WebView
366
 <WebView
363
   source={{ uri: 'https://reactnative.dev/=' }}
367
   source={{ uri: 'https://reactnative.dev/=' }}
364
-  onLoadStart={syntheticEvent => {
368
+  onLoadStart={(syntheticEvent) => {
365
     // update component to be aware of loading status
369
     // update component to be aware of loading status
366
     const { nativeEvent } = syntheticEvent;
370
     const { nativeEvent } = syntheticEvent;
367
     this.isLoading = nativeEvent.loading;
371
     this.isLoading = nativeEvent.loading;
386
 
390
 
387
 Function that is invoked when the `WebView` is loading.
391
 Function that is invoked when the `WebView` is loading.
388
 
392
 
389
-| Type     | Required | Platform |
390
-| -------- | -------- | --------- |
393
+| Type     | Required | Platform            |
394
+| -------- | -------- | ------------------- |
391
 | function | No       | iOS, Android, macOS |
395
 | function | No       | iOS, Android, macOS |
392
 
396
 
393
 Example:
397
 Example:
431
 ```jsx
435
 ```jsx
432
 <WebView
436
 <WebView
433
   source={{ uri: 'https://reactnative.dev' }}
437
   source={{ uri: 'https://reactnative.dev' }}
434
-  onHttpError={syntheticEvent => {
438
+  onHttpError={(syntheticEvent) => {
435
     const { nativeEvent } = syntheticEvent;
439
     const { nativeEvent } = syntheticEvent;
436
     console.warn(
440
     console.warn(
437
       'WebView received error status code: ',
441
       'WebView received error status code: ',
519
 ```jsx
523
 ```jsx
520
 <WebView
524
 <WebView
521
   source={{ uri: 'https://reactnative.dev' }}
525
   source={{ uri: 'https://reactnative.dev' }}
522
-  onNavigationStateChange={navState => {
526
+  onNavigationStateChange={(navState) => {
523
     // Keep track of going back navigation within component
527
     // Keep track of going back navigation within component
524
     this.canGoBack = navState.canGoBack;
528
     this.canGoBack = navState.canGoBack;
525
   }}
529
   }}
538
 url
542
 url
539
 ```
543
 ```
540
 
544
 
541
-Note that this method will not be invoked on hash URL changes (e.g. from `https://example.com/users#list` to `https://example.com/users#help`). There is a workaround for this that is described [in the Guide](Guide.md#intercepting-hash-url-changes).
542
-
543
 ---
545
 ---
544
 
546
 
545
 ### `onContentProcessDidTerminate`[⬆](#props-index)<!-- Link generated with jump2header -->
547
 ### `onContentProcessDidTerminate`[⬆](#props-index)<!-- Link generated with jump2header -->
555
 ```jsx
557
 ```jsx
556
 <WebView
558
 <WebView
557
   source={{ uri: 'https://reactnative.dev' }}
559
   source={{ uri: 'https://reactnative.dev' }}
558
-  onContentProcessDidTerminate={syntheticEvent => {
560
+  onContentProcessDidTerminate={(syntheticEvent) => {
559
     const { nativeEvent } = syntheticEvent;
561
     const { nativeEvent } = syntheticEvent;
560
     console.warn('Content process terminated, reloading', nativeEvent);
562
     console.warn('Content process terminated, reloading', nativeEvent);
561
     this.refs.webview.reload();
563
     this.refs.webview.reload();
580
 
582
 
581
 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://*".
583
 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://*".
582
 
584
 
583
-| Type             | Required | Platform |
584
-| ---------------- | -------- | -------- |
585
+| Type             | Required | Platform            |
586
+| ---------------- | -------- | ------------------- |
585
 | array of strings | No       | iOS, Android, macOS |
587
 | array of strings | No       | iOS, Android, macOS |
586
 
588
 
587
 Example:
589
 Example:
600
 
602
 
601
 Function that returns a view to show if there's an error.
603
 Function that returns a view to show if there's an error.
602
 
604
 
603
-| Type     | Required | Platform |
604
-| -------- | -------- | -------- |
605
+| Type     | Required | Platform            |
606
+| -------- | -------- | ------------------- |
605
 | function | No       | iOS, Android, macOS |
607
 | function | No       | iOS, Android, macOS |
606
 
608
 
607
 Example:
609
 Example:
609
 ```jsx
611
 ```jsx
610
 <WebView
612
 <WebView
611
   source={{ uri: 'https://reactnative.dev' }}
613
   source={{ uri: 'https://reactnative.dev' }}
612
-  renderError={errorName => <Error name={errorName} />}
614
+  renderError={(errorName) => <Error name={errorName} />}
613
 />
615
 />
614
 ```
616
 ```
615
 
617
 
621
 
623
 
622
 Function that returns a loading indicator. The startInLoadingState prop must be set to true in order to use this prop.
624
 Function that returns a loading indicator. The startInLoadingState prop must be set to true in order to use this prop.
623
 
625
 
624
-| Type     | Required | Platform |
625
-| -------- | -------- | -------- |
626
+| Type     | Required | Platform            |
627
+| -------- | -------- | ------------------- |
626
 | function | No       | iOS, Android, macOS |
628
 | function | No       | iOS, Android, macOS |
627
 
629
 
628
 Example:
630
 Example:
653
 
655
 
654
 On Android, is not called on the first load.
656
 On Android, is not called on the first load.
655
 
657
 
656
-| Type     | Required | Platform |
657
-| -------- | -------- | -------- |
658
+| Type     | Required | Platform            |
659
+| -------- | -------- | ------------------- |
658
 | function | No       | iOS, Android, macOS |
660
 | function | No       | iOS, Android, macOS |
659
 
661
 
660
 Example:
662
 Example:
662
 ```jsx
664
 ```jsx
663
 <WebView
665
 <WebView
664
   source={{ uri: 'https://reactnative.dev' }}
666
   source={{ uri: 'https://reactnative.dev' }}
665
-  onShouldStartLoadWithRequest={request => {
667
+  onShouldStartLoadWithRequest={(request) => {
666
     // Only allow navigating within this website
668
     // Only allow navigating within this website
667
     return request.url.startsWith('https://reactnative.dev');
669
     return request.url.startsWith('https://reactnative.dev');
668
   }}
670
   }}
681
 lockIdentifier
683
 lockIdentifier
682
 mainDocumentURL (iOS only)
684
 mainDocumentURL (iOS only)
683
 navigationType
685
 navigationType
686
+isTopFrame
684
 ```
687
 ```
685
 
688
 
686
 ---
689
 ---
689
 
692
 
690
 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.
693
 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.
691
 
694
 
692
-| Type | Required | Platform |
693
-| ---- | -------- | -------- |
695
+| Type | Required | Platform            |
696
+| ---- | -------- | ------------------- |
694
 | bool | No       | iOS, Android, macOS |
697
 | bool | No       | iOS, Android, macOS |
695
 
698
 
696
 ---
699
 ---
778
 
781
 
779
 ### `androidHardwareAccelerationDisabled`[⬆](#props-index)<!-- Link generated with jump2header -->
782
 ### `androidHardwareAccelerationDisabled`[⬆](#props-index)<!-- Link generated with jump2header -->
780
 
783
 
781
-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`.
784
+**Deprecated.** Use the `androidLayerType` prop instead. 
782
 
785
 
783
 | Type | Required | Platform |
786
 | Type | Required | Platform |
784
 | ---- | -------- | -------- |
787
 | ---- | -------- | -------- |
786
 
789
 
787
 ---
790
 ---
788
 
791
 
792
+### `androidLayerType`[⬆](#props-index)<!-- Link generated with jump2header -->
793
+
794
+Specifies the layer type. 
795
+
796
+Possible values for `androidLayerType` are:
797
+
798
+- `none` (default) - The view does not have a layer.
799
+- `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.
800
+- `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.
801
+
802
+Avoid setting both `androidLayerType` and `androidHardwareAccelerationDisabled` props at the same time, as this may cause undefined behaviour.
803
+
804
+| Type   | Required | Platform |
805
+| ------ | -------- | -------- |
806
+| string | No       | Android  |
807
+
808
+---
809
+
789
 ### `mixedContentMode`[⬆](#props-index)<!-- Link generated with jump2header -->
810
 ### `mixedContentMode`[⬆](#props-index)<!-- Link generated with jump2header -->
790
 
811
 
791
 Specifies the mixed content mode. i.e WebView will allow a secure origin to load content from any other origin.
812
 Specifies the mixed content mode. i.e WebView will allow a secure origin to load content from any other origin.
816
 
837
 
817
 Sets the user-agent for the `WebView`.
838
 Sets the user-agent for the `WebView`.
818
 
839
 
819
-| Type   | Required | Platform |
820
-| ------ | -------- | -------- |
840
+| Type   | Required | Platform            |
841
+| ------ | -------- | ------------------- |
821
 | string | No       | iOS, Android, macOS |
842
 | string | No       | iOS, Android, macOS |
822
 
843
 
823
 ---
844
 ---
826
 
847
 
827
 Append to the existing user-agent. Setting `userAgent` will override this.
848
 Append to the existing user-agent. Setting `userAgent` will override this.
828
 
849
 
829
-| Type   | Required | Platform |
830
-| ------ | -------- | -------- |
850
+| Type   | Required | Platform            |
851
+| ------ | -------- | ------------------- |
831
 | string | No       | iOS, Android, macOS |
852
 | string | No       | iOS, Android, macOS |
832
 
853
 
833
 ```jsx
854
 ```jsx
917
 
938
 
918
 ---
939
 ---
919
 
940
 
941
+### `contentMode`[⬆](#props-index)<!-- Link generated with jump2header -->
942
+
943
+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.
944
+
945
+See [Introducing Desktop-class Browsing on iPad](https://developer.apple.com/videos/play/wwdc2019/203/) for more.
946
+
947
+Possible values:
948
+
949
+- `recommended`
950
+- `mobile`
951
+- `desktop`
952
+
953
+| Type   | Required | Platform |
954
+| ------ | -------- | -------- |
955
+| string | No       | iOS      |
956
+
957
+---
958
+
920
 ### `dataDetectorTypes`[⬆](#props-index)<!-- Link generated with jump2header -->
959
 ### `dataDetectorTypes`[⬆](#props-index)<!-- Link generated with jump2header -->
921
 
960
 
922
 Determines the types of data converted to clickable URLs in the web view's content. By default only phone numbers are detected.
961
 Determines the types of data converted to clickable URLs in the web view's content. By default only phone numbers are detected.
966
 
1005
 
967
 Boolean value that determines whether a horizontal scroll indicator is shown in the `WebView`. The default value is `true`.
1006
 Boolean value that determines whether a horizontal scroll indicator is shown in the `WebView`. The default value is `true`.
968
 
1007
 
969
-| Type | Required | Platform |
970
-| ---- | -------- | -------- |
1008
+| Type | Required | Platform            |
1009
+| ---- | -------- | ------------------- |
971
 | bool | No       | iOS, Android, macOS |
1010
 | bool | No       | iOS, Android, macOS |
972
 
1011
 
973
 ---
1012
 ---
976
 
1015
 
977
 Boolean value that determines whether a vertical scroll indicator is shown in the `WebView`. The default value is `true`.
1016
 Boolean value that determines whether a vertical scroll indicator is shown in the `WebView`. The default value is `true`.
978
 
1017
 
979
-| Type | Required | Platform |
980
-| ---- | -------- | -------- |
1018
+| Type | Required | Platform            |
1019
+| ---- | -------- | ------------------- |
981
 | bool | No       | iOS, Android, macOS |
1020
 | bool | No       | iOS, Android, macOS |
982
 
1021
 
983
 ---
1022
 ---
996
 
1035
 
997
 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`.
1036
 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`.
998
 
1037
 
999
-| Type | Required | Platform |
1000
-| ---- | -------- | -------- |
1038
+| Type | Required | Platform            |
1039
+| ---- | -------- | ------------------- |
1001
 | bool | No       | iOS, Android, macOS |
1040
 | bool | No       | iOS, Android, macOS |
1002
 
1041
 
1003
 ---
1042
 ---
1076
 
1115
 
1077
 Does not store any data within the lifetime of the WebView.
1116
 Does not store any data within the lifetime of the WebView.
1078
 
1117
 
1079
-| Type    | Required | Platform |
1080
-| ------- | -------- | -------- |
1118
+| Type    | Required | Platform            |
1119
+| ------- | -------- | ------------------- |
1081
 | boolean | No       | iOS, Android, macOS |
1120
 | boolean | No       | iOS, Android, macOS |
1082
 
1121
 
1083
 ---
1122
 ---
1106
 
1145
 
1107
 Sets whether WebView should use browser caching.
1146
 Sets whether WebView should use browser caching.
1108
 
1147
 
1109
-| Type    | Required | Default | Platform |
1110
-| ------- | -------- | ------- | -------- |
1148
+| Type    | Required | Default | Platform            |
1149
+| ------- | -------- | ------- | ------------------- |
1111
 | boolean | No       | true    | iOS, Android, macOS |
1150
 | boolean | No       | true    | iOS, Android, macOS |
1112
 
1151
 
1113
 ---
1152
 ---
1173
 
1212
 
1174
 `<WebView textZoom={100} />`
1213
 `<WebView textZoom={100} />`
1175
 
1214
 
1215
+---
1216
+
1217
+### `pullToRefreshEnabled`[⬆](#props-index)<!-- Link generated with jump2header -->
1218
+
1219
+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`.
1220
+
1221
+| Type    | Required | Platform |
1222
+| ------- | -------- | -------- |
1223
+| boolean | No       | iOS      |
1224
+
1176
 ### `ignoreSilentHardwareSwitch`[⬆](#props-index)<!-- Link generated with jump2header -->
1225
 ### `ignoreSilentHardwareSwitch`[⬆](#props-index)<!-- Link generated with jump2header -->
1177
 
1226
 
1178
 (ios only)
1227
 (ios only)
1202
 If not provided, the default is to let the webview try to render the file.
1251
 If not provided, the default is to let the webview try to render the file.
1203
 
1252
 
1204
 Example:
1253
 Example:
1254
+
1205
 ```jsx
1255
 ```jsx
1206
 <WebView
1256
 <WebView
1207
   source={{ uri: 'https://reactnative.dev' }}
1257
   source={{ uri: 'https://reactnative.dev' }}
1208
-  onFileDownload={ ( { nativeEvent: { downloadUrl } } ) => {
1258
+  onFileDownload={({ nativeEvent: { downloadUrl } }) => {
1209
     // You use downloadUrl which is a string to download files however you want.
1259
     // You use downloadUrl which is a string to download files however you want.
1210
   }}
1260
   }}
1211
-  />
1261
+/>
1212
 ```
1262
 ```
1213
 
1263
 
1264
+| Type     | Required | Platform |
1265
+| -------- | -------- | -------- |
1266
+| function | No       | iOS      |
1267
+
1268
+---
1269
+
1270
+### `autoManageStatusBarEnabled`
1271
+
1272
+If set to `true`, the status bar will be automatically hidden/shown by WebView, specifically when full screen video is being watched. If `false`, WebView will not manage the status bar at all. The default value is `true`.
1273
+
1214
 | Type    | Required | Platform |
1274
 | Type    | Required | Platform |
1215
 | ------- | -------- | -------- |
1275
 | ------- | -------- | -------- |
1216
-| function | No       | iOS      |
1276
+| boolean | No       | iOS      |
1277
+
1278
+Example:
1279
+
1280
+```javascript
1281
+<WebView autoManageStatusBarEnabled={false} />
1282
+```
1217
 
1283
 
1218
 ## Methods
1284
 ## Methods
1219
 
1285
 
1278
 ```javascript
1344
 ```javascript
1279
 postMessage('message');
1345
 postMessage('message');
1280
 ```
1346
 ```
1347
+
1281
 Post a message to WebView, handled by [`onMessage`](Reference.md#onmessage).
1348
 Post a message to WebView, handled by [`onMessage`](Reference.md#onmessage).
1282
 
1349
 
1283
 ### `clearFormData()`[⬆](#methods-index)<!-- Link generated with jump2header -->
1350
 ### `clearFormData()`[⬆](#methods-index)<!-- Link generated with jump2header -->

+ 24
- 1
index.d.ts Zobrazit soubor

6
 
6
 
7
 export type WebViewProps = IOSWebViewProps & AndroidWebViewProps;
7
 export type WebViewProps = IOSWebViewProps & AndroidWebViewProps;
8
 
8
 
9
-declare class WebView extends Component<WebViewProps> {
9
+declare class WebView<P = {}> extends Component<WebViewProps & P> {
10
     /**
10
     /**
11
      * Go back one page in the webview's history.
11
      * Go back one page in the webview's history.
12
      */
12
      */
41
      * Focuses on WebView redered page.
41
      * Focuses on WebView redered page.
42
      */
42
      */
43
     requestFocus: () => void;
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
 export {WebView};
69
 export {WebView};

+ 2
- 0
metro.config.windows.js Zobrazit soubor

35
       new RegExp(
35
       new RegExp(
36
         `${path.resolve(__dirname, 'windows').replace(/[/\\]/g, '/')}.*`,
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
   transformer: {
42
   transformer: {

+ 2
- 3
package.json Zobrazit soubor

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

+ 8
- 3
src/WebView.android.tsx Zobrazit soubor

61
     saveFormDataDisabled: false,
61
     saveFormDataDisabled: false,
62
     cacheEnabled: true,
62
     cacheEnabled: true,
63
     androidHardwareAccelerationDisabled: false,
63
     androidHardwareAccelerationDisabled: false,
64
+    androidLayerType: 'none',
64
     originWhitelist: defaultOriginWhitelist,
65
     originWhitelist: defaultOriginWhitelist,
65
   };
66
   };
66
 
67
 
76
     lastErrorEvent: null,
77
     lastErrorEvent: null,
77
   };
78
   };
78
 
79
 
80
+  onShouldStartLoadWithRequest: ReturnType<typeof createOnShouldStartLoadWithRequest> | null = null;
79
 
81
 
80
   webViewRef = React.createRef<NativeWebViewAndroid>();
82
   webViewRef = React.createRef<NativeWebViewAndroid>();
81
 
83
 
279
   onShouldStartLoadWithRequestCallback = (
281
   onShouldStartLoadWithRequestCallback = (
280
     shouldStart: boolean,
282
     shouldStart: boolean,
281
     url: string,
283
     url: string,
284
+    lockIdentifier?: number,
282
   ) => {
285
   ) => {
283
-    if (shouldStart) {
286
+    if (lockIdentifier) {
287
+      NativeModules.RNCWebView.onShouldStartLoadWithRequestCallback(shouldStart, lockIdentifier);
288
+    } else if (shouldStart) {
284
       UIManager.dispatchViewManagerCommand(
289
       UIManager.dispatchViewManagerCommand(
285
         this.getWebViewHandle(),
290
         this.getWebViewHandle(),
286
         this.getCommands().loadUrl,
291
         this.getCommands().loadUrl,
337
     const NativeWebView
342
     const NativeWebView
338
       = (nativeConfig.component as typeof NativeWebViewAndroid) || RNCWebView;
343
       = (nativeConfig.component as typeof NativeWebViewAndroid) || RNCWebView;
339
 
344
 
340
-    const onShouldStartLoadWithRequest = createOnShouldStartLoadWithRequest(
345
+    this.onShouldStartLoadWithRequest = createOnShouldStartLoadWithRequest(
341
       this.onShouldStartLoadWithRequestCallback,
346
       this.onShouldStartLoadWithRequestCallback,
342
       // casting cause it's in the default props
347
       // casting cause it's in the default props
343
       originWhitelist as readonly string[],
348
       originWhitelist as readonly string[],
357
         onHttpError={this.onHttpError}
362
         onHttpError={this.onHttpError}
358
         onRenderProcessGone={this.onRenderProcessGone}
363
         onRenderProcessGone={this.onRenderProcessGone}
359
         onMessage={this.onMessage}
364
         onMessage={this.onMessage}
360
-        onShouldStartLoadWithRequest={onShouldStartLoadWithRequest}
365
+        onShouldStartLoadWithRequest={this.onShouldStartLoadWithRequest}
361
         ref={this.webViewRef}
366
         ref={this.webViewRef}
362
         // TODO: find a better way to type this.
367
         // TODO: find a better way to type this.
363
         source={resolveAssetSource(source as ImageSourcePropType)}
368
         source={resolveAssetSource(source as ImageSourcePropType)}

+ 2
- 2
src/WebViewShared.tsx Zobrazit soubor

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

+ 57
- 9
src/WebViewTypes.ts Zobrazit soubor

113
   mainDocumentURL?: string;
113
   mainDocumentURL?: string;
114
 }
114
 }
115
 
115
 
116
+export interface ShouldStartLoadRequest extends WebViewNavigation {
117
+  isTopFrame: boolean;
118
+}
119
+
116
 export interface FileDownload {
120
 export interface FileDownload {
117
   downloadUrl: string;
121
   downloadUrl: string;
118
 }
122
 }
149
 
153
 
150
 export type WebViewNavigationEvent = NativeSyntheticEvent<WebViewNavigation>;
154
 export type WebViewNavigationEvent = NativeSyntheticEvent<WebViewNavigation>;
151
 
155
 
156
+export type ShouldStartLoadRequestEvent = NativeSyntheticEvent<ShouldStartLoadRequest>;
157
+
152
 export type FileDownloadEvent = NativeSyntheticEvent<FileDownload>;
158
 export type FileDownloadEvent = NativeSyntheticEvent<FileDownload>;
153
 
159
 
154
 export type WebViewMessageEvent = NativeSyntheticEvent<WebViewMessage>;
160
 export type WebViewMessageEvent = NativeSyntheticEvent<WebViewMessage>;
176
 
182
 
177
 export type CacheMode = 'LOAD_DEFAULT' | 'LOAD_CACHE_ONLY' | 'LOAD_CACHE_ELSE_NETWORK' | 'LOAD_NO_CACHE';
183
 export type CacheMode = 'LOAD_DEFAULT' | 'LOAD_CACHE_ONLY' | 'LOAD_CACHE_ELSE_NETWORK' | 'LOAD_NO_CACHE';
178
 
184
 
185
+export type AndroidLayerType = 'none' | 'software' | 'hardware';
186
+
179
 export interface WebViewSourceUri {
187
 export interface WebViewSourceUri {
180
   /**
188
   /**
181
    * The URI to load in the `WebView`. Can be a local or remote file.
189
    * The URI to load in the `WebView`. Can be a local or remote file.
238
 }
246
 }
239
 
247
 
240
 export type OnShouldStartLoadWithRequest = (
248
 export type OnShouldStartLoadWithRequest = (
241
-  event: WebViewNavigation,
249
+  event: ShouldStartLoadRequest,
242
 ) => boolean;
250
 ) => boolean;
243
 
251
 
244
 export interface CommonNativeWebViewProps extends ViewProps {
252
 export interface CommonNativeWebViewProps extends ViewProps {
258
   onLoadingStart: (event: WebViewNavigationEvent) => void;
266
   onLoadingStart: (event: WebViewNavigationEvent) => void;
259
   onHttpError: (event: WebViewHttpErrorEvent) => void;
267
   onHttpError: (event: WebViewHttpErrorEvent) => void;
260
   onMessage: (event: WebViewMessageEvent) => void;
268
   onMessage: (event: WebViewMessageEvent) => void;
261
-  onShouldStartLoadWithRequest: (event: WebViewNavigationEvent) => void;
269
+  onShouldStartLoadWithRequest: (event: ShouldStartLoadRequestEvent) => void;
262
   showsHorizontalScrollIndicator?: boolean;
270
   showsHorizontalScrollIndicator?: boolean;
263
   showsVerticalScrollIndicator?: boolean;
271
   showsVerticalScrollIndicator?: boolean;
264
   // TODO: find a better way to type this.
272
   // TODO: find a better way to type this.
266
   source: any;
274
   source: any;
267
   userAgent?: string;
275
   userAgent?: string;
268
   /**
276
   /**
269
-   * Append to the existing user-agent. Overriden if `userAgent` is set.
277
+   * Append to the existing user-agent. Overridden if `userAgent` is set.
270
    */
278
    */
271
   applicationNameForUserAgent?: string;
279
   applicationNameForUserAgent?: string;
272
 }
280
 }
278
   allowFileAccessFromFileURLs?: boolean;
286
   allowFileAccessFromFileURLs?: boolean;
279
   allowUniversalAccessFromFileURLs?: boolean;
287
   allowUniversalAccessFromFileURLs?: boolean;
280
   androidHardwareAccelerationDisabled?: boolean;
288
   androidHardwareAccelerationDisabled?: boolean;
289
+  androidLayerType?: AndroidLayerType;
281
   domStorageEnabled?: boolean;
290
   domStorageEnabled?: boolean;
282
   geolocationEnabled?: boolean;
291
   geolocationEnabled?: boolean;
283
   javaScriptEnabled?: boolean;
292
   javaScriptEnabled?: boolean;
292
   readonly urlPrefixesForDefaultIntent?: string[];
301
   readonly urlPrefixesForDefaultIntent?: string[];
293
 }
302
 }
294
 
303
 
295
-export enum ContentInsetAdjustmentBehavior {
296
-  automatic = 'automatic',
297
-  scrollableAxes = 'scrollableAxes',
298
-  never = 'never',
299
-  always = 'always'
300
-};
304
+export declare type ContentInsetAdjustmentBehavior = 'automatic' | 'scrollableAxes' | 'never' | 'always';
305
+
306
+export declare type ContentMode = 'recommended' | 'mobile' | 'desktop';
301
 
307
 
302
 export interface IOSNativeWebViewProps extends CommonNativeWebViewProps {
308
 export interface IOSNativeWebViewProps extends CommonNativeWebViewProps {
303
   allowingReadAccessToURL?: string;
309
   allowingReadAccessToURL?: string;
305
   allowsInlineMediaPlayback?: boolean;
311
   allowsInlineMediaPlayback?: boolean;
306
   allowsLinkPreview?: boolean;
312
   allowsLinkPreview?: boolean;
307
   automaticallyAdjustContentInsets?: boolean;
313
   automaticallyAdjustContentInsets?: boolean;
314
+  autoManageStatusBarEnabled?: boolean;
308
   bounces?: boolean;
315
   bounces?: boolean;
309
   contentInset?: ContentInsetProp;
316
   contentInset?: ContentInsetProp;
310
   contentInsetAdjustmentBehavior?: ContentInsetAdjustmentBehavior;
317
   contentInsetAdjustmentBehavior?: ContentInsetAdjustmentBehavior;
318
+  contentMode?: ContentMode;
311
   readonly dataDetectorTypes?: DataDetectorTypes | DataDetectorTypes[];
319
   readonly dataDetectorTypes?: DataDetectorTypes | DataDetectorTypes[];
312
   decelerationRate?: number;
320
   decelerationRate?: number;
313
   directionalLockEnabled?: boolean;
321
   directionalLockEnabled?: boolean;
405
    */
413
    */
406
   contentInset?: ContentInsetProp;
414
   contentInset?: ContentInsetProp;
407
 
415
 
416
+  /**
417
+   * Defaults to `recommended`, which loads mobile content on iPhone
418
+   * and iPad Mini but desktop content on other iPads.
419
+   *
420
+   * Possible values are:
421
+   * - `'recommended'`
422
+   * - `'mobile'`
423
+   * - `'desktop'`
424
+   * @platform ios
425
+   */
426
+  contentMode?: ContentMode;
427
+
408
   /**
428
   /**
409
    * Determines the types of data converted to clickable URLs in the web view's content.
429
    * Determines the types of data converted to clickable URLs in the web view's content.
410
    * By default only phone numbers are detected.
430
    * By default only phone numbers are detected.
479
    */
499
    */
480
   sharedCookiesEnabled?: boolean;
500
   sharedCookiesEnabled?: boolean;
481
 
501
 
502
+  /**
503
+   * Set true if StatusBar should be light when user watch video fullscreen.
504
+   * The default value is `true`.
505
+   * @platform ios
506
+   */
507
+  autoManageStatusBarEnabled?: boolean;
508
+
482
   /**
509
   /**
483
    * A Boolean value that determines whether scrolling is disabled in a particular direction.
510
    * A Boolean value that determines whether scrolling is disabled in a particular direction.
484
    * The default value is `true`.
511
    * The default value is `true`.
530
   */
557
   */
531
   injectedJavaScriptBeforeContentLoadedForMainFrameOnly?: boolean;
558
   injectedJavaScriptBeforeContentLoadedForMainFrameOnly?: boolean;
532
 
559
 
560
+  /**
561
+   * Boolean value that determines whether a pull to refresh gesture is
562
+   * available in the `WebView`. The default value is `false`.
563
+   * If `true`, sets `bounces` automatically to `true`
564
+   * @platform ios
565
+   *
566
+  */
567
+  pullToRefreshEnabled?: boolean;
568
+
533
   /**
569
   /**
534
    * Function that is invoked when the client needs to download a file.
570
    * Function that is invoked when the client needs to download a file.
535
    *
571
    *
779
    */
815
    */
780
   androidHardwareAccelerationDisabled?: boolean;
816
   androidHardwareAccelerationDisabled?: boolean;
781
 
817
 
818
+    /**
819
+   * https://developer.android.com/reference/android/webkit/WebView#setLayerType(int,%20android.graphics.Paint)
820
+   * Sets the layerType. Possible values are:
821
+   *
822
+   * - `'none'` (default)
823
+   * - `'software'`
824
+   * - `'hardware'`
825
+   *
826
+   * @platform android
827
+   */
828
+  androidLayerType?: AndroidLayerType;
829
+
782
   /**
830
   /**
783
    * Boolean value to enable third party cookies in the `WebView`. Used on
831
    * Boolean value to enable third party cookies in the `WebView`. Used on
784
    * Android Lollipop and above only as third party cookies are enabled by
832
    * Android Lollipop and above only as third party cookies are enabled by