React-native-onesignal: [クラッシュ] [Android] getDeviceStateのNullPointerException

作成日 2021年02月06日  ·  28コメント  ·  ソース: OneSignal/react-native-onesignal

説明:
RNOneSignal.getDeviceStateから発生した多数のクラッシュレポートを受け取っています。スタックトレースは以下に添付されています。

これは、すべてのAndroidSDKのバージョンとメーカーに影響します。

環境
"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

問題を再現する手順:
問題を再現できませんでした。GooglePlayのクラッシュダッシュボードで報告されています。

他に何か:

  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

最も参考になるコメント

@ diego-pairedの一時的な回避策は、OneSingalの初期化後にgetDeviceState()への呼び出しを遅らせること

ヒントをありがとう

全てのコメント28件

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

ハウディディエゴ、
この問題を報告していただきありがとうございます。

使用しているコードを含めていただけますか? また、環境情報(例:デバイスのメーカーとモデル、OSなど)を提供していただけますか?

乾杯

ハウディディエゴ、
この問題を報告していただきありがとうございます。

使用しているコードを含めていただけますか? また、環境情報(例:デバイスのメーカーとモデル、OSなど)を提供していただけますか?

乾杯

お返事をありがとうございます。

Google Play Consoleで、週に約50回のクラッシュが報告されていますが、再現する方法がありません。

image

こっちも一緒。

infoシステムとライブラリの情報を取得しています。
システム:
OS:macOS 10.15.7
CPU:(4)x64 Intel(R)Core(TM)i5-5257U CPU @ 2.70GHz
メモリ:36.86 MB / 8.00 GB
シェル:5.7.1- / bin / zsh
バイナリ:
ノード:10.22.0-〜 / .nvm / versions / node / v10.22.0 / bin / node
毛糸:1.22.4- / usr / local / bin / yarn
npm:6.14.6-〜 / .nvm / versions / node / v10.22.0 / bin / npm
ウォッチマン:4.9.0- / usr / local / bin / watchman
マネージャー:
CocoaPods:1.10.0- / usr / local / bin / pod
SDK:
iOS SDK:
プラットフォーム:iOS 13.6、DriverKit 19.0、macOS 10.15、tvOS 13.4、watchOS 6.2
Android SDK:
APIレベル:23、25、26、28、29
ビルドツール:28.0.3、29.0.2、29.0.3
Android NDK:見つかりません
IDE:
Android Studio:3.6 AI-192.7142.36.36.6308749
Xcode:11.6 / 11E708- / usr / bin / xcodebuild
言語:
Java:1.8.0_242- / usr / bin / javac
Python:2.7.16- / usr / bin / python
npmPackages:
@ react-native-community / cli:見つかりません
反応:16.13.1 => 16.13.1
反応ネイティブ:0.63.3 => 0.63.3
react-native-macos:見つかりません
npmGlobalPackages:
react-native :見つかりません

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

致命的な例外:java.lang.NullPointerException
nullオブジェクト参照で仮想メソッド 'org.json.JSONObject com.onesignal.OSDeviceState.toJSONObject()'を呼び出そうとしました

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)

複製を容易にするために、コードスニペットを提供してください。

乾杯

@rgomezp

OneSignal.getDeviceState()呼び出しでエラーが発生します:

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

例外は次のとおりです。

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)

OneSignalおよびReactNativeパッケージは次のとおりです。

"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

同じ問題が発生します。

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

「react-native-onesignal」:「^ 3.9.3」から「react-native-onesignal」:「^ 4.0.3」にアップグレードしました。 私は今クラッシュしています。 上記と同じinitコードを更新しました。 新たに追加しました。

..。
デバイス= await OneSignal.getDeviceState();
..。

Playストアのクラッシュログから

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

Firebaseクラッシュログ

致命的な例外:java.lang.NullPointerException:nullオブジェクト参照で仮想メソッド 'org.json.JSONObject com.onesignal.g0.a()'を呼び出そうとしました
com.geektime.rnonesignalandroid.RNOneSignal.getDeviceState(RNOneSignal.java:4)で
java.lang.reflect.Method.invoke(Method.java)で

ハウディ、
情報をありがとうございますが、誰かが最も役立つコード例を提供できれば。 この

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

再現するのに十分な情報を提供していません。 必要なのは、これがどのように、どこで使用されているかについてのもう少しのコンテキストです。

例: getDeviceStateの呼び出しは、OneSignalの初期化とどのように関連していますか? または、これはどのRNライフサイクル関数で呼び出されていますか?

提供されたスタックトレースは必要なものを完全に提供していないため、これを解決するために必要なすべてのコンテキストを必ず提供してください。

getDeviceState呼び出しが速すぎると、これが発生している可能性があります。 OneSignalの初期化が完了した後に実行されることが保証されているコード内のポイントにgetDeviceStateを移動してみてください。 例:サブスクリプション変更オブザーバーへのコールバックに入れます。

getDeviceStateは、呼び出されたときにスナップショットをキャプチャすることに注意してください。 そのため、状態をキャッシュするのではなく、必要に応じて再取得します。

参照

@rgomezp

こんにちは。エントリポイントであるApp.tsxには、次のものがあります。

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

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

  }, []);

return (
    <LoginFlow />
);

}

