Last active
May 9, 2016 02:01
-
-
Save cameronbourke/df4241c75f402aa2f1a1dda89e6182bf to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { StyleSheet, Alert, TouchableOpacity } from 'react-native'; | |
import codePush from 'react-native-code-push'; | |
import Promise from 'promise'; | |
const { PENDING } = codePush.UpdateState; | |
const { IMMEDIATE } = codePush.InstallMode; | |
export const downloadNewVersion = (downloadProgressCallback) => { | |
return new Promise((resolve, reject) => { | |
// Queries the CodePush service to see whether the configured app deployment has an update available. | |
// By default, it will use the deployment key that is configured in your Info.plist file (iOS), or MainActivity.java file (Android) | |
codePush.checkForUpdate().then((remotePackage) => { | |
/* | |
update === null can be due to the following reasons: | |
- The configured deployment doesn't contain any releases, and therefore, nothing to update. | |
- The latest release within the configured deployment is targeting a different binary version than what you're currently running (either older or newer). | |
- The currently running app already has the latest release from the configured deployment, and therefore, doesn't need it again. | |
*/ | |
if (!remotePackage) { | |
getNewLocalVersion.then((localPackage) => { | |
if (!localPackage) return resolve({ message: 'The app is up to date!' }); | |
resolve(localPackage); | |
}); | |
} else { | |
// remoteUpdate is an instance of a RemotePackage which contains details | |
// about an update that is available for download from the CodePush server | |
const downloadPackage = remotePackage.download(downloadProgressCallback); | |
// downloadProgressCallback is periodically called with a DownloadProgress object | |
// than looks like { totalBytes: Number, receivedBytes: Number } | |
downloadPackage.then((localPackage) => { | |
if (localPackage) return resolve({ newVersion: localPackage }); | |
reject({ message: 'New version failed to download' }); | |
}); | |
}; | |
}); | |
}); | |
}; | |
export const getNewLocalVersion = () => { | |
return new Promise((resolve, reject) => { | |
codePush.getUpdateMetadata(PENDING) | |
.then(resolve) | |
.catch(reject); | |
}); | |
}; | |
// call in the root component's on componentDidMount so that | |
// it is only called once (or just call in this file) | |
codePush.notifyAppReady(); | |
/* EXAMPLE USAGE | |
-------------------------------- | |
... | |
handleNewAppVersion (newAppVersion) { | |
this.setState({ newAppVersion }) | |
} | |
... | |
const {newAppVersion} = this.state; | |
<UpdateAppButton | |
showWhenUpdateAvailable={true} // default to true instead ?? | |
onNewVersion={this.handleNewAppVersion}> | |
<Text>Update to {newAppVersion.versionNumber}></Text> | |
</UpdateAppButton> | |
*/ | |
export class UpdateAppButton extends React.Component { | |
constructor () { | |
super(); | |
this.state = { | |
newVersion: null, | |
}; | |
} | |
componentDidMount () { | |
downloadNewVersion().then(this._handleNewVersion) | |
.catch(console.log.bind(this, 'err')); | |
} | |
_handleNewVersion (newVersion) { | |
this.setState({ newVersion }); | |
} | |
handleUpdatePress (visible) { | |
const { newVersion } = this.state; | |
const alertMessage = `Version ${newVersion.description} now available. Do you want to upgrade now? Note: Upgrading the app will restart the app and any changes not saved will be lost.`; | |
Alert.alert('New Version Available', alertMessage, [{ | |
text: 'Update Now', | |
onPress: () => this.install(), | |
}, { | |
text: 'Cancel', | |
onPress: () => console.log('Cancel Pressed'), | |
style: 'cancel', | |
}]); | |
} | |
install () { | |
this.state.newVersion.install(IMMEDIATE); | |
} | |
render () { | |
const { children, style } = this.props; | |
if (!this.state.newVersion) return null; | |
return ( | |
<TouchableOpacity | |
style={[style, styles.updateApp]} | |
onPress={() => this.handleUpdatePress(true)}> | |
{children || <Text>Update</Text>} | |
</TouchableOpacity> | |
); | |
} | |
}; | |
UpdateAppButton.defaultProps = { | |
// yet to be determined | |
}; | |
UpdateAppButton.propTypes = { | |
// yet to be determined | |
}; | |
export class AppVersion extends React.Component { | |
constructor () { | |
super(); | |
this.state = { | |
versionNumber: '', | |
}; | |
} | |
componentDidMount () { | |
getNewLocalVersion().then(this._handleLocalVersion); | |
} | |
_handleLocalVersion ({ description }) { | |
// the hack here is that we are using the description to specify the latest | |
// app version and not app version that was compiled with the binary | |
this.setState({ versionNumber: description }); | |
} | |
render () { | |
return ( | |
<span style={[styles.appVersion, this.props.style]}> | |
{this.state.versionNumber} | |
</span> | |
); | |
} | |
} | |
AppVersion.defaultProps = { | |
// yet to be determined | |
}; | |
AppVersion.propTypes = { | |
// yet to be determined | |
}; | |
// styles for both components | |
const styles = StyleSheet.create({ | |
updateApp: { | |
borderRadius: 5, | |
flex: 1, | |
height: 44, | |
alignSelf: 'stretch', | |
justifyContent: 'center', | |
overflow: 'hidden', | |
}, | |
appVersion: { | |
flex: 1, | |
}, | |
}); | |
export default UpdateAppButton; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment