React本机自动高度WebView不';我不能在安卓上工作

React本机自动高度WebView不';我不能在安卓上工作,webview,android-webview,react-native,Webview,Android Webview,React Native,我正在实现一个动态高度的WebView。我发现这个解决方案在iOS上很有魅力,但在android上却不起作用。该解决方案在WV中使用JS将标题设置为内容高度的值。代码如下: ... this.state = {webViewHeight: 0}; ... <WebView source={{html: this.wrapWevViewHtml(this.state.content)}} style={{width: Dimensions.get('window').widt

我正在实现一个动态高度的WebView。我发现这个解决方案在iOS上很有魅力,但在android上却不起作用。该解决方案在WV中使用JS将标题设置为内容高度的值。代码如下:

...
this.state = {webViewHeight: 0};
...
<WebView
    source={{html: this.wrapWevViewHtml(this.state.content)}}
    style={{width: Dimensions.get('window').width - 20, height: this.state.webViewHeight}}
    scrollEnabled={false}
    javaScriptEnabled={true}
    injectedJavaScript="window.location.hash = 1;document.title = document.height;"
    onNavigationStateChange={this.onWebViewNavigationStateChange.bind(this)}
/>
...
onWebViewNavigationStateChange(navState) {
    // navState.title == height on iOS and html content on android
    if (navState.title) {
        this.setState({
            webViewHeight: Number(navState.title)
        });
    }
}
...
。。。
this.state={webViewHeight:0};
...
...
onWebViewNavigationStateChange(导航状态){
//navState.title==iOS上的高度和android上的html内容
if(导航状态标题){
这是我的国家({
webViewHeight:编号(navState.title)
});
}
}
...
但是在android上,WebViewNavigationStateChange中的标题值等于页面内容


我做错了什么?

我也被这件事弄糊涂了。它实际上可以工作,但很难调试为什么不能工作,因为Android上的React原生WebView没有启用Chrome远程调试

