meteorrn / meteor-react-native

Meteor client for React Native matching Meteor Spec
https://guide.meteor.com/react-native.html
Other
59 stars 31 forks source link

Expo app crashes right after launch due to Meteor.connect() #141

Closed eminx closed 9 months ago

eminx commented 9 months ago

I have an expo app and trying to do my first release in TestFlight. The app is built successfully in the eas servers and then delivered to Apple for deployment. Everything goes well until I download and open the app: After only like 2 seconds of rendering the register/login page, it just goes immediately blank white. I could not have found a way to address the issue or debug.

Locally, I have no problem using the app either.

I have found out that the crash is due to using Meteor's React Native api-connection function:

import Meteor, { useTracker } from '@meteorrn/core';
import AsyncStorage from '@react-native-async-storage/async-storage';
Meteor.connect('wss://myapp.com/websocket', { AsyncStorage });

I verified that by removing the Meteor.connect() and then the page didn't crash.

Why could it be so? How can I fix this? Thanks!

"@meteorrn/core": "^2.6.0", "expo": "~49.0.11", "react-native": "0.72.6",

jankapunkt commented 9 months ago

Thanks for reporting @eminx

Is it possible for you to upgrade to @meteorrn/core@2.7.1 and if so, does the error persist or is resolved?

If not, do remember if the error did not occur in a version, prior to 2.6.0?

And last - can you log the connection status on your Meteor server:

Meteor.onConnection(connection => {
  console.debug('client connected', connection)
  connection.onClose(() => console.debug('disconnected', connection)  
})

Do you see the client being disconnected there or only being connected?

eminx commented 9 months ago

Thanks @jankapunkt ! I will try all the points you suggested and will get back the soonest!

eminx commented 9 months ago

Hi @jankapunkt

So I tried to update to the latest version of @meteorrn/core -> 2.7.1 but there's no success...

It's my first time trying an app on the appstore/testflight, so I can't tell if it would work with previous versions...

Then I entered the code you supplied to the server, and I'm logging below the logged info:

client connected {
    id: 'TpTisHXb8A4uijpNq',
    close: [Function: close],
    onClose: [Function: onClose],
    clientAddress: '10.1.21.85',
    httpHeaders: {
        'x-forwarded-for': '5.25.174.20',
        'x-forwarded-port': '443',
        via: '1.1 vegur',
        'x-forwarded-proto': 'https',
        host: 'librella.app'
    }
}

It only logs the disconnected ... info when I manually close the app, not when it crashes to blank. Any ideas further what could be the issue?

By the way, I really appreciate your work and motivations on meteor as well as leaonline. Thanks for those too! :)

jankapunkt commented 9 months ago

@eminx Is the app accessible on GitHub?

eminx commented 9 months ago

@jankapunkt sure!

Here I just uploaded the client: https://github.com/eminx/librellarn And here is the webapp/server: https://github.com/eminx/pomegra-next

You can access the webapp here: https://app.librella.co

Just to avoid confusion: I just changed the app url from librella.app to app.librella.co - just trying different scenarios...

jankapunkt commented 9 months ago

Does the error also occur, when connecting to the production server but on your local dev setup using, 'wss://app.librella.co/websocket ?

eminx commented 9 months ago

@jankapunkt No it doesn't. It works perfectly fine.

jankapunkt commented 9 months ago

Okay this is getting tricky but I think we might be able to do find the root cause with the following:

app -> App.js

const errToBody = err => {
  const errProps = Object.getOwnPropertyNames(err) ;
  const formBody = [];
  for (const prop of errProps) {
    const encodedKey = encodeURIComponent(prop);
    const encodedValue = encodeURIComponent(err[prop]);
    formBody.push(encodedKey + "=" + encodedValue);
  }
  return formBody.join("&");
}

const sendErr = err => {
  const body = errToBody(err)
  fetch('https://app.librella.co/errorlog', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'
    },
    body
  })
    .then(console.debug)
    .catch(console.error)
}

try {
  Meteor.connect(api, { AsyncStorage });
} catch (err) {
  sendErr(err)
}

server -> main.js

import { WebApp } from 'meteor/webapp'
import querystring from 'node:querystring';

WebApp.rawConnectHandlers.use('/errorlog', async (req, res) => {
  let data = ''
  req.on('data', chunk => data += chunk);
  req.on('end', () => console.debug(querystring.parse(data)))
  res.end() // send ok to client
})

The above code catches the error and transforms it into a request body then sends it to a http endpoint of the Meteor server. This should reveal the cause of the error.

