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

Criado em 6 fev. 2021  ·  28Comentários  ·  Fonte: OneSignal/react-native-onesignal

Descrição:
Estamos recebendo vários relatórios de falha originados em RNOneSignal.getDeviceState , rastreamento de pilha anexado abaixo.

Afeta todas as versões e fabricantes do Android SDK.

Meio 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

Etapas para reproduzir o problema:
Não foi possível reproduzir o problema, ele é relatado no painel de travamento do Google Play.

Algo mais:

  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

Comentários muito úteis

@diego-emparelhou nossa solução temporária foi atrasar a chamada para getDeviceState() após a inicialização do OneSingal (adicionamos um atraso de 2 segundos)

Obrigado pela dica

Todos 28 comentários

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

Olá Diego,
Obrigado por comunicar este problema.

Você pode incluir o código que está usando? Além disso, você pode fornecer informações sobre o ambiente (por exemplo: marca e modelo do dispositivo, sistema operacional, etc ...)?

Saúde

Olá Diego,
Obrigado por comunicar este problema.

Você pode incluir o código que está usando? Além disso, você pode fornecer informações sobre o ambiente (por exemplo: marca e modelo do dispositivo, sistema operacional, etc ...)?

Saúde

Obrigado pela sua resposta.

Está sendo relatado em nosso console do Google Play a uma taxa de cerca de 50 falhas por semana, não tenho como reproduzi-lo.

image

Mesmo aqui.

Informações Buscando informações do sistema e das bibliotecas ...
Sistema:
SO: macOS 10.15.7
CPU: (4) x64 Intel (R) Core (TM) i5-5257U CPU @ 2,70 GHz
Memória: 36,86 MB / 8,00 GB
Shell: 5.7.1 - / bin / zsh
Binários:
Nó: 10.22.0 - ~ / .nvm / versions / node / v10.22.0 / bin / node
Fio: 1.22.4 - / usr / local / bin / yarn
npm: 6.14.6 - ~ / .nvm / versions / node / v10.22.0 / bin / npm
Vigia: 4.9.0 - / usr / local / bin / vigilante
Gestores:
CocoaPods: 1.10.0 - / usr / local / bin / pod
SDKs:
iOS SDK:
Plataformas: iOS 13.6, DriverKit 19.0, macOS 10.15, tvOS 13.4, watchOS 6.2
Android SDK:
Níveis API: 23, 25, 26, 28, 29
Ferramentas de construção: 28.0.3, 29.0.2, 29.0.3
Android NDK: não encontrado
IDEs:
Android Studio: 3.6 AI-192.7142.36.36.6308749
Xcode: 11.6 / 11E708 - / usr / bin / xcodebuild
Línguas:
Java: 1.8.0_242 - / usr / bin / javac
Python: 2.7.16 - / usr / bin / python
npmPacotes:
@ react-native-community / cli: Não encontrado
reagir: 16.13.1 => 16.13.1
reagente nativo: 0,63,3 => 0,63,3
react-native-macos: Não encontrado
npmGlobalPackages:
reagente nativo : não encontrado

"reagir nativo": "0,63,3",
"react-native-onesignal": "^ 4.0.1",

Exceção fatal: java.lang.NullPointerException
Tentativa de invocar o método virtual 'org.json.JSONObject com.onesignal.OSDeviceState.toJSONObject ()' em uma referência 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)

Forneça um snippet de código para facilitar a reprodução.

Saúde

@rgomezp

O erro ocorre na chamada OneSignal.getDeviceState ():

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

A exceção é:

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)

Os pacotes OneSignal e React Native são:

"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

Obtendo o mesmo problema.

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

Eu atualizei de "react-native-onesignal": "^ 3.9.3" para "react-native-onesignal": "^ 4.0.3". Estou tendo travamentos agora. Eu atualizei o código init igual ao anterior. Eu adicionei recentemente.

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

Do registro de falhas da Play Store

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

Firebase Crash log

Exceção fatal: java.lang.NullPointerException: tentativa de invocar o método virtual 'org.json.JSONObject com.onesignal.g0.a ()' em uma referência de objeto nulo
em com.geektime.rnonesignalandroid.RNOneSignal.getDeviceState (RNOneSignal.java:4)
em java.lang.reflect.Method.invoke (Method.java)

Olá,
Obrigado pela informação, mas se alguém pudesse fornecer um exemplo de código, isso seria muito útil. Esta

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

não fornece informações suficientes para reproduzir. O que precisamos é um pouco mais de contexto sobre como e onde isso está sendo usado.

Por exemplo: como a chamada para getDeviceState relaciona com a inicialização do OneSignal? ou em qual função de ciclo de vida RN isso está sendo chamado?

Certifique-se de fornecer todo o contexto necessário para resolver isso, pois os rastreamentos de pilha fornecidos não fornecem exatamente o que precisamos.

Suspeito que isso possa estar acontecendo se getDeviceState for chamado muito rapidamente. Você pode tentar mover getDeviceState para um ponto em seu código que tem garantia de execução após a conclusão da inicialização do OneSignal? por exemplo: coloque-o no retorno de chamada para o observador de alteração de assinatura.

Lembre-se de que getDeviceState captura um instantâneo no momento em que é chamado. Por esse motivo, não armazene o estado em cache, mas recupere-o conforme necessário.

Referência

@rgomezp

Olá, no App.tsx, nosso ponto de entrada, temos:

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

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

  }, []);

return (
    <LoginFlow />
);

}

Após o fluxo de login, se for bem sucedido, temos uma tela de boas-vindas:

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

Olá @renatobentorocha ,
Obrigado por compartilhar o código conosco!
O gancho useEffect aqui pode ser chamado para inicializar o SDK no componente principal do aplicativo. Esta é essencialmente uma chamada assíncrona que é chamada assim que o componente é montado, mas não há estado que verifica se a inicialização foi concluída.

