Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[expo-branch] null is not an object (evaluating RNBranch.STANDARD_EVENT_ADD_TO_CART #5349

Closed
AryanJ-NYC opened this issue Aug 15, 2019 · 50 comments
Labels

Comments

@AryanJ-NYC
Copy link
Contributor

AryanJ-NYC commented Aug 15, 2019

🐛 Bug Report

Environment

This bug happens in Android


  Expo CLI 3.0.9 environment info:
    System:
      OS: macOS 10.14.6
      Shell: 5.3 - /bin/zsh
    Binaries:
      Node: 10.16.0 - ~/.nvm/versions/node/v10.16.0/bin/node
      Yarn: 1.17.3 - /usr/local/bin/yarn
      npm: 6.9.2 - ~/.nvm/versions/node/v10.16.0/bin/npm
      Watchman: 4.9.0 - /usr/local/bin/watchman
    IDEs:
      Android Studio: 3.4 AI-183.6156.11.34.5522156
      Xcode: 10.3/10G8 - /usr/bin/xcodebuild
    npmPackages:
      expo: ^34.0.1 => 34.0.4 
      react: 16.8.3 => 16.8.3 
      react-native: https://github.com/expo/react-native/archive/sdk-34.0.0.tar.gz => 0.59.8 
    npmGlobalPackages:
      expo-cli: 3.0.9

Steps to Reproduce

import * as whatever from 'expo-branch'
OR
import whatever from 'expo-branch'
OR
import { Branch } from 'expo-branch'

  1. npm start
  2. Scan QR code on Expo on Android app
  3. See red screen of death:
    WhatsApp Image 2019-08-15 at 4 14 01 PM

Expected Behavior

It does not break.

Actual Behavior

It breaks.

Reproducible Demo

https://github.com/AryanJ-NYC/expo-sandbox

@AryanJ-NYC AryanJ-NYC added the bug label Aug 15, 2019
@cruzach
Copy link
Contributor

cruzach commented Aug 16, 2019

You'll want to run expo install react-native-branch and to import like this:

import Branch, { BranchEvent } from 'react-native-branch'

@cruzach cruzach closed this as completed Aug 16, 2019
@AryanJ-NYC
Copy link
Contributor Author

AryanJ-NYC commented Aug 16, 2019

This works on iOS but still results in the same screen (shown in OP) on Android.

I've updated https://github.com/AryanJ-NYC/expo-sandbox to reflect the changes you suggest.

@cruzach
Copy link
Contributor

cruzach commented Aug 16, 2019

We state in Expo's Branch docs:

This module is currently not supported on standalone or ExpoKit Android builds. If you'd like to use Branch in your Android app, we recommend that you use the bare workflow and install the react-native-branch module separately.

@AryanJ-NYC
Copy link
Contributor Author

I see. I was under the impression that Branch was re-added as an optional module for Android.

@cruzach
Copy link
Contributor

cruzach commented Aug 16, 2019

That will probably go out with SDK 35

@AryanJ-NYC
Copy link
Contributor Author

I don't this is an issue that will be fixed with Expo SDK 35. Instead, it's a bug in the expo-branch unimodule.

I think this issue should be re-opened. @sjchmiela, thoughts?

@sjchmiela
Copy link
Contributor

This hasn't been communicated clearly anywhere, since we haven't announced this feature publicly yet, but when trying to use Branch you will need to remember that:

  • nothing has changed when it comes to Expo client — it didn't have Branch and it won't. So, trying to import and/or call any Branch methods in Expo client will raise an error, since RNBranch, i. e. native module, is null in Expo client.
  • Branch module is only added to Android standalone apps. expo-branch is a wrapper around react-native-branch which allows us to optionally include it in standalone applications depending on dependencies field in package.json. Branch will be available in your application only in Expo-built apps (expo build:android) and only if you add expo-branch to your NPM dependencies.
  • If you build your app with expo-branch included and importing from expo-branch doesn't work due to some problem with exports, try importing from react-native-branch, as @cruzach proposed here.
  • As always you can eject to either bare workflow or ExpoKit and add expo-branch/react-native-branch there. 🙂

Has this description helped understand current situation? 😅

@AryanJ-NYC
Copy link
Contributor Author

AryanJ-NYC commented Aug 19, 2019

Yes, it has, @sjchmiela.

This would mean that, while import { DangerZone } from 'expo' was a safe import, import ... from 'expo-branch' // or react-native-branch is unsafe since RNBranch is null in Expo client. This lead me to use the following pattern:

if (Constants.appOwnership === 'standalone') {
  const { BranchEvent } = await import('expo-branch')
  const branchEvent = new BranchEvent(eventType, null, properties) // assume properties is defined
  branchEvent.logEvent()
}

which now does not return the same error as above. Unfortunately, I'm still unsuccessfully able to run a built app. Will keep updated.

@sjchmiela
Copy link
Contributor

That's right, that should do the work! To inspect whether expo-branch has been added to the build, expand the resolve native modules step in expo.io/builds and verify whether Adding expo-branch:1.0.0 is present there. If it is, most probably all the required native modules have been added to the application.

Zrzut ekranu 2019-08-19 o 20 55 09

@AryanJ-NYC
Copy link
Contributor Author

AryanJ-NYC commented Aug 19, 2019

I can confirm that expo-branch is added to the build.

Additionally, trying to import react-native-branch breaks the app (as it is not added to the build).

Lastly, I can also confirm that expo-branch is not default exporting a Branch() singleton (which makes it difficult to use as most of the functionality is tied to that singleton). I was able to get some functions to work (such as logout() and setIdentity()) but calling branchUniversalObject.generateShortUrl() break the app (the app restarts) without the necessary singleton (#5391).

I logged the non-existence of a default export here: #5348

@nmakiya
Copy link

nmakiya commented Sep 12, 2019

I've found import Branch, { BranchEvent } from 'react-native-branch' works on iOS but still not on Android with SDK 34. I have confirmed looking at the build that both expo-branch and react-native-branch are included in the build:android output.

@matias91
Copy link

I'm stuck with the same problem.

I'm trying with SDK 35 and still getting that error on IOS and Android.
The error happens importing as

import Branch from 'expo-branch'

and

import Branch from 'react-native-branch'

I read about the Android support here, and followed this instructions.

error: null is not an object (evaluating 'RNBranch.STANDARD_EVENT_ADD_TO_CART')

i'm missing something?

@sjchmiela
Copy link
Contributor

Branch is only included in standalone apps (expo build:android) and only if at the moment of executing that command you have expo-branch listed among dependencies in package.json. So no support in Expo client. 🙂

@matias91
Copy link

matias91 commented Sep 25, 2019

Branch is only included in standalone apps (expo build:android) and only if at the moment of executing that command you have expo-branch listed among dependencies in package.json. So no support in Expo client. 🙂

Thanks for the reply, @sjchmiela!
So is included in the build but can't be tested first because the app crashes. What about IOS? Is also crashing in Expo client in SDK 35, but works on SDK 34.
Seems to me that is the same as before and devs need to eject from expo to use it properly.
Or there is a way to integrate it without breaking the app?

Please, correct me if I'm wrong. Thanks

EDIT:
Well, @AryanJ-NYC suggestion will work without broking the app. That point is covered.

@JTambunt
Copy link

JTambunt commented Oct 3, 2019

Just want some clarification on @sjchmiela reply.

So since there is no support with the Expo client, would that mean in order to test branch functionality (for iOS) we would have to do a standalone build and upload to Testflight?

Is there any other workflow for this at the moment? And is Expo client support for branch something in the works?

Thanks for your help.

@davidbiller
Copy link
Contributor

davidbiller commented Oct 9, 2019

Same here. We can´t test in in the iOS Simulator?
SDK 35, get the same error in iOS: RNBranch.Standard_Event_Add_to_Card

@cruzach
Copy link
Contributor

cruzach commented Oct 9, 2019

Correct, you can't test in the Expo Client, but you can install your binary onto a simulator before moving on to TestFlight, if you wish

@binchik
Copy link

binchik commented Oct 28, 2019

Branch doesn't work for me even in standalone builds. I tried iOS only.

if (Constants.appOwnership === 'standalone') {
      const branch = await import('expo-branch') // tried react-native-branch here too

      branch.subscribe(({error, params}) => {
     }
}

@davidbiller
Copy link
Contributor

Branch doesn't work for me even in standalone builds. I tried iOS only.

if (Constants.appOwnership === 'standalone') {
      const branch = await import('expo-branch') // tried react-native-branch here too

      branch.subscribe(({error, params}) => {
     }
}

Did you tried to import it direct for testing? without condition.
I have the same issue, but it works if i import it from start.

@binchik
Copy link

binchik commented Oct 28, 2019

@davidbiller do you mean the regular import without await? And how do you import it? expo-branch or react-native-branch?

Just tried import branch from 'expo-branch'. Didn't work.

@davidbiller
Copy link
Contributor

//import Branch from "expo-branch";

this works for me.

@binchik
Copy link

binchik commented Oct 28, 2019

@davidbiller are you using expo v35?

@davidbiller
Copy link
Contributor

@davidbiller are you using expo v35?

Yes.
import is in app.js

So what error do you get?

@binchik
Copy link

binchik commented Oct 28, 2019

@davidbiller

I get the following error:

Can't find variable: Branch

@davidbiller
Copy link
Contributor

so you do the import with branch and not Branch

@binchik
Copy link

binchik commented Oct 28, 2019

@davidbiller it used to be Branch. Forget about Can't find variable: Branch.

Here is the error I get from sentry:

TypeError
undefined is not a function (near '...o.sent.subscribe...')

with the following code:

if (Constants.appOwnership === 'standalone') {
      const Branch = await import('expo-branch')
      Branch.subscribe(({error, params}) => {
        console.log('Branch.io deeplink handler', JSON.stringify(params))
        ...

I don't know what error I get when importing branch the regular way because it doesn't get reported to sentry. App just crashes on launch.

@davidbiller
Copy link
Contributor

@davidbiller it used to be Branch. Forget about Can't find variable: Branch.

Here is the error I get from sentry:

TypeError
undefined is not a function (near '...o.sent.subscribe...')

with the following code:

if (Constants.appOwnership === 'standalone') {
      const Branch = await import('expo-branch')
      Branch.subscribe(({error, params}) => {
        console.log('Branch.io deeplink handler', JSON.stringify(params))
        ...

I don't know what error I get when importing branch the regular way because it doesn't get reported to sentry. App just crashes on launch.

Looks like you dont use it in a standalone app, without expo.

@binchik
Copy link

binchik commented Oct 28, 2019

@davidbiller I'm doing a build with expo build:ios -t simulator and run it on simulator. It's standalone. https://docs.expo.io/versions/latest/distribution/building-standalone-apps/#5-test-it-on-your-device-or

@davidbiller
Copy link
Contributor

davidbiller commented Oct 28, 2019

@davidbiller I'm doing a build with expo build:ios -t simulator and run it on simulator. It's standalone. https://docs.expo.io/versions/latest/distribution/building-standalone-apps/#5-test-it-on-your-device-or

mhhh okay.
so try:
import Branch from "expo-branch";
Without if(...
and than you can do expo publish for testing.
Run again in Simulator

@binchik
Copy link

binchik commented Oct 28, 2019

@davidbiller I don't know why, but it works now. I import it with regular top import and I left the if (Constants.appOwnership === 'standalone') {.

Thank you! I spent about 5 hours on this.

@yodaheis
Copy link

So I have struggled a lot with this issue and tried both sdk 34 as well as 35. Now I've got it up and running (functional in standalone app and error-less build in expo-cli for development purpose)

This error will appear only if actively importing Branch from 'expo-branch' in any module at the time of building the app.

So a simple conditional if(Constants.appOwnership === 'standalone') {
const Branch = import('expo-branch)
// Your code here ...
}
works perfectly fine

@AryanJ-NYC
Copy link
Contributor Author

AryanJ-NYC commented Nov 22, 2019

@yodaheis Just be aware that import() returns a Promise. You should probably make it something like...

const someAsyncFunction = async () => {
  if(Constants.appOwnership === 'standalone') {
    const Branch = await import('expo-branch')
    // Your code here ...
  }
}

@walidvb
Copy link

walidvb commented Dec 5, 2019

I'm running this on a standalone app on my device, expo 35, and getting a undefined is not a function on Branch.subscribe with that approach (i do use await).

Also, when importing normally(without the standalone condition), and running as standalone on a device, the code within subscribe doesn't run, even when opening from a branch url.

Any pointers?

@0duaht
Copy link

0duaht commented Dec 7, 2019

To import dynamically using await, what worked for us was:

const ExpoBranch = await import('expo-branch')
const Branch = ExpoBranch.default;
Branch.setIdentity('user_id')

@walidvb
Copy link

walidvb commented Dec 16, 2019

I tried importing as @0duaht suggested, but am still getting an error on importing the library:
null is not an object (evaluating 'c.STANDARD_EVENT_ADD_TO_CART').
I've
I'm running a standalone build on Android.

Not sure what i'm doing wrong?
Here is my full source:

// ./Branch.js
import { Alert } from 'react-native';
import Constants from 'expo-constants';

(async function(){
  if (Constants.appOwnership === 'standalone') {
    const ExpoBranch = await import('expo-branch')
    const Branch = ExpoBranch.default;
    Alert.alert(`branch ${typeof ExpoBranch} | ${typeof Branch}`)

    // Branch.subscribe((bundle) => {
    //   Alert.alert(`bundle ${typeof bundle}`, JSON.stringify(bundle))
    //   if (bundle && bundle.params && !bundle.error) {
    //     Alert.alert(`bundle exists ${typeof bundle}`, JSON.stringify(bundle))
    //     console.log(bundle.params)
    //   }
    // });
  }
})()

Update, i've finally made it work. Perhaps because i didn't have the correct associatedDomains declared in my app.json

@walidvb
Copy link

walidvb commented Dec 19, 2019

Also, for those interested, I've ended up handling it this way:

// /my-branch.js
import Constants from 'expo-constants';

if (Constants.appOwnership !== 'standalone') {
  module.exports = {
    subscribe: console.log,
    createBranchUniversalObject: async () => ({
      showShareSheet: console.log,
    })
  }
}
else{
  module.exports = require('expo-branch')
}

and then import Branch from 'my-branch'. The above code would obviously need to mock all functions called by your code.

@nsdub
Copy link

nsdub commented Jan 29, 2020

I struggled getting the syntax correct to export the nested logEvent function inside BranchEvent. Here's how you can do it (riffing off of @walidvb 's comment)...

import Constants from 'expo-constants'

if (Constants.appOwnership !== 'standalone') {
  module.exports = {
    BranchEvent: function(eventName, buo) {
      this.logEvent = function() {
        console.log(eventName) // or whatever...
      }
    }
  }
}
else {
  module.exports = require('expo-branch')
}

@augustolp
Copy link

Hello! is there any experienced dev here that can help me with expo & branch implementation? Please contact me at augusto@lemmonet.com to discuss collaboration fees ... thanks!

@Winnie16
Copy link

Winnie16 commented Aug 8, 2020

Also, for those interested, I've ended up handling it this way:

// /my-branch.js
import Constants from 'expo-constants';

if (Constants.appOwnership !== 'standalone') {
  module.exports = {
    subscribe: console.log,
    createBranchUniversalObject: async () => ({
      showShareSheet: console.log,
    })
  }
}
else{
  module.exports = require('expo-branch')
}

and then import Branch from 'my-branch'. The above code would obviously need to mock all functions called by your code.

Hey @walidvb , I am new to branch and expo.I am trying to integrate branch on expo v36 for android. I am not quite clear on those function implementations. Can you please elaborate on it?

@walidvb
Copy link

walidvb commented Aug 12, 2020

@Winnie16 the idea is to conditionally load branch, depending on your environment.

Across your codebase, instead of doing import Branch from 'expo-branch', you would import Branch from 'my-branch', which would give you a real branch instance in standalone(production), and a mock in the expo client(development).

I'm now adding branch for web, and seeing that this will be needed either way, as they have quite different implementations. In this case, I will have a MyBranch which would interface with either the WebSDK(web prod/dev), the ReactNativeSDK(prod) or the mock(dev).

Makes sense?

@Winnie16
Copy link

@Winnie16 the idea is to conditionally load branch, depending on your environment.

Across your codebase, instead of doing import Branch from 'expo-branch', you would import Branch from 'my-branch', which would give you a real branch instance in standalone(production), and a mock in the expo client(development).

I'm now adding branch for web, and seeing that this will be needed either way, as they have quite different implementations. In this case, I will have a MyBranch which would interface with either the WebSDK(web prod/dev), the ReactNativeSDK(prod) or the mock(dev).

Makes sense?

Yes this does make things clear. Can you give me an idea about mocking the functions?

@walidvb
Copy link

walidvb commented Aug 16, 2020

As per my previous post, which only mocks subscribe and createBranchUniversalObject, although Branch has more methods than that. I've been adding them as they are called in my codebase.
The mocked functions do nothing more than logging(so that I can see the calls being made)

@augustolp
Copy link

Hello @walidvb / @Winnie16
Have you tried Branch links? I'm struggling to make it work ... when doing an install test using a branch link, it doesn't attribute the install in Branch dashboard, and I'm not able to read link data within subscribe method in standalone.

Here is my app.js code, as you can see I'm logging with Sentry:

import React from 'react';
import { Provider } from 'react-redux';
import Main from './src/index.js';
import store from './src/store';
import Constants from 'expo-constants';
import * as Sentry from 'sentry-expo';
import * as Facebook from 'expo-facebook';

Sentry.init({
dsn:
'-----------------------------------------',
enableInExpoDevelopment: true,
debug: true,
});

class App extends React.Component {
constructor(props) {
super(props);
}

async componentDidMount() {
//Sentry.captureMessage(appOwnership: ${Constants.appOwnership}, debug);
try {
//await Facebook.initializeAsync('----------------');

  if (Constants.appOwnership === 'standalone') {
    const Branch = await import('expo-branch');

    Branch.default.subscribe((bundle) => {
      Sentry.captureMessage(
        `Branch Subscribed: ${JSON.stringify(bundle)}`,
        `debug`
      );
      if (bundle && bundle.params && !bundle.error) {
        // `bundle.params` contains all the info about the link.
        Sentry.captureMessage(`Params: ${bundle.params}`, `debug`);
        Sentry.captureMessage(
          `Params length: ${bundle.params.length}`,
          `debug`
        );

        for (const i = 0; i < bundle.params.length; i++) {
          Sentry.captureMessage(
            `Params(${i}): ${bundle.params[i]}`,
            `debug`
          );
        }
      } else {
        Sentry.captureMessage(
          `Branch Subscription Error: ${bundle.error}`,
          `debug`
        );
      }
    });
    Sentry.captureMessage(`Branch Ok`, `debug`);
  }
} catch (error) {
  Sentry.captureMessage(`Branch Error: ${error}`, `debug`);
}

}

render() {
return (



);
}
}

export default App;

@SirPhemmiey
Copy link

Hi @walidvb, @Winnie16, i used your method and was able to run it in Expo client. But when I make a new build with expo build:android the app crashes on opening.

Please, help!

@walidvb
Copy link

walidvb commented Feb 16, 2021

@SirPhemmiey share your code? Were you able to see the error? Can you run in debug?

@augustolp Haven't played much with the link attribution on their dashboard, but I can confirm I can most of the time my app can retrieve the data of the link. I save these on the server, too, and i can usually see that +first_install(or whatever the param is) is present.

I want to point out that Branch is not a good solution if you plan a web release too, as it is blocked by adblockers, breaking the Branch.link functionality! (as the client won't be able to read it)

@SirPhemmiey
Copy link

Hi @walidvb , thanks for your response.

Below is the code I'm using
//myBranch.ts

(async function(){
  if (Constants.appOwnership === 'standalone') {
    const ExpoBranch = await import('expo-branch') //i have tried react-native-branch also
    const Branch = ExpoBranch;
    module.exports = ExpoBranch;

  }
   else {
    module.exports = {
      initSessionTtl: console.log(''),
      subscribe: async(bundle: any) => {
        console.log({bundleLol: bundle});
      },
      createBranchUniversalObject: async () => ({
        showShareSheet: (opts: {}, props: any, params: {}) => {
          console.log({});
        }
      })
    }
  }
})()

And I'm importing it normally as in:

const Branch = require('../clients/branch/branch');

Thanks for your help

@walidvb
Copy link

walidvb commented Feb 16, 2021

@SirPhemmiey i'm not expert enough in js to have a proper answer, but why the wrap in async? Could be the issue. I think expo has added conditional and/or async imports recently, but i don't know how it works exactly, or whether it is already available in the latest SDK

@SirPhemmiey
Copy link

SirPhemmiey commented Feb 17, 2021

Hi @walidvb , i removed the async and it was still the same when I made a new build. It was still crashing when I opened it. And when I checked the logs via adb logs, the error is something like e.subscribe is undefined

@walidvb
Copy link

walidvb commented Feb 17, 2021

@SirPhemmiey it's difficult to tell without a crash log. Build your app in debug mode and see what that says.

@yzalvov
Copy link

yzalvov commented Mar 13, 2021

Hello everyone. Thanks to a number of comments, I now handle the Branch code in dev and production environments.

But can anyone please help me to set up a simple thing? I need to count installs. Expo 40, managed workflow.

  • I installed expo-branch according to the Expo docs.
  • I successfully import the Branch module and can confirm it works on a stand-alone build.
  • I do Branch.setIdentity('user_id')

As a result – nothing on my dashboard.branch.io: no installs, no opens, nothing.
Please advise, should I consider any setup on dashboard.branch.io side? Many thanks for considering my request.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests