Skip to content

NullPointerException: context must not be null #378

@Daniabbasi25

Description

@Daniabbasi25

Hi! 👋

Firstly, thanks for your work on this project! 🙂

Today I used patch-package to patch @hmscore/react-native-hms-safetydetect@6.7.0-300 for the project I'm working on.

Problem Description

I'm experiencing a NullPointerException: context must not be null crash when calling HMSHuaweiApi.isHuaweiMobileServicesAvailable() in my React Native Android app. This occurs when the method is called early in the app lifecycle (e.g., in useEffect hooks or notification handlers) before the React Native context is fully initialized.

Error Stack Trace:

Fatal Exception: java.lang.NullPointerException: context must not be null
at com.huawei.hms.utils.Checker.checkNonNull(Checker.java:2)
at com.huawei.hms.api.HuaweiApiAvailabilityImpl.isHuaweiMobileServicesAvailable(HuaweiApiAvailabilityImpl.java:1)
at com.huawei.hms.rn.safetydetect.huaweiapi.HuaweiApiService.isHuaweiMobileServicesAvailable(HuaweiApiService.java:30)
at com.huawei.hms.rn.safetydetect.huaweiapi.HuaweiApiModule.isHuaweiMobileServicesAvailable(HuaweiApiModule.java:42)

Root Cause:
The getCurrentActivity() method in HuaweiApiModule.java can return null when called before the React Native bridge is fully initialized or when the app is in the background. This null value is then passed directly to the HMS SDK, which throws a NullPointerException because it requires a non-null context.

When It Happens:

  • During app initialization in useEffect hooks
  • When handling foreground/background notifications
  • When the app is transitioning between states
  • Before the React Native Activity context is ready

Solution

I've created a patch that adds proper null checks and gracefully handles the null context scenario by:

  1. Checking if getCurrentActivity() returns null
  2. Falling back to getReactApplicationContext() when Activity is null (Application context is always available)
  3. Adding null checks and exception handling in HuaweiApiService.java
  4. Returning false gracefully instead of crashing when context is unavailable

Here is the diff that solved my problem:

diff --git a/node_modules/@hmscore/react-native-hms-safetydetect/android/src/main/java/com/huawei/hms/rn/safetydetect/huaweiapi/HuaweiApiModule.java b/node_modules/@hmscore/react-native-hms-safetydetect/android/src/main/java/com/huawei/hms/rn/safetydetect/huaweiapi/HuaweiApiModule.java
index b9281b3..ef19cfb 100644
--- a/node_modules/@hmscore/react-native-hms-safetydetect/android/src/main/java/com/huawei/hms/rn/safetydetect/huaweiapi/HuaweiApiModule.java
+++ b/node_modules/@hmscore/react-native-hms-safetydetect/android/src/main/java/com/huawei/hms/rn/safetydetect/huaweiapi/HuaweiApiModule.java
@@ -39,7 +39,14 @@ public class HuaweiApiModule extends ReactContextBaseJavaModule {
     @ReactMethod
     public void isHuaweiMobileServicesAvailable(Promise promise) {
         hmsLogger.sendSingleEvent("isHuaweiMobileServicesAvailable");
-        huaweiApiService.isHuaweiMobileServicesAvailable(getCurrentActivity(), promise);
+        // Check if current activity is available, fallback to application context if null
+        android.app.Activity activity = getCurrentActivity();
+        if (activity == null) {
+            // If activity is null, use application context as fallback
+            huaweiApiService.isHuaweiMobileServicesAvailable(getReactApplicationContext(), promise);
+        } else {
+            huaweiApiService.isHuaweiMobileServicesAvailable(activity, promise);
+        }
     }
 
     @ReactMethod
diff --git a/node_modules/@hmscore/react-native-hms-safetydetect/android/src/main/java/com/huawei/hms/rn/safetydetect/huaweiapi/HuaweiApiService.java b/node_modules/@hmscore/react-native-hms-safetydetect/android/src/main/java/com/huawei/hms/rn/safetydetect/huaweiapi/HuaweiApiService.java
index 28d60f2..cdc6801 100644
--- a/node_modules/@hmscore/react-native-hms-safetydetect/android/src/main/java/com/huawei/hms/rn/safetydetect/huaweiapi/HuaweiApiService.java
+++ b/node_modules/@hmscore/react-native-hms-safetydetect/android/src/main/java/com/huawei/hms/rn/safetydetect/huaweiapi/HuaweiApiService.java
@@ -17,6 +17,7 @@ limitations under the License.
 package com.huawei.hms.rn.safetydetect.huaweiapi;
 
 import android.app.Activity;
+import android.content.Context;
 import android.util.Log;
 
 import com.facebook.react.bridge.Promise;
@@ -27,11 +28,45 @@ public class HuaweiApiService {
     private final String TAG = HuaweiApiService.class.getSimpleName();
 
     public void isHuaweiMobileServicesAvailable(Activity activity, Promise promise) {
-        if (HuaweiApiAvailability.getInstance().isHuaweiMobileServicesAvailable(activity) == ConnectionResult.SUCCESS) {
-            Log.i(TAG, "HMS is Available");
-            promise.resolve(true);
-        } else {
-            Log.e(TAG, "ERROR: Unavailable. Please update your HMS");
+        // Handle null activity by returning false gracefully
+        if (activity == null) {
+            Log.w(TAG, "Activity context is null, returning false");
+            promise.resolve(false);
+            return;
+        }
+        
+        try {
+            if (HuaweiApiAvailability.getInstance().isHuaweiMobileServicesAvailable(activity) == ConnectionResult.SUCCESS) {
+                Log.i(TAG, "HMS is Available");
+                promise.resolve(true);
+            } else {
+                Log.e(TAG, "ERROR: Unavailable. Please update your HMS");
+                promise.resolve(false);
+            }
+        } catch (Exception e) {
+            Log.e(TAG, "Error checking HMS availability: " + e.getMessage());
+            promise.resolve(false);
+        }
+    }
+
+    public void isHuaweiMobileServicesAvailable(Context context, Promise promise) {
+        // Handle null context by returning false gracefully
+        if (context == null) {
+            Log.w(TAG, "Context is null, returning false");
+            promise.resolve(false);
+            return;
+        }
+        
+        try {
+            if (HuaweiApiAvailability.getInstance().isHuaweiMobileServicesAvailable(context) == ConnectionResult.SUCCESS) {
+                Log.i(TAG, "HMS is Available");
+                promise.resolve(true);
+            } else {
+                Log.e(TAG, "ERROR: Unavailable. Please update your HMS");
+                promise.resolve(false);
+            }
+        } catch (Exception e) {
+            Log.e(TAG, "Error checking HMS availability: " + e.getMessage());
             promise.resolve(false);
         }
     }
 }

Benefits of This Fix

  1. Prevents crashes: The app no longer crashes when getCurrentActivity() returns null
  2. Graceful degradation: Returns false instead of throwing an exception when context is unavailable
  3. Better error handling: Wraps HMS SDK calls in try-catch blocks to handle any unexpected exceptions
  4. Fallback mechanism: Uses Application context when Activity context is not available
  5. Backward compatible: Doesn't change the API contract - still returns a boolean promise

Request

Could this fix be incorporated into the main package? This would prevent other developers from experiencing the same crash and improve the overall stability of the library.

Thank you for your consideration! 🙏

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions