Android RN和native 嵌套pop返回2层页面的实现

如题,现在有如下场景:
页面A是RN的,跳转到页面B是native的,再从页面B跳转到页面C,C页面是RN的。
即: RN -> Native -> RN

在C页面执行了一些逻辑(如在酒店详情页选择了一个房型价格计划),现在需要直接返回到页面A,即需要把页面C、页面B都 finish掉,即pop两层。


实现分析

因为RN页面特殊,不能直接通过finish两层的思路来实现。
原因: RN 依赖的activity TNReactNativeActivity,是Standard模式,在JS通过RNUtilModule调用Native的 popBackStack方法,通过ReactContextBaseJavaModule.java 中getCurrentActivity 获取activity,只能获取到当前依附的activity (页面C)(Get the activity to which this context is currently attached, or {@code null} if not attached),不能获取到Native 的activity(页面B)
public class RNUtilModule extends ReactContextBaseJavaModule implements ActivityEventListener, LifecycleEventListener {

RNUtilModule.java
/**
     * 不安全的方法,仅提供给RN页面
     * 用于RN页面,跳转到A-->B-->C-->D
     * D点击按钮回到A页面,不点击时可返回到B,C页面,
     * RNActivity暂时也无法设置为SingleTask
     *
     * @param request
     * @param callback
     */
    @ReactMethod
    public void popBackStack(String request, Callback callback) {
        LogUtils.i(TAG, "call native method : resolveUrl, request:{}", request);
        final PopStackRequest popStackRequest = RNUtil.decodeFromJson(request, PopStackRequest.class);
        if (getCurrentActivity() == null || popStackRequest == null) {
            RNUtil.invokeErrorCallback(callback, RNConstant.ErrorCode.NOT_FOUND);
            return;
        }

        mIndex = popStackRequest.popCount;
        if (mIndex > 0 && getCurrentActivity() != null && !getCurrentActivity().isFinishing()) {
            mIndex--;
            getCurrentActivity().finish();
        }
    }

ReactContextBaseJavaModule.java
/**
   * 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.
   *
   * For example, never store the value returned by this method in a member variable. Instead, call
   * this method whenever you actually need the Activity and make sure to check for {@code null}.
   */
  protected @Nullable final Activity getCurrentActivity() {
    return mReactApplicationContext.getCurrentActivity();
  }

finish两层的实现参考:

mIndex = popStackRequest.popCount;
        if (mIndex > 0 && getCurrentActivity() != null && !getCurrentActivity().isFinishing()) {
            mIndex--;
            getCurrentActivity().finish();
        }

实现思路

在页面C,调用返回并发送通知(页面C通知页面B自己销毁),返回到页面B,监听到页面C发来的销毁通知,页面B执行finish,销毁自己,这样就返回到页面A了。

代码参考

// pop两层,即回退2个页面
if (Platform.OS === 'android') {
              bridge.emitNativeEventEmitter('TNReactNativeHotelListFinishNotification', {}); // 销毁酒店列表页
                        bridge.setLinkBack(null, function (d) {});
                    } else {  // ios可直接pop两层
                        bridge.popBackStack({popCount:2},function (d) {
                        });
                    }

通过EventBus发送销毁通知:

@ReactMethod
    public void emitEventRN(String request, final Callback callback) {
        LogUtils.i(TAG, "call native method : emitEventRN, request:{}", request);
        NotificationRequest notify = RNUtil.decodeFromJson(request, NotificationRequest.class);
        if (notify == null) {
            return;
        }
        EventBus.getDefault().post(notify);
    }

页面B监听销毁通知、执行销毁逻辑:

B Activity

public void onEventMainThread(NotificationRequest event) {
if (event != null && HotelConstants.NotifName.FINISH_HOTEL_LIST.equals(event.notifName)) {
            // 销毁当前页面
            finish();
        }
       

以上实现思路供参考,欢迎大家留意讨论~~

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