No Description

index.android.js 6.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  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. const RCTAutoHeightWebView = requireNativeComponent('RCTAutoHeightWebView', AutoHeightWebView, { nativeOnly: { messagingEnabled: PropTypes.bool } });
  18. export default class AutoHeightWebView extends ImmutableComponent {
  19. constructor(props) {
  20. super(props);
  21. this.onMessage = this.onMessage.bind(this);
  22. if (IsBelowKitKat) {
  23. this.listenWebViewBridgeMessage = this.listenWebViewBridgeMessage.bind(this);
  24. }
  25. const initialScript = props.files ? this.appendFilesToHead(props.files, BaseScript) : BaseScript;
  26. this.state = {
  27. isChangingSource: false,
  28. height: 0,
  29. heightOffset: 0,
  30. script: initialScript
  31. };
  32. }
  33. componentWillMount() {
  34. if (IsBelowKitKat) {
  35. DeviceEventEmitter.addListener("webViewBridgeMessage", this.listenWebViewBridgeMessage);
  36. }
  37. }
  38. componentDidMount() {
  39. this.startInterval();
  40. }
  41. componentWillReceiveProps(nextProps) {
  42. // injectedJavaScript only works when webview reload (html changed)
  43. if (nextProps.html === this.props.html) {
  44. this.htmlHasChanged = false;
  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 source = this.props.enableBaseUrl ? {
  135. html: this.props.html,
  136. baseUrl: 'file:///android_asset/web/'
  137. } : { html: this.props.html };
  138. return (
  139. <View style={[{
  140. width: ScreenWidth,
  141. height: this.state.height + this.state.heightOffset
  142. }, this.props.style]}>
  143. {
  144. this.state.isChangingSource ? null :
  145. <RCTAutoHeightWebView
  146. ref={webview => this.webview = webview}
  147. style={{ flex: 1 }}
  148. javaScriptEnabled={true}
  149. injectedJavaScript={this.state.script + this.props.customScript}
  150. scrollEnabled={false}
  151. source={source}
  152. // below kitkat
  153. onChange={this.onMessage}
  154. onMessage={this.onMessage}
  155. messagingEnabled={true} />
  156. }
  157. </View>
  158. );
  159. }
  160. }
  161. AutoHeightWebView.propTypes = {
  162. ...WebView.propTypes,
  163. html: PropTypes.string,
  164. onHeightUpdated: PropTypes.func,
  165. customScript: PropTypes.string,
  166. // offset rn webview margin
  167. heightOffset: PropTypes.number,
  168. // baseUrl not work in android 4.3 or below version
  169. enableBaseUrl: PropTypes.bool,
  170. // works if set enableBaseUrl to true; add web/files... to android/app/src/assets/
  171. files: PropTypes.arrayOf(PropTypes.shape({
  172. href: PropTypes.string,
  173. type: PropTypes.string,
  174. rel: PropTypes.string
  175. }))
  176. }
  177. AutoHeightWebView.defaultProps = {
  178. enableBaseUrl: false,
  179. heightOffset: 20
  180. }
  181. const ScreenWidth = Dimensions.get('window').width;
  182. const IsBelowKitKat = Platform.Version < 19;
  183. const BaseScript =
  184. IsBelowKitKat ?
  185. `
  186. (function () {
  187. AutoHeightWebView.onMessage = function (message) {
  188. AutoHeightWebView.send(String(document.body.offsetHeight));
  189. };
  190. } ());
  191. ` :
  192. `
  193. ; (function () {
  194. document.addEventListener('message', function (e) {
  195. window.postMessage(String(document.body.offsetHeight));
  196. });
  197. } ());
  198. `;