React-native-code-push: Android: getJSBundleFile() Method does not override method from it's super class.

Created on 18 Aug 2017  路  33Comments  路  Source: microsoft/react-native-code-push

Hi There, I'm getting this error but I have it in the correct place and the correct versions:

React Native: 0.46.4
React Native Code Push: 4.1.0-beta

public class ReactNative extends Activity implements DefaultHardwareBackBtnHandler, ReactApplication {

    private static final int OVERLAY_PERMISSION_REQ_CODE = 1;
    private ReactRootView mReactRootView;
    private ReactInstanceManager mReactInstanceManager;

    @Override // <-- Method does not override method from it's super class.
    public String getJSBundleFile() {
        return CodePush.getJSBundleFile();
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // ...
    }

I think this is the reason why my app sees that there is an update, downloads the update, restarts the app but nothing actually changes. I imagine it's because it's not getting the updated JS bundle.

Help please! :)

android waiting-for-clarification

All 33 comments

Hi @joshuapinter,

So I'm seeing that you are using not the recommended way of integration CodePush within your app (well I mean here that not the way we suppose to use it in our docs:) ).
That probably could be an issue. Can you try to move away getJSBundleFile method from ReactNative class to MainApplication.java class. Also can you please take a look at the example with similar integration logic that promise to work well: https://github.com/youngcube/AwesomeProject/blob/master/android/app/src/main/java/com/awesomeproject/MainActivity.java

If it doesn't help could you please try to repoduce your issue within this sample so we could also try to build it on our side and see if it works?

Please let us know if it helps.

HI @max-mironov. Thanks for getting back to me so quickly!

This is an existing Android application that we've integrated React Native into, so there is no MainApplication.java class. But we do have an application file that I can try moving it to. Let me try that...

Still the same error with trying to Override the getJSBundleFile() method. Where does this method live that we're trying to override it? I'll try loading up your example app and see what I can find out there.

@joshuapinter - hi again.

So regarding your questions:
getJSBundleFile method lives as a method for react-native ReactNativeHost class, so in the example I've provided above it is overriding exactly ReactNativeHost class instance, which in turns is the member of ReactApplication interface, implemented by MainApplicationclass.
Probably you should implement this interface in your application file and do all this stuff in order to make it work.

Also when using onCreate(Bundle savedInstanceState) method you build the instance of ReactInstanceManager here (see example provided), so jsBundleFile is injected here by calling overriden getJsBundleFile method.

Please let us know what you found out and if it helps.

@max-mironov Thanks for the reply, Max. This is what my application file looks like:

public class TrakApp extends MultiDexApplication {

I'll try implementing ReactApplication here and overriding getJSBundleFile to see if it "takes".

Does that sound like the right plan or am I off base?

@joshuapinter yep, that looks the right way. The same as in the example from my first post.
Let us know if it works.

Hey @joshuapinter, do you have any updates on this?

I'm having the same issue with

React Native: 0.45.1
React Native Code Push: 5.0.0-beta

My Android app extends MultiDexApplication too but I put @Override for getJSBundleFile in MainApplication.java.

My error log below

/Users/luciano/apps/Luvbook/luvbook-app/node_modules/react-native-code-push/android/app/src/main/java/com/microsoft/codepush/react/CodePushNativeModule.java:14: error: cannot find symbol
import com.facebook.react.bridge.JSBundleLoader;
                                ^
  symbol:   class JSBundleLoader
  location: package com.facebook.react.bridge
/Users/luciano/apps/Luvbook/luvbook-app/node_modules/react-native-code-push/android/app/src/main/java/com/microsoft/codepush/react/CodePush.java:21: error: CodePush is not abstract and does not override abstract method createJSModules() in ReactPackage
public class CodePush implements ReactPackage {
       ^
/Users/luciano/apps/Luvbook/luvbook-app/node_modules/react-native-code-push/android/app/src/main/java/com/microsoft/codepush/react/CodePushNativeModule.java:103: error: cannot find symbol
            JSBundleLoader latestJSBundleLoader;
            ^
  symbol:   class JSBundleLoader
  location: class CodePushNativeModule
/Users/luciano/apps/Luvbook/luvbook-app/node_modules/react-native-code-push/android/app/src/main/java/com/microsoft/codepush/react/CodePushNativeModule.java:105: error: cannot find symbol
                latestJSBundleLoader = JSBundleLoader.createAssetLoader(getReactApplicationContext(), latestJSBundleFile, false);
                                       ^
  symbol:   variable JSBundleLoader
  location: class CodePushNativeModule
/Users/luciano/apps/Luvbook/luvbook-app/node_modules/react-native-code-push/android/app/src/main/java/com/microsoft/codepush/react/CodePushNativeModule.java:107: error: cannot find symbol
                latestJSBundleLoader = JSBundleLoader.createFileLoader(latestJSBundleFile);
                                       ^
  symbol:   variable JSBundleLoader
  location: class CodePushNativeModule
Note: /Users/luciano/apps/Luvbook/luvbook-app/node_modules/react-native-code-push/android/app/src/main/java/com/microsoft/codepush/react/CodePushNativeModule.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
5 errors
:react-native-code-push:compileReleaseJavaWithJavac FAILED

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':react-native-code-push:compileReleaseJavaWithJavac'.
> Compilation failed; see the compiler error output for details.

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.

BUILD FAILED

Total time: 48.95 secs
Could not install the app on the device, read the error above for details.
Make sure you have an Android emulator running or a device connected and have
set up your Android development environment:
https://facebook.github.io/react-native/docs/android-setup.html

@lucianomlima
I believe that

React Native: 0.45.1
React Native Code Push: 5.0.0-beta

are not compatible for android at all. Please use RNCP v3.0+ in this case. Checkout our Compatibility Table for reference.

For Android works! Thanks. But now on iOS (which build successfully with v5.0.0-beta) now fails with error config.h file not found

Lexical or Preprocessor Issue Group
/Users/luciano/apps/Luvbook/luvbook-app/node_modules/react-native/third-party/glog-0.3.4/src/base/mutex.h:105:10: 'config.h' file not found
/Users/luciano/apps/Luvbook/luvbook-app/node_modules/react-native/third-party/glog-0.3.4/src/signalhandler.cc:34:10: In file included from /Users/luciano/apps/Luvbook/luvbook-app/node_modules/react-native/third-party/glog-0.3.4/src/signalhandler.cc:34:
/Users/luciano/apps/Luvbook/luvbook-app/node_modules/react-native/third-party/glog-0.3.4/src/utilities.h:73:10: In file included from /Users/luciano/apps/Luvbook/luvbook-app/node_modules/react-native/React/../third-party/glog-0.3.4/src/utilities.h:73:

Build error after downgrade to v3.0.1-beta

@lucianomlima glad to hear that it is working now for andoird :)

As for iOS - I suppose it should also work well. The error you have provided looks like an issue with changing react-native versions, not a code-push issue.

Please also take a look at this issue in react-native repo first that probably could be related to your case.

It's really weird. My app didn't have React Native update. Only CodePush downgrade. I'll see this issue. Thanks.

Thanks @max-mironov, after Xcode Clean, close Xcode, delete node_modules, yarn cache clean, yarn install, yarn start and open Xcode, build and run successfully.

Thanks for update @lucianomlima , I'm happy that it is working now.

BTW just for reference for @joshuapinter - you are also extending MultiDexApplication and it is working well, am I correct?

@max-mironov Hey Max. Playing with this some more again.

Question: Why do you need to have the following in MainApplication.java's getPackages():

new CodePush("REE371AKjKfRHTSMvttFfLYNo36oEJNr1Idb7", getApplicationContext(), BuildConfig.DEBUG)

and then have the following in MainActivity.java's ReactInstanceManager.builder()?

.addPackage(new CodePush("dGwE7TupBMiZyAxCAPABUpAg-FjL8157884c-07f4-462d-87f8-bfa0f5f1d9e6", getApplicationContext(), BuildConfig.DEBUG))

And why do you use different CodePush keys for each of them?

Thanks!

Joshua

Hey @joshuapinter
Frankly that is an example I've taken from a user who reported the similar issue, not created by me.
Well I think that it is some kind of copy-paste issue and I'm pretty sure that you don't need both of it :)
I think only the latter is needed in your case

@max Okay, perfect. That was my thought as well so I wanted to make sure I wasn't missing anything.

If I can confirm that you don't need the first piece, I'll send a PR to remove it.

That make sense, while I'm not sure if this repository is actively watching by the maintainer it would be good to have it anyway.

Okay, so when I don't have the following in my ReactNative.java Activity:

codePush.getJSBundleFile();

I get the following error:

com.microsoft.codepush.react.CodePushInvalidUpdateException: Update is invalid - A JS bundle file named "null" could not be found within the downloaded contents. Please check that you are releasing your CodePush updates using the exact same JS bundle file name that was shipped with your app's binary.
at com.microsoft.codepush.react.CodePushUpdateManager.downloadPackage(CodePushUpdateManager.java:239)
at com.microsoft.codepush.react.CodePushNativeModule$3.doInBackground(CodePushNativeModule.java:210)
at com.microsoft.codepush.react.CodePushNativeModule$3.doInBackground(CodePushNativeModule.java:204)

When I do have that, the logs show that it's loading the package but then I get the following error:

java.lang.AssertionError: recreateReactContextInBackground should only be called after the initial createReactContextInBackground call.
at com.facebook.infer.annotation.Assertions.assertCondition(Assertions.java:72)
at com.facebook.react.ReactInstanceManager.recreateReactContextInBackground(ReactInstanceManager.java:311)
at com.microsoft.codepush.react.CodePushNativeModule$2.run(CodePushNativeModule.java:145)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5254)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)

@max-mironov Yes, i'm extending from MultiDexApplication and after downgrade to v3.0.1-beta works well.

Hey @lucianomlima, can you share how you've implemented it. I'm also extending MultiDexApplication and running into trouble (see above).

I would really appreciate it! Thanks!

@joshuapinter, I had to downgrade to v 3.0.1-beta, after that, remove node_modules, cache clean wires, install wires, in Xcode run a clean and finally worked on both platforms.

@lucianomlima - thanks for answering. I believe @joshuapinter is asking mostly about how you've integrated codepush within your app. Is your configuration logic looks alike that was provided in sample app from the above? In other words can you share steps that you have performed in your app (which extends MultiDexApplication) to add code-push? We appreciate your help here with this.

@max-mironov Any thoughts on the errors I posted? I feel like I'm very very close to getting this to work. And when I do I'll adjust your docs to help others along the way.

Hey @joshuapinter, so just to reiterate:
1) You have configured your Application class as follows:

public class YourApplication extends MultiDexApplication implements ReactApplication {

    private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
        @Override
        protected String getJSBundleFile() {
            return CodePush.getJSBundleFile();
        }
        @Override
        protected boolean getUseDeveloperSupport() {
            return BuildConfig.DEBUG;
        }

        @Override
        protected List<ReactPackage> getPackages() {
            List<ReactPackage> packages = new ArrayList<>();
            packages.add(new MainReactPackage());
            packages.add(new CodePush(BuildConfig.CODEPUSH_KEY, getApplicationContext(), BuildConfig.DEBUG));
            return packages;
        }
    };

    @Override
    public ReactNativeHost getReactNativeHost() {
        return mReactNativeHost;
    }

    @Override
      public void onCreate() {
      super.onCreate();
      SoLoader.init(this, /* native exopackage */ false);
  }

}
  1. You have removed getJSBundleFile and anything else code-push related from your public class ReactNative extends Activity implements DefaultHardwareBackBtnHandler, ReactApplication { class

  2. Try to run the app

If the issue still persist and you would like, you can email me directly at v-maximi AT microsoft.com , so that I can try your build and run it on my own (because it is not easy to say what's wrong here without seeing what you have done exactly).

Hey Max. Thanks for the reply. I'm going to email you directly so we can do a screen share and walk through this.

However, when we do finally get it working I'll make sure to post my results here for others that land here.

Okay, @max-mironov was able to help me by working on our repo in private. I wanted to come back here and let everybody know what's involved to get Code Push integrated when you have an existing Android application that you have added React Native to. It's quite different and isn't documented so this should help anybody with the same issue as myself.

Here are the changes necessary:

1. Add the appropriate version of react-native-code-push to your package.json.

package.json

"react-native-code-push": "^4.1.0-beta",

2. Add the react-native-code-push to settings.gradle.

settings.gradle

include ':react-native-code-push'
project(':react-native-code-push').projectDir = new File(rootProject.projectDir, './node_modules/react-native-code-push/android/app')

_Ensure that the path to node_modules is correct. In our case, we don't have an ios and android directory so we only need ./node_modules/ instead of the typical ../node_modules/._

3. In your build.gradle apply the build.gradle files from react-native and react-native-code-push.

ourApp/build.gradle

apply from: "../node_modules/react-native/react.gradle"
apply from: "../node_modules/react-native-code-push/android/codepush.gradle"

_I added this right below apply plugin: 'com.android.application'._

4. In the same build.gradle file, compile react-native-code-push.

ourApp/build.gradle

compile project(':react-native-code-push')

_That goes in the dependencies { ... } block._

5. In your Activity where you instantiate React Native, in our case ReactNative.java, you'll need to do the following:

5a. Import Code Push:

import com.microsoft.codepush.react.CodePush;

5b. Add the CodePush package to the ReactInstanceManager.builder() chain:

.addPackage(new CodePush("your-code-push-key-goes-here", getApplicationContext(), BuildConfig.DEBUG))

_It's important that you use the correct key, Staging, for testing purposes. Once you get that working, you can follow other instructions to setup the correct key for Debug (Staging) builds and Release (Production) builds._

5c. Get the JS Bundle File via Code Push:

CodePush.getJSBundleFile("index.android.bundle");

_This can go right above setContentView( mReactRootView );. It's also important that you use the correct name of your bundle file as the param here. In our chase it's the default index.android.bundle._

That should be it!

To test, you can do something simple like this:

Add the following to your first React Native view render:

<TouchableOpacity onPress={this.checkForUpdates.bind(this)}>
  <Text style={{fontSize: 24}}>Version 1</Text>
</TouchableOpacity>

And add the checkForUpdates() method:

async checkForUpdates() {
  let response = await CodePush.sync({
    updateDialog: true,
    installMode:  CodePush.InstallMode.IMMEDIATE,
    deploymentKey: 'your-code-push-key-goes-here',
  });
}

That will allow you to check for new versions manually (great for initial testing).

Then change Version 1 to Version 2 and run the following command to build a fresh Code Push bundle:

code-push release-react OurApp android

_You might have to specify options on there to successfully build a fresh bundle, but that depends on your specific setup._

You can check your current Code Push bundles with:

code-push deployment history OurApp Staging

The idea is that you should be able to update the Version in your React Native view, publish a new bundle via Code Push and then update to that bundle by pressing "Version X" and installing the new bundle. All without restarting the app or manually reloading from the React Native package manager.

I hope that helps others that might be struggling with this. I suppose some of this should end up in the docs for people that also have unorthodox React Native apps.

Thanks again to @max-mironov for his help.

Thanks for getting it back @joshuapinter! I'm also all for adding this information to our docs, hope we'll have a chance to manage it soon.

Hey @joshuapinter, I'm trying to do the exact same thing with my current android app and am going through a similar issue.

In my case, the codepush never detects that an android bundle is even present on the server. I have made my Application which extends MultiDexApplication implement ReactApplication and have overriden the methods in ReactNativeHost

In my ReactActivityClass, I'm using the builder pattern to create an instance of mReactInstanceManager where CodePush has been added as a package and the setJSBundleFile has also been added. I'm not sure where I'm going wrong, but it seems like the codepush server is bever hit or checked.

public class MyReactActivity extends ReactActivity implements DefaultHardwareBackBtnHandler {
    private ReactRootView mReactRootView;
    private ReactInstanceManager mReactInstanceManager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        mReactRootView = new ReactRootView(this);
        mReactInstanceManager = ReactInstanceManager.builder()
                .setApplication(getApplication())
                //.setBundleAssetName(null)
                .setJSMainModulePath("index")
                .addPackage(new MainReactPackage())
                .addPackage(new ActivityStarterReactPackage())
                .setUseDeveloperSupport(false)
                .addPackage(new CodePush("65d05a1b-4fb6-4514-9cca-5fc6fef269e2",getApplicationContext(),false))
                .setInitialLifecycleState(LifecycleState.RESUMED)
                .setJSBundleFile(CodePush.getJSBundleFile())
                .build();
        mReactRootView.startReactApplication(mReactInstanceManager, "AwesomeProject", null);

        setContentView(mReactRootView);
    }

Is there something wrong in my onCreate here?

Hey @rushabhnagda11.

I can see 3 things that you can try:

1) Explicitly set your bundle asset name.

2) Explicitly set your main module path.

3) Explicitly set your JS bundle file in setJSBundleFile().

To help, here is what my working onCreate looks like (with some of my
packages removed for simplicity):

mReactInstanceManager = ReactInstanceManager.builder()
.setApplication( getApplication() )
.setBundleAssetName( "index.android.bundle" )
.setJSMainModuleName( "index.android" )
.addPackage( new MainReactPackage() )
.addPackage(new CodePush(BuildConfig.CODEPUSH_KEY, getApplicationContext(), BuildConfig.DEBUG))
.setUseDeveloperSupport( BuildConfig.DEBUG )
.setInitialLifecycleState( LifecycleState.RESUMED )
.setJSBundleFile(CodePush.getJSBundleFile("index.android.bundle"))
.build();

Try each of those 1 by 1 and see which one, if any, makes a difference.

You鈥檙e close to getting it working. :)

Hey Joshua, I managed to get it working, my issue was in the deployment keys I was using.

Thanks for the detailed steps in #970, without which I'd have been stuck here for a few more days.

@rushabhnagda11 Great to hear! And you're Welcome.

I had a similar problem, the codepush perform restartApp() but my activity do pause then destroy.
I found the reason and way to fix it final.
My code is also set in activity not application. but the restartApp() function need to get the ReactInstanceManager of the app:

@ReactMethod
    public void restartApp(boolean onlyIfUpdateIsPending, Promise promise) {
        // If this is an unconditional restart request, or there
        // is current pending update, then reload the app.
        if (!onlyIfUpdateIsPending || mSettingsManager.isPendingUpdate(null)) {
            loadBundle();
            ...
            return;
        }
...
    }


private void loadBundle() {
        clearLifecycleEventListener();
        mCodePush.clearDebugCacheIfNeeded();
        try {
            // #1) Get the ReactInstanceManager instance, which is what includes the
            //     logic to reload the current React context.
            **final ReactInstanceManager instanceManager = resolveInstanceManager();**
            if (instanceManager == null) {
                return;
            }

            String latestJSBundleFile = mCodePush.getJSBundleFileInternal(mCodePush.getAssetsBundleFileName());

            // #2) Update the locally stored JS bundle file path
            setJSBundle(instanceManager, latestJSBundleFile);

            // #3) Get the context creation method and fire it on the UI thread (which RN enforces)
            new Handler(Looper.getMainLooper()).post(new Runnable() {
                @Override
                public void run() {
                    try {
                        // We don't need to resetReactRootViews anymore 
                        // due the issue https://github.com/facebook/react-native/issues/14533
                        // has been fixed in RN 0.46.0
                        //resetReactRootViews(instanceManager);

                        instanceManager.recreateReactContextInBackground();
                        mCodePush.initializeUpdateAfterRestart();
                    } catch (Exception e) {
                        // The recreation method threw an unknown exception
                        // so just simply fallback to restarting the Activity (if it exists)
                        loadBundleLegacy();
                    }
                }
            });

        } catch (Exception e) {
            // Our reflection logic failed somewhere
            // so fall back to restarting the Activity (if it exists)
            loadBundleLegacy();
        }
    }

my old code dont set the instance for codepush, so it carshed and went to loadBundleLegacy();,finally exit activity.
so I create a ReactInstanceHolder with ReactInstanceManager and set it to codepush:

CodePush.setReactInstanceHolder(new ReactInstanceHolder() {
                    @Override
                    public ReactInstanceManager getReactInstanceManager() {
                        return mReactInstanceManager;
                    }
                });

That works!

Was this page helpful?
0 / 5 - 0 ratings