ログインフローの後、これが成功した場合、ウェルカム画面が表示されます。

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

こんにちは@renatobentorocha
コードを共有していただきありがとうございます。
ここでのuseEffectフックは、メインのAppコンポーネント内でSDKを初期化するために呼び出すことができます。 これは基本的に、コンポーネントがマウントされるとすぐに呼び出される非同期呼び出しですが、初期化が完了したかどうかを確認する状態はありません。

useStateフックを使用して状態を追加し、ようこそ画面をレンダリングする前に初期化ステータスを確認できます。

@rgomezpによって提案されているように、別の推奨事項は、

これが問題の解決に役立つかどうかをお知らせください。

ありがとう

こんにちは@ tyang1注意していただきありがとうございますが、そのコールバック(getPermissionSubscriptionState)のワンシグナルドキュメントは次のように述べています。

Screen Shot 2021-02-22 at 09 07 47

addSubscriptionObserverテストし、何が起こるかをお知らせします

これも取得します。 再現方法がわからない。 @rgomezpおそらくスレッドの問題ですか? これはランダムに発生しますが、かなり多く発生します。 クラッシュレポートに多くの痕跡が見られます

image

ハウディ、
スタックトレースはラッパーレベルで発生する可能性が高いことを示しているため、これはスレッドの問題ではないと思います。 これは確かにバグである可能性があります。 解決策を進めるには、信頼できる複製手順が必要です。

@renatobentorochaが、バックグラウンドで98%

@oferRounds @dijinshopwiseこれもあなたが見ているものですか?

+1

image

@rgomezpはコードに従います:

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

        // ...
}

古いバージョンにダウングレードすると、GooglePlayが同じエラーについて警告します。

com.geektime.rnonesignalandroid.RNOneSignal.getDeviceState

なにか提案を? 一時的な解決策はありますか?

私たちはまだ何百ものこれらのクラッシュを受け取っています、何かニュースはありますか?
image

@ diego-pairedの一時的な回避策は、OneSingalの初期化後にgetDeviceState()への呼び出しを遅らせること

@ diego-pairedの一時的な回避策は、OneSingalの初期化後にgetDeviceState()への呼び出しを遅らせること

ヒントをありがとう

こんにちは@renatobentorocha
コードを共有していただきありがとうございます。
ここでのuseEffectフックは、メインのAppコンポーネント内でSDKを初期化するために呼び出すことができます。 これは基本的に、コンポーネントがマウントされるとすぐに呼び出される非同期呼び出しですが、初期化が完了したかどうかを確認する状態はありません。

useStateフックを使用して状態を追加し、ようこそ画面をレンダリングする前に初期化ステータスを確認できます。

@rgomezpによって提案されているように、別の推奨事項は、

これが問題の解決に役立つかどうかをお知らせください。

ありがとう

@ diego-paired @ dan-developer

@rgomezpの提案に従いましたが、クラッシュは今のところ停止しています。

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

テストアプリを使用して、次のコードをボタンに追加しました。

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

ログは次のことを示しています。

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

ただし、componentDidMountで提供されている場合

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

ログは次のことを示しています。

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はシナリオ1の予想される動作ですか?

@ diego-paired @renatobentorocha @ dan-developerはあなたの例を共有したり、上記の両方の状況があなたが見ているものであるかどうかを確認したりできますか?

この方法をどのように使用しているかを詳しく説明し、再現するための手順を含めてください。

@ jfishman1ドキュメントをご覧ください。 getDeviceStateは非同期関数であることがわかりますので、必ず待つか、 then

とにかく、これらのクラッシュを回避するために、SDKでこれを処理する良い機会があるようです。 浮上してくれてありがとう。 これらをよりシームレスに処理するためにどのような変更を加えることができるかを探ります。

これをもう少し掘り下げてみると、これの最も可能性の高い原因は、ネイティブ側がコンテキストがロードされる前にデバイスの状態を取得しようとしていることであるように見えます。

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

ソース

確認するには、ネイティブlogcatでOneSignal.initWithContext has not been called. Could not get OSDeviceStateを探してください(例:Android Studioを開きます)。

それまでの間、Androidブリッジにチェックを追加して、クラッシュ時にフルになるのを防ぐことができるようです。

とにかく、注意してください:
デバイスの状態が早すぎないように、サブスクリプション変更オブザーバーを介してのみデバイスの状態を取得することをお勧めします。

しばらくお待ちいただきますようお願いいたします。


#1085から:
タイマーを介してデバイス状態ゲッターを遅らせる代わりに、サブスクリプションオブザーバーにgetDeviceState関数呼び出しを入れてみてください。 このように、あなたはそれが購読されていることを知るでしょう。 例えば:

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

更新:これは最新バージョン4.0.7で修正されました

最新の4.0.7リポジトリに更新しました。 適切な場所で質問しているかどうかはわかりませんが、一部のiOSシミュレーターとAndroidデバイスでは、たとえばこのようなdeviceStateでのみこれらのフィールドを取得します。 userIdフィールドもありません。

{"rootTag":21,"initialProps":{}}
 WARN  {"hasNotificationPermission": false, "isEmailSubscribed": false, "isPushDisabled": false, "isSMSSubscribed": false, "isSubscribed": false, "notificationPermissionStatus": 0}
このページは役に立ちましたか?
0 / 5 - 0 評価