RN code push自定义弹框
最近在弄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弹框的自定义展示。
RN code push自定义弹框的更多相关文章
- vue3系列:vue3.0自定义弹框组件V3Popup|vue3.x手机端弹框组件
基于Vue3.0开发的轻量级手机端弹框组件V3Popup. 之前有分享一个vue2.x移动端弹框组件,今天给大家带来的是Vue3实现自定义弹框组件. V3Popup 基于vue3.x实现的移动端弹出框 ...
- vue自定义弹框
vue 全局自定义简单弹框 https://www.jianshu.com/p/1307329aa09e https://www.cnblogs.com/crazycode2/p/7907905.ht ...
- html自定义弹框
一.要实现的功能 1.弹框弹出时有遮罩 2.弹框内的文字过多时右侧有滚动条 3.根据执行结果变更弹框title的样式 二.具体实现 思路:定义一个有宽高的div,默认隐藏,当要显示时,设置为dis ...
- swift 自定义弹框
// // ViewController.swift // animationAlert // // Created by su on 15/12/9. // Copyright © 2015 ...
- artDialog自定义弹框
弹框内容:<div class='boxy' style="display:none;" id="boxy"> //将div设置成隐藏效果 < ...
- android之自定义弹框
step1 创建窗体 final AlertDialog dialog =new Builder(this).create(); step2 获取View View viewDialog =View. ...
- svelte组件:Svelte自定义弹窗Popup组件|svelte移动端弹框组件
基于Svelte3.x自定义多功能svPopup弹出框组件(组件式+函数式) 前几天有分享一个svelte自定义tabbar+navbar组件,今天继续带来svelte自定义弹窗组件. svPopup ...
- layer弹框在实际项目中的一些应用
官方介绍:layer至今仍作为layui的代表作,受众广泛并非偶然,而是这五年多的坚持,不断完善和维护.不断建设和提升社区服务,使得猿们纷纷自发传播,乃至于成为今天的Layui最强劲的源动力.目前,l ...
- 考拉Android统一弹框
作者:钱成杰 背景 在快速开发的背景下,经历了n个版本后的考拉Android App中已经存在了各种各样看似相同却各有差别的弹框样式.其中包括系统弹框和自定义弹框,并且在线上时常会出现IllegalA ...
随机推荐
- bzoj 4247: 挂饰【dp】
bzoj上访问负下标会跑到奇怪的地方-- 其实可以滚动数组优化,但是我看能过就懒得改了 设f[i][j]为已经算了前i个挂饰,当前有j个空的钩子,转移就是f[i][j]=max(f[i-1][j],f ...
- [App Store Connect帮助]八、维护您的 App(1)App 维护概述
您在 App Store 上发行 App 后,需要执行一些任务来回复顾客反馈并在整个产品周期内维护您的 App.您可以按任何顺序执行这些任务. 监控顾客评论.销售情况和分析 您可以在 App 页面的“ ...
- 【react native】有关入坑3个月RN的心路历程
由于一些原因,笔者最近变更到了RN的团队,回归到了hybrid app的开发的圈子中,固然是有蛮多新鲜感和新机遇的,不过遥想起以前在hybrid中各种view之前跳转的头疼等各种问题,笔者怀着忐忑的心 ...
- Race to 1 Again LightOJ - 1038
Race to 1 Again LightOJ - 1038 题意:有一个数字D,每次把D变为它的一个因数(变到所有因数的概率相等,可能是本身),变到1后停止.求对于某个初始的D变到1的期望步数. x ...
- 题解报告:poj 2559 Largest Rectangle in a Histogram(单调栈)
Description A histogram is a polygon composed of a sequence of rectangles aligned at a common base l ...
- OAuth 开放授权 Open Authorization
http://oauth.net/ http://tools.ietf.org/html/rfc6749 http://reg.163.com/help/help_oauth2.html 网易通行证O ...
- java封装的优点
在面向对象程式设计方法中,封装(英语:Encapsulation)是指一种将抽象性函式接口的实现细节部份包装.隐藏起来的方法. 封装可以被认为是一个保护屏障,防止该类的代码和数据被外部类定义的代码随机 ...
- Linux 之 2>&1
我们在Linux下经常会碰到nohup command>/dev/null 2>&1 &这样形式的命令.首先我们把这条命令大概分解下首先就是一个nohup表示当前用户和系统 ...
- js实现表单checkbox的单选,全选
全选&单选 //<input type="checkbox" name="" class="quan" value=" ...
- npm run dev报错--Error: Cannot find module 'yargs-parser'
Error: Cannot find module 'yargs-parser' ---报错不知何解??? 百度了很久没找到方法,是缺少“ yargs-parser ”模块,需要安装一下即可:cnp ...