Nice side-effect: you can send all uncaught errors via


ErrorUtils.setGlobalHandler((error, isFatal) => {
  error.isFatal = isFatal
  sendErr(error)    
})
eminx commented 9 months ago

@jankapunkt Brilliant! Will try and update you here. Thanks a lot!

eminx commented 9 months ago

@jankapunkt I have done exactly what you suggested, but there's no difference in the behavior of the app. There's no error logs in the server console either. Why is that you think?

Here are the changed files:

Client: https://github.com/eminx/librellarn/blob/main/App.js Server: https://github.com/eminx/pomegra-next/blob/main/imports/startup/server/index.js

There's one significant difference: I deleted the app from my phone before I installed the next version. Then I could actually go through the Auth Screen - trying to log in. It even found my password to be false. Then as soon as I entered the correct password, it crashed again. And then when I opened the app again, it crashed immediately.

Since it found my password to be false, there must be a connection to the db. And also if the problem was int he connect(), it would work to log. What could it be, really? Something like I activated the push notifications but not really using it?

I have also tried to build locally and test it locally on XCode but Expo/Eas kept giving me errors. They don't make it easy... I guess they want to get paid...

jankapunkt commented 9 months ago

Then it seems likely not to be the issue with connection but actually with the auth. Something breaks when you login and it broke before at connect, because it auto signs in the user, when there is a login token saved.

You can scan for login errors via

const sendError = () => { ... }

const Data = Meteor.getData()
Data.on('onLoginFailure', (e) => sendError(e));

Meteor.connect(...)

I have also tried to build locally and test it locally on XCode but Expo/Eas kept giving me errors. They don't make it easy... I guess they want to get paid...

Yes, they do, I'm building locally but only on Android, on iOS we currently gather more knowledge on XCode, Pods etc.

jankapunkt commented 9 months ago

Following up my last comment, I think you might want to create a more versatile logging to really see what's going on. You can listen to the folllowing DDP events:

/**
 * Contains all public events that externals can listen to.
 * @type {string[]}
 */
const PUBLIC_EVENTS = [
  'connected',
  'disconnected',
  // Subscription messages
  'ready',
  'nosub',
  'added',
  'changed',
  'removed',
  // Method messages
  'result',
  'updated',
  // Error messages
  'error',
];

You can listen on them using

const Data = Meteor.getData()
Data.ddp.on('error',  (e) => sendError(e));

You can similarly setup listeners for the other events as well and create a distinct logging endpoint like the /errorlog but for logging any other DDP messages that the client received. Maybe this finally provides a hint about the root cause.

In the meantime I decided to create a Meteor package for these types of logging that is soon to be published on this org.

eminx commented 9 months ago

Thanks for the comments and the help. Yes, I definitely need to implement more error logging feature...

How do people normally debug ios/TestFlight apps? It just feels so weird to have a crashing app that I cannot at all understand where it comes from. So miserable... I can't be the only one.

I tried to implement above error log function with the logging in but it feels again no success, no logs... :/

Thank you again. I will try to post it on meteor forums to see if anyone has an idea.

jankapunkt commented 9 months ago

Usually apps are full with trackers scanning the sh*t out of users devices, sending more log/tracking than actual data.... I will get back to you ASAP once I updated the library with better docs and logging abilities

eminx commented 9 months ago

I see, yes, I'm looking into Sentry for example.

Thank you @jankapunkt !!

eminx commented 9 months ago

@jankapunkt An update: When I logged in Meteor server with the Accounts.onLoginFailure and onLogin, it seems like there’s no error in logging. It renders success… Only onLogin fires...

I guess then it seems like another issue than logging in. Any ideas what it could be?

jankapunkt commented 9 months ago

@eminx there is a new PR #144 which contains extensive documentation about logging events and errros. Maybe it helps you to find the root cause. Please review (especially the README). I will also provide an RC release, specifically for this issue which you can use for testing.

eminx commented 9 months ago

@jankapunkt Some updates!

It was actually nothing to do with Meteor or this package. It was regarding a few UI related packages missing and therefore the crash. The missing packages were like react-native-svg.

The way I fixed the problem was by successfully building the ios build locally and running it in the XCode simulator, which is somehow more identical to the end-release. Having access to the error console was the way to fix it in a few minutes.

I could then also upload the build directly to TestFlight.

Thanks again @jankapunkt for all the help!

jankapunkt commented 9 months ago

Great to hear it's all working! Can you write me one or two paragraphs on this debugging method? I would add it to a "Troubleshooting" Section in #144