当前位置: 移动技术网 > IT编程>开发语言>JavaScript > RN code push自定义弹框

RN code push自定义弹框

2018年10月15日  | 移动技术网IT编程  | 我要评论

最近在弄react native的code push热更新问题。开始是用的后台默默更新配置。由于微软服务器速度问题,经常遇到用户一直在下载中问题。而用户也不知道代码需要更新才能使用新功能,影响了正常业务流程。而目前公司也无力搭建自己的服务器和dns设置。所以比较快速的方案就是,前端自定义热更新弹框,在需要更新代码的情况下禁止用户向下操作。

ok,废话少说,直接上代码:

这是构建一个弹框,强制文案提示和非强制文案提示弹框。

/**
 * created by susie on 2018/9/20.
 */
import react, { component } from 'react';
import {view, text, stylesheet, modal, touchableopacity, image , dimensions , alert} from 'react-native'
import codepush from "react-native-code-push"
import progress from './cusprogressbar';
import color from '../../styles/theme';
import {showloadingimg,hideloadingimg,px2pt} from '../../utils/util';
import global from "../../constants/global";


let screen_width = dimensions.get('window').width;//宽
let screen_height = dimensions.get('window').height;//高

let codepushoptions = {
    checkfrequency : codepush.checkfrequency.on_app_start,
    installmode: codepush.installmode.immediate
}

 class codepushmodal extends component {

    constructor(props) {
        super(props)
        this.currprogress = 0.0
        this.syncmessage = ''
        this.state = {
            modalvisible: false, //是否有更新
            ismandatory: false, //是否为强制更新
            immediateupdate: false, //是否在更新中
            updateinfo: {}
        }
    }

    codepushstatusdidchange(syncstatus) {
        if (this.state.immediateupdate) {
            switch(syncstatus) {
                case codepush.syncstatus.checking_for_update:
                    this.syncmessage = 'checking for update'
                    break;
                case codepush.syncstatus.downloading_package:
                    this.syncmessage = 'downloading package'
                    break;
                case codepush.syncstatus.awaiting_user_action:
                    this.syncmessage = 'awaiting user action'
                    break;
                case codepush.syncstatus.installing_update:
                    this.syncmessage = 'installing update'
                    break;
                case codepush.syncstatus.up_to_date:
                    this.syncmessage = 'app up to date.'
                    break;
                case codepush.syncstatus.update_ignored:
                    this.syncmessage = 'update cancelled by user'
                    break;
                case codepush.syncstatus.update_installed:
                    this.syncmessage = 'update installed and will be applied on restart.'
                    break;
                case codepush.syncstatus.unknown_error:
                    this.syncmessage = 'an unknown error occurred'
                    //toast.showerror('更新出错,请重启应用!')
                    this.setstate({modalvisible: false})
                    codepush.allowrestart();
                    break;
            }
        }
    }

    codepushdownloaddidprogress(progress) {
        var self = this;
        if(self.state.immediateupdate){
            self.currprogress = parsefloat(progress.receivedbytes / progress.totalbytes).tofixed(2);
            if(self.currprogress >= 1) {
                self.setstate({modalvisible: false})
            } else if(self.refs.progressbar) {
                self.refs.progressbar.progress = self.currprogress;
                self.refs.progressbar.buffer = self.currprogress;
            }
        }
    }

     syncimmediate() {
        codepush.checkforupdate().then((update) => {
            global.ischeckcodepush = false;
            hideloadingimg();
            if (!update) {
                codepush.allowrestart();
            } else {
                this.setstate({modalvisible: true, updateinfo: update, ismandatory: update.ismandatory})
            }
        }).catch(function () {
            global.ischeckcodepush = false;
            codepush.allowrestart();
        })
    }

    componentwillmount() {
        global.ischeckcodepush = true;
        showloadingimg();
        codepush.disallowrestart()
        this.syncimmediate()
    }

    componentdidmount() {
        //codepush.allowrestart()
    }

    _immediateupdatenew() {
        this.setstate({immediateupdate: true});
        let self = this;
        var timer = settimeout(function () {
            codepush.sync(
                {
                    updatedialog: {},
                    installmode: codepush.installmode.immediate},
                self.codepushstatusdidchange.bind(self),
                self.codepushdownloaddidprogress.bind(self)
            )
            cleartimeout(timer);
            codepush.allowrestart();
        },10);
    }

    render() {
        return (
            <view style={styles.container}>
            <modal
                animationtype={"none"}
                transparent={true}
                onrequestclose={() => {}}
                visible={this.state.modalvisible}
            >
                <view style={styles.modal}>
                    <view style={styles.modalcontainer}>
                        {
                            !this.state.immediateupdate ?
                                <view>
                                    <view style={styles.modalcontent}>
                                        <view>
                                            <text style={styles.modaltitle}>页面升级</text>
                                        </view>
                                        <view style={styles.updatedes}>
                                            <text style={styles.updatedestext}>升级内容:</text>
                                            <text style={styles.updatedestext}>{this.state.updateinfo.description}</text>
                                        </view>
                                        <view style={styles.updatetip}>
                                            <text style={styles.updatetiptext}>本升级非app更新,wifi环境下30s内即可完成</text>
                                        </view>
                                        {
                                            !this.state.ismandatory ?
                                                <view style={styles.updatebtns}>
                                                    <touchableopacity
                                                        onpress={() => this.setstate({modalvisible: false})}>
                                                        <view style={[styles.btnright,styles.btnleft]}>
                                                            <text style={{fontsize: 16, color: '#989898'}}>残忍拒绝</text>
                                                        </view>
                                                    </touchableopacity>
                                                    <touchableopacity
                                                        style={styles.btnright}
                                                        onpress={() => this._immediateupdatenew()}
                                                    >
                                                        <view style={styles.btnrighttext}>
                                                            <text style={{fontsize: 16, color: color.theme}}>立即升级</text>
                                                        </view>
                                                    </touchableopacity>
                                                </view> :
                                                <view style={styles.updatebtns}>
                                                    <touchableopacity
                                                        style={[styles.btnright,styles.onlybtn]}
                                                        onpress={() => this._immediateupdatenew()}
                                                    >
                                                        <view style={[styles.btnrighttext,{marginhorizontal: 40}]}>
                                                            <text style={{fontsize: 16, color: color.theme, letterspacing:1}}>立即升级</text>
                                                        </view>
                                                    </touchableopacity>
                                                </view>
                                        }
                                    </view>
                                </view> : <view style={styles.modalcontent}>
                                        <view>
                                            <text style={styles.modaltitle}>页面升级中</text>
                                        </view>
                                        <view style={{ paddingvertical: 20, alignitems: 'center'}}>
                                            <progress
                                                ref="progressbar"
                                                progresscolor={'#89c0ff'}
                                                style={{
                                                    margintop: 20,
                                                    width: screen_width - 80,
                                                    marginleft:10,
                                                    marginright:10
                                                }}
                                            />
                                            <view style={styles.updatetip}>
                                                <text style={styles.updatetiptext}>本升级非app更新,wifi环境下30s内即可完成</text>
                                            </view>
                                        </view>
                                </view>

                        }
                    </view>
                </view>
            </modal>
            </view>
        );
    }
}
let modalw = screen_width - 40;
const styles = stylesheet.create({
    container: {
        flex: 1,
        justifycontent: 'center',
        alignitems: 'center'
    },
    modal: {
        height: screen_height,
        width: screen_width,
        alignitems: 'center',
        justifycontent: 'center',
        backgroundcolor: 'rgba(0,0,0,0.3)'
    },
    modalcontainer: {
        marginhorizontal: px2pt(120),
        borderbottomleftradius: px2pt(20),
        borderbottomrightradius: px2pt(20),
    },
    modalcontent:{
        backgroundcolor: '#fff',
        borderradius:5,
        width: modalw
    },
    modaltitle:{
        margintop:px2pt(70),
        fontsize:px2pt(36),
        color:color.gray3,
        textalign:'center',
        width:'100%'
    },
    modaltips:{
        fontsize:px2pt(28),
        color:color.darkorange,
        textalign:'center',
        marginbottom:px2pt(10)
    },
    updatedes:{
        marginleft:px2pt(40),
        marginright:px2pt(40),
        margintop:px2pt(30)
    },
    updatedestext:{
        fontsize:px2pt(32),
        color: color.gray6,
        lineheight:px2pt(44)
    },
    updatetip:{
        alignitems: 'center',
        margintop: px2pt(40)
    },
    updatetiptext:{
        fontsize: px2pt(28),
        color: color.gray6
    },
    updatebtns:{
        flexdirection: 'row',
        height: px2pt(100),
        alignitems: 'center',
        margintop: px2pt(40),
        bordertopcolor: '#e6e6e6',
        bordertopwidth: 1
    },
    btnleft:{
        borderrightcolor: '#e6e6e6',
        borderrightwidth: 1
    },
    btnright:{
        flexdirection: 'row',
        alignitems: 'center',
        width: modalw / 2,
        height:px2pt(100),
        justifycontent: 'center'
    },
    btnrighttext:{
        flex: 1,
        height:px2pt(80),
        alignitems: 'center',
        justifycontent: 'center'
    },
    onlybtn:{
        width: modalw
    }
})

export default codepush(codepushoptions)(codepushmodal)

  其中,注意installmode 的设置问题,在初始化codepush参数时,就要设置。否则在非强制更新下会出现 不立即刷新的问题。

然后是进度条展示处理:

/**
 * created by susie on 2018/9/20.
 */
import react, {component}from 'react'
import {view, stylesheet, animated, easing,text}from 'react-native'
import lineargradient from 'react-native-linear-gradient'

import proptypes from 'prop-types'

export default class cusprogressbar extends component {

    static proptypes = {
        ...view.proptypes,
        // 当前进度
        progress: proptypes.number,
        // second progress进度
        buffer: proptypes.number,
        // 进度条颜色
        progresscolor: proptypes.string,
        // 进度动画时长
        progressaniduration: proptypes.number,
        // buffer动画时长
        bufferaniduration: proptypes.number
    }

    static defaultprops = {
        // 进度条颜色
        progresscolor: 'white',
        // 进度条动画时长
        progressaniduration: 100,
        // buffer进度条动画时长
        bufferaniduration: 100
    }

    constructor(props) {
        super(props)
        this._progressani = new animated.value(0)
        this._bufferani = new animated.value(0)
    }

    componentwillreceiveprops(nextprops) {
        this._progress = nextprops.progress
        this._buffer = nextprops.buffer
    }

