React Native 应用程序内部的 SurfaceView 使一切空白

SurfaceView inside of React Native app makes everything blank

我正在创建一个 React Native Android 应用程序,我想嵌入一个使用 Vulkan 呈现的控件。我通过创建一个名为 VkSurfaceViewSurfaceView 的子类并使用 JNI 调用在 Rust 中实现 Vulkan 代码来实现此控件。

我打开了显示所有视图边界的调试设置,以便清楚地看到视图仍然存在。

这是简单 Android 布局(无 React Native)内的 Vulkan 控件(目前,它只呈现一个三角形):

这是我没有 Vulkan 控件的 React Native 布局(正方形代表我尝试放置 Vulkan 控件的位置):

但是当我放置 Vulkan 控件时,其他所有内容都变暗了,即使布局检查器和调试覆盖表明其他视图仍然存在:

为什么会发生这种情况?如上所示,Vulkan 控件在 pure-Android 布局中工作,因此我认为它必须以某种方式与 React Native 进行不利的交互。但是,我发现像 this and this 这样的示例可以在 React Native 中使用 SurfaceView/TextureView/VideoView 而不会引起问题。

编辑: 即使我把VkSurfaceView中的所有代码都注释掉了,黑屏问题依然存在(但是三角形明显消失了),所以我不要认为这是因为我的 Vulkan 代码有问题。

编辑 2: 如果我从 TextureView 而不是 SurfaceView 派生,它会起作用。但为什么?我怀疑这与所解释的差异有关here,但我仍然不明白为什么视图是否使用 OpenGL 合成很重要。

这是我的代码:

React Native index.js:

import React from 'react';
import {
  AppRegistry,
  StyleSheet,
  Text,
  View
} from 'react-native';
import VkSurfaceView from './surface-view';

const HelloWorld = () => {
  return (
    <View style={[styles.container, {
      // Try setting `flexDirection` to `"row"`.
      flexDirection: "column"
    }]}>
      <Text style={styles.hello}>Hello, World</Text>
      <View style={{ width: 100, height: 100, alignSelf: 'center', backgroundColor: 'pink' }}>
        <VkSurfaceView style={{ width: 100, height: 100 }}/>
      </View>
    </View>
  );
};
var styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    backgroundColor: '#ffffff'
  },
  hello: {
    fontSize: 20,
    textAlign: 'center',
    margin: 10,
    color: 'green'
  }
});

AppRegistry.registerComponent(
  'MyReactNativeApp',
  () => HelloWorld
);

React Native surface-view.js:

import { requireNativeComponent } from 'react-native';

module.exports = requireNativeComponent('SPVkSurfaceView');

Java SurfaceReactPackage.java:

public class SurfaceReactPackage implements ReactPackage {
    @NonNull
    @Override
    public List<NativeModule> createNativeModules(@NonNull ReactApplicationContext reactContext) {
        return Collections.emptyList();
    }

    @NonNull
    @Override
    public List<ViewManager> createViewManagers(
            @NonNull ReactApplicationContext reactContext) {
        return Collections.singletonList(
                new ReactSurfaceManager(reactContext)
        );
    }
}

Java ReactSurfaceManager.java:

public class ReactSurfaceManager extends SimpleViewManager<VkSurfaceView> {
    public static final String REACT_CLASS = "SPVkSurfaceView";
    ReactApplicationContext mCallerContext;

    public ReactSurfaceManager(ReactApplicationContext reactContext) {
        mCallerContext = reactContext;
    }

    @NonNull
    @Override
    public VkSurfaceView createViewInstance(ThemedReactContext context) {
        return new VkSurfaceView(context);
    }

    @Override
    public String getName() {
        return REACT_CLASS;
    }
}

Java MainActivity.java

public class MainActivity extends AppCompatActivity implements DefaultHardwareBackBtnHandler {
    private ReactRootView mReactRootView;
    private ReactInstanceManager mReactInstanceManager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // initialize native code library before using VkSurfaceView
        MyNativeLibary.init();

        // initialize React Native
        mReactRootView = new ReactRootView(this);
        List<ReactPackage> packages = new PackageList(getApplication()).getPackages();
        packages.add(new SurfaceReactPackage());

        mReactInstanceManager = ReactInstanceManager.builder()
                .setApplication(getApplication())
                .setCurrentActivity(this)
                .setBundleAssetName("index.android.bundle")
                .setJSMainModulePath("index")
                .addPackages(packages)
                .setUseDeveloperSupport(BuildConfig.DEBUG)
                .setInitialLifecycleState(LifecycleState.RESUMED)
                .build();
        // The string here (e.g. "MyReactNativeApp") has to match
        // the string in AppRegistry.registerComponent() in index.js
        mReactRootView.startReactApplication(mReactInstanceManager, "MyReactNativeApp", null);

        setContentView(mReactRootView);
    }

    @Override
    protected void onPause() {
        super.onPause();

        if (mReactInstanceManager != null) {
            mReactInstanceManager.onHostPause(this);
        }
    }

    @Override
    protected void onResume() {
        super.onResume();

        if (mReactInstanceManager != null) {
            mReactInstanceManager.onHostResume(this, this);
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();

        if (mReactInstanceManager != null) {
            mReactInstanceManager.onHostDestroy(this);
        }
        if (mReactRootView != null) {
            mReactRootView.unmountReactApplication();
        }
    }

    @Override
    public void invokeDefaultOnBackPressed() {
        this.onBackPressed();
    }

    @Override
    public void onBackPressed() {
        if (mReactInstanceManager != null) {
            mReactInstanceManager.onBackPressed();
        } else {
            super.onBackPressed();
        }
    }
}

一个解决方案是使用 TextureView 而不是 SurfaceView。但是,这似乎不太有效,因为每隔几秒我就会遇到与帧缓冲相关的超时问题。我实际最终使用的解决方案是将我的 SurfaceView 包裹在 FrameLayout.