解决 getCurrentActivity is not public ‘com.facebook.react.bridge.React Context` cannot be accessed from outside package
在编译公司自定义的一个 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;
}
}