    componentwillmount() {
        this._progress = this.props.progress
        this._buffer = this.props.buffer
    }

    render() {
        return (
            <view
                style={[styles.container,this.props.style]}
                onlayout={this._onlayout.bind(this)}>
                <lineargradient colors={['#daddff', '#d3eeff']} start={{ x: 0, y: 0 }} end={{ x: 1, y: 0 }} style={{position:'absolute',borderradius:10,width:'100%',height:'100%'}}></lineargradient>
                <animated.view
                    ref="progress"
                    style={{
                        position:'absolute',
                        width: this._progressani,
                        borderradius:10
                    }}>
                    <lineargradient colors={['#4669ff', '#3eefff']} start={{ x: 0, y: 0 }} end={{ x: 1, y: 0 }} style={{borderradius:10,width:'100%',height:'100%'}}></lineargradient>
                </animated.view>
                <animated.image
                    ref="buffer"
                    style={{
                        position:'absolute',
                        left: this._bufferani,
                        marginleft:0,
                        top : -3,
                        width:35
                    }}  source={require('../../styles/images/huojian.png')}  />
            </view>
        )
    }

    _onlayout({nativeevent: {layout:{width, height}}}) {
        // 防止多次调用,当第一次获取后,后面就不再去获取了
        if (width > 0 && this.totalwidth !== width) {
            // 获取progress控件引用
            let progress = this._getprogress()
            // 获取buffer控件引用
            let buffer = this._getbuffer()
            // 获取父布局宽度
            this.totalwidth = width
            //给progress控件设置高度
            progress.setnativeprops({
                style: {
                    height: height
                }
            })

            // 给buffer控件设置高度
            buffer.setnativeprops({
                style: {
                    height: height+6
                }
            })
        }
    }

    _startaniprogress(progress) {
        if (this._progress >= 0 && this.totalwidth !== 0) {
            animated.timing(this._progressani, {
                tovalue: progress * this.totalwidth,
                duration: this.props.progressaniduration,
                easing: easing.linear
            }).start()
        }
    }

    _startanibuffer(buffer) {
        if (this._buffer >= 0 && this.totalwidth !== 0) {
            animated.timing(this._bufferani, {
                tovalue: buffer * this.totalwidth,
                duration: this.props.bufferaniduration,
            }).start()
        }
    }

    _getprogress() {
        if (typeof this.refs.progress.refs.node !== 'undefined') {
            return this.refs.progress.refs.node
        }
        return this.refs.progress._component
    }

    _getbuffer() {
        if (typeof this.refs.buffer.refs.node !== 'undefined') {
            return this.refs.buffer.refs.node;
        }
        return this.refs.buffer._component;
    }
}

object.defineproperty(cusprogressbar.prototype, 'progress', {
    set(value){
        if (value >= 0 && this._progress !== value) {
            this._progress = value;
            this._startaniprogress(value);
        }
    },
    get() {
        return this._progress;
    },
    enumerable: true,
})

object.defineproperty(cusprogressbar.prototype, 'buffer', {
    set(value){
        if (value >= 0 && this._buffer !== value) {
            this._buffer = value;
            this._startanibuffer(value);
        }
    },
    get() {
        return this._buffer;
    },
    enumerable: true,
})

const styles = stylesheet.create({
    container: {
        height: 12
    }
})

 以上就完成了自定义 code push弹框的自定义展示。

 

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网