You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

index.native.js 5.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. // @flow
  2. // FIXME The bundler-related (and the browser-related) polyfills were born at
  3. // the very early days of prototyping the execution of lib-jitsi-meet on
  4. // react-native. Today, the feature base/lib-jitsi-meet should not be
  5. // responsible for such polyfills because it is not the only feature relying on
  6. // them. Additionally, the polyfills are usually necessary earlier than the
  7. // execution of base/lib-jitsi-meet (which is understandable given that the
  8. // polyfills are globals). The remaining problem to be solved here is where to
  9. // collect the polyfills' files.
  10. import './features/base/lib-jitsi-meet/native/polyfills-bundler';
  11. import React, { Component } from 'react';
  12. import { AppRegistry, Linking, NativeModules } from 'react-native';
  13. import { App } from './features/app';
  14. import { equals } from './features/base/redux';
  15. import { IncomingCallApp } from './features/mobile/incoming-call';
  16. const logger = require('jitsi-meet-logger').getLogger(__filename);
  17. /**
  18. * The type of the React {@code Component} props of {@link Root}.
  19. */
  20. type Props = {
  21. /**
  22. * The URL, if any, with which the app was launched.
  23. */
  24. url: Object | string
  25. };
  26. /**
  27. * The type of the React {@code Component} state of {@link Root}.
  28. */
  29. type State = {
  30. /**
  31. * The URL, if any, with which the app was launched.
  32. */
  33. url: ?Object | string
  34. };
  35. /**
  36. * React Native doesn't support specifying props to the main/root component (in
  37. * the JS/JSX source code). So create a wrapper React Component (class) around
  38. * features/app's App instead.
  39. *
  40. * @extends Component
  41. */
  42. class Root extends Component<Props, State> {
  43. /**
  44. * Initializes a new {@code Root} instance.
  45. *
  46. * @param {Props} props - The read-only properties with which the new
  47. * instance is to be initialized.
  48. */
  49. constructor(props) {
  50. super(props);
  51. this.state = {
  52. url: this.props.url
  53. };
  54. // Handle the URL, if any, with which the app was launched. But props
  55. // have precedence.
  56. if (typeof this.props.url === 'undefined') {
  57. this._getInitialURL()
  58. .then(url => {
  59. if (typeof this.state.url === 'undefined') {
  60. this.setState({ url });
  61. }
  62. })
  63. .catch(err => {
  64. logger.error('Failed to get initial URL', err);
  65. if (typeof this.state.url === 'undefined') {
  66. // Start with an empty URL if getting the initial URL
  67. // fails; otherwise, nothing will be rendered.
  68. this.setState({ url: null });
  69. }
  70. });
  71. }
  72. }
  73. /**
  74. * Gets the initial URL the app was launched with. This can be a universal
  75. * (or deep) link, or a CallKit intent in iOS. Since the native
  76. * {@code Linking} module doesn't provide a way to access intents in iOS,
  77. * those are handled with the {@code LaunchOptions} module, which
  78. * essentially provides a replacement which takes that into consideration.
  79. *
  80. * @private
  81. * @returns {Promise} - A promise which will be fulfilled with the URL that
  82. * the app was launched with.
  83. */
  84. _getInitialURL() {
  85. if (NativeModules.LaunchOptions) {
  86. return NativeModules.LaunchOptions.getInitialURL();
  87. }
  88. return Linking.getInitialURL();
  89. }
  90. /**
  91. * Implements React's {@link Component#componentDidUpdate()}.
  92. *
  93. * New props can be set from the native side by setting the appProperties
  94. * property (on iOS) or calling setAppProperties (on Android).
  95. *
  96. * @inheritdoc
  97. */
  98. componentDidUpdate(prevProps, prevState) {
  99. // Ignore the special state update triggered on {@code Root}
  100. // instantiation where an undefined url prop is set to a default.
  101. if (typeof prevState.url === 'undefined'
  102. && typeof this.state.url !== 'undefined') {
  103. return;
  104. }
  105. if (!equals(prevProps.url, this.props.url)) {
  106. // eslint-disable-next-line react/no-did-update-set-state
  107. this.setState({ url: this.props.url || null });
  108. }
  109. }
  110. /**
  111. * Implements React's {@link Component#render()}.
  112. *
  113. * @inheritdoc
  114. * @returns {ReactElement}
  115. */
  116. render() {
  117. const { url } = this.state;
  118. // XXX We don't render the App component until we get the initial URL.
  119. // Either it's null or some other non-null defined value.
  120. if (typeof url === 'undefined') {
  121. return null;
  122. }
  123. const {
  124. // The following props are forked in state:
  125. url: _, // eslint-disable-line no-unused-vars
  126. // The remaining props are passed through to App.
  127. ...props
  128. } = this.props;
  129. return (
  130. <App
  131. { ...props }
  132. url = { url } />
  133. );
  134. }
  135. }
  136. // Register the main/root Component of JitsiMeetView.
  137. AppRegistry.registerComponent('App', () => Root);
  138. // Register the main/root Component of IncomingCallView.
  139. AppRegistry.registerComponent('IncomingCallApp', () => IncomingCallApp);