Você pode usar o gancho useState para adicionar um estado para verificar o status do init antes de renderizar a tela de boas-vindas.

Outra recomendação, conforme sugerido por @rgomezp , seria executá-lo no retorno de chamada para addSubscriptionObserver (desculpe falar muito rápido sobre o obsoleto getPermissionSubscriptionState anterior), o que garantiria que o SDK foi inicializado com sucesso antes de acessar o estado do dispositivo.

Deixe-nos saber se isso ajuda a resolver o problema,

Obrigado

Olá @ tyang1 Obrigado pela atenção, mas os documentos de um sinal para esse retorno de chamada (getPermissionSubscriptionState) dizem:

Screen Shot 2021-02-22 at 09 07 47

Vou testar com addSubscriptionObserver e vou deixar você saber o que acontecer

Pegando isso também. Não sei como reproduzir. @rgomezp talvez seja um problema de threading? Isso acontece de forma aleatória, mas bastante. Vemos muitos traços em nosso relatório de falha

image

Olá,
Não acho que seja um problema de threading, pois os rastreamentos de pilha apontam para que ele ocorra mais provavelmente no nível do wrapper. Isso certamente pode ser um bug. Precisamos apenas de etapas de reprodução confiáveis ​​para avançar com uma resolução.

É interessante @renatobentorocha que você relate que está acontecendo 98% em background.

@oferRounds @dijinshopwise, isso é algo que você também está vendo?

+1

image

@rgomezp siga o 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) {
                //
            });
        }

        // ...
}

Eu faço o downgrade para uma versão antiga e o Google Play avisa sobre o mesmo erro.

com.geektime.rnonesignalandroid.RNOneSignal.getDeviceState

Alguma sugestão? Alguma solução temporária?

Ainda estamos recebendo centenas dessas falhas, alguma notícia?
image

@diego-emparelhou nossa solução temporária foi atrasar a chamada para getDeviceState() após a inicialização do OneSingal (adicionamos um atraso de 2 segundos)

@diego-emparelhou nossa solução temporária foi atrasar a chamada para getDeviceState() após a inicialização do OneSingal (adicionamos um atraso de 2 segundos)

Obrigado pela dica

Olá @renatobentorocha ,
Obrigado por compartilhar o código conosco!
O gancho useEffect aqui pode ser chamado para inicializar o SDK no componente principal do aplicativo. Esta é essencialmente uma chamada assíncrona que é chamada assim que o componente é montado, mas não há estado que verifica se a inicialização foi concluída.

Você pode usar o gancho useState para adicionar um estado para verificar o status do init antes de renderizar a tela de boas-vindas.

Outra recomendação, conforme sugerido por @rgomezp , seria executá-lo no retorno de chamada para addSubscriptionObserver (desculpe falar muito rápido sobre o obsoleto getPermissionSubscriptionState anterior), o que garantiria que o SDK foi inicializado com sucesso antes de acessar o estado do dispositivo.

Deixe-nos saber se isso ajuda a resolver o problema,

Obrigado

@ diego-parired @ dan-developer

Segui a sugestão do @rgomezp e os travamentos, por enquanto, pararam de ocorrer.

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

Usando o aplicativo de teste , adicionou este código a um botão:

Situação 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)
});
});

Log mostra:

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

No entanto, ao usar o código de exemplo fornecido no componentDidMount :

Situação 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);
}

O log mostra:

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 é o comportamento esperado do cenário 1?

@ diego- parired @renatobentorocha @ dan-developer vocês poderiam compartilhar seus exemplos ou confirmar se as duas situações acima são o que vocês veem?

Por favor, seja detalhado sobre como você está usando este método e inclua etapas para que possamos reproduzir.

@ jfishman1 Dê uma olhada na documentação . Você verá que getDeviceState é uma função assíncrona, portanto, espere por ela ou use um then .

Independentemente disso, parece que há uma boa oportunidade de lidar com isso no SDK para evitar essas falhas. Obrigado por aparecer. Exploraremos as mudanças que podem ser feitas para lidar com isso de maneira mais integrada.

Analisando um pouco mais a fundo, parece que a causa mais provável disso é que o lado nativo está tentando obter o estado do dispositivo antes que o contexto seja carregado.

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

fonte

Para confirmar, procure OneSignal.initWithContext has not been called. Could not get OSDeviceState em seu logcat nativo (por exemplo: abra o Android Studio).

Enquanto isso, parece que podemos adicionar uma verificação na ponte Android para evitar um travamento total.

Independentemente disso, observe:
Ainda recomendamos obter apenas o estado do dispositivo por meio do observador de alteração de assinatura para garantir que você não obtenha o estado do dispositivo muito cedo

Obrigado por sua paciência a todos.


De # 1085:
Em vez de atrasar o getter de estado do dispositivo por meio de um cronômetro, tente colocar a chamada de função getDeviceState no observador de assinatura. Assim, você saberá que está inscrito. por exemplo:

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

Atualização: isso agora foi corrigido na última versão 4.0.7

Eu atualizei para o repo 4.0.7 mais recente. Não tenho certeza se estou perguntando no lugar certo, mas em alguns simuladores iOS e dispositivos Android eu só recebo esses campos com deviceState, por exemplo, como este. Não há nem campo userId.

{"rootTag":21,"initialProps":{}}
 WARN  {"hasNotificationPermission": false, "isEmailSubscribed": false, "isPushDisabled": false, "isSMSSubscribed": false, "isSubscribed": false, "notificationPermissionStatus": 0}
Esta página foi útil?
0 / 5 - 0 avaliações