React-native-code-push: Code Push Android App crash after Update

Created on 13 Sep 2017  路  17Comments  路  Source: microsoft/react-native-code-push

Steps to Reproduce

  1. Open the app and got the update dialog from code push
  2. Install the update
  3. App got crash after getting updated

Expected Behavior

What you expected to happen?

Update the app from code push

Actual Behavior

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)

Environment

  • react-native-code-push version: 4.0.0-beta
  • react-native version:0.46.1
  • iOS/Android/Windows version: kitkat
  • Does this reproduce on a debug build or release build? release build
  • Does this reproduce on a simulator, or only on a physical device? I have tested only in physical device

(The more info the faster we will be able to address it!)

android no-repro waiting-for-clarification

Most helpful comment

FYI - The problem was also fixed for me by removing the state change in UPDATE_INSTALLED.

All 17 comments

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.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ninjz picture ninjz  路  4Comments

Phredward picture Phredward  路  3Comments

quanzaiyu picture quanzaiyu  路  3Comments

diegocouto picture diegocouto  路  4Comments

Adr1ann picture Adr1ann  路  3Comments