我对此有两个问题:

  • 我注入Webview的脚本包含了一些单行注释,在Android上所有的换行符都被删除了(另一个bug?)。它导致WebView中出现语法错误

  • 第一次调用时,标题内容实际上是Webview的全部内容。不知道为什么,但在后面的电话中,是高度。那就处理这个案子吧

  • 下面是我现在使用的代码,它在Android和iOS上运行于React Native 0.22

    import React, {WebView, View, Text} from "react-native";
    
    
    const BODY_TAG_PATTERN = /\<\/ *body\>/;
    
    // Do not add any comments to this! It will break line breaks will removed for
    // some weird reason.
    var script = `
    ;(function() {
    var wrapper = document.createElement("div");
    wrapper.id = "height-wrapper";
    while (document.body.firstChild) {
        wrapper.appendChild(document.body.firstChild);
    }
    
    document.body.appendChild(wrapper);
    
    var i = 0;
    function updateHeight() {
        document.title = wrapper.clientHeight;
        window.location.hash = ++i;
    }
    updateHeight();
    
    window.addEventListener("load", function() {
        updateHeight();
        setTimeout(updateHeight, 1000);
    });
    
    window.addEventListener("resize", updateHeight);
    }());
    `;
    
    
    const style = `
    <style>
    body, html, #height-wrapper {
        margin: 0;
        padding: 0;
    }
    #height-wrapper {
        position: absolute;
        top: 0;
        left: 0;
        right: 0;
    }
    </style>
    <script>
    ${script}
    </script>
    `;
    
    const codeInject = (html) => html.replace(BODY_TAG_PATTERN, style + "</body>");
    
    
    /**
     * Wrapped Webview which automatically sets the height according to the
     * content. Scrolling is always disabled. Required when the Webview is embedded
     * into a ScrollView with other components.
     *
     * Inspired by this SO answer http://stackoverflow.com/a/33012545
     * */
    var WebViewAutoHeight = React.createClass({
    
        propTypes: {
            source: React.PropTypes.object.isRequired,
            injectedJavaScript: React.PropTypes.string,
            minHeight: React.PropTypes.number,
            onNavigationStateChange: React.PropTypes.func,
            style: WebView.propTypes.style,
        },
    
        getDefaultProps() {
            return {minHeight: 100};
        },
    
        getInitialState() {
            return {
                realContentHeight: this.props.minHeight,
            };
        },
    
        handleNavigationChange(navState) {
            if (navState.title) {
                const realContentHeight = parseInt(navState.title, 10) || 0; // turn NaN to 0
                this.setState({realContentHeight});
            }
            if (typeof this.props.onNavigationStateChange === "function") {
                this.props.onNavigationStateChange(navState);
            }
        },
    
        render() {
            const {source, style, minHeight, ...otherProps} = this.props;
            const html = source.html;
    
            if (!html) {
                throw new Error("WebViewAutoHeight supports only source.html");
            }
    
            if (!BODY_TAG_PATTERN.test(html)) {
                throw new Error("Cannot find </body> from: " + html);
            }
    
            return (
                <View>
                    <WebView
                        {...otherProps}
                        source={{html: codeInject(html)}}
                        scrollEnabled={false}
                        style={[style, {height: Math.max(this.state.realContentHeight, minHeight)}]}
                        javaScriptEnabled
                        onNavigationStateChange={this.handleNavigationChange}
                    />
                    {process.env.NODE_ENV !== "production" &&
                    <Text>Web content height: {this.state.realContentHeight}</Text>}
                </View>
            );
        },
    
    });
    
    
    export default WebViewAutoHeight;
    
    import React,{WebView,View,Text}来自“React native”;
    const BODY_TAG_PATTERN=/\/;
    //不要对此添加任何评论!它将断开换行符将被删除
    //一些奇怪的原因。
    变量脚本=`
    ;(功能(){
    var wrapper=document.createElement(“div”);
    wrapper.id=“高度包装”;
    while(document.body.firstChild){
    appendChild(document.body.firstChild);
    }
    document.body.appendChild(包装器);
    var i=0;
    函数updateHeight(){
    document.title=wrapper.clientHeight;
    window.location.hash=++i;
    }
    updateHeight();
    addEventListener(“加载”,函数(){
    updateHeight();
    setTimeout(updateHeight,1000);
    });
    addEventListener(“调整大小”,更新高度);
    }());
    `;
    常量样式=`
    正文,html,#高度包装{
    保证金:0;
    填充:0;
    }
    #高度包装{
    位置:绝对位置;
    排名:0;
    左:0;
    右:0;
    }
    ${script}
    `;
    constcodeinject=(html)=>html.replace(BODY_-TAG_-PATTERN,style+);
    /**
    *Wrapped Webview,可根据
    *内容。滚动始终处于禁用状态。嵌入Webview时需要
    *与其他组件一起进入滚动视图。
    *
    *受到这个答案的启发http://stackoverflow.com/a/33012545
    * */
    var WebViewAutoHeight=React.createClass({
    道具类型:{
    来源:React.PropTypes.object.isRequired,
    injectedJavaScript:React.PropTypes.string,
    最小高度:React.PropTypes.number,
    onNavigationStateChange:React.PropTypes.func,
    样式:WebView.propTypes.style,
    },
    getDefaultProps(){
    返回{minHeight:100};
    },
    getInitialState(){
    返回{
    realContentHeight:this.props.minHeight,
    };
    },
    handleNavigationChange(导航状态){
    if(导航状态标题){
    const realContentHeight=parseInt(navState.title,10)| | 0;//将NaN变为0
    this.setState({realContentHeight});
    }
    if(this.props.onNavigationStateChange==“函数”的类型){
    this.props.onNavigationStateChange(navState);
    }
    },
    render(){
    const{source,style,minHeight,…otherProps}=this.props;
    const html=source.html;
    如果(!html){
    抛出新错误(“WebViewAutoHeight仅支持source.html”);
    }
    如果(!BODY_TAG_PATTERN.test(html)){
    抛出新错误(“无法从“+html”中找到);
    }
    返回(
    {process.env.NODE_env!==“生产”&&
    Web内容高度:{this.state.realContentHeight}
    );
    },
    });
    导出默认WebViewAutoHeight;
    

    正如gist所示,在设备上加载本地HTML文件并注入JS是我在Android中找到的唯一正确设置标题/哈希的方法

    /app/src/main/assets/blank.html

    <!doctype html>
    <html>
    <head>
    <title id="title">Go Web!</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <style>
    </style>
    </head>
    <body>
    <div id="content"></div>
    <script>
    var content = document.getElementById('content');
    
    var fireEvent = function(event, data) {
      document.title = data;
      window.location.hash = event;
    };
    
    var setContent = function(html) {
      content.innerHTML = html;
    };
    </script>
    </body>
    </html>
    
    
    上网!
    var content=document.getElementById('content');
    var firevent=函数(事件、数据){
    document.title=数据;
    window.location.hash=事件;
    };
    var setContent=函数(html){
    content.innerHTML=html;
    };
    
    以及组件

    class ResizingWebView extends Component {
      constructor(props) {
        super(props)
    
        this.state = {
          height: 0
        }
      }
      onNavigationStateChange(navState) {
        var event = navState.url.split('#')[1]
        var data = navState.title
    
        console.log(event, data)
        if (event == 'resize') {
          this.setState({ height: data })
        }
      }
      render() {
        var scripts = "setContent('<h1>Yay!</h1>');fireEvent('resize', '300')";
        return (
          <WebView
            source={{ uri: 'file:///android_asset/blank.html' }}
            injectedJavaScript={ scripts }
            scalesPageToFit={ false }
            style={{ height: this.state.height }}
            onNavigationStateChange={ this.onNavigationStateChange.bind(this) }
          />
        )
      }
    }
    
    类大小调整WebView扩展组件{
    建造师(道具){
    超级(道具)
    此.state={
    身高:0
    }
    }
    onNavigationStateChange(导航状态){
    var event=navState.url.split(“#”)[1]
    var data=navState.title
    console.log(事件、数据)
    如果(事件==“调整大小”){
    this.setState({height:data})
    }
    }
    render(){
    var scripts=“setContent('Yay!');firevent('resize','300');
    返回(
    )
    }
    }
    
    如果你想知道为什么你的代码不能在Android上运行,我会用下面的评论: