在编译公司自定义的一个 react native Android 组件时,出现 ReactContext 的 getCurrentActivity() 方法不是 public

居然提示 getCurrentActivity() 方法不是 public 的,于是我点进去看了一下 ReactContext 的代码

/**
 * Copyright (c) 2015-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */

package com.facebook.react.bridge;

import javax.annotation.Nullable;

import java.util.concurrent.CopyOnWriteArraySet;

import android.app.Activity;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
import android.os.Bundle;
import android.view.LayoutInflater;

import com.facebook.infer.annotation.Assertions;
import com.facebook.react.bridge.queue.ReactQueueConfiguration;
import com.facebook.react.bridge.queue.MessageQueueThread;

/**
 * Abstract ContextWrapper for Android applicaiton or activity {@link Context} and
 * {@link CatalystInstance}
 */
public class ReactContext extends ContextWrapper {

  private final CopyOnWriteArraySet<LifecycleEventListener> mLifecycleEventListeners =
      new CopyOnWriteArraySet<>();
  private final CopyOnWriteArraySet<ActivityEventListener> mActivityEventListeners =
      new CopyOnWriteArraySet<>();

  private @Nullable CatalystInstance mCatalystInstance;
  private @Nullable LayoutInflater mInflater;
  private @Nullable MessageQueueThread mUiMessageQueueThread;
  private @Nullable MessageQueueThread mNativeModulesMessageQueueThread;
  private @Nullable MessageQueueThread mJSMessageQueueThread;
  private @Nullable NativeModuleCallExceptionHandler mNativeModuleCallExceptionHandler;
  private @Nullable Activity mCurrentActivity;

  public ReactContext(Context base) {
    super(base);
  }

  /**
   * Set and initialize CatalystInstance for this Context. This should be called exactly once.
   */
  public void initializeWithInstance(CatalystInstance catalystInstance) {
    if (catalystInstance == null) {
      throw new IllegalArgumentException("CatalystInstance cannot be null.");
    }
    if (mCatalystInstance != null) {
      throw new IllegalStateException("ReactContext has been already initialized");
    }

    mCatalystInstance = catalystInstance;

    ReactQueueConfiguration queueConfig = catalystInstance.getReactQueueConfiguration();
    mUiMessageQueueThread = queueConfig.getUIQueueThread();
    mNativeModulesMessageQueueThread = queueConfig.getNativeModulesQueueThread();
    mJSMessageQueueThread = queueConfig.getJSQueueThread();
  }

  public void setNativeModuleCallExceptionHandler(
      @Nullable NativeModuleCallExceptionHandler nativeModuleCallExceptionHandler) {
    mNativeModuleCallExceptionHandler = nativeModuleCallExceptionHandler;
  }

  // We override the following method so that views inflated with the inflater obtained from this
  // context return the ReactContext in #getContext(). The default implementation uses the base
  // context instead, so it couldn't be cast to ReactContext.
  // TODO: T7538796 Check requirement for Override of getSystemService ReactContext
  @Override
  public Object getSystemService(String name) {
    if (LAYOUT_INFLATER_SERVICE.equals(name)) {
      if (mInflater == null) {
        mInflater = LayoutInflater.from(getBaseContext()).cloneInContext(this);
      }
      return mInflater;
    }
    return getBaseContext().getSystemService(name);
  }

  /**
   * @return handle to the specified JS module for the CatalystInstance associated with this Context
   */
  public <T extends JavaScriptModule> T getJSModule(Class<T> jsInterface) {
    if (mCatalystInstance == null) {
      throw new RuntimeException("Trying to invoke JS before CatalystInstance has been set!");
    }
    return mCatalystInstance.getJSModule(jsInterface);
  }

  /**
   * @return the instance of the specified module interface associated with this ReactContext.
   */
  public <T extends NativeModule> T getNativeModule(Class<T> nativeModuleInterface) {
    if (mCatalystInstance == null) {
      throw new RuntimeException("Trying to invoke JS before CatalystInstance has been set!");
    }
    return mCatalystInstance.getNativeModule(nativeModuleInterface);
  }

  public CatalystInstance getCatalystInstance() {
    return Assertions.assertNotNull(mCatalystInstance);
  }

  public boolean hasActiveCatalystInstance() {
    return mCatalystInstance != null && !mCatalystInstance.isDestroyed();
  }

