React-native-code-push: App crashing after restart on Android with react-native-navigation when starting app after AsyncStorage access

Created on 24 Nov 2017  路  29Comments  路  Source: microsoft/react-native-code-push

Steps to Reproduce

  1. Install and configure last versions of react-native-code-push and react-native-navigation
  2. Set index.js as following:
import { AsyncStorage } from 'react-native';
import { Navigation } from 'react-native-navigation';
import React from 'react';
import { Text } from 'react-native';
import codePush from "react-native-code-push";

const App = () =>
    <Text onPress={() => codePush.restartApp(false)}>
        Touch to run codePush.restartApp and see the crash
    </Text>
;

AsyncStorage.getItem('environment', () => {
    Navigation.registerComponent('app', () => App);
    Navigation.startSingleScreenApp({
        screen: {
            screen: 'app',
        },
        passProps: { },
    });
});
  1. Build and run Android app
  2. Tap to restart app

Expected Behavior

App restarts

Actual Behavior

App crashes with error:

Module AppRegistry is not a registered callable module (calling runApplication)

It's similar to https://github.com/Microsoft/react-native-code-push/issues/852
It also crashes after an immediate update.

Reproducible Demo

Cf repro steps.

Environment

+-- [email protected]
+-- [email protected]
+-- [email protected]
+-- [email protected]

  • iOS/Android/Windows version: Android only
  • Does this reproduce on a debug build or release build? release only
  • Does this reproduce on a simulator, or only on a physical device? on both

I really need to access AsyncStorage before starting the app to decide which screen display to the user.
Thanks for your help !

android bug react-native-navigation

Most helpful comment

@die20 just add import com.facebook.react.ReactInstanceManager; to other imports.

All 29 comments

Hi @jay1337 and thanks for submitting the issue. Please try to replace index.js content with the following:

import { AsyncStorage } from 'react-native';
import { Navigation } from 'react-native-navigation';
import React from 'react';
import { Text } from 'react-native';
import codePush from "react-native-code-push";

class App extends React.Component {

    constructor(props) {
        super(props);
    }

    render() {
        return (
            <Text onPress={() => codePush.restartApp(false)}>
            Touch to run codePush.restartApp and see the crash
            </Text>
        );
    }
}
Navigation.registerComponent('app', () => codePush(App));
AsyncStorage.getItem('environment', () => {
    Navigation.startSingleScreenApp({
        screen: {
            screen: 'app',
        },
        passProps: { },
    });
});

Let us know if it helps.

Thanks for your help.

With your code, the app does not crash.
But I need the result of AsyncStorage.getItem to register screens so your code is not a fix nor a workaround for me. I need to read a value in AsyncStorage, in order to get the server url to use when connecting screens wrapped with GraphQL Apollo client, before registering them.

An other interesting case that makes the app crash:

import { AsyncStorage } from 'react-native';
import { Navigation } from 'react-native-navigation';
import React from 'react';
import { Text } from 'react-native';
import codePush from "react-native-code-push";

const App = () =>
    <Text onPress={() => codePush.restartApp(false)}>
        Touch to run codePush.restartApp and see the crash
    </Text>
;

const screenName = Math.random().toString();

Navigation.registerComponent(screenName, () => App);
Navigation.startSingleScreenApp({
    screen: {
        screen: screenName,
    },
    passProps: { },
});

Here are the logs:

