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

Créé le 6 févr. 2021  ·  28Commentaires  ·  Source: OneSignal/react-native-onesignal

La description:
Nous recevons un certain nombre de rapports de plantage provenant de RNOneSignal.getDeviceState , trace de pile jointe ci-dessous.

Il affecte toutes les versions et tous les fabricants de SDK Android.

Environnement
"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

Étapes pour reproduire le problème :
Je n'ai pas pu reproduire le problème, il est signalé sur le tableau de bord des plantages de Google Play.

Rien d'autre:

  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

Commentaire le plus utile

@diego-paired notre solution de contournement temporaire consistait à retarder l'appel à getDeviceState() après l'initialisation de OneSingal (nous avons ajouté un délai de 2 secondes)

Merci pour le conseil

Tous les 28 commentaires

+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)

Bonjour Diego,
Merci d'avoir signalé ce problème.

Pouvez-vous s'il vous plaît inclure le code que vous utilisez? Pouvez-vous également fournir des informations sur l'environnement (par exemple : marque et modèle de l'appareil, système d'exploitation, etc...) ?

Acclamations

Bonjour Diego,
Merci d'avoir signalé ce problème.

Pouvez-vous s'il vous plaît inclure le code que vous utilisez? Pouvez-vous également fournir des informations sur l'environnement (par exemple : marque et modèle de l'appareil, système d'exploitation, etc...) ?

Acclamations

Merci pour votre réponse.

Il est signalé sur notre console Google Play au rythme d'environ 50 plantages par semaine, je n'ai aucun moyen de le reproduire.

image

Pareil ici.

info Récupération des informations sur le système et les bibliothèques...
Système:
Système d'exploitation : macOS 10.15.7
Processeur : (4) processeur Intel(R) Core(TM) i5-5257U x64 à 2,70 GHz
Mémoire : 36,86 Mo / 8,00 Go
Shell : 5.7.1 - /bin/zsh
Binaires :
Nœud : 10.22.0 - ~/.nvm/versions/node/v10.22.0/bin/node
Fil : 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
Gestionnaires :
CocoaPods : 1.10.0 - /usr/local/bin/pod
SDK :
SDK iOS :
Plateformes : iOS 13.6, DriverKit 19.0, macOS 10.15, tvOS 13.4, watchOS 6.2
SDK Android :
Niveaux d'API : 23, 25, 26, 28, 29
Outils de création : 28.0.3, 29.0.2, 29.0.3
NDK Android : introuvable
IDE :
Android Studio : 3.6 AI-192.7142.36.36.6308749
Xcode : 11.6/11E708 - /usr/bin/xcodebuild
Langues :
Java : 1.8.0_242 - /usr/bin/javac
Python : 2.7.16 - /usr/bin/python
npmPaquets :
@react-native-community/cli : introuvable
réagir : 16.13.1 => 16.13.1
réactif natif : 0.63.3 => 0.63.3
react-native-macos : introuvable
npmGlobalPackages :
react-native : introuvable

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

Exception fatale : java.lang.NullPointerException
Tentative d'appel de la méthode virtuelle 'org.json.JSONObject com.onesignal.OSDeviceState.toJSONObject()' sur une référence d'objet null

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)

Veuillez fournir un extrait de code afin de faciliter la reproduction.

Acclamations

@rgomezp

L'erreur se produit dans l'appel OneSignal.getDeviceState() :

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

L'exception est :

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)

Les packages OneSignal et React Native sont :

"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

Obtenir le même problème.

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

Je suis passé de "react-native-onesignal": "^3.9.3" à "react-native-onesignal": "^4.0.3". Je reçois des plantages maintenant. J'ai mis à jour le code d'initialisation comme ci-dessus. J'ai ajouté fraîchement.

...
laisser l'appareil = attendre OneSignal.getDeviceState();
...

Depuis le journal des plantages du Play Store

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

Journal des plantages de Firebase

Exception fatale : java.lang.NullPointerException : essayez d'invoquer la méthode virtuelle 'org.json.JSONObject com.onesignal.g0.a()' sur une référence d'objet null
à com.geektime.rnonesignalandroid.RNOneSignal.getDeviceState(RNOneSignal.java:4)
à java.lang.reflect.Method.invoke(Method.java)

Salut,
Merci pour l'information, mais si quelqu'un pouvait fournir un exemple de code, ce serait très utile. Cette

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

ne fournit pas assez d'informations pour se reproduire. Ce dont nous avons besoin, c'est d'un peu plus de contexte pour savoir comment et où cela est utilisé.

Ex : quel est le rapport entre l'appel de getDeviceState et l'initialisation de OneSignal ? ou dans quelle fonction de cycle de vie RN cela est-il appelé ?

Assurez-vous de fournir tout le contexte nécessaire pour résoudre ce problème, car les traces de pile fournies ne fournissent pas tout à fait ce dont nous avons besoin.

Je soupçonne que cela pourrait se produire si getDeviceState est appelé trop rapidement. Pouvez-vous essayer de déplacer getDeviceState vers un point de votre code dont l'exécution est garantie une fois l'initialisation de OneSignal terminée ? par exemple : placez-le dans le rappel de l'observateur de changement d'abonnement.

N'oubliez pas que getDeviceState capture un instantané au moment où il est appelé. Pour cette raison, ne cachez pas l'état, mais récupérez-le plutôt si nécessaire.

Référence

@rgomezp

Bonjour, dans l'App.tsx, notre point d'entrée, nous avons :

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

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

  }, []);

return (
    <LoginFlow />
);

}

Après le flux de connexion, si cela a réussi, nous avons un écran de bienvenue :

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

Salut @renatobentorocha ,
Merci d'avoir partagé le code avec nous !
Le hook useEffect ici peut être appelé pour initialiser le SDK dans le composant principal de l'application. Il s'agit essentiellement d'un appel asynchrone qui est appelé dès que le composant est monté, mais aucun état ne vérifie si l'initialisation est terminée.
se
Vous pouvez utiliser le hook useState pour ajouter un état afin de vérifier l'état d'initialisation avant d'afficher l'écran de bienvenue.
se
Une autre recommandation, comme suggéré par @rgomezp , serait de l'exécuter dans le rappel de l'addSubscriptionObserver (désolé pour moi d'avoir parlé trop rapidement du getPermissionSubscriptionState obsolète plus tôt), ce qui garantirait que le SDK a été correctement initialisé avant d'accéder à l'état de l'appareil.
se
Faites-nous savoir si cela aide à résoudre le problème,
se
Merci
se

Salut @ tyang1 Merci par attention, mais les documents à un signal pour ce rappel (getPermissionSubscriptionState) disent :

Screen Shot 2021-02-22 at 09 07 47

Je vais tester avec addSubscriptionObserver et je vous tiendrai au courant de ce qui se passe

Obtenir cela aussi. Je ne sais pas reproduire. @rgomezp c'est peut-être un problème de threading ? Cela se produit au hasard, mais beaucoup. Nous voyons de nombreuses traces dans notre rapport de crash

image

Salut,
Je ne pense pas qu'il s'agisse d'un problème de thread, car les traces de la pile indiquent qu'il se produit plus probablement au niveau de l'encapsuleur. Cela pourrait certainement être un bug. Nous avons juste besoin d'étapes de reproduction fiables pour avancer avec une résolution.

C'est intéressant @renatobentorocha que vous

@oferRounds @dijinshopwise est-ce quelque chose que vous voyez aussi ?

+1

image

@rgomezp suivez le code :

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) {
                //
            });
        }

        // ...
}

Je rétrograde à l'ancienne version et Google Play met en garde contre la même erreur.

com.geektime.rnonesignalandroid.RNOneSignal.getDeviceState

Toute suggestion? Une solution temporaire ?

Nous recevons toujours des centaines de ces crashs, des nouvelles ?
image

@diego-paired notre solution de contournement temporaire consistait à retarder l'appel à getDeviceState() après l'initialisation de OneSingal (nous avons ajouté un délai de 2 secondes)

