React-native-onesignal: [CRASH] [ANDROID] NullPointerException en getDeviceState

Creado en 6 feb. 2021  ·  28Comentarios  ·  Fuente: OneSignal/react-native-onesignal

Descripción:
Estamos recibiendo una serie de informes de fallos que se originan en RNOneSignal.getDeviceState , seguimiento de pila adjunto a continuación.

Afecta a todas las versiones y fabricantes de Android SDK.

Ambiente
"react-native-onesignal": "^4.0.2",
react: 17.0.1 => 17.0.1 react-native: 0.64.0-rc.2 => 0.64.0-rc.2

Pasos para reproducir el problema:
No se ha podido reproducir el problema, se informa en el panel de control de fallos de Google Play.

Algo más:

  at com.geektime.rnonesignalandroid.RNOneSignal.getDeviceState (RNOneSignal.java:4)
  at java.lang.reflect.Method.invoke (Method.java)
  at com.facebook.react.bridge.JavaMethodWrapper.invoke (JavaMethodWrapper.java:147)
  at com.facebook.react.bridge.JavaModuleWrapper.invoke (JavaModuleWrapper.java:21)
  at com.facebook.react.bridge.queue.NativeRunnable.run (NativeRunnable.java)
  at android.os.Handler.handleCallback (Handler.java:883)
  at android.os.Handler.dispatchMessage (Handler.java:100)
  at com.facebook.react.bridge.queue.MessageQueueThreadHandler.dispatchMessage (MessageQueueThreadHandler.java)
  at android.os.Looper.loop (Looper.java:237)
  at com.facebook.react.bridge.queue.MessageQueueThreadImpl$4.run (MessageQueueThreadImpl.java:37)
  at java.lang.Thread.run (Thread.java:919)
Android Possible Bug

Comentario más útil

@ diego-paired nuestra solución temporal fue retrasar la llamada a getDeviceState() después de la inicialización de OneSingal (agregamos 2 segundos de retraso)

gracias por el consejo

Todos 28 comentarios

+1.

java.lang.NullPointerException: at com.geektime.rnonesignalandroid.RNOneSignal.getDeviceState (RNOneSignal.java:4) at java.lang.reflect.Method.invoke (Method.java) at com.facebook.react.bridge.JavaMethodWrapper.invoke (JavaMethodWrapper.java:147) at com.facebook.react.bridge.JavaModuleWrapper.invoke (JavaModuleWrapper.java:21) at com.facebook.react.bridge.queue.NativeRunnable.run (NativeRunnable.java) at android.os.Handler.handleCallback (Handler.java:873) at android.os.Handler.dispatchMessage (Handler.java:99) at com.facebook.react.bridge.queue.MessageQueueThreadHandler.dispatchMessage (MessageQueueThreadHandler.java) at android.os.Looper.loop (Looper.java:224) at com.facebook.react.bridge.queue.MessageQueueThreadImpl$4.run (MessageQueueThreadImpl.java:37) at java.lang.Thread.run (Thread.java:764)

Hola Diego,
Gracias por informar de este problema.

¿Puedes incluir el código que estás usando? ¿También puede proporcionar información del entorno (por ejemplo, marca y modelo del dispositivo, sistema operativo, etc.)?

Salud

Hola Diego,
Gracias por informar de este problema.

¿Puedes incluir el código que estás usando? ¿También puede proporcionar información del entorno (por ejemplo, marca y modelo del dispositivo, sistema operativo, etc.)?

Salud

Gracias por su respuesta.

Se informa en nuestra consola Google Play a una tasa de aproximadamente 50 bloqueos por semana, no tengo ninguna forma de reproducirlo.

image

Aquí igual.