  public void addLifecycleEventListener(LifecycleEventListener listener) {
    mLifecycleEventListeners.add(listener);
  }

  public void removeLifecycleEventListener(LifecycleEventListener listener) {
    mLifecycleEventListeners.remove(listener);
  }

  public void addActivityEventListener(ActivityEventListener listener) {
    mActivityEventListeners.add(listener);
  }

  public void removeActivityEventListener(ActivityEventListener listener) {
    mActivityEventListeners.remove(listener);
  }

  /**
   * Should be called by the hosting Fragment in {@link Fragment#onResume}
   */
  public void onResume(@Nullable Activity activity) {
    UiThreadUtil.assertOnUiThread();
    mCurrentActivity = activity;
    for (LifecycleEventListener listener : mLifecycleEventListeners) {
      listener.onHostResume();
    }
  }

  /**
   * Should be called by the hosting Fragment in {@link Fragment#onPause}
   */
  public void onPause() {
    UiThreadUtil.assertOnUiThread();
    for (LifecycleEventListener listener : mLifecycleEventListeners) {
      listener.onHostPause();
    }
  }

  /**
   * Should be called by the hosting Fragment in {@link Fragment#onDestroy}
   */
  public void onDestroy() {
    UiThreadUtil.assertOnUiThread();
    for (LifecycleEventListener listener : mLifecycleEventListeners) {
      listener.onHostDestroy();
    }
    if (mCatalystInstance != null) {
      mCatalystInstance.destroy();
    }
    mCurrentActivity = null;
  }

  /**
   * Should be called by the hosting Fragment in {@link Fragment#onActivityResult}
   */
  public void onActivityResult(int requestCode, int resultCode, Intent data) {
    for (ActivityEventListener listener : mActivityEventListeners) {
      listener.onActivityResult(requestCode, resultCode, data);
    }
  }

  public void assertOnUiQueueThread() {
    Assertions.assertNotNull(mUiMessageQueueThread).assertIsOnThread();
  }

  public boolean isOnUiQueueThread() {
    return Assertions.assertNotNull(mUiMessageQueueThread).isOnThread();
  }

  public void runOnUiQueueThread(Runnable runnable) {
    Assertions.assertNotNull(mUiMessageQueueThread).runOnQueue(runnable);
  }

  public void assertOnNativeModulesQueueThread() {
    Assertions.assertNotNull(mNativeModulesMessageQueueThread).assertIsOnThread();
  }

  public boolean isOnNativeModulesQueueThread() {
    return Assertions.assertNotNull(mNativeModulesMessageQueueThread).isOnThread();
  }

  public void runOnNativeModulesQueueThread(Runnable runnable) {
    Assertions.assertNotNull(mNativeModulesMessageQueueThread).runOnQueue(runnable);
  }

  public void assertOnJSQueueThread() {
    Assertions.assertNotNull(mJSMessageQueueThread).assertIsOnThread();
  }

  public boolean isOnJSQueueThread() {
    return Assertions.assertNotNull(mJSMessageQueueThread).isOnThread();
  }

  public void runOnJSQueueThread(Runnable runnable) {
    Assertions.assertNotNull(mJSMessageQueueThread).runOnQueue(runnable);
  }

  /**
   * Passes the given exception to the current
   * {@link com.facebook.react.bridge.NativeModuleCallExceptionHandler} if one exists, rethrowing
   * otherwise.
   */
  public void handleException(RuntimeException e) {
    if (mCatalystInstance != null &&
        !mCatalystInstance.isDestroyed() &&
        mNativeModuleCallExceptionHandler != null) {
      mNativeModuleCallExceptionHandler.handleException(e);
    } else {
      throw e;
    }
  }

  public boolean hasCurrentActivity() {
    return mCurrentActivity != null;
  }

  /**
   * Same as {@link Activity#startActivityForResult(Intent, int)}, this just redirects the call to
   * the current activity. Returns whether the activity was started, as this might fail if this
   * was called before the context is in the right state.
   */
  public boolean startActivityForResult(Intent intent, int code, Bundle bundle) {
    Assertions.assertNotNull(mCurrentActivity);
    mCurrentActivity.startActivityForResult(intent, code, bundle);
    return true;
  }

  /**
   * Get the activity to which this context is currently attached, or {@code null} if not attached.
   * DO NOT HOLD LONG-LIVED REFERENCES TO THE OBJECT RETURNED BY THIS METHOD, AS THIS WILL CAUSE
   * MEMORY LEAKS.
   */
  /* package */ @Nullable Activity getCurrentActivity() {
    return mCurrentActivity;
  }
}

看最后发现现在的版本 getCurrentActivity 方法确实没有公开了,于是我想了一个曲线救国的方法,新建一个 RcContext 继承至 ReactContext 重写 getCurrentActivity 方法让其暴露出来

import javax.annotation.Nullable;

import java.util.concurrent.CopyOnWriteArraySet;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.LayoutInflater;

import com.facebook.infer.annotation.Assertions;
import com.facebook.react.bridge.ActivityEventListener;
import com.facebook.react.bridge.CatalystInstance;
import com.facebook.react.bridge.JavaScriptModule;
import com.facebook.react.bridge.LifecycleEventListener;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.NativeModuleCallExceptionHandler;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.UiThreadUtil;
import com.facebook.react.bridge.queue.ReactQueueConfiguration;
import com.facebook.react.bridge.queue.MessageQueueThread;

/**
 * Abstract ContextWrapper for Android applicaiton or activity {@link android.content.Context} and
 * {@link CatalystInstance}
 */
public class RcContext extends ReactContext {

    private final CopyOnWriteArraySet<LifecycleEventListener> mLifecycleEventListeners =
            new CopyOnWriteArraySet<>();
    private final CopyOnWriteArraySet<ActivityEventListener> mActivityEventListeners =
            new CopyOnWriteArraySet<>();

    private @Nullable CatalystInstance mCatalystInstance;
    private @Nullable LayoutInflater mInflater;
    private @Nullable MessageQueueThread mUiMessageQueueThread;
    private @Nullable MessageQueueThread mNativeModulesMessageQueueThread;
    private @Nullable MessageQueueThread mJSMessageQueueThread;
    private @Nullable
    NativeModuleCallExceptionHandler mNativeModuleCallExceptionHandler;
    private @Nullable Activity mCurrentActivity;

    public RcContext(android.content.Context base) {
        super(base);
    }

    /**
     * Set and initialize CatalystInstance for this Context. This should be called exactly once.
     */
    public void initializeWithInstance(CatalystInstance catalystInstance) {
        if (catalystInstance == null) {
            throw new IllegalArgumentException("CatalystInstance cannot be null.");
        }
        if (mCatalystInstance != null) {
            throw new IllegalStateException("ReactContext has been already initialized");
        }

        mCatalystInstance = catalystInstance;

        ReactQueueConfiguration queueConfig = catalystInstance.getReactQueueConfiguration();
        mUiMessageQueueThread = queueConfig.getUIQueueThread();
        mNativeModulesMessageQueueThread = queueConfig.getNativeModulesQueueThread();
        mJSMessageQueueThread = queueConfig.getJSQueueThread();
    }

    public void setNativeModuleCallExceptionHandler(
            @Nullable NativeModuleCallExceptionHandler nativeModuleCallExceptionHandler) {
        mNativeModuleCallExceptionHandler = nativeModuleCallExceptionHandler;
    }

    // We override the following method so that views inflated with the inflater obtained from this
    // context return the ReactContext in #getContext(). The default implementation uses the base
    // context instead, so it couldn't be cast to ReactContext.
    // TODO: T7538796 Check requirement for Override of getSystemService ReactContext
    @Override
    public Object getSystemService(String name) {
        if (LAYOUT_INFLATER_SERVICE.equals(name)) {
            if (mInflater == null) {
                mInflater = LayoutInflater.from(getBaseContext()).cloneInContext(this);
            }
            return mInflater;
        }
        return getBaseContext().getSystemService(name);
    }

    /**
     * @return handle to the specified JS module for the CatalystInstance associated with this Context
     */
    public <T extends JavaScriptModule> T getJSModule(Class<T> jsInterface) {
        if (mCatalystInstance == null) {
            throw new RuntimeException("Trying to invoke JS before CatalystInstance has been set!");
        }
        return mCatalystInstance.getJSModule(jsInterface);
    }

    /**
     * @return the instance of the specified module interface associated with this ReactContext.
     */
    public <T extends NativeModule> T getNativeModule(Class<T> nativeModuleInterface) {
        if (mCatalystInstance == null) {
            throw new RuntimeException("Trying to invoke JS before CatalystInstance has been set!");
        }
        return mCatalystInstance.getNativeModule(nativeModuleInterface);
    }

