Attempt to invoke virtual method 'void com.facebook.react.uimanager.UlManagerModule.onBatchComplete()' on a null object reference

オープン
#3,594 コメント 15 件 リアクション 25 件 担当者 0 名 GitHub で見る

メンテナーはふだん 1 日以内に返信

まだ誰も着手していません。

評価

難易度
4/5
見積もり時間
3〜5日
初心者へのやさしさ
35/100
issue の種類
バグ
明瞭さ
明確に書かれている
活発さ
停滞
技術スタック
android, java, react-native
領域
mobile

調査の方向性

まず、uilib-native/android/src/main/java/com/wix/reactnativeuilib/keyboardinput/utils/ 配下の react-native-ui-lib/react-native.config.js と RuntimeUtils.java を調べます。記載されている React Native とパッケージのバージョンで Android キーボードの操作を再現し、その後、両方のパッケージソースが更新され、UIManagerModule が利用できない場合にクラッシュが発生しなくなったことを確認します。

索引モデルが issue の本文から書いたものです。

説明

bug waiting-for-response

Description

Android crashes due to NullPointerException in RuntimeUtils.java when using the keyboard input features. The issue stems from the React Native UI Lib package's dependency structure for Android, where patches need to be applied to both react-native-ui-lib AND uilib-native packages.

Related to
  • Components
  • Demo
  • Docs
  • Typings
Steps to reproduce
  1. Use react-native-ui-lib in a React Native application
  2. Implement components that use keyboard-related features
  3. Run on Android
  4. App crashes with NullPointerException in RuntimeUtils.java during keyboard interaction
  5. Apply patch to react-native-ui-lib but crashes continue
Expected behavior

The app should handle keyboard interactions properly without crashing.

Actual behavior

The app crashes with errors like:

Fatal Exception: java.lang.NullPointerException
Attempt to invoke virtual method 'void com.facebook.react.uimanager.UIManagerModule.onBatchComplete()' on a null object reference
       at com.wix.reactnativeuilib.keyboardinput.utils.RuntimeUtils$1.run(RuntimeUtils.java:13)

More Info

Root Cause Analysis

The root cause of this issue is a non-obvious relationship between react-native-ui-lib and uilib-native packages.

When building the Android app, the react-native-ui-lib package doesn't use its own native Android code. Instead, it points to the uilib-native package's Android code, as configured in react-native-ui-lib/react-native.config.js:

// node_modules/react-native-ui-lib/react-native.config.js
module.exports = {
  dependency: {
    platforms: {
      android: {
        sourceDir: "../uilib-native/android/",
        // Other config...
      },
    },
  },
};

This means that patching only react-native-ui-lib doesn't affect the Android build, since it's actually using code from uilib-native.

Code snippet
Original problematic code in uilib-native:
// node_modules/uilib-native/android/src/main/java/com/wix/reactnativeuilib/keyboardinput/utils/RuntimeUtils.java
package com.wix.reactnativeuilib.keyboardinput.utils;

import com.facebook.react.uimanager.UIManagerModule;
import com.wix.reactnativeuilib.keyboardinput.ReactContextHolder;

public class RuntimeUtils {
    private static final Runnable sUIUpdateClosure = new Runnable() {
        @Override
        public void run() {
            ReactContextHolder.getContext().getNativeModule(UIManagerModule.class).onBatchComplete();
        }
    };

    public static void runOnUIThread(Runnable runnable) {
        if (ReactContextHolder.getContext() != null) {
            ReactContextHolder.getContext().runOnUiQueueThread(runnable);
        }
    }

    public static void dispatchUIUpdates(final Runnable userRunnable) {
        runOnUIThread(new Runnable() {
            @Override
            public void run() {
                userRunnable.run();
                if (ReactContextHolder.getContext() != null) {
                    ReactContextHolder.getContext().runOnNativeModulesQueueThread(sUIUpdateClosure);
                }
            }
        });
    }
}
Fixed version with proper null checks:
package com.wix.reactnativeuilib.keyboardinput.utils;

import android.util.Log;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.uimanager.UIManagerModule;
import com.wix.reactnativeuilib.keyboardinput.ReactContextHolder;

public class RuntimeUtils {
    private static final Runnable sUIUpdateClosure = new Runnable() {
        @Override
        public void run() {
            try {
                ReactContext context = ReactContextHolder.getContext();
                if (context != null) {
                    UIManagerModule uiManager = context.getNativeModule(UIManagerModule.class);
                    if (uiManager != null) {
                        uiManager.onBatchComplete();
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    };

    public static void runOnUIThread(Runnable runnable) {
        try {
            if (ReactContextHolder.getContext() != null) {
                ReactContextHolder.getContext().runOnUiQueueThread(runnable);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void dispatchUIUpdates(final Runnable userRunnable) {
        if (ReactContextHolder.getContext() == null) {
            return; // Skip if context is null
        }

        try {
            runOnUIThread(new Runnable() {
                @Override
                public void run() {
                    try {
                        // Re-check context before running user code
                        if (ReactContextHolder.getContext() != null) {
                            userRunnable.run();

                            // Get a fresh context reference before queue operation
                            ReactContext context = ReactContextHolder.getContext();
                            if (context != null) {
                                context.runOnNativeModulesQueueThread(sUIUpdateClosure);
                            }
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
Solution

To fix this issue, you need to patch both packages using patch-package:

  1. First, patch react-native-ui-lib
  2. Then, patch uilib-native
  3. Apply both patches using patch-package in your postinstall script

Example patches are provided in the code snippets above.

Verification

To verify that patches are correctly applied:

  1. Check that both package source files contain your patches
  2. Add Log statements in the patched code (like Log.d("TAG", "message"))
  3. Monitor the Android logs during app execution to confirm the patched code is running
Screenshots/Video

N/A

Environment
  • React Native version: 0.76.x
  • React Native UI Lib version: 7.38.1
  • uilib-native version: 4.5.1 (indirectly used by react-native-ui-lib)
Affected platforms
  • Android
  • iOS
  • Web

Reference: https://github.com/facebook/react-native/issues/47662

主要言語
TypeScript
スター
7.2k
フォーク
749
平均マージ
2日 4時間
マージ済み PR(30日)
4

環境構築

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

wix/react-native-ui-lib のほかの issue

wix/react-native-ui-lib の issue をすべて見る

似ている issue

TypeScript の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。