info Obteniendo información del sistema y bibliotecas ...
Sistema:
SO: macOS 10.15.7
CPU: (4) CPU x64 Intel (R) Core (TM) i5-5257U a 2,70 GHz
Memoria: 36,86 MB / 8,00 GB
Shell: 5.7.1 - / bin / zsh
Binarios:
Nodo: 10.22.0 - ~ / .nvm / versions / node / v10.22.0 / bin / node
Hilado: 1.22.4 - / usr / local / bin / yarn
npm: 6.14.6 - ~ / .nvm / versions / node / v10.22.0 / bin / npm
Vigilante: 4.9.0 - / usr / local / bin / vigilante
Gerentes:
CocoaPods: 1.10.0 - / usr / local / bin / pod
SDK:
SDK de iOS:
Plataformas: iOS 13.6, DriverKit 19.0, macOS 10.15, tvOS 13.4, watchOS 6.2
SDK de Android:
Niveles API: 23, 25, 26, 28, 29
Herramientas de compilación: 28.0.3, 29.0.2, 29.0.3
NDK de Android: no encontrado
IDE:
Android Studio: 3.6 AI-192.7142.36.36.6308749
Xcode: 11.6 / 11E708 - / usr / bin / xcodebuild
Idiomas:
Java: 1.8.0_242 - / usr / bin / javac
Python: 2.7.16 - / usr / bin / python
npm Paquetes:
@ react-native-community / cli: No encontrado
reaccionar: 16.13.1 => 16.13.1
react-nativo: 0.63.3 => 0.63.3
react-native-macos: No encontrado
npmGlobalPackages:
react-native : no encontrado

"react-native": "0.63.3",
"react-native-onesignal": "^ 4.0.1",

Excepción fatal: java.lang.NullPointerException
Intente invocar el método virtual 'org.json.JSONObject com.onesignal.OSDeviceState.toJSONObject ()' en una referencia de objeto nulo

com.geektime.rnonesignalandroid.RNOneSignal.getDeviceState (RNOneSignal.java:239)
java.lang.reflect.Method.invoke (Method.java)
com.facebook.react.bridge.JavaMethodWrapper.invoke (JavaMethodWrapper.java:372)
com.facebook.react.bridge.JavaModuleWrapper.invoke (JavaModuleWrapper.java:151)
com.facebook.react.bridge.queue.NativeRunnable.run (NativeRunnable.java)
android.os.Handler.handleCallback (Handler.java:883)
android.os.Handler.dispatchMessage (Handler.java:100)
com.facebook.react.bridge.queue.MessageQueueThreadHandler.dispatchMessage (MessageQueueThreadHandler.java:27)
android.os.Looper.loop (Looper.java:241)
com.facebook.react.bridge.queue.MessageQueueThreadImpl $ 4.run (MessageQueueThreadImpl.java:226)
java.lang.Thread.run (Thread.java:919)

Proporcione un fragmento de código para facilitar la reproducción.

Salud

@rgomezp

El error ocurre en la llamada OneSignal.getDeviceState ():

const getDeviceState =  async () => {
     const deviceState = await OneSignal.getDeviceState();
     console.log({ deviceState });
}

La excepción es:

Fatal Exception: java.lang.NullPointerException
Attempt to invoke virtual method 'org.json.JSONObject com.onesignal.OSDeviceState.toJSONObject()' on a null object reference

com.geektime.rnonesignalandroid.RNOneSignal.getDeviceState (RNOneSignal.java:239)
java.lang.reflect.Method.invoke (Method.java)
com.facebook.react.bridge.JavaMethodWrapper.invoke (JavaMethodWrapper.java:372)
com.facebook.react.bridge.JavaModuleWrapper.invoke (JavaModuleWrapper.java:151)
com.facebook.react.bridge.queue.NativeRunnable.run (NativeRunnable.java)
android.os.Handler.handleCallback (Handler.java:883)
android.os.Handler.dispatchMessage (Handler.java:100)
com.facebook.react.bridge.queue.MessageQueueThreadHandler.dispatchMessage (MessageQueueThreadHandler.java:27)
android.os.Looper.loop (Looper.java:241)
com.facebook.react.bridge.queue.MessageQueueThreadImpl$4.run (MessageQueueThreadImpl.java:226)
java.lang.Thread.run (Thread.java:919)

