react-native-webview.git

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787
  1. /**
  2. * Copyright (c) 2015-present, Facebook, Inc.
  3. *
  4. * This source code is licensed under the MIT license found in the
  5. * LICENSE file in the root directory of this source tree.
  6. *
  7. * @format
  8. * @noflow
  9. */
  10. 'use strict';
  11. import React from 'react';
  12. import PropTypes from 'prop-types';
  13. import ReactNative from 'react-native'
  14. import {
  15. ActivityIndicator,
  16. EdgeInsetsPropType,
  17. Linking,
  18. StyleSheet,
  19. Text,
  20. UIManager,
  21. View,
  22. ViewPropTypes,
  23. requireNativeComponent,
  24. NativeModules,
  25. Image
  26. } from 'react-native';
  27. import invariant from 'fbjs/lib/invariant';
  28. import keyMirror from 'fbjs/lib/keyMirror';
  29. import deprecatedPropType from 'deprecated-prop-type';
  30. import WebViewShared from './WebViewShared';
  31. const resolveAssetSource = Image.resolveAssetSource;
  32. // Imported from https://github.com/facebook/react-native/blob/master/Libraries/Components/ScrollView/processDecelerationRate.js
  33. function processDecelerationRate(decelerationRate) {
  34. if (decelerationRate === 'normal') {
  35. decelerationRate = 0.998;
  36. } else if (decelerationRate === 'fast') {
  37. decelerationRate = 0.99;
  38. }
  39. return decelerationRate;
  40. }
  41. const RNCWebViewManager = NativeModules.WebViewManager;
  42. const BGWASH = 'rgba(255,255,255,0.8)';
  43. const RCT_WEBVIEW_REF = 'webview';
  44. const WebViewState = keyMirror({
  45. IDLE: null,
  46. LOADING: null,
  47. ERROR: null,
  48. });
  49. const NavigationType = keyMirror({
  50. click: true,
  51. formsubmit: true,
  52. backforward: true,
  53. reload: true,
  54. formresubmit: true,
  55. other: true,
  56. });
  57. const JSNavigationScheme = 'react-js-navigation';
  58. // type ErrorEvent = {
  59. // domain: any,
  60. // code: any,
  61. // description: any,
  62. // };
  63. // type Event = Object;
  64. const DataDetectorTypes = [
  65. 'phoneNumber',
  66. 'link',
  67. 'address',
  68. 'calendarEvent',
  69. 'trackingNumber',
  70. 'flightNumber',
  71. 'lookupSuggestion',
  72. 'none',
  73. 'all',
  74. ];
  75. const defaultRenderLoading = () => (
  76. <View style={styles.loadingView}>
  77. <ActivityIndicator />
  78. </View>
  79. );
  80. const defaultRenderError = (errorDomain, errorCode, errorDesc) => (
  81. <View style={styles.errorContainer}>
  82. <Text style={styles.errorTextTitle}>Error loading page</Text>
  83. <Text style={styles.errorText}>{'Domain: ' + errorDomain}</Text>
  84. <Text style={styles.errorText}>{'Error Code: ' + errorCode}</Text>
  85. <Text style={styles.errorText}>{'Description: ' + errorDesc}</Text>
  86. </View>
  87. );
  88. /**
  89. * `WebView` renders web content in a native view.
  90. *
  91. *```
  92. * import React, { Component } from 'react';
  93. * import { WebView } from 'react-native';
  94. *
  95. * class MyWeb extends Component {
  96. * render() {
  97. * return (
  98. * <WebView
  99. * source={{uri: 'https://github.com/facebook/react-native'}}
  100. * style={{marginTop: 20}}
  101. * />
  102. * );
  103. * }
  104. * }
  105. *```
  106. *
  107. * You can use this component to navigate back and forth in the web view's
  108. * history and configure various properties for the web content.
  109. */
  110. class WebView extends React.Component {
  111. static JSNavigationScheme = JSNavigationScheme;
  112. static NavigationType = NavigationType;
  113. static propTypes = {
  114. ...DeprecatedViewPropTypes,
  115. html: deprecatedPropType(
  116. PropTypes.string,
  117. 'Use the `source` prop instead.',
  118. ),
  119. url: deprecatedPropType(PropTypes.string, 'Use the `source` prop instead.'),
  120. /**
  121. * Loads static html or a uri (with optional headers) in the WebView.
  122. */
  123. source: PropTypes.oneOfType([
  124. PropTypes.shape({
  125. /*
  126. * The URI to load in the `WebView`. Can be a local or remote file.
  127. */
  128. uri: PropTypes.string,
  129. /*
  130. * The HTTP Method to use. Defaults to GET if not specified.
  131. * NOTE: On Android, only GET and POST are supported.
  132. */
  133. method: PropTypes.string,
  134. /*
  135. * Additional HTTP headers to send with the request.
  136. * NOTE: On Android, this can only be used with GET requests.
  137. */
  138. headers: PropTypes.object,
  139. /*
  140. * The HTTP body to send with the request. This must be a valid
  141. * UTF-8 string, and will be sent exactly as specified, with no
  142. * additional encoding (e.g. URL-escaping or base64) applied.
  143. * NOTE: On Android, this can only be used with POST requests.
  144. */
  145. body: PropTypes.string,
  146. }),
  147. PropTypes.shape({
  148. /*
  149. * A static HTML page to display in the WebView.
  150. */
  151. html: PropTypes.string,
  152. /*
  153. * The base URL to be used for any relative links in the HTML.
  154. */
  155. baseUrl: PropTypes.string,
  156. }),
  157. /*
  158. * Used internally by packager.
  159. */
  160. PropTypes.number,
  161. ]),
  162. /**
  163. * If true, use WKWebView instead of UIWebView.
  164. * @platform ios
  165. */
  166. useWebKit: PropTypes.bool,
  167. /**
  168. * Function that returns a view to show if there's an error.
  169. */
  170. renderError: PropTypes.func, // view to show if there's an error
  171. /**
  172. * Function that returns a loading indicator.
  173. */
  174. renderLoading: PropTypes.func,
  175. /**
  176. * Function that is invoked when the `WebView` has finished loading.
  177. */
  178. onLoad: PropTypes.func,
  179. /**
  180. * Function that is invoked when the `WebView` load succeeds or fails.
  181. */
  182. onLoadEnd: PropTypes.func,
  183. /**
  184. * Function that is invoked when the `WebView` starts loading.
  185. */
  186. onLoadStart: PropTypes.func,
  187. /**
  188. * Function that is invoked when the `WebView` load fails.
  189. */
  190. onError: PropTypes.func,
  191. /**
  192. * Boolean value that determines whether the web view bounces
  193. * when it reaches the edge of the content. The default value is `true`.
  194. * @platform ios
  195. */
  196. bounces: PropTypes.bool,
  197. /**
  198. * A floating-point number that determines how quickly the scroll view
  199. * decelerates after the user lifts their finger. You may also use the
  200. * string shortcuts `"normal"` and `"fast"` which match the underlying iOS
  201. * settings for `UIScrollViewDecelerationRateNormal` and
  202. * `UIScrollViewDecelerationRateFast` respectively:
  203. *
  204. * - normal: 0.998
  205. * - fast: 0.99 (the default for iOS web view)
  206. * @platform ios
  207. */
  208. decelerationRate: PropTypes.oneOfType([
  209. PropTypes.oneOf(['fast', 'normal']),
  210. PropTypes.number,
  211. ]),
  212. /**
  213. * Boolean value that determines whether scrolling is enabled in the
  214. * `WebView`. The default value is `true`.
  215. * @platform ios
  216. */
  217. scrollEnabled: PropTypes.bool,
  218. /**
  219. * Controls whether to adjust the content inset for web views that are
  220. * placed behind a navigation bar, tab bar, or toolbar. The default value
  221. * is `true`.
  222. */
  223. automaticallyAdjustContentInsets: PropTypes.bool,
  224. /**
  225. * The amount by which the web view content is inset from the edges of
  226. * the scroll view. Defaults to {top: 0, left: 0, bottom: 0, right: 0}.
  227. * @platform ios
  228. */
  229. contentInset: EdgeInsetsPropType,
  230. /**
  231. * Function that is invoked when the `WebView` loading starts or ends.
  232. */
  233. onNavigationStateChange: PropTypes.func,
  234. /**
  235. * A function that is invoked when the webview calls `window.postMessage`.
  236. * Setting this property will inject a `postMessage` global into your
  237. * webview, but will still call pre-existing values of `postMessage`.
  238. *
  239. * `window.postMessage` accepts one argument, `data`, which will be
  240. * available on the event object, `event.nativeEvent.data`. `data`
  241. * must be a string.
  242. */
  243. onMessage: PropTypes.func,
  244. /**
  245. * Boolean value that forces the `WebView` to show the loading view
  246. * on the first load.
  247. */
  248. startInLoadingState: PropTypes.bool,
  249. /**
  250. * The style to apply to the `WebView`.
  251. */
  252. style: DeprecatedViewPropTypes.style,
  253. /**
  254. * Determines the types of data converted to clickable URLs in the web view's content.
  255. * By default only phone numbers are detected.
  256. *
  257. * You can provide one type or an array of many types.
  258. *
  259. * Possible values for `dataDetectorTypes` are:
  260. *
  261. * - `'phoneNumber'`
  262. * - `'link'`
  263. * - `'address'`
  264. * - `'calendarEvent'`
  265. * - `'none'`
  266. * - `'all'`
  267. *
  268. * With the new WebKit implementation, we have three new values:
  269. * - `'trackingNumber'`,
  270. * - `'flightNumber'`,
  271. * - `'lookupSuggestion'`,
  272. *
  273. * @platform ios
  274. */
  275. dataDetectorTypes: PropTypes.oneOfType([
  276. PropTypes.oneOf(DataDetectorTypes),
  277. PropTypes.arrayOf(PropTypes.oneOf(DataDetectorTypes)),
  278. ]),
  279. /**
  280. * Boolean value to enable JavaScript in the `WebView`. Used on Android only
  281. * as JavaScript is enabled by default on iOS. The default value is `true`.
  282. * @platform android
  283. */
  284. javaScriptEnabled: PropTypes.bool,
  285. /**
  286. * Boolean value to enable third party cookies in the `WebView`. Used on
  287. * Android Lollipop and above only as third party cookies are enabled by
  288. * default on Android Kitkat and below and on iOS. The default value is `true`.
  289. * @platform android
  290. */
  291. thirdPartyCookiesEnabled: PropTypes.bool,
  292. /**
  293. * Boolean value to control whether DOM Storage is enabled. Used only in
  294. * Android.
  295. * @platform android
  296. */
  297. domStorageEnabled: PropTypes.bool,
  298. /**
  299. * Set this to provide JavaScript that will be injected into the web page
  300. * when the view loads.
  301. */
  302. injectedJavaScript: PropTypes.string,
  303. /**
  304. * Sets the user-agent for the `WebView`.
  305. * @platform android
  306. */
  307. userAgent: PropTypes.string,
  308. /**
  309. * Boolean that controls whether the web content is scaled to fit
  310. * the view and enables the user to change the scale. The default value
  311. * is `true`.
  312. *
  313. * On iOS, when `useWebKit=true`, this prop will not work.
  314. */
  315. scalesPageToFit: PropTypes.bool,
  316. /**
  317. * Function that allows custom handling of any web view requests. Return
  318. * `true` from the function to continue loading the request and `false`
  319. * to stop loading.
  320. * @platform ios
  321. */
  322. onShouldStartLoadWithRequest: PropTypes.func,
  323. /**
  324. * Boolean that determines whether HTML5 videos play inline or use the
  325. * native full-screen controller. The default value is `false`.
  326. *
  327. * **NOTE** : In order for video to play inline, not only does this
  328. * property need to be set to `true`, but the video element in the HTML
  329. * document must also include the `webkit-playsinline` attribute.
  330. * @platform ios
  331. */
  332. allowsInlineMediaPlayback: PropTypes.bool,
  333. /**
  334. * Boolean that determines whether HTML5 audio and video requires the user
  335. * to tap them before they start playing. The default value is `true`.
  336. */
  337. mediaPlaybackRequiresUserAction: PropTypes.bool,
  338. /**
  339. * List of origin strings to allow being navigated to. The strings allow
  340. * wildcards and get matched against *just* the origin (not the full URL).
  341. * If the user taps to navigate to a new page but the new page is not in
  342. * this whitelist, we will open the URL in Safari.
  343. * The default whitelisted origins are "http://*" and "https://*".
  344. */
  345. originWhitelist: PropTypes.arrayOf(PropTypes.string),
  346. /**
  347. * Function that accepts a string that will be passed to the WebView and
  348. * executed immediately as JavaScript.
  349. */
  350. injectJavaScript: PropTypes.func,
  351. /**
  352. * Specifies the mixed content mode. i.e WebView will allow a secure origin to load content from any other origin.
  353. *
  354. * Possible values for `mixedContentMode` are:
  355. *
  356. * - `'never'` (default) - WebView will not allow a secure origin to load content from an insecure origin.
  357. * - `'always'` - WebView will allow a secure origin to load content from any other origin, even if that origin is insecure.
  358. * - `'compatibility'` - WebView will attempt to be compatible with the approach of a modern web browser with regard to mixed content.
  359. * @platform android
  360. */
  361. mixedContentMode: PropTypes.oneOf(['never', 'always', 'compatibility']),
  362. /**
  363. * Override the native component used to render the WebView. Enables a custom native
  364. * WebView which uses the same JavaScript as the original WebView.
  365. */
  366. nativeConfig: PropTypes.shape({
  367. /*
  368. * The native component used to render the WebView.
  369. */
  370. component: PropTypes.any,
  371. /*
  372. * Set props directly on the native component WebView. Enables custom props which the
  373. * original WebView doesn't pass through.
  374. */
  375. props: PropTypes.object,
  376. /*
  377. * Set the ViewManager to use for communication with the native side.
  378. * @platform ios
  379. */
  380. viewManager: PropTypes.object,
  381. }),
  382. };
  383. static defaultProps = {
  384. originWhitelist: WebViewShared.defaultOriginWhitelist,
  385. };
  386. state = {
  387. viewState: WebViewState.IDLE,
  388. lastErrorEvent: null,
  389. startInLoadingState: true,
  390. };
  391. UNSAFE_componentWillMount() {
  392. if (this.props.startInLoadingState) {
  393. this.setState({ viewState: WebViewState.LOADING });
  394. }
  395. if (
  396. this.props.useWebKit === true &&
  397. this.props.scalesPageToFit !== undefined
  398. ) {
  399. console.warn(
  400. 'The scalesPageToFit property is not supported when useWebKit = true',
  401. );
  402. }
  403. }
  404. render() {
  405. let otherView = null;
  406. let scalesPageToFit;
  407. if (this.props.useWebKit) {
  408. ({ scalesPageToFit } = this.props);
  409. } else {
  410. ({ scalesPageToFit = true } = this.props);
  411. }
  412. if (this.state.viewState === WebViewState.LOADING) {
  413. otherView = (this.props.renderLoading || defaultRenderLoading)();
  414. } else if (this.state.viewState === WebViewState.ERROR) {
  415. const errorEvent = this.state.lastErrorEvent;
  416. invariant(errorEvent != null, 'lastErrorEvent expected to be non-null');
  417. otherView = (this.props.renderError || defaultRenderError)(
  418. errorEvent.domain,
  419. errorEvent.code,
  420. errorEvent.description,
  421. );
  422. } else if (this.state.viewState !== WebViewState.IDLE) {
  423. console.error(
  424. 'RCTWebView invalid state encountered: ' + this.state.loading,
  425. );
  426. }
  427. const webViewStyles = [styles.container, styles.webView, this.props.style];
  428. if (
  429. this.state.viewState === WebViewState.LOADING ||
  430. this.state.viewState === WebViewState.ERROR
  431. ) {
  432. // if we're in either LOADING or ERROR states, don't show the webView
  433. webViewStyles.push(styles.hidden);
  434. }
  435. const nativeConfig = this.props.nativeConfig || {};
  436. let viewManager = nativeConfig.viewManager;
  437. if (this.props.useWebKit) {
  438. viewManager = viewManager || RCTWKWebViewManager;
  439. } else {
  440. viewManager = viewManager || RCTWebViewManager;
  441. }
  442. const compiledWhitelist = [
  443. 'about:blank',
  444. ...(this.props.originWhitelist || []),
  445. ].map(WebViewShared.originWhitelistToRegex);
  446. const onShouldStartLoadWithRequest = (event) => {
  447. let shouldStart = true;
  448. const { url } = event.nativeEvent;
  449. const origin = WebViewShared.extractOrigin(url);
  450. const passesWhitelist = compiledWhitelist.some(x =>
  451. new RegExp(x).test(origin),
  452. );
  453. shouldStart = shouldStart && passesWhitelist;
  454. if (!passesWhitelist) {
  455. Linking.openURL(url);
  456. }
  457. if (this.props.onShouldStartLoadWithRequest) {
  458. shouldStart =
  459. shouldStart &&
  460. this.props.onShouldStartLoadWithRequest(event.nativeEvent);
  461. }
  462. viewManager.startLoadWithResult(
  463. !!shouldStart,
  464. event.nativeEvent.lockIdentifier,
  465. );
  466. };
  467. const decelerationRate = processDecelerationRate(
  468. this.props.decelerationRate,
  469. );
  470. const source = this.props.source || {};
  471. if (this.props.html) {
  472. source.html = this.props.html;
  473. } else if (this.props.url) {
  474. source.uri = this.props.url;
  475. }
  476. const messagingEnabled = typeof this.props.onMessage === 'function';
  477. let NativeWebView = nativeConfig.component;
  478. if (this.props.useWebKit) {
  479. NativeWebView = NativeWebView || RCTWKWebView;
  480. } else {
  481. NativeWebView = NativeWebView || RCTWebView;
  482. }
  483. const webView = (
  484. <NativeWebView
  485. ref={RCT_WEBVIEW_REF}
  486. key="webViewKey"
  487. style={webViewStyles}
  488. source={resolveAssetSource(source)}
  489. injectedJavaScript={this.props.injectedJavaScript}
  490. bounces={this.props.bounces}
  491. scrollEnabled={this.props.scrollEnabled}
  492. decelerationRate={decelerationRate}
  493. contentInset={this.props.contentInset}
  494. automaticallyAdjustContentInsets={
  495. this.props.automaticallyAdjustContentInsets
  496. }
  497. onLoadingStart={this._onLoadingStart}
  498. onLoadingFinish={this._onLoadingFinish}
  499. onLoadingError={this._onLoadingError}
  500. messagingEnabled={messagingEnabled}
  501. onMessage={this._onMessage}
  502. onShouldStartLoadWithRequest={onShouldStartLoadWithRequest}
  503. scalesPageToFit={scalesPageToFit}
  504. allowsInlineMediaPlayback={this.props.allowsInlineMediaPlayback}
  505. mediaPlaybackRequiresUserAction={
  506. this.props.mediaPlaybackRequiresUserAction
  507. }
  508. dataDetectorTypes={this.props.dataDetectorTypes}
  509. {...nativeConfig.props}
  510. />
  511. );
  512. return (
  513. <View style={styles.container}>
  514. {webView}
  515. {otherView}
  516. </View>
  517. );
  518. }
  519. _getCommands() {
  520. if (!this.props.useWebKit) {
  521. return UIManager.RCTWebView.Commands;
  522. }
  523. return UIManager.RCTWKWebView.Commands;
  524. }
  525. /**
  526. * Go forward one page in the web view's history.
  527. */
  528. goForward = () => {
  529. UIManager.dispatchViewManagerCommand(
  530. this.getWebViewHandle(),
  531. this._getCommands().goForward,
  532. null,
  533. );
  534. };
  535. /**
  536. * Go back one page in the web view's history.
  537. */
  538. goBack = () => {
  539. UIManager.dispatchViewManagerCommand(
  540. this.getWebViewHandle(),
  541. this._getCommands().goBack,
  542. null,
  543. );
  544. };
  545. /**
  546. * Reloads the current page.
  547. */
  548. reload = () => {
  549. this.setState({ viewState: WebViewState.LOADING });
  550. UIManager.dispatchViewManagerCommand(
  551. this.getWebViewHandle(),
  552. this._getCommands().reload,
  553. null,
  554. );
  555. };
  556. /**
  557. * Stop loading the current page.
  558. */
  559. stopLoading = () => {
  560. UIManager.dispatchViewManagerCommand(
  561. this.getWebViewHandle(),
  562. this._getCommands().stopLoading,
  563. null,
  564. );
  565. };
  566. /**
  567. * Posts a message to the web view, which will emit a `message` event.
  568. * Accepts one argument, `data`, which must be a string.
  569. *
  570. * In your webview, you'll need to something like the following.
  571. *
  572. * ```js
  573. * document.addEventListener('message', e => { document.title = e.data; });
  574. * ```
  575. */
  576. postMessage = data => {
  577. UIManager.dispatchViewManagerCommand(
  578. this.getWebViewHandle(),
  579. this._getCommands().postMessage,
  580. [String(data)],
  581. );
  582. };
  583. /**
  584. * Injects a javascript string into the referenced WebView. Deliberately does not
  585. * return a response because using eval() to return a response breaks this method
  586. * on pages with a Content Security Policy that disallows eval(). If you need that
  587. * functionality, look into postMessage/onMessage.
  588. */
  589. injectJavaScript = data => {
  590. UIManager.dispatchViewManagerCommand(
  591. this.getWebViewHandle(),
  592. this._getCommands().injectJavaScript,
  593. [data],
  594. );
  595. };
  596. /**
  597. * We return an event with a bunch of fields including:
  598. * url, title, loading, canGoBack, canGoForward
  599. */
  600. _updateNavigationState = (event) => {
  601. if (this.props.onNavigationStateChange) {
  602. this.props.onNavigationStateChange(event.nativeEvent);
  603. }
  604. };
  605. /**
  606. * Returns the native `WebView` node.
  607. */
  608. getWebViewHandle = () => {
  609. return ReactNative.findNodeHandle(this.refs[RCT_WEBVIEW_REF]);
  610. };
  611. _onLoadingStart = (event) => {
  612. const onLoadStart = this.props.onLoadStart;
  613. onLoadStart && onLoadStart(event);
  614. this._updateNavigationState(event);
  615. };
  616. _onLoadingError = (event) => {
  617. event.persist(); // persist this event because we need to store it
  618. const { onError, onLoadEnd } = this.props;
  619. onError && onError(event);
  620. onLoadEnd && onLoadEnd(event);
  621. console.warn('Encountered an error loading page', event.nativeEvent);
  622. this.setState({
  623. lastErrorEvent: event.nativeEvent,
  624. viewState: WebViewState.ERROR,
  625. });
  626. };
  627. _onLoadingFinish = (event) => {
  628. const { onLoad, onLoadEnd } = this.props;
  629. onLoad && onLoad(event);
  630. onLoadEnd && onLoadEnd(event);
  631. this.setState({
  632. viewState: WebViewState.IDLE,
  633. });
  634. this._updateNavigationState(event);
  635. };
  636. _onMessage = (event) => {
  637. const { onMessage } = this.props;
  638. onMessage && onMessage(event);
  639. };
  640. componentDidUpdate(prevProps) {
  641. if (!(prevProps.useWebKit && this.props.useWebKit)) {
  642. return;
  643. }
  644. this._showRedboxOnPropChanges(prevProps, 'allowsInlineMediaPlayback');
  645. this._showRedboxOnPropChanges(prevProps, 'mediaPlaybackRequiresUserAction');
  646. this._showRedboxOnPropChanges(prevProps, 'dataDetectorTypes');
  647. if (this.props.scalesPageToFit !== undefined) {
  648. console.warn(
  649. 'The scalesPageToFit property is not supported when useWebKit = true',
  650. );
  651. }
  652. }
  653. _showRedboxOnPropChanges(prevProps, propName) {
  654. if (this.props[propName] !== prevProps[propName]) {
  655. console.error(
  656. `Changes to property ${propName} do nothing after the initial render.`,
  657. );
  658. }
  659. }
  660. }
  661. const RCTWebView = requireNativeComponent(
  662. 'RCTWebView',
  663. WebView,
  664. WebView.extraNativeComponentConfig,
  665. );
  666. const RCTWKWebView = requireNativeComponent(
  667. 'RCTWKWebView',
  668. WebView,
  669. WebView.extraNativeComponentConfig,
  670. );
  671. const styles = StyleSheet.create({
  672. container: {
  673. flex: 1,
  674. },
  675. errorContainer: {
  676. flex: 1,
  677. justifyContent: 'center',
  678. alignItems: 'center',
  679. backgroundColor: BGWASH,
  680. },
  681. errorText: {
  682. fontSize: 14,
  683. textAlign: 'center',
  684. marginBottom: 2,
  685. },
  686. errorTextTitle: {
  687. fontSize: 15,
  688. fontWeight: '500',
  689. marginBottom: 10,
  690. },
  691. hidden: {
  692. height: 0,
  693. flex: 0, // disable 'flex:1' when hiding a View
  694. },
  695. loadingView: {
  696. backgroundColor: BGWASH,
  697. flex: 1,
  698. justifyContent: 'center',
  699. alignItems: 'center',
  700. height: 100,
  701. },
  702. webView: {
  703. backgroundColor: '#ffffff',
  704. },
  705. });
  706. module.exports = WebView;