What you expected to happen?
Update the app from code push
What actually happens?
com.facebook.react.uimanager.IllegalViewOperationException: Trying to remove a view index above child count 0 view tag: 11
detail: View tag:-1
children(0): [
],
indicesToRemove(1): [
0,
],
tagsToDelete(1): [
156,
]
at com.facebook.react.uimanager.NativeViewHierarchyManager.manageChildren(NativeViewHierarchyManager.java:346)
at com.facebook.react.uimanager.UIViewOperationQueue$ManageChildrenOperation.execute(UIViewOperationQueue.java:177)
at com.facebook.react.uimanager.UIViewOperationQueue$1.run(UIViewOperationQueue.java:776)
at com.facebook.react.uimanager.UIViewOperationQueue.flushPendingBatches(UIViewOperationQueue.java:855)
at com.facebook.react.uimanager.UIViewOperationQueue.access$1600(UIViewOperationQueue.java:46)
at com.facebook.react.uimanager.UIViewOperationQueue$2.runGuarded(UIViewOperationQueue.java:813)
at com.facebook.react.bridge.GuardedRunnable.run(GuardedRunnable.java:21)
at android.os.Handler.handleCallback(Handler.java:733)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5584)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1268)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1084)
at dalvik.system.NativeStart.main(Native Method)
(The more info the faster we will be able to address it!)
Relates to https://github.com/Microsoft/react-native-code-push/issues/986 issue.
@kumark86 - do you have any stable conditions where we can replicate it? Can you share a quick sample app so we can reproduce it locally?
@kumark86 do you have any updates regarding this? Are you able to reproduce it constantly?
@max-mironov Yes this can be constantly reproduced with the CodePush.sync() method defined as in #986
@sood03 thanks, got it! I'll try to reproduce your issue with configuration you have provided on demo app and let you know the results. BTW what is the android version you are testing? Is it android 7? Do you have any other aspects in your application that I could probably miss?
Hi @max-mironov , I am on RN 0.45.1 and RNCP 3.0.0-beta. I tried on Android 7 (emulator) and on Android 6.0 on Redmi Note 3 facing the same error. The same settings work perfectly fine on iOS. I am also using react-native-modalbox to show the installation progress.
This is the render method in my js which handles CodePush
import Modal from 'react-native-modalbox';
render() {
if (this.state.showDownloadingModal) {
return (
<Container>
<Content style={styles.container}>
<Modal
style={[styles.modal, styles.modal1]}
backdrop={false}
ref={c => {
this._modal = c;
}}
swipeToClose={false}
>
<View
style={{
flex: 1,
alignSelf: "stretch",
justifyContent: "center",
}}
>
{this.state.showInstalling
? <Text
style={{
textAlign: "center",
marginBottom: 15,
fontSize: 15
}}
>
Installing update...
</Text>
: <View
style={{
flex: 1,
alignSelf: "stretch",
justifyContent: "center",
padding: 20
}}
>
<Text
style={{
color: 'white',
textAlign: "center",
marginBottom: 15,
fontSize: 15
}}
>
Downloading update...
{" "}
{`${parseInt(this.state.downloadProgress, 10)} %`}
</Text>
<ProgressBar
color="white"
progress={parseInt(this.state.downloadProgress, 10)}
/>
</View>}
</View>
</Modal>
</Content>
</Container>
);
}
return <MainStackRouter />;
}
Sorry for the formatting. Don't know why are the tabs not honored if I add it like a code snippet.
@sood03 np, you should use ``instead of to keep tabs.
As for your issue - I've tried to reproduce it with RN45.1 and RNCP3.0.0 but with no luck.
I've attached archive with my demo (you'll need to npm i and change code-push deployment key), so you can try it locally to see if you will be able to reproduce the issue somehow.
Please let us know if you can find anything.
AndroidCrash.zip
@sood03 sorry to bother you but did you have a chance to try to reproduce your case with the demo app I've provided?
Hi @max-mironov , Sorry I couldn't get time to check this until now. I will try this today and get back to you soon.
@sood03 thanks for reply, please let us know if you could find anything.
I think this issue might have something to do with updating state (and causing a render) on the UPDATE_INSTALLED event.
After this event the app will restart. This could cause issues if you are updating the same thing that is being destroyed.
Still need to test this theory though.
@AndrewJack thanks for reply, what do you mean by
updating the same thing that is being destroyed.
I've tried immediate update and remove visible element from the app but seems ok. Do you have more precise scenario we can try to test to see if we have an issue?
Hi @max-mironov , thanks for your attached project.
I replaced Modal to be used to from react-native instead of Modal from react-native-modalbox.
Also removing this piece of code from UPDATE_INSTALLED case made my code-push working
this._modal.close();
this.setState({ showDownloadingModal: false });
So my UPDATE_INSTALLED case is just empty. It seemed I was trying to set a state variable after app went for a restart. Taking this clue from @AndrewJack 's comment above.
Hello @sood03, thanks for reply.
So do I get it right the issue is fixed at that moment for you?
BTW I've also tried to replicate your case but with no luck, my demo.js is the following:
Click to expand
import React, { Component } from "react";
import {
AppRegistry,
Dimensions,
Image,
StyleSheet,
Text,
Container,
Content,
TouchableOpacity,
View,
} from "react-native";
import CodePush from "react-native-code-push";
import Modal from 'react-native-modalbox';
class AndroidCrash extends Component {
constructor() {
super();
this.state = { restartAllowed: true };
}
codePushStatusDidChange(syncStatus) {
switch(syncStatus) {
case CodePush.SyncStatus.CHECKING_FOR_UPDATE:
this.setState({ syncMessage: "Checking for update." });
break;
case CodePush.SyncStatus.DOWNLOADING_PACKAGE:
this.setState({ showDownloadingModal: true });
this.setState({ syncMessage: "Downloading package." });
this._modal.open();
break;
case CodePush.SyncStatus.AWAITING_USER_ACTION:
this.setState({ syncMessage: "Awaiting user action." });
break;
case CodePush.SyncStatus.INSTALLING_UPDATE:
this.setState({ syncMessage: "Installing update." });
break;
case CodePush.SyncStatus.UP_TO_DATE:
this.setState({ syncMessage: "App up to date.", progress: false });
break;
case CodePush.SyncStatus.UPDATE_IGNORED:
this.setState({ syncMessage: "Update cancelled by user.", progress: false });
break;
case CodePush.SyncStatus.UPDATE_INSTALLED:
this._modal.close();
this.setState({ showDownloadingModal: false });
this.setState({ syncMessage: "Update installed and will be applied on restart.", progress: false });
break;
case CodePush.SyncStatus.UNKNOWN_ERROR:
this.setState({ syncMessage: "An unknown error occurred.", progress: false });
break;
}
}
codePushDownloadDidProgress(progress) {
this.setState({ progress });
}
toggleAllowRestart() {
this.state.restartAllowed
? CodePush.disallowRestart()
: CodePush.allowRestart();
this.setState({ restartAllowed: !this.state.restartAllowed });
}
getUpdateMetadata() {
CodePush.getUpdateMetadata(CodePush.UpdateState.RUNNING)
.then((metadata: LocalPackage) => {
this.setState({ syncMessage: metadata ? JSON.stringify(metadata) : "Running binary version", progress: false });
}, (error: any) => {
this.setState({ syncMessage: "Error: " + error, progress: false });
});
}
/** Update is downloaded silently, and applied on restart (recommended) */
sync() {
CodePush.sync(
{},
this.codePushStatusDidChange.bind(this),
this.codePushDownloadDidProgress.bind(this)
);
}
/** Update pops a confirmation dialog, and then immediately reboots the app */
syncImmediate() {
CodePush.sync(
{ installMode: CodePush.InstallMode.IMMEDIATE, updateDialog: true },
this.codePushStatusDidChange.bind(this),
this.codePushDownloadDidProgress.bind(this)
);
}
btnPressed(){
this.setState({ syncMessage: "Btn pressed: "});
this._modal.open();
}
render() {
let progressView;
if (this.state.progress) {
progressView = (
<Text style={styles.messages}>{this.state.progress.receivedBytes} of {this.state.progress.totalBytes} bytes received</Text>
);
}
return (
<View style={styles.container}>
<Modal
ref={c => {
this._modal = c;
}}
>
<View>
<Text>Hi Modal downloading update</Text>
</View>
</Modal>
<Text style={styles.welcome}>
Welcome to CodePush! 111
</Text>
<TouchableOpacity onPress={this.syncImmediate.bind(this)}>
<Text style={styles.syncButton}>Press for dialog-driven sync</Text>
</TouchableOpacity>
<TouchableOpacity onPress={this.btnPressed.bind(this)}>
<Text style={styles.syncButton}>Newly added button</Text>
</TouchableOpacity>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: "center",
backgroundColor: "#F5FCFF",
paddingTop: 50
},
image: {
margin: 30,
width: Dimensions.get("window").width - 100,
height: 365 * (Dimensions.get("window").width - 100) / 651,
},
messages: {
marginTop: 30,
textAlign: "center",
},
restartToggleButton: {
color: "blue",
fontSize: 17
},
syncButton: {
color: "green",
fontSize: 17
},
welcome: {
fontSize: 20,
textAlign: "center",
margin: 20
},
});
/**
* Configured with a MANUAL check frequency for easy testing. For production apps, it is recommended to configure a
* different check frequency, such as ON_APP_START, for a 'hands-off' approach where CodePush.sync() does not
* need to be explicitly called. All options of CodePush.sync() are also available in this decorator.
*/
let codePushOptions = { checkFrequency: CodePush.CheckFrequency.MANUAL };
AndroidCrash = CodePush(codePushOptions)(AndroidCrash);
AppRegistry.registerComponent("AndroidCrash", () => AndroidCrash);
So I've
this._modal.close();
this.setState({ showDownloadingModal: false });
in my UpdateInstalled event but it is still working.
Hi @max-mironov , Yes currently this issue is fixed for me but I will be keeping a close eye on my code push updates. You may close this for now. I will update in case I get any issues.
Thank you so much for your input :+1:
Thanks @sood03, please let us know if any updates!
FYI - The problem was also fixed for me by removing the state change in UPDATE_INSTALLED.
Most helpful comment
FYI - The problem was also fixed for me by removing the state change in
UPDATE_INSTALLED.