经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » JSJS库框架 » JavaScript » 查看文章
RN code push自定义弹框
来源:cnblogs  作者:susieWang  时间:2018/10/16 9:29:28  对本文有异议

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

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

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

  1. /**
  2. * Created by susie on 2018/9/20.
  3. */
  4. import React, { Component } from 'react';
  5. import {View, Text, StyleSheet, Modal, TouchableOpacity, Image , Dimensions , Alert} from 'react-native'
  6. import CodePush from "react-native-code-push"
  7. import Progress from './CusProgressBar';
  8. import color from '../../styles/theme';
  9. import {showLoadingImg,hideLoadingImg,px2pt} from '../../utils/util';
  10. import Global from "../../constants/global";
  11.  
  12.  
  13. let SCREEN_WIDTH = Dimensions.get('window').width;//宽
  14. let SCREEN_HEIGHT = Dimensions.get('window').height;//高
  15.  
  16. let codePushOptions = {
  17. checkFrequency : CodePush.CheckFrequency.ON_APP_START,
  18. installMode: CodePush.InstallMode.IMMEDIATE
  19. }
  20.  
  21. class CodePushModal extends Component {
  22.  
  23. constructor(props) {
  24. super(props)
  25. this.currProgress = 0.0
  26. this.syncMessage = ''
  27. this.state = {
  28. modalVisible: false, //是否有更新
  29. isMandatory: false, //是否为强制更新
  30. immediateUpdate: false, //是否在更新中
  31. updateInfo: {}
  32. }
  33. }
  34.  
  35. codePushStatusDidChange(syncStatus) {
  36. if (this.state.immediateUpdate) {
  37. switch(syncStatus) {
  38. case CodePush.SyncStatus.CHECKING_FOR_UPDATE:
  39. this.syncMessage = 'Checking for update'
  40. break;
  41. case CodePush.SyncStatus.DOWNLOADING_PACKAGE:
  42. this.syncMessage = 'Downloading package'
  43. break;
  44. case CodePush.SyncStatus.AWAITING_USER_ACTION:
  45. this.syncMessage = 'Awaiting user action'
  46. break;
  47. case CodePush.SyncStatus.INSTALLING_UPDATE:
  48. this.syncMessage = 'Installing update'
  49. break;
  50. case CodePush.SyncStatus.UP_TO_DATE:
  51. this.syncMessage = 'App up to date.'
  52. break;
  53. case CodePush.SyncStatus.UPDATE_IGNORED:
  54. this.syncMessage = 'Update cancelled by user'
  55. break;
  56. case CodePush.SyncStatus.UPDATE_INSTALLED:
  57. this.syncMessage = 'Update installed and will be applied on restart.'
  58. break;
  59. case CodePush.SyncStatus.UNKNOWN_ERROR:
  60. this.syncMessage = 'An unknown error occurred'
  61. //Toast.showError('更新出错,请重启应用!')
  62. this.setState({modalVisible: false})
  63. CodePush.allowRestart();
  64. break;
  65. }
  66. }
  67. }
  68.  
  69. codePushDownloadDidProgress(progress) {
  70. var self = this;
  71. if(self.state.immediateUpdate){
  72. self.currProgress = parseFloat(progress.receivedBytes / progress.totalBytes).toFixed(2);
  73. if(self.currProgress >= 1) {
  74. self.setState({modalVisible: false})
  75. } else if(self.refs.progressBar) {
  76. self.refs.progressBar.progress = self.currProgress;
  77. self.refs.progressBar.buffer = self.currProgress;
  78. }
  79. }
  80. }
  81.  
  82. syncImmediate() {
  83. CodePush.checkForUpdate().then((update) => {
  84. Global.isCheckCodePush = false;
  85. hideLoadingImg();
  86. if (!update) {
  87. CodePush.allowRestart();
  88. } else {
  89. this.setState({modalVisible: true, updateInfo: update, isMandatory: update.isMandatory})
  90. }
  91. }).catch(function () {
  92. Global.isCheckCodePush = false;
  93. CodePush.allowRestart();
  94. })
  95. }
  96.  
  97. componentWillMount() {
  98. Global.isCheckCodePush = true;
  99. showLoadingImg();
  100. CodePush.disallowRestart()
  101. this.syncImmediate()
  102. }
  103.  
  104. componentDidMount() {
  105. //CodePush.allowRestart()
  106. }
  107.  
  108. _immediateUpdateNew() {
  109. this.setState({immediateUpdate: true});
  110. let self = this;
  111. var timer = setTimeout(function () {
  112. CodePush.sync(
  113. {
  114. updateDialog: {},
  115. installMode: CodePush.InstallMode.IMMEDIATE},
  116. self.codePushStatusDidChange.bind(self),
  117. self.codePushDownloadDidProgress.bind(self)
  118. )
  119. clearTimeout(timer);
  120. CodePush.allowRestart();
  121. },10);
  122. }
  123.  
  124. render() {
  125. return (
  126. <View style={styles.container}>
  127. <Modal
  128. animationType={"none"}
  129. transparent={true}
  130. onRequestClose={() => {}}
  131. visible={this.state.modalVisible}
  132. >
  133. <View style={styles.modal}>
  134. <View style={styles.modalContainer}>
  135. {
  136. !this.state.immediateUpdate ?
  137. <View>
  138. <View style={styles.modalContent}>
  139. <View>
  140. <Text style={styles.modalTitle}>页面升级</Text>
  141. </View>
  142. <View style={styles.updateDes}>
  143. <Text style={styles.updateDesText}>升级内容:</Text>
  144. <Text style={styles.updateDesText}>{this.state.updateInfo.description}</Text>
  145. </View>
  146. <View style={styles.updateTip}>
  147. <Text style={styles.updateTipText}>本升级非APP更新,wifi环境下30s内即可完成</Text>
  148. </View>
  149. {
  150. !this.state.isMandatory ?
  151. <View style={styles.updateBtns}>
  152. <TouchableOpacity
  153. onPress={() => this.setState({modalVisible: false})}>
  154. <View style={[styles.btnRight,styles.btnLeft]}>
  155. <Text style={{fontSize: 16, color: '#989898'}}>残忍拒绝</Text>
  156. </View>
  157. </TouchableOpacity>
  158. <TouchableOpacity
  159. style={styles.btnRight}
  160. onPress={() => this._immediateUpdateNew()}
  161. >
  162. <View style={styles.btnRightText}>
  163. <Text style={{fontSize: 16, color: color.theme}}>立即升级</Text>
  164. </View>
  165. </TouchableOpacity>
  166. </View> :
  167. <View style={styles.updateBtns}>
  168. <TouchableOpacity
  169. style={[styles.btnRight,styles.onlyBtn]}
  170. onPress={() => this._immediateUpdateNew()}
  171. >
  172. <View style={[styles.btnRightText,{marginHorizontal: 40}]}>
  173. <Text style={{fontSize: 16, color: color.theme, letterSpacing:1}}>立即升级</Text>
  174. </View>
  175. </TouchableOpacity>
  176. </View>
  177. }
  178. </View>
  179. </View> : <View style={styles.modalContent}>
  180. <View>
  181. <Text style={styles.modalTitle}>页面升级中</Text>
  182. </View>
  183. <View style={{ paddingVertical: 20, alignItems: 'center'}}>
  184. <Progress
  185. ref="progressBar"
  186. progressColor={'#89C0FF'}
  187. style={{
  188. marginTop: 20,
  189. width: SCREEN_WIDTH - 80,
  190. marginLeft:10,
  191. marginRight:10
  192. }}
  193. />
  194. <View style={styles.updateTip}>
  195. <Text style={styles.updateTipText}>本升级非APP更新,wifi环境下30s内即可完成</Text>
  196. </View>
  197. </View>
  198. </View>
  199.  
  200. }
  201. </View>
  202. </View>
  203. </Modal>
  204. </View>
  205. );
  206. }
  207. }
  208. let modalW = SCREEN_WIDTH - 40;
  209. const styles = StyleSheet.create({
  210. container: {
  211. flex: 1,
  212. justifyContent: 'center',
  213. alignItems: 'center'
  214. },
  215. modal: {
  216. height: SCREEN_HEIGHT,
  217. width: SCREEN_WIDTH,
  218. alignItems: 'center',
  219. justifyContent: 'center',
  220. backgroundColor: 'rgba(0,0,0,0.3)'
  221. },
  222. modalContainer: {
  223. marginHorizontal: px2pt(120),
  224. borderBottomLeftRadius: px2pt(20),
  225. borderBottomRightRadius: px2pt(20),
  226. },
  227. modalContent:{
  228. backgroundColor: '#FFF',
  229. borderRadius:5,
  230. width: modalW
  231. },
  232. modalTitle:{
  233. marginTop:px2pt(70),
  234. fontSize:px2pt(36),
  235. color:color.gray3,
  236. textAlign:'center',
  237. width:'100%'
  238. },
  239. modalTips:{
  240. fontSize:px2pt(28),
  241. color:color.darkOrange,
  242. textAlign:'center',
  243. marginBottom:px2pt(10)
  244. },
  245. updateDes:{
  246. marginLeft:px2pt(40),
  247. marginRight:px2pt(40),
  248. marginTop:px2pt(30)
  249. },
  250. updateDesText:{
  251. fontSize:px2pt(32),
  252. color: color.gray6,
  253. lineHeight:px2pt(44)
  254. },
  255. updateTip:{
  256. alignItems: 'center',
  257. marginTop: px2pt(40)
  258. },
  259. updateTipText:{
  260. fontSize: px2pt(28),
  261. color: color.gray6
  262. },
  263. updateBtns:{
  264. flexDirection: 'row',
  265. height: px2pt(100),
  266. alignItems: 'center',
  267. marginTop: px2pt(40),
  268. borderTopColor: '#E6E6E6',
  269. borderTopWidth: 1
  270. },
  271. btnLeft:{
  272. borderRightColor: '#E6E6E6',
  273. borderRightWidth: 1
  274. },
  275. btnRight:{
  276. flexDirection: 'row',
  277. alignItems: 'center',
  278. width: modalW / 2,
  279. height:px2pt(100),
  280. justifyContent: 'center'
  281. },
  282. btnRightText:{
  283. flex: 1,
  284. height:px2pt(80),
  285. alignItems: 'center',
  286. justifyContent: 'center'
  287. },
  288. onlyBtn:{
  289. width: modalW
  290. }
  291. })
  292.  
  293. export default CodePush(codePushOptions)(CodePushModal)

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

然后是进度条展示处理:

  1. /**
  2. * Created by susie on 2018/9/20.
  3. */
  4. import React, {Component}from 'react'
  5. import {View, StyleSheet, Animated, Easing,Text}from 'react-native'
  6. import LinearGradient from 'react-native-linear-gradient'
  7.  
  8. import PropTypes from 'prop-types'
  9.  
  10. export default class CusProgressBar extends Component {
  11.  
  12. static propTypes = {
  13. ...View.propTypes,
  14. // 当前进度
  15. progress: PropTypes.number,
  16. // second progress进度
  17. buffer: PropTypes.number,
  18. // 进度条颜色
  19. progressColor: PropTypes.string,
  20. // 进度动画时长
  21. progressAniDuration: PropTypes.number,
  22. // buffer动画时长
  23. bufferAniDuration: PropTypes.number
  24. }
  25.  
  26. static defaultProps = {
  27. // 进度条颜色
  28. progressColor: 'white',
  29. // 进度条动画时长
  30. progressAniDuration: 100,
  31. // buffer进度条动画时长
  32. bufferAniDuration: 100
  33. }
  34.  
  35. constructor(props) {
  36. super(props)
  37. this._progressAni = new Animated.Value(0)
  38. this._bufferAni = new Animated.Value(0)
  39. }
  40.  
  41. componentWillReceiveProps(nextProps) {
  42. this._progress = nextProps.progress
  43. this._buffer = nextProps.buffer
  44. }
  45.  
  46. componentWillMount() {
  47. this._progress = this.props.progress
  48. this._buffer = this.props.buffer
  49. }
  50.  
  51. render() {
  52. return (
  53. <View
  54. style={[styles.container,this.props.style]}
  55. onLayout={this._onLayout.bind(this)}>
  56. <LinearGradient colors={['#daddff', '#d3eeff']} start={{ x: 0, y: 0 }} end={{ x: 1, y: 0 }} style={{position:'absolute',borderRadius:10,width:'100%',height:'100%'}}></LinearGradient>
  57. <Animated.View
  58. ref="progress"
  59. style={{
  60. position:'absolute',
  61. width: this._progressAni,
  62. borderRadius:10
  63. }}>
  64. <LinearGradient colors={['#4669ff', '#3eefff']} start={{ x: 0, y: 0 }} end={{ x: 1, y: 0 }} style={{borderRadius:10,width:'100%',height:'100%'}}></LinearGradient>
  65. </Animated.View>
  66. <Animated.Image
  67. ref="buffer"
  68. style={{
  69. position:'absolute',
  70. left: this._bufferAni,
  71. marginLeft:0,
  72. top : -3,
  73. width:35
  74. }} source={require('../../styles/images/huojian.png')} />
  75. </View>
  76. )
  77. }
  78.  
  79. _onLayout({nativeEvent: {layout:{width, height}}}) {
  80. // 防止多次调用,当第一次获取后,后面就不再去获取了
  81. if (width > 0 && this.totalWidth !== width) {
  82. // 获取progress控件引用
  83. let progress = this._getProgress()
  84. // 获取buffer控件引用
  85. let buffer = this._getBuffer()
  86. // 获取父布局宽度
  87. this.totalWidth = width
  88. //给progress控件设置高度
  89. progress.setNativeProps({
  90. style: {
  91. height: height
  92. }
  93. })
  94.  
  95. // 给buffer控件设置高度
  96. buffer.setNativeProps({
  97. style: {
  98. height: height+6
  99. }
  100. })
  101. }
  102. }
  103.  
  104. _startAniProgress(progress) {
  105. if (this._progress >= 0 && this.totalWidth !== 0) {
  106. Animated.timing(this._progressAni, {
  107. toValue: progress * this.totalWidth,
  108. duration: this.props.progressAniDuration,
  109. easing: Easing.linear
  110. }).start()
  111. }
  112. }
  113.  
  114. _startAniBuffer(buffer) {
  115. if (this._buffer >= 0 && this.totalWidth !== 0) {
  116. Animated.timing(this._bufferAni, {
  117. toValue: buffer * this.totalWidth,
  118. duration: this.props.bufferAniDuration,
  119. }).start()
  120. }
  121. }
  122.  
  123. _getProgress() {
  124. if (typeof this.refs.progress.refs.node !== 'undefined') {
  125. return this.refs.progress.refs.node
  126. }
  127. return this.refs.progress._component
  128. }
  129.  
  130. _getBuffer() {
  131. if (typeof this.refs.buffer.refs.node !== 'undefined') {
  132. return this.refs.buffer.refs.node;
  133. }
  134. return this.refs.buffer._component;
  135. }
  136. }
  137.  
  138. Object.defineProperty(CusProgressBar.prototype, 'progress', {
  139. set(value){
  140. if (value >= 0 && this._progress !== value) {
  141. this._progress = value;
  142. this._startAniProgress(value);
  143. }
  144. },
  145. get() {
  146. return this._progress;
  147. },
  148. enumerable: true,
  149. })
  150.  
  151. Object.defineProperty(CusProgressBar.prototype, 'buffer', {
  152. set(value){
  153. if (value >= 0 && this._buffer !== value) {
  154. this._buffer = value;
  155. this._startAniBuffer(value);
  156. }
  157. },
  158. get() {
  159. return this._buffer;
  160. },
  161. enumerable: true,
  162. })
  163.  
  164. const styles = StyleSheet.create({
  165. container: {
  166. height: 12
  167. }
  168. })

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

 

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号