@diego-paired notre solution de contournement temporaire consistait à retarder l'appel à getDeviceState() après l'initialisation de OneSingal (nous avons ajouté un délai de 2 secondes)

Merci pour le conseil

Salut @renatobentorocha ,
Merci d'avoir partagé le code avec nous !
Le hook useEffect ici peut être appelé pour initialiser le SDK dans le composant principal de l'application. Il s'agit essentiellement d'un appel asynchrone qui est appelé dès que le composant est monté, mais aucun état ne vérifie si l'initialisation est terminée.
se
Vous pouvez utiliser le hook useState pour ajouter un état afin de vérifier l'état d'initialisation avant d'afficher l'écran de bienvenue.
se
Une autre recommandation, comme suggéré par @rgomezp , serait de l'exécuter dans le rappel de l'addSubscriptionObserver (désolé pour moi d'avoir parlé trop rapidement du getPermissionSubscriptionState obsolète plus tôt), ce qui garantirait que le SDK a été correctement initialisé avant d'accéder à l'état de l'appareil.
se
Faites-nous savoir si cela aide à résoudre le problème,
se
Merci

@diego-paired @dan-developer

J'ai suivi la suggestion de @rgomezp et les plantages, pour l'instant, se sont arrêtés.

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

À l'aide de l' application de test , ajoutez ce code à un bouton :

Situation 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)
});
});

Le journal affiche :

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

Cependant, lors de l'utilisation de l' exemple de code fourni dans componentDidMount :

Situation 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);
}

Le journal indique :

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 est le comportement attendu du scénario 1 ?

@diego-paired @renatobentorocha @dan-developer pourriez-vous tous partager vos exemples ou confirmer si les deux situations ci-dessus sont ce que vous voyez ?

Veuillez être détaillé dans la façon dont vous utilisez cette méthode et inclure des étapes pour que nous puissions reproduire.

@jfishman1 Jetez un œil à la documentation . Vous verrez que getDeviceState est une fonction asynchrone alors assurez-vous d'attendre dessus, ou d'utiliser un then .

Quoi qu'il en soit, il semble qu'il existe une bonne opportunité de gérer cela dans le SDK pour éviter ces plantages. Merci d'avoir fait surface. Nous explorerons les changements qui peuvent être apportés pour les gérer de manière plus transparente.

En creusant un peu plus loin, il semble que la cause la plus probable est que le côté natif essaie d'obtenir l'état du périphérique avant que le contexte ne soit chargé.

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

la source

Pour confirmer, veuillez rechercher OneSignal.initWithContext has not been called. Could not get OSDeviceState dans votre logcat natif (par exemple : ouvrez Android Studio).

En attendant, il semble que nous puissions ajouter une vérification dans le pont Android pour éviter un plantage complet.

Quoi qu'il en soit, veuillez noter :
Nous vous recommandons toujours d'obtenir l'état de l'appareil uniquement via l'observateur de changement d'abonnement pour vous assurer que vous n'obtenez pas l'état de l'appareil trop tôt.

Merci de votre patience à tous.


À partir du #1085 :
Au lieu de retarder l'obtention de l'état du périphérique via une minuterie, essayez de placer l'appel de fonction getDeviceState dans l'observateur d'abonnement. De cette façon, vous saurez qu'il est abonné. par exemple:

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
    }
});

Mise à jour : ceci est désormais corrigé dans la dernière version 4.0.7

J'ai mis à jour le dernier repo 4.0.7. Je ne sais pas si je demande au bon endroit, mais sur certains simulateurs iOS et appareils Android, je n'obtiens même que ces champs avec deviceState par exemple comme celui-ci. Il n'y a même pas de champ userId.

{"rootTag":21,"initialProps":{}}
 WARN  {"hasNotificationPermission": false, "isEmailSubscribed": false, "isPushDisabled": false, "isSMSSubscribed": false, "isSubscribed": false, "notificationPermissionStatus": 0}
Cette page vous a été utile?
0 / 5 - 0 notes