Los paquetes OneSignal y React Native son:

"react-native": "0.63.3",
"react-native-onesignal": "^4.0.1",
````

The react native info:

```typescript
info Fetching system and libraries information...
System:
OS: macOS 10.15.7
CPU: (4) x64 Intel(R) Core(TM) i5-5257U CPU @ 2.70GHz
Memory: 36.86 MB / 8.00 GB
Shell: 5.7.1 - /bin/zsh
Binaries:
Node: 10.22.0 - ~/.nvm/versions/node/v10.22.0/bin/node
Yarn: 1.22.4 - /usr/local/bin/yarn
npm: 6.14.6 - ~/.nvm/versions/node/v10.22.0/bin/npm
Watchman: 4.9.0 - /usr/local/bin/watchman
Managers:
CocoaPods: 1.10.0 - /usr/local/bin/pod
SDKs:
iOS SDK:
Platforms: iOS 13.6, DriverKit 19.0, macOS 10.15, tvOS 13.4, watchOS 6.2
Android SDK:
API Levels: 23, 25, 26, 28, 29
Build Tools: 28.0.3, 29.0.2, 29.0.3
Android NDK: Not Found
IDEs:
Android Studio: 3.6 AI-192.7142.36.36.6308749
Xcode: 11.6/11E708 - /usr/bin/xcodebuild
Languages:
Java: 1.8.0_242 - /usr/bin/javac
Python: 2.7.16 - /usr/bin/python
npmPackages:
@react-native-community/cli: Not Found
react: 16.13.1 => 16.13.1
react-native: 0.63.3 => 0.63.3
react-native-macos: Not Found
npmGlobalPackages:
react-native: Not Found

Obteniendo el mismo problema.

"react-native": "^ 0.63.4",
"react-native-onesignal": "^ 4.0.3"

Actualicé de "react-native-onesignal": "^ 3.9.3" a "react-native-onesignal": "^ 4.0.3". Estoy teniendo accidentes ahora. He actualizado el código de inicio igual que el anterior. Agregué recientemente.

...
let device = await OneSignal.getDeviceState ();
...

Desde Play Store Crash Log

java.lang.NullPointerException:
en com.geektime.rnonesignalandroid.RNOneSignal.getDeviceState (RNOneSignal.java)
en java.lang.reflect.Method.invoke (Method.java)
en com.facebook.react.bridge.JavaMethodWrapper.invoke (JavaMethodWrapper.java)
en com.facebook.react.bridge.JavaModuleWrapper.invoke (JavaModuleWrapper.java)
en com.facebook.react.bridge.queue.NativeRunnable.run (NativeRunnable.java)
en android.os.Handler.handleCallback (Handler.java:739)
en android.os.Handler.dispatchMessage (Handler.java:95)
en com.facebook.react.bridge.queue.MessageQueueThreadHandler.dispatchMessage (MessageQueueThreadHandler.java)
en android.os.Looper.loop (Looper.java:148)
en com.facebook.react.bridge.queue.MessageQueueThreadImpl $ 4.run (MessageQueueThreadImpl.java)
en java.lang.Thread.run (Thread.java:818)

Registro de fallos de Firebase

Excepción fatal: java.lang.NullPointerException: intento de invocar el método virtual 'org.json.JSONObject com.onesignal.g0.a ()' en una referencia de objeto nulo
en com.geektime.rnonesignalandroid.RNOneSignal.getDeviceState (RNOneSignal.java:4)
en java.lang.reflect.Method.invoke (Method.java)

Hola,
Gracias por la información, pero si alguien pudiera proporcionar un ejemplo de código, sería de gran ayuda. Esto

const getDeviceState = async () => {
const deviceState = aguardar OneSignal.getDeviceState ();
console.log ({deviceState});
}

no proporciona suficiente información para reproducir. Lo que necesitamos es más contexto sobre cómo y dónde se está utilizando.

Por ejemplo: ¿cómo se relaciona la llamada a getDeviceState con la inicialización de OneSignal? o ¿en qué función del ciclo de vida de RN se está llamando?

Asegúrese de proporcionar todo el contexto necesario para resolver esto, ya que los seguimientos de pila proporcionados no proporcionan lo que necesitamos.

Sospecho que esto podría estar sucediendo si getDeviceState se llama demasiado rápido. ¿Puede intentar mover getDeviceState a un punto en su código que esté garantizado para ejecutarse después de que se complete la inicialización de OneSignal? por ejemplo: póngalo en la devolución de llamada al observador de cambio de suscripción.

Recuerde que getDeviceState captura una instantánea en el momento en que se llama. Por esa razón, no almacene el estado en caché, sino que vuelva a obtenerlo según sea necesario.

Referencia

@rgomezp

Hola, en App.tsx, nuestro punto de entrada, tenemos:

const oneSignalIntialize = async () => {
  OneSignal.setAppId('xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx');
}

const App = () => {
  useEffect(() => {
    oneSignalIntialize();

  }, []);

return (
    <LoginFlow />
);

}

Después del flujo de inicio de sesión, si esto se realizó correctamente, tenemos una pantalla de bienvenida:

const getDeviceState = async () => {
    const deviceState = await OneSignal.getDeviceState(); 
    console.log({ deviceState });
}

const WelcomeScreen = () => {
  useEffect(() => {
    getDeviceState();

  }, []);

return (
    <Components />
);

}

Screen Shot 2021-02-18 at 10 59 35

Hola @renatobentorocha ,
¡Gracias por compartir el código con nosotros!
El gancho useEffect aquí se puede llamar para inicializar el SDK dentro del componente principal de la aplicación. Esta es esencialmente una llamada asincrónica que se llama tan pronto como se monta el componente, pero no hay un estado que verifique si la inicialización se ha completado.

Puede usar el gancho useState para agregar un estado para verificar el estado de inicio antes de mostrar la pantalla de bienvenida.

Otra recomendación, como lo sugirió @rgomezp , sería ejecutarlo en la devolución de llamada al addSubscriptionObserver (lo siento por haber hablado demasiado rápido en el obsoleto getPermissionSubscriptionState antes), lo que garantizaría que el SDK se haya inicializado correctamente antes de acceder al estado del dispositivo.

Háganos saber si esto ayuda a resolver el problema,

Gracias

Hola @ tyang1 Gracias por su atención, pero los documentos de una señal para esa devolución de llamada (getPermissionSubscriptionState) dicen:

Screen Shot 2021-02-22 at 09 07 47

Probaré con addSubscriptionObserver y les haré saber qué sucedió

Obteniendo esto también. No sé cómo reproducirse. @rgomezp ¿ quizás es un problema de subprocesos? Esto sucede al azar, pero bastante. Vemos muchos rastros de en nuestro informe de fallas.

image

Hola,
No creo que esto sea un problema de subprocesos, ya que los seguimientos de la pila apuntan a que es más probable que ocurra en el nivel del contenedor. Sin duda, esto podría ser un error. Solo necesitamos pasos de reproducción confiables para avanzar con una resolución.

Es interesante @renatobentorocha que reportes que está sucediendo en un 98% en segundo plano.

@oferRounds @dijinshopwise ¿ Es esto algo que también estás viendo?

+1

image

@rgomezp sigue el código:

async componentDidMount() {
        this._isMounted = true

        /* O N E S I G N A L   S E T U P */
        OneSignal.setAppId('***********************************')
        OneSignal.setLogLevel(0, 0)
        OneSignal.setRequiresUserPrivacyConsent(false)

        /* O N E S I G N A L  H A N D L E R S */
        OneSignal.setNotificationWillShowInForegroundHandler(notifReceivedEvent => {
            let notification = notifReceivedEvent.getNotification()

            const buttonOk = {
                text: 'OK', onPress: () => {
                    notifReceivedEvent.complete()
                },
            }

            Alert.alert(notification.title, notification.body, [buttonOk])

            if (notification.additionalData) {
                //
            }

        })
        OneSignal.setNotificationOpenedHandler(notification => {
            //
        })


        OneSignal.disablePush(true)

        const deviceState = await OneSignal.getDeviceState()

        if (Platform.OS === 'ios' && !deviceState.isSubscribed) {
            OneSignal.promptForPushNotificationsWithUserResponse(function(accepted) {
                //
            });
        }

        // ...
}

Cambié a la versión anterior y Google Play advierte sobre el mismo error.

com.geektime.rnonesignalandroid.RNOneSignal.getDeviceState

¿Cualquier sugerencia? ¿Alguna solución temporal?

Todavía estamos recibiendo cientos de estos accidentes, ¿alguna noticia?
image

@ diego-paired nuestra solución temporal fue retrasar la llamada a getDeviceState() después de la inicialización de OneSingal (agregamos 2 segundos de retraso)

@ diego-paired nuestra solución temporal fue retrasar la llamada a getDeviceState() después de la inicialización de OneSingal (agregamos 2 segundos de retraso)

gracias por el consejo

Hola @renatobentorocha ,
¡Gracias por compartir el código con nosotros!
El gancho useEffect aquí se puede llamar para inicializar el SDK dentro del componente principal de la aplicación. Esta es esencialmente una llamada asincrónica que se llama tan pronto como se monta el componente, pero no hay un estado que verifique si la inicialización se ha completado.

Puede usar el gancho useState para agregar un estado para verificar el estado de inicio antes de mostrar la pantalla de bienvenida.

Otra recomendación, como lo sugirió @rgomezp , sería ejecutarlo en la devolución de llamada al addSubscriptionObserver (lo siento por haber hablado demasiado rápido en el obsoleto getPermissionSubscriptionState antes), lo que garantizaría que el SDK se haya inicializado correctamente antes de acceder al estado del dispositivo.

Háganos saber si esto ayuda a resolver el problema,

Gracias

@ diego-emparejado @ dan-desarrollador

Seguí la sugerencia de @rgomezp y los bloqueos, por ahora, dejaron de ocurrir.

OneSignal.addSubscriptionObserver(() => {
    OneSignal.getDeviceState().then((deviceState) => {
      console.log({deviceState})
    });
  });

Usando la aplicación de prueba , agregué este código a un botón:

Situación 1

let getDeviceStateButton = this.renderButtonView(
"Get Device State",
isExternalUserIdLoading || isPrivacyConsentLoading,
() => {

console.log("Attempting to get device state");
this.setState({ isExternalUserIdLoading: true }, () => {
// OneSignal getDeviceState
let deviceState = OneSignal.getDeviceState();
console.log("deviceState: ", deviceState);
console.log("deviceState.isSubscribed: ", deviceState.isSubscribed);
this.setState({ isExternalUserIdLoading: false, isSubscribed: deviceState.isSubscribed });
console.log("this.state.isSubscribed after calling setState: ", this.state.isSubscribed);
console.log("deviceState.userId: ", deviceState.userId)
});
});

El registro muestra:

2021-03-25 20:06:14.589544-0700 jonexample[751:27269] [javascript] Attempting to get device state
2021-03-25 20:06:14.645290-0700 jonexample[751:27269] [javascript] 'deviceState: ', { _U: 0, _V: 0, _W: null, _X: null }
2021-03-25 20:06:14.647385-0700 jonexample[751:27269] [javascript] 'deviceState.isSubscribed: ', undefined
2021-03-25 20:06:14.647768-0700 jonexample[751:27269] [javascript] 'this.state.isSubscribed after calling setState: ', undefined
2021-03-25 20:06:14.647897-0700 jonexample[751:27269] [javascript] 'deviceState.userId: ', undefined

Sin embargo, al usar el código de ejemplo proporcionado en componentDidMount :

Situación 2

async componentDidMount(){
 const deviceState = await OneSignal.getDeviceState();
this.setState({ isSubscribed : deviceState.isSubscribed});
console.log("componentDidMount deviceState: ", deviceState);
console.log("componentDidMount deviceState.isSubscribed: ", deviceState.isSubscribed);
console.log("componentDidMount deviceState.userId: ", deviceState.userId);
}

El registro muestra:

2021-03-25 20:14:46.521099-0700 jonexample[1326:55465] [javascript] 'componentDidMount deviceState: ', { userId: '92aa2978-3f53-454e-b1a6-652c43f0dba4',
2021-03-25 20:14:46.521328-0700 jonexample[1326:55465] [javascript] 'componentDidMount deviceState.isSubscribed: ', true
2021-03-25 20:14:46.521435-0700 jonexample[1326:55465] [javascript] 'componentDidMount deviceState.userId: ', '92aa2978-3f53-454e-b1a6-652c43f0dba4'

@rgomezp es el comportamiento esperado del escenario 1?

@ diego-paired @renatobentorocha @ dan-developer ¿Podrían compartir sus ejemplos o confirmar si las dos situaciones anteriores es lo que ven?

Detalla cómo estás usando este método e incluye los pasos para que lo reproduzcamos.

@ jfishman1 Eche un vistazo a la documentación . Verá que getDeviceState es una función asíncrona, así que asegúrese de esperarla o de usar then .

Independientemente, parece que hay una buena oportunidad para manejar esto en el SDK para evitar estos bloqueos. Gracias por salir a la superficie. Exploraremos qué cambios se pueden hacer para manejarlos sin problemas.

Profundizando un poco más en esto, parece que la causa más probable de esto es que el lado nativo está tratando de obtener el estado del dispositivo antes de que se cargue el contexto.

if (appContext == null) {
         logger.error("OneSignal.initWithContext has not been called. Could not get OSDeviceState");
         return null;
      }

fuente

Para confirmar, busque OneSignal.initWithContext has not been called. Could not get OSDeviceState en su logcat nativo (por ejemplo: abra Android Studio).

Mientras tanto, parece que podemos agregar una marca en el puente de Android para evitar un bloqueo total.

Independientemente, tenga en cuenta:
Todavía recomendamos obtener solo el estado del dispositivo a través del observador de cambio de suscripción para garantizar que no obtenga el estado del dispositivo demasiado pronto

Gracias a todos por vuestra paciencia.


Desde # 1085:
En lugar de retrasar el captador de estado del dispositivo mediante un temporizador, intente poner la llamada a la función getDeviceState en el observador de suscripción. De esta forma, sabrás que está suscrito. p.ej:

OneSignal.addSubscriptionObserver(async (event) => {
    this.OSLog("OneSignal: subscription changed:", event);
    if (event.to.isSubscribed) {
        const state = await OneSignal.getDeviceState();
        // do something with the device state
    }
});

Actualización: esto ahora está arreglado en la última versión 4.0.7

Actualicé al último repositorio 4.0.7. No estoy seguro de si estoy preguntando en el lugar correcto, pero en algunos simuladores iOS y dispositivos Android solo obtengo estos campos con deviceState, por ejemplo, como este. Ni siquiera hay un campo userId.

{"rootTag":21,"initialProps":{}}
 WARN  {"hasNotificationPermission": false, "isEmailSubscribed": false, "isPushDisabled": false, "isSMSSubscribed": false, "isSubscribed": false, "notificationPermissionStatus": 0}
¿Fue útil esta página
0 / 5 - 0 calificaciones