Nav apraksta

index.android.js 6.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. 'use strict'
  2. import React, {
  3. Component,
  4. PropTypes
  5. } from 'react';
  6. import {
  7. findNodeHandle,
  8. requireNativeComponent,
  9. DeviceEventEmitter,
  10. Dimensions,
  11. Platform,
  12. UIManager,
  13. View,
  14. WebView
  15. } from 'react-native';
  16. import ImmutableComponent from 'react-immutable-component';
  17. import Immutable from 'immutable';
  18. const RCTAutoHeightWebView = requireNativeComponent('RCTAutoHeightWebView', AutoHeightWebView, { nativeOnly: { messagingEnabled: PropTypes.bool } });
  19. export default class AutoHeightWebView extends ImmutableComponent {
  20. constructor(props) {
  21. super(props);
  22. this.onMessage = this.onMessage.bind(this);
  23. if (IsBelowKitKat) {
  24. this.listenWebViewBridgeMessage = this.listenWebViewBridgeMessage.bind(this);
  25. }
  26. const initialScript = props.files ? this.appendFilesToHead(props.files, BaseScript) : BaseScript;
  27. this.state = {
  28. isChangingSource: false,
  29. height: 0,
  30. heightOffset: 0,
  31. script: initialScript
  32. };
  33. }
  34. componentWillMount() {
  35. if (IsBelowKitKat) {
  36. DeviceEventEmitter.addListener("webViewBridgeMessage", this.listenWebViewBridgeMessage);
  37. }
  38. }
  39. componentDidMount() {
  40. this.startInterval();
  41. }
  42. componentWillReceiveProps(nextProps) {
  43. // injectedJavaScript only works when webview reload (source changed)
  44. if (Immutable.is(Immutable.fromJS(this.props.source), Immutable.fromJS(nextProps.source))) {
  45. return;
  46. }
  47. else {
  48. this.setState({
  49. isChangingSource: true,
  50. height: 0,
  51. heightOffset: 0
  52. });
  53. }
  54. let currentScript = BaseScript;
  55. if (nextProps.files) {
  56. currentScript = this.appendFilesToHead(nextProps.files, BaseScript);
  57. }
  58. this.setState({ script: currentScript });
  59. }
  60. componentDidUpdate(prevProps, prevState) {
  61. // redisplay webview when changing source
  62. if (this.state.isChangingSource) {
  63. this.startInterval();
  64. this.setState({ isChangingSource: false });
  65. }
  66. }
  67. componentWillUnmount() {
  68. this.stopInterval();
  69. if (IsBelowKitKat) {
  70. DeviceEventEmitter.removeListener("webViewBridgeMessage", this.listenWebViewBridgeMessage);
  71. }
  72. }
  73. // below kitkat
  74. listenWebViewBridgeMessage(body) {
  75. this.onMessage(body.message);
  76. }
  77. postMessage(data) {
  78. UIManager.dispatchViewManagerCommand(
  79. findNodeHandle(this.webview),
  80. UIManager.RCTAutoHeightWebView.Commands.postMessage,
  81. [String(data)]
  82. );
  83. };
  84. // below kitkat
  85. sendToWebView(message) {
  86. UIManager.dispatchViewManagerCommand(
  87. findNodeHandle(this.webview),
  88. UIManager.RCTAutoHeightWebView.Commands.sendToWebView,
  89. [String(message)]
  90. );
  91. }
  92. startInterval() {
  93. this.finishInterval = false;
  94. this.interval = setInterval(() => {
  95. if (!this.finishInterval) {
  96. IsBelowKitKat ? this.sendToWebView('getBodyHeight') : this.postMessage('getBodyHeight');
  97. }
  98. }, 205);
  99. }
  100. stopInterval() {
  101. this.finishInterval = true;
  102. clearInterval(this.interval);
  103. }
  104. onMessage(e) {
  105. const height = parseInt(IsBelowKitKat ? e.nativeEvent.message : e.nativeEvent.data);
  106. if (height) {
  107. this.stopInterval();
  108. this.setState({
  109. heightOffset: this.props.heightOffset,
  110. height
  111. });
  112. if (this.props.onHeightUpdated) {
  113. this.props.onHeightUpdated(height);
  114. }
  115. }
  116. }
  117. appendFilesToHead(files, script) {
  118. if (!files) {
  119. return script;
  120. }
  121. for (let file of files) {
  122. script =
  123. `
  124. var link = document.createElement('link');
  125. link.rel = '` + file.rel + `';
  126. link.type = '` + file.type + `';
  127. link.href = '` + file.href + `';
  128. document.head.appendChild(link);
  129. `+ script;
  130. }
  131. return script;
  132. }
  133. render() {
  134. const { height, script, isChangingSource } = this.state;
  135. const { source, heightOffset, customScript, style, enableBaseUrl } = this.props;
  136. let webViewSource = source;
  137. if (enableBaseUrl) {
  138. webViewSource = Object.assign({}, source, { baseUrl: 'file:///android_asset/web/' });
  139. }
  140. return (
  141. <View style={[{
  142. width: ScreenWidth,
  143. height: height + heightOffset,
  144. backgroundColor: 'transparent'
  145. }, style]}>
  146. {
  147. isChangingSource ? null :
  148. <RCTAutoHeightWebView
  149. ref={webview => this.webview = webview}
  150. style={{
  151. flex: 1,
  152. backgroundColor: 'transparent'
  153. }}
  154. javaScriptEnabled={true}
  155. injectedJavaScript={script + customScript}
  156. scrollEnabled={false}
  157. source={webViewSource}
  158. // below kitkat
  159. onChange={this.onMessage}
  160. onMessage={this.onMessage}
  161. messagingEnabled={true} />
  162. }
  163. </View>
  164. );
  165. }
  166. }
  167. AutoHeightWebView.propTypes = {
  168. source: WebView.propTypes.source,
  169. onHeightUpdated: PropTypes.func,
  170. customScript: PropTypes.string,
  171. // offset rn webview margin
  172. heightOffset: PropTypes.number,
  173. // baseUrl not work in android 4.3 or below version
  174. enableBaseUrl: PropTypes.bool,
  175. style: View.propTypes.style,
  176. // works if set enableBaseUrl to true; add web/files... to android/app/src/assets/
  177. files: PropTypes.arrayOf(PropTypes.shape({
  178. href: PropTypes.string,
  179. type: PropTypes.string,
  180. rel: PropTypes.string
  181. }))
  182. }
  183. AutoHeightWebView.defaultProps = {
  184. enableBaseUrl: false,
  185. heightOffset: 20
  186. }
  187. const ScreenWidth = Dimensions.get('window').width;
  188. const IsBelowKitKat = Platform.Version < 19;
  189. const BaseScript =
  190. IsBelowKitKat ?
  191. `
  192. ; (function () {
  193. AutoHeightWebView.onMessage = function (message) {
  194. AutoHeightWebView.send(String(document.body.offsetHeight));
  195. };
  196. } ());
  197. ` :
  198. `
  199. ; (function () {
  200. document.addEventListener('message', function (e) {
  201. window.postMessage(String(document.body.offsetHeight));
  202. });
  203. } ());
  204. `;