在本机应用程序中添加原生Android UnityPlayer会导致黑屏

时间:2018-01-05 15:52:30

标签: android unity3d react-native native

解决!阅读我的回答。

我试图在原生React应用程序中显示Unity视图。 UnityPlayer使用Vuforia显示AR的摄像头源。我们需要在iOS和Android的React原生应用程序中包含此视图。

我关注了许多指南,但Android版本中有黑屏。 如果我在react-native(而不是ReactActivity)生成的Android项目中运行UnityPlayerActivity(来自Unity导出的Android项目),我会正确看到我的UnityPlayer。所以我想我的项目包含了所有必要的依赖项。

我的js代码的代码片段:

volumes:
  - ./code:/home/app/code

遵循本指南https://facebook.github.io/react-native/docs/native-components-android.html 我有一个自定义包

const UnityIosContainerView = requireNativeComponent("UnityContainerView",
null);
const UnityAndroidContainerView = requireNativeComponent("RCT3DView", null);

class ArPage extends React.Component {
  render() {
    return (
      <View style={{ flex: 1, backgroundColor: "red" }}>
       {Platform.OS === "ios" ? (
         <UnityIosContainerView style={{ flex: 1 }} />
        ) : (
         <UnityAndroidContainerView style={{ flex: 1 }} />
        )}
      </View>
    );
  }
}

这是我的ViewManager连接到MainReactActivity的生命周期以正确管理UnityPlayer

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

  @Override
  public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
    return Arrays.<ViewManager>asList(
      new React3DViewManager()
    );
  }
}

生成的屏幕截图:

enter image description here

验证点:

  • 显示原生ImageView的作品。
  • 显示一个简单的GLSurfaceView。
  • 如果Android项目中存在所有要求,请尝试启动UnityPlayerActivity而不是ReactActivity。一切正常。
  • 尝试在自定义本机视图中嵌入UnityPlayer无效。
  • 将UnityPlayer连接到活动生命周期(在ViewManager中)无效,即使调用了生命周期事件。

Unity 2017.2.0f3

React 16.0.0.0-alpha12

React-native 0.48.4

有没有人遇到过这个问题?

应用程序日志:

public class React3DViewManager extends SimpleViewManager<View> implements LifecycleEventListener {

  public static final String REACT_CLASS = "RCT3DView";

  private UnityPlayer mUnityPlayer;

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

  @Override
  protected View createViewInstance(ThemedReactContext reactContext) {

    reactContext.addLifecycleEventListener(this);
    mUnityPlayer = new UnityPlayer(reactContext);
    int glesMode = mUnityPlayer.getSettings().getInt("gles_mode", 1);
    boolean trueColor8888 = false;
    mUnityPlayer.init(glesMode, trueColor8888);
    mUnityPlayer.start();
    mUnityPlayer.requestFocus();

    return mUnityPlayer.getView();
  }

  @Override
  public void onHostResume() {
    mUnityPlayer.resume();
  }

  @Override
  public void onHostPause() {
   mUnityPlayer.pause();
  }

  @Override
  public void onHostDestroy() {
    mUnityPlayer.quit();
  }
}

1 个答案:

答案 0 :(得分:5)

有关详细信息,请在此处描述: Part 1 Part 2

好多次尝试后我找到了解决方案。 将UnityPlayer连接到MainActivity的所有生命周期非常重要。 ViewManager类不支持所有活动生命周期。您可以将管理器连接到Resume,暂停和销毁。但UnityPlayer需要onConfigurationChanged以确保布局正确。我直接从Unity生成的UnityPlayerActivity类中获取代码,并在UnityManager中公开UnityPlayer以供使用。

这是我使用UnityPlayer init的MainActivity。

public class MainActivity extends ReactActivity {

  private UnityPlayer mUnityPlayer;

  public UnityPlayer getUnityPlayer() {
    return mUnityPlayer;
  }

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

    getWindow().setFormat(PixelFormat.RGBX_8888); // <--- This makes xperia play happy
    mUnityPlayer = new UnityPlayer(this);
  }

  public void onDestroy() {
    super.onDestroy();
    mUnityPlayer.quit();

  }

  public void onResume() {
    super.onResume();
    mUnityPlayer.resume();

  }

  /**
   * Returns the name of the main component registered from JavaScript.
   * This is used to schedule rendering of the component.
   */
  @Override
  protected String getMainComponentName() {
        return "protoreactnative";
  }

  // Low Memory Unity
  @Override public void onLowMemory()
  {
    super.onLowMemory();
    mUnityPlayer.lowMemory();
  }

  // Trim Memory Unity
  @Override public void onTrimMemory(int level)
  {
    super.onTrimMemory(level);
    if (level == TRIM_MEMORY_RUNNING_CRITICAL)
    {
      mUnityPlayer.lowMemory();
    }
  }

  // This ensures the layout will be correct.
  @Override public void onConfigurationChanged(Configuration newConfig)
  {
    super.onConfigurationChanged(newConfig);
    mUnityPlayer.configurationChanged(newConfig);
  }

  // Notify Unity of the focus change.
  @Override public void onWindowFocusChanged(boolean hasFocus)
  {
    super.onWindowFocusChanged(hasFocus);
    mUnityPlayer.windowFocusChanged(hasFocus);
  }

  // For some reason the multiple keyevent type is not supported by the ndk.
  // Force event injection by overriding dispatchKeyEvent().
  @Override public boolean dispatchKeyEvent(KeyEvent event)
  {
    if (event.getAction() == KeyEvent.ACTION_MULTIPLE)
      return mUnityPlayer.injectEvent(event);
    return super.dispatchKeyEvent(event);
  }

  // Pass any events not handled by (unfocused) views straight to UnityPlayer
  @Override public boolean onKeyUp(int keyCode, KeyEvent event)     { return mUnityPlayer.injectEvent(event); }
  @Override public boolean onKeyDown(int keyCode, KeyEvent event)   { return mUnityPlayer.injectEvent(event); }
  @Override public boolean onTouchEvent(MotionEvent event)          { return mUnityPlayer.injectEvent(event); }
  /*API12*/ public boolean onGenericMotionEvent(MotionEvent event)  { return mUnityPlayer.injectEvent(event); }
}

以下是视图管理员:

public class React3DViewManager extends SimpleViewManager<UnityPlayer>  {

  public static final String REACT_CLASS = "RCT3DView";

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

  @Override
  protected UnityPlayer createViewInstance(ThemedReactContext reactContext) {
    MainActivity activity = (MainActivity)reactContext.getCurrentActivity();
    return activity.getUnityPlayer();
  }
}

我不知道这个解决方案是否是最佳解决方案,但此解决方案可以满足我的需求。

由于