D/ReactNative( 2166): ReactInstanceManager.createReactContextInBackground()
D/ReactNative( 2166): ReactInstanceManager.recreateReactContextInBackgroundInner()
D/ReactNative( 2166): ReactInstanceManager.recreateReactContextInBackgroundFromBundleLoader()
D/ReactNative( 2166): ReactInstanceManager.recreateReactContextInBackground()
D/ReactNative( 2166): ReactInstanceManager.runCreateReactContextOnNewThread()
D/ReactNative( 2166): ReactInstanceManager.createReactContext()
D/ReactNative( 2166): Initializing React Xplat Bridge.
D/ReactNative( 2166): Initializing React Xplat Bridge before initializeBridge
D/ReactNative( 2166): Initializing React Xplat Bridge after initializeBridge
D/ReactNative( 2166): CatalystInstanceImpl.runJSBundle()
D/ReactNative( 2166): ReactInstanceManager.setupReactContext()
D/ReactNative( 2166): CatalystInstanceImpl.initialize()
D/ReactNative( 2166): ReactInstanceManager.attachRootViewToInstance()
I/ReactNativeJS( 2166): Running application "0.9843317680060863" with appParams: {"initialProps":{"screenInstanceID":"screenInstanceID2","navigatorID":"navigatorID1_nav","navigatorEventID":"screenInstanceID2_events"},"rootTag":1}. __DEV__ === false, development-level warning are OFF, performance optimizations are ON

=========== restart =========

E/ReactNativeJS( 2166): Application 0.9843317680060863 has not been registered.
E/ReactNativeJS( 2166):
E/ReactNativeJS( 2166): Hint: This error often happens when you're running the packager (local dev server) from a wrong folder. For example you have multiple apps and the packager is still running for the app you were working on before.
E/ReactNativeJS( 2166): If this is the case, simply kill the old packager instance (e.g. close the packager terminal window) and start the packager in the correct app folder (e.g. cd into app folder and run 'npm start').
E/ReactNativeJS( 2166):
E/ReactNativeJS( 2166): This error can also happen due to a require() error during initialization or failure to call AppRegistry.registerComponent.
E/ReactNativeJS( 2166):
D/ReactNative( 2166): ReactInstanceManager.attachRootViewToInstance()
I/ReactNativeJS( 2166): Running application "0.07154778391122818" with appParams: {"initialProps":{"screenInstanceID":"screenInstanceID2","navigatorID":"navigatorID1_nav","navigatorEventID":"screenInstanceID2_events"},"rootTag":21}. __DEV__ === false, development-level warning are OFF, performance optimizations are ON
D/ReactNative( 2166): ReactInstanceManager.detachViewFromInstance()
D/ReactNative( 2166): CatalystInstanceImpl.destroy() start
D/ReactNative( 2166): [CodePush] Loading JS bundle from "assets://index.android.bundle"
D/ReactNative( 2166): ReactInstanceManager.ctor()

My feeling is that everything is not perfectly cleared before starting the app again (previous app id expected by RN) and also the app is not started again the good RN Navigation way (RN should not expect any app id to be registered since with RNN there is no getMainComponentName in MainActivity.java)...

@jay1337

RN should not expect any app id to be registered since with RNN there is no getMainComponentName in MainActivity.java

As documentation for react-native-navigation said,

Every screen that you want to be able to place in a tab, push to the navigation stack or present modally needs to be registered.

I believe, you have to place Navigation.registerComponent('app', () => codePush(App)); before AsyncStorage.getItem(..) anyway so probably you should change your approach for screen registration. Be aware to use codePush(App) instead of just App to "codepushify" your application the proper way to prevent errors in the future.

@ruslan-bikkinin, with registration after AsynStorage, everything works find except CodePush restart (that's why I've posted an issue here). Also everything is ok on iOS. So it's not a bad implementation of RNN.

I think that the way CodePush restarts the app is not compatible with RNN screens registration. Again, it's strange that RN expects a specific app id to be registered.

Have you tried to reproduce the bug on your side ?

As for codePush(App) I call codePush.sync manually and everything works fine.

Hi @jay1337 sorry for late response. After further investigation, yeah, I believe you was right, something isn't clearing up completely after CodePush.restart() in case of RNN. I am working on fix now so I'll keep you posted.

@ruslan-bikkinin Thanks for this update.

@jay1337 JFYI we've created issue in react-native-navigation repo as we have no clues what could be the source of problem and whether that approach for screen registration (generate random name on each programmatic restart) is valid or not. No worries, we will be able to continue investigation as we'll get help/response from folks from RNN.

@ruslan-bikkinin thanks a lot for the update and for your precious help.

@ruslan-bikkinin Is their anywhere I can go to find the correct MainApplication.java and MainActivity.java with CodePush and React Native Navigation? We had no problems with code push before integrating react-native-navigation, but after we are experiencing this same issue on android only - iOS has been working great!

@ruslan-bikkinin here are mine:

package com.awesomeproject;

import com.facebook.react.ReactActivity;
import com.reactnativenavigation.controllers.SplashActivity;

public class MainActivity extends SplashActivity {

}
package com.awesomeproject;

import android.app.Application;

import com.facebook.react.ReactApplication;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.react.shell.MainReactPackage;
import com.facebook.soloader.SoLoader;
import com.microsoft.codepush.react.CodePush;
import com.reactnativenavigation.NavigationApplication;

import java.util.Arrays;
import java.util.List;

public class MainApplication extends NavigationApplication {

    @Override
    public boolean isDebug() {
        // Make sure you are using BuildConfig from your own application
        return BuildConfig.DEBUG;
    }

    protected List<ReactPackage> getPackages() {
        // Add additional packages you require here
        // No need to add RnnPackage and MainReactPackage
        return Arrays.<ReactPackage>asList(
            new CodePush("deployment-key-here", getApplicationContext(), BuildConfig.DEBUG)
        );
    }

    @Override
    public List<ReactPackage> createAdditionalReactPackages() {
        return getPackages();
    }

    @Override
    public String getJSBundleFile() {
        return CodePush.getJSBundleFile();
    }


    @Override
    public String getJSMainModuleName() {
        return "index";
    }
}

@die20 @jay1337 The correct way to integrate CodePush SDK into RNN application is the following:

  • MainActivity.java:
import com.facebook.react.ReactActivity;
import com.reactnativenavigation.controllers.SplashActivity;

public class MainActivity extends SplashActivity {

}
  • MainApplication.java:
import android.app.Application;

import com.facebook.react.ReactApplication;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.react.shell.MainReactPackage;
import com.facebook.soloader.SoLoader;
import com.microsoft.codepush.react.CodePush;
import com.reactnativenavigation.NavigationApplication;

import com.microsoft.codepush.react.ReactInstanceHolder;

import java.util.Arrays;
import java.util.List;

public class MainApplication extends NavigationApplication  implements ReactInstanceHolder {

    @Override
    public boolean isDebug() {
        // Make sure you are using BuildConfig from your own application
        return BuildConfig.DEBUG;
    }

    protected List<ReactPackage> getPackages() {
        // Add additional packages you require here
        return Arrays.<ReactPackage>asList(
            new CodePush("deployment-key-here", getApplicationContext(), BuildConfig.DEBUG)
        );
    }

    @Override
    public List<ReactPackage> createAdditionalReactPackages() {
        return getPackages();
    }

    @Override
    public String getJSBundleFile() {
        return CodePush.getJSBundleFile();
    }


    @Override
    public String getJSMainModuleName() {
        return "index";
    }

        @Override
        public ReactInstanceManager getReactInstanceManager() {
            return getReactNativeHost().getReactInstanceManager();
        }
}

@ruslan-bikkinin the only difference is the use of ReactInstanceHolder. Why should we use it ? Especially if we never call CodePush.setReactInstanceHolder... Everything (expect this tread issue) works fine without it...

@jay1337 We should use it because CodePush must be told how to find React Native instance. In RNN case you can implement ReactInstanceHolder as was shown above or alternatively use CodePush.setReactInstanceHolder in onCreate method with getReactNativeHost().getReactInstanceManager(); value. In some cases ignoring addition of this may lead to undesired behavior as it was in https://github.com/Microsoft/react-native-code-push/issues/1096

@ruslan-bikkinin Thanks for that info! - I came across issue #1096 but when I add ReactInstanceManager I get this build error on android