    public CatalystInstance getCatalystInstance() {
        return Assertions.assertNotNull(mCatalystInstance);
    }

    public boolean hasActiveCatalystInstance() {
        return mCatalystInstance != null && !mCatalystInstance.isDestroyed();
    }

    public void addLifecycleEventListener(LifecycleEventListener listener) {
        mLifecycleEventListeners.add(listener);
    }

    public void removeLifecycleEventListener(LifecycleEventListener listener) {
        mLifecycleEventListeners.remove(listener);
    }

    public void addActivityEventListener(ActivityEventListener listener) {
        mActivityEventListeners.add(listener);
    }

    public void removeActivityEventListener(ActivityEventListener listener) {
        mActivityEventListeners.remove(listener);
    }

    public void onResume(@Nullable Activity activity) {
        UiThreadUtil.assertOnUiThread();
        mCurrentActivity = activity;
        for (LifecycleEventListener listener : mLifecycleEventListeners) {
            listener.onHostResume();
        }
    }

    public void onPause() {
        UiThreadUtil.assertOnUiThread();
        for (LifecycleEventListener listener : mLifecycleEventListeners) {
            listener.onHostPause();
        }
    }


    public void onDestroy() {
        UiThreadUtil.assertOnUiThread();
        for (LifecycleEventListener listener : mLifecycleEventListeners) {
            listener.onHostDestroy();
        }
        if (mCatalystInstance != null) {
            mCatalystInstance.destroy();
        }
        mCurrentActivity = null;
    }

    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        for (ActivityEventListener listener : mActivityEventListeners) {
            listener.onActivityResult(requestCode, resultCode, data);
        }
    }

    public void assertOnUiQueueThread() {
        Assertions.assertNotNull(mUiMessageQueueThread).assertIsOnThread();
    }

    public boolean isOnUiQueueThread() {
        return Assertions.assertNotNull(mUiMessageQueueThread).isOnThread();
    }

    public void runOnUiQueueThread(Runnable runnable) {
        Assertions.assertNotNull(mUiMessageQueueThread).runOnQueue(runnable);
    }

    public void assertOnNativeModulesQueueThread() {
        Assertions.assertNotNull(mNativeModulesMessageQueueThread).assertIsOnThread();
    }

    public boolean isOnNativeModulesQueueThread() {
        return Assertions.assertNotNull(mNativeModulesMessageQueueThread).isOnThread();
    }

    public void runOnNativeModulesQueueThread(Runnable runnable) {
        Assertions.assertNotNull(mNativeModulesMessageQueueThread).runOnQueue(runnable);
    }

    public void assertOnJSQueueThread() {
        Assertions.assertNotNull(mJSMessageQueueThread).assertIsOnThread();
    }

    public boolean isOnJSQueueThread() {
        return Assertions.assertNotNull(mJSMessageQueueThread).isOnThread();
    }

    public void runOnJSQueueThread(Runnable runnable) {
        Assertions.assertNotNull(mJSMessageQueueThread).runOnQueue(runnable);
    }

    /**
     * Passes the given exception to the current
     * {@link com.facebook.react.bridge.NativeModuleCallExceptionHandler} if one exists, rethrowing
     * otherwise.
     */
    public void handleException(RuntimeException e) {
        if (mCatalystInstance != null &&
                !mCatalystInstance.isDestroyed() &&
                mNativeModuleCallExceptionHandler != null) {
            mNativeModuleCallExceptionHandler.handleException(e);
        } else {
            throw e;
        }
    }

    public boolean hasCurrentActivity() {
        return mCurrentActivity != null;
    }

    /**
     * Same as {@link Activity#startActivityForResult(Intent, int)}, this just redirects the call to
     * the current activity. Returns whether the activity was started, as this might fail if this
     * was called before the context is in the right state.
     */
    public boolean startActivityForResult(Intent intent, int code, Bundle bundle) {
        Assertions.assertNotNull(mCurrentActivity);
        mCurrentActivity.startActivityForResult(intent, code, bundle);
        return true;
    }

    /**
     * Get the activity to which this context is currently attached, or {@code null} if not attached.
     * DO NOT HOLD LONG-LIVED REFERENCES TO THE OBJECT RETURNED BY THIS METHOD, AS THIS WILL CAUSE
     * MEMORY LEAKS.
     */
    /* package */
    @Nullable
    public Activity getCurrentActivity() {
        return mCurrentActivity;
    }
}