error: cannot find symbol public ReactInstanceManager getReactInstanceManager() { ^ symbol: class ReactInstanceManager location: class MainApplication 1 error :app:compileDebugJavaWithJavac FAILED

I'm using
react-native 0.47.1
react-native-navigation 1.1.295
react-code-push 5.1.1-beta

@die20 just add import com.facebook.react.ReactInstanceManager; to other imports.

Thanks @jay1337 that worked!

I'm so glad I found that issue, I thought I was the only one experiencing this error.
Here's our production stacktrace:

01-04 14:56:40.351 28508-28636/? I/ReactNativeJS: Running application "WELCOME" with appParams: {"initialProps":{"screenInstanceID":"screenInstanceID2","navigatorID":"navigatorID1_nav","navigatorEventID":"screenInstanceID2_events"},"rootTag":31}. __DEV__ === false, development-level warning are OFF, performance optimizations are ON
01-04 14:56:40.351 28508-28636/? E/ReactNativeJS: Application WELCOME has not been registered.

        Hint: This error often happens when you're running the packager (local dev server) from a wrong folder. For example you have multiple apps and the packager is still running for the app you were working on before.
        If this is the case, simply kill the old packager instance (e.g. close the packager terminal window) and start the packager in the correct app folder (e.g. cd into app folder and run 'npm start').

        This error can also happen due to a require() error during initialization or failure to call AppRegistry.registerComponent.
01-04 14:56:40.375 28508-28525/? V/FA: Session started, time: 421664741
01-04 14:56:40.378 28508-28525/? D/FA: Logging event (FE): _s, Bundle[{_o=auto, _sc=NavigationActivity, _si=-2780332768407465954}]
01-04 14:56:40.383 28508-28637/? E/AndroidRuntime: FATAL EXCEPTION: mqt_native_modules
         Process: com.ourBelovedApp.app.android, PID: 28508
         com.facebook.react.common.JavascriptException: Application WELCOME has not been registered.

         Hint: This error often happens when you're running the packager (local dev server) from a wrong folder. For example you have multiple apps and the packager is still running for the app you were working on before.
         If this is the case, simply kill the old packager instance (e.g. close the packager terminal window) and start the packager in the correct app folder (e.g. cd into app folder and run 'npm start').

         This error can also happen due to a require() error during initialization or failure to call AppRegistry.registerComponent.

         , stack:
         runApplication@311:1390
         value@64:3177
         <unknown>@64:911
         value@64:2606
         value@64:883

             at com.facebook.react.modules.core.ExceptionsManagerModule.showOrThrowError(ExceptionsManagerModule.java:56)
             at com.facebook.react.modules.core.ExceptionsManagerModule.reportFatalException(ExceptionsManagerModule.java:40)
             at java.lang.reflect.Method.invoke(Native Method)
             at com.facebook.react.bridge.JavaMethodWrapper.invoke(JavaMethodWrapper.java:374)
             at com.facebook.react.bridge.JavaModuleWrapper.invoke(JavaModuleWrapper.java:162)
             at com.facebook.react.bridge.queue.NativeRunnable.run(Native Method)
             at android.os.Handler.handleCallback(Handler.java:790)
             at android.os.Handler.dispatchMessage(Handler.java:99)
             at com.facebook.react.bridge.queue.MessageQueueThreadHandler.dispatchMessage(MessageQueueThreadHandler.java:31)
             at android.os.Looper.loop(Looper.java:164)
             at com.facebook.react.bridge.queue.MessageQueueThreadImpl$3.run(MessageQueueThreadImpl.java:194)
             at java.lang.Thread.run(Thread.java:764)
01-04 14:56:40.420 28508-28525/? V/FA: Using measurement service

So do you think adding implements ReactInstanceHolder will also fix the app crash?

@SudoPlz

So do you think adding implements ReactInstanceHolder will also fix the app crash?

It is required for RNN apps which is using CodePush. Please add it and let us know if it helps you.

Hey @jay1337, sorry for the delayed response, I鈥檝e investigated this issue once again and unfortunately I cannot see any simple and reliable ways to resolve it right now, so please let me know if you have any ideas how we could avoid this issue.

Anyway we鈥檒l try to get any feedback from wix/react-native-navigation guys and monitor this issue https://github.com/wix/react-native-navigation/issues/2331 to see how we could resolve it.

As for now, since your use case looks very specific and we haven鈥檛 received such kind of issues before - we are going to close it and focus on other hight priority features.

But please feel free to reopen the issue if you have any news or ideas how to resolve it, we鈥檒l also reopen this issue in case of a lot of similar requests.

@ruslan-bikkinin thanks for the news. I understand your decision. I don't have any idea how to resolve that...

@ruslan-bikkinin Nope, the problem isn't resolved, after adding that code I still received the same crash on Staging and Production. I'm also using AsyncStorage while initialising, but the initialisation does not depend on this.
Can you tell me what the golden rule is here? Use AsyncStorage AFTER codepush has initialised? Is that it?

Thanks!

@SudoPlz You must NOT wait for AsyncStorage before registering screens.

Good, thanks, I'll try that and post back if it worked.

On the mean time, I guess we can disable force-restarting the app.

Perhaps downloading the patch but updating the next time the app starts naturally might be a good way around that issue until it's resolved, since that won't force the app to restart and thus crash.

Unfortunately that doesn't do it for me, I'm still getting the crash after downloading an update even with ON_NEXT_RESTART install mode.

So that solution did work for me. I'm no longer receiving a crash.
Besides that, I did register my react-native-navigation screens (before doing anything else in the code) so I'm sure that helped too.

@SudoPlz Thanks for the tip, I'll try that. Do you also call startTabBasedApp (or startSingleScreenApp) before the code push update happens as well?

I'm using startSingleScreenApp and that's absolutely the last thing I call (even after updating code push).

It does work after I move the call to codePush.sync after registerScreens and wait for the Promise to complete before calling startTabBasedApp. Thanks!

I did what you suggested but navigation is not working for me. Here are the logs I get

06-07 10:30:51.359 9800-9862/? E/unknown:ReactNative: Invariant Violation: Minified React error #143; visit http://facebook.github.io/react/docs/error-decoder.html?invariant=143 for the full message or use the non-minified dev environment for full errors and additional helpful warnings.

    This error is located at:
        in r
        in t
        in RCTView
        in t
        in Connect(t)
        in RCTView
        in t
        in Connect(t)
        in RCTView
        in t
        in Connect(t)
        in r
        in n
        in s
        in RCTView
        in RCTView
        in t, stack:
    only@101:4233
    value@659:1338
    l@44:54398
    beginWork@44:56240
    n@44:82237
    i@44:82566
    o@44:82907
    C@44:87082
    b@44:86624
    m@44:85850
    d@44:85131
    f@44:84822
    t@44:50910
    updateContainer@44:101734
    render@44:69237
    exports@283:730
    run@279:615
    runApplication@279:2046
    value@21:3582
    <unknown>@21:1067
    value@21:3009
    value@21:1039
06-07 10:30:51.359 9800-9861/? E/ReactNativeJS: 'Unhandled promise rejection', { [ReferenceError: Can't find variable: AsyncStorage]
      line: 1199,
      column: 895,
      sourceURL: '/data/user/0/fi.taskuparkki.app/files/CodePush/a23158e284ff200eda3120985783f8bf574ee5ab2743218be6b2f32caeb5c7bc/CodePush/index.android.bundle' }
06-07 10:30:51.361 9800-9861/? E/ReactNativeJS: 'Unhandled promise rejection', { [ReferenceError: Can't find variable: AsyncStorage]
      line: 1199,
      column: 895,
      sourceURL: '/data/user/0/fi.taskuparkki.app/files/CodePush/a23158e284ff200eda3120985783f8bf574ee5ab2743218be6b2f32caeb5c7bc/CodePush/index.android.bundle' }
06-07 10:30:51.362 9800-9862/? E/unknown:ReactNative: console.error: "Unhandled promise rejection", {"line":1199,"column":895,"sourceURL":"/data/user/0/fi.taskuparkki.app/files/CodePush/a23158e284ff200eda3120985783f8bf574ee5ab2743218be6b2f32caeb5c7bc/CodePush/index.android.bundle"}, stack:
    <unknown>@1078:1147
    exports@1085:66
    <unknown>@1078:1018
    <unknown>@26:1779
    u@26:513
    c@26:877
    callImmediates@26:3180
    value@21:3183
    <unknown>@21:1516
    value@21:3009
    value@21:1486
    value@21:1094
06-07 10:30:51.363 9800-9862/? E/unknown:ReactNative: console.error: "Unhandled promise rejection", {"line":1199,"column":895,"sourceURL":"/data/user/0/fi.taskuparkki.app/files/CodePush/a23158e284ff200eda3120985783f8bf574ee5ab2743218be6b2f32caeb5c7bc/CodePush/index.android.bundle"}, stack:
    <unknown>@1078:1147
    exports@1085:66
    <unknown>@1078:1018
    <unknown>@26:1779
    u@26:513
    c@26:877
    callImmediates@26:3180
    value@21:3183
    <unknown>@21:1516
    value@21:3009
    value@21:1486
    value@21:1094
06-07 10:30:51.558 9800-9800/? E/zygote: The String#value field is not present on Android versions >= 6.0
06-07 10:30:51.878 9800-9861/? E/ReactNativeJS: 'Unhandled promise rejection', { [ReferenceError: Can't find variable: AsyncStorage]
      line: 1199,
      column: 895,
      sourceURL: '/data/user/0/fi.taskuparkki.app/files/CodePush/a23158e284ff200eda3120985783f8bf574ee5ab2743218be6b2f32caeb5c7bc/CodePush/index.android.bundle' }
06-07 10:30:51.880 9800-9861/? E/ReactNativeJS: 'Unhandled promise rejection', { [ReferenceError: Can't find variable: AsyncStorage]
      line: 1199,
      column: 895,
      sourceURL: '/data/user/0/fi.taskuparkki.app/files/CodePush/a23158e284ff200eda3120985783f8bf574ee5ab2743218be6b2f32caeb5c7bc/CodePush/index.android.bundle' }
06-07 10:30:51.881 9800-9862/? E/unknown:ReactNative: console.error: "Unhandled promise rejection", {"line":1199,"column":895,"sourceURL":"/data/user/0/fi.taskuparkki.app/files/CodePush/a23158e284ff200eda3120985783f8bf574ee5ab2743218be6b2f32caeb5c7bc/CodePush/index.android.bundle"}, stack:
    <unknown>@1078:1147
    exports@1085:66
    <unknown>@1078:1018
    <unknown>@26:1779
    u@26:513
    c@26:877
    callImmediates@26:3180
    value@21:3183
    <unknown>@21:1516
    value@21:3009
    value@21:1486
    value@21:1094
06-07 10:30:51.882 9800-9862/? E/unknown:ReactNative: console.error: "Unhandled promise rejection", {"line":1199,"column":895,"sourceURL":"/data/user/0/fi.taskuparkki.app/files/CodePush/a23158e284ff200eda3120985783f8bf574ee5ab2743218be6b2f32caeb5c7bc/CodePush/index.android.bundle"}, stack:
    <unknown>@1078:1147
    exports@1085:66
    <unknown>@1078:1018
    <unknown>@26:1779
    u@26:513
    c@26:877
    callImmediates@26:3180
    value@21:3183
    <unknown>@21:1516
    value@21:3009
    value@21:1486
    value@21:1094
Was this page helpful?
0 / 5 - 0 ratings

Related issues

marcmo picture marcmo  路  26Comments

niftylettuce picture niftylettuce  路  28Comments

huangkaiw3n picture huangkaiw3n  路  58Comments

colarlady picture colarlady  路  64Comments

vedovato picture vedovato  路  26Comments