- Home /
Importing a Unity3D scene into Android Fragment
I've searched online for similar questions, and while I've found several similar questions, none had reliable answers, which is why I'm posting here.
When the Unity3D project is compiled for Android, it basically just gives the scene as an Activity that you can start/end/etc. I want to change this Activity into a Fragment in order to display it as a tab inside a navigation drawer, and as a sub-view inside another fragment/activity.
So basically I had a MainActivity
with an Open button, and a UnityPlayerNativeActivity
which is the actual Unity3D project.
I searched how to change a general activity to a fragment, and changed the UnityPlayerNativeActivity
to match. For example, in the newly-titled UnityPlayerNativeFragment
below (with comments reflecting what exactly was changed from before):
import com.unity3d.player.UnityPlayer;
// Other imports available in full code linked to below
public class UnityPlayerNativeFragment extends Fragment
{
// Changes in this class:
// 1- 'this' references changed to "getActivity()"
// 2- onCreate -> onCreateView
// 3- protected -> public in function names
// 4- @Override added before function calls
// 5- newInstance and onAttach added
protected UnityPlayer mUnityPlayer; // don't change the name of this variable; referenced from native code
private static final String ARG_SECTION_NUMBER = "section_number";
public static UnityPlayerNativeFragment newInstance(int sectionNumber) {
UnityPlayerNativeFragment fragment = new UnityPlayerNativeFragment();
Bundle args = new Bundle();
args.putInt(ARG_SECTION_NUMBER, sectionNumber);
fragment.setArguments(args);
return fragment;
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
((HomeActivity) activity).onSectionAttached(
getArguments().getInt(ARG_SECTION_NUMBER));
}
// UnityPlayer.init() should be called before attaching the view to a layout - it will load the native code.
// UnityPlayer.quit() should be the last thing called - it will unload the native code.
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{
//below line removed because it was causing errors
//getActivity().requestWindowFeature(Window.FEATURE_NO_TITLE);
getActivity().getWindow().takeSurface(null);
getActivity().setTheme(android.R.style.Theme_NoTitleBar_Fullscreen);
getActivity().getWindow().setFormat(PixelFormat.RGB_565);
mUnityPlayer = new UnityPlayer(getActivity());
if (mUnityPlayer.getSettings ().getBoolean ("hide_status_bar", true))
getActivity().getWindow ().setFlags (WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
int glesMode = mUnityPlayer.getSettings().getInt("gles_mode", 1);
boolean trueColor8888 = false;
mUnityPlayer.init(glesMode, trueColor8888);
View playerView = mUnityPlayer.getView();
return playerView;
}
@Override
public void onDestroy ()
{
mUnityPlayer.quit();
super.onDestroy();
}
// onPause()/onResume() must be sent to UnityPlayer to enable pause and resource recreation on resume.
@Override
public void onPause()
{
super.onPause();
mUnityPlayer.pause();
}
@Override
public void onResume()
{
super.onResume();
mUnityPlayer.resume();
}
@Override
public void onConfigurationChanged(Configuration newConfig)
{
super.onConfigurationChanged(newConfig);
mUnityPlayer.configurationChanged(newConfig);
}
}
The AndroidManifest.xml
:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.SamerBekhazi.Test" android:versionName="1.0" android:versionCode="1" android:installLocation="preferExternal">
<supports-screens android:smallScreens="true" android:normalScreens="true" android:largeScreens="true" android:xlargeScreens="true" android:anyDensity="true" />
<application android:theme="@style/AppTheme" android:icon="@drawable/app_icon" android:label="@string/app_name">
<activity android:launchMode="singleTask" android:label="@string/app_name" android:configChanges="fontScale|keyboard|keyboardHidden|locale|mnc|mcc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|uiMode|touchscreen" android:screenOrientation="portrait" android:name=".HomeActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data android:name="unityplayer.ForwardNativeEventsToDalvik" android:value="false" />
</activity>
</application>
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="21" />
<uses-feature android:glEsVersion="0x00020000" />
</manifest>
I only included those 2 files here because I figure the problem is from one or the other. The full code is downloadable here. Extract/Import into Android Studio - you may need to press Sync Project with Gradle Files
once for it to work.
The rest of the project is based on the Navigation Drawer Activity
project that Android Studio auto-creates for you when creating a new project. I basically just call a newInstance
of the above UnityPlayerNativeFragment
when its corresponding icon is pressed in the NavigationDrawer
.
What results when I press the tab for the scene: A black screen, with the Action Bar showing still, but nothing else. The top-right "Settings" button is still press-able, as is the Navigation Drawer button, but when one presses another tab on the Navigation Drawer, the entire app freezes and you have to force exit. I think the latter issue is because you can't close a UnityPlayer
that hasn't opened properly, so the main issue is in actually making the UnityPlayer
open up properly inside the Fragment. The rest of the app (the other tabs) work fine. I tried several variations (everything I could think of) in the above code and AndroidManifest.xml
file, but nothing worked.
Logcat doesn't show any errors, it just says:
11-11 21:22:19.681 29280-29280/com.Bekhazi.Bouncy_Ball W/linker﹕ libmain.so has text relocations. This is wasting memory and is a security risk. Please fix.
11-11 21:22:19.681 29280-29280/com.Bekhazi.Bouncy_Ball D/dalvikvm﹕ Added shared lib /data/app-lib/com.Bekhazi.Bouncy_Ball-2/libmain.so 0x42d64cd8
11-11 21:22:19.691 29280-29280/com.Bekhazi.Bouncy_Ball W/linker﹕ libmono.so has text relocations. This is wasting memory and is a security risk. Please fix.
11-11 21:22:19.691 29280-29280/com.Bekhazi.Bouncy_Ball W/linker﹕ libunity.so has text relocations. This is wasting memory and is a security risk. Please fix.
What exactly is wrong here? The target build is for Android 5.0 and I'm using Android Studio 0.8.14. Worth noting: I was able to successfully load the scene onto my Nexus 5 when it was an Activity.
I don't have an answer, but I'm getting a similar behavior: Unity app embedded in an Android fragment (Unity 5.3.2f1 Personal edition, Android Studio 1.5.1) results in the contents of the fragment being black.
Unity folks: I'd be happy to help resolve this and write up a tutorial on it, but I need some help just getting it to work. Help! (please)
@jimmy_ I'm assu$$anonymous$$g based on your other question that you got this piece working. Could you update us on how? I'm having the same issue with getting Unity to start in a fragment. Thanks!
I've seen in recent versions of Android API (>= 6.0), the onAttach() method has been deprecated, so overriding that method can be ignored.
Answer by iRYO400 · Jan 20, 2017 at 08:48 AM
I fix that with one line of code. So I put code snippet here Checkout last lines of onCreateView
My Fragment:
public class UnityFragment extends Fragment {
protected UnityPlayer mUnityPlayer; // don't change the name of this variable; referenced from native code
//Declare a FrameLayout object
FrameLayout fl_forUnity;
//Test Button
Button button;
public UnityFragment() {
// Required empty public constructor
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
mUnityPlayer = new UnityPlayer(getActivity());
View view = inflater.inflate(R.layout.fragment_unity, container, false);
//Inflate the frame layout from XML
this.fl_forUnity = (FrameLayout) view.findViewById(R.id.fl_forUnity);
//Add the mUnityPlayer view to the FrameLayout, and set it to fill all the area available
this.fl_forUnity.addView(mUnityPlayer.getView(),
FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);
button = (Button) view.findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(view.getContext(), "BOOM!", Toast.LENGTH_SHORT).show();
}
});
//Requesting the Focus
mUnityPlayer.requestFocus();
//The main fix of resolving BLACK SCREEN PLAYER ISSUE
mUnityPlayer.windowFocusChanged(true);//First fix Line
// Yes, it's "static" way and should to be more dynamic, anyway, it works well
return view;
}
// Quit Unity
@Override
public void onDestroy() {
mUnityPlayer.quit();
super.onDestroy();
}
// Pause Unity
@Override
public void onPause() {
super.onPause();
mUnityPlayer.pause();
}
// Resume Unity
@Override
public void onResume() {
super.onResume();
mUnityPlayer.resume();
}
// This ensures the layout will be correct.
// @Override
// public void onConfigurationChanged(Configuration newConfig) {
// super.onConfigurationChanged(newConfig);
// mUnityPlayer.configurationChanged(newConfig);
// }
}
and Xml layout of fragment
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.marsstudio.project.grand.UnityFragment">
<FrameLayout
android:id="@+id/fl_forUnity"
android:layout_width="match_parent"
android:layout_height="250dip"
android:background="#ff90ff15"/>
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|center_horizontal"
android:text="Button" />
</FrameLayout>
Hi @iRYO400 ! Thanks for your post, it helped me.
However I have one issue and my app often crashes when I try to start my Unity fragment. The problem comes from the line mUnityPlayer.windowFocusChanged(true);
which leads me to this error when called (and then crashes) :
Attempt to invoke virtual method 'boolean android.os.Handler.send$$anonymous$$essage(android.os.$$anonymous$$essage)' on a null object reference at android.os.$$anonymous$$essage.sendToTarget($$anonymous$$essage.java:416) at com.unity3d.player.UnityPlayer$b.a($$anonymous$$ Source) at com.unity3d.player.UnityPlayer$b.a($$anonymous$$ Source) at com.unity3d.player.UnityPlayer.windowFocusChanged($$anonymous$$ Source) at fr.artefacto.testfragments.Unity$$anonymous$$anagerFragment.onCreateView(Unity$$anonymous$$anagerFragment.java:40) at android.support.v4.app.Fragment.performCreateView(Fragment.java:2192) at android.support.v4.app.Fragment$$anonymous$$anagerImpl.moveToState(Fragment$$anonymous$$anager.java:1299) at android.support.v4.app.Fragment$$anonymous$$anagerImpl.moveFragmentToExpectedState(Fragment$$anonymous$$anager.java:1528) at android.support.v4.app.Fragment$$anonymous$$anagerImpl.moveToState(Fragment$$anonymous$$anager.java:1595) at android.support.v4.app.BackStackRecord.executeOps(BackStackRecord.java:758) at android.support.v4.app.Fragment$$anonymous$$anagerImpl.executeOps(Fragment$$anonymous$$anager.java:2363) at android.support.v4.app.Fragment$$anonymous$$anagerImpl.executeOpsTogether(Fragment$$anonymous$$anager.java:2149) at android.support.v4.app.Fragment$$anonymous$$anagerImpl.optimizeAndExecuteOps(Fragment$$anonymous$$anager.java:2103) at android.support.v4.app.Fragment$$anonymous$$anagerImpl.execPendingActions(Fragment$$anonymous$$anager.java:2013) at android.support.v4.app.Fragment$$anonymous$$anagerImpl$1.run(Fragment$$anonymous$$anager.java:710) at android.os.Handler.handleCallback(Handler.java:739) at android.os.Handler.dispatch$$anonymous$$essage(Handler.java:95) at android.os.Looper.loop(Looper.java:145) at android.app.ActivityThread.main(ActivityThread.java:6873) at java.lang.reflect.$$anonymous$$ethod.invoke(Native $$anonymous$$ethod) at java.lang.reflect.$$anonymous$$ethod.invoke($$anonymous$$ethod.java:372) at com.android.internal.os.ZygoteInit$$$anonymous$$ethodAndArgsCaller.run(ZygoteInit.java:1404) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1199)
To avoid this, I always need to completely shut down my app then relaunch it. And if the error doesn't disappear, I need to clean my project then reinstall my app. Did you get into this error before ?
Thanks !
Samsung Galaxy J6 (j6lte), Android 8.0 java.lang.Error: FATAL EXCEPTION [main] Unity version : 2017.4.12f1 Device model : samsung S$$anonymous$$-J600GT Device fingerprint: samsung/j6ltedtvvj/j6lte:8.0.0/R16NW/J600GTVJS3ARL1:user/release-keys Caused by at android.os.$$anonymous$$essage.sendToTarget ($$anonymous$$essage.java:418) at com.unity3d.player.UnityPlayer$e.a ($$anonymous$$ Source:8) at com.unity3d.player.UnityPlayer$e.c ($$anonymous$$ Source:2) at com.unity3d.player.UnityPlayer.windowFocusChanged ($$anonymous$$ Source:24) at com.unity3d.player.UnityPlayerActivity.onWindowFocusChanged ($$anonymous$$ Source:5) at com.android.internal.policy.DecorView.onWindowFocusChanged (DecorView.java:1879) at android.view.View.dispatchWindowFocusChanged (View.java:12814) at android.view.ViewGroup.dispatchWindowFocusChanged (ViewGroup.java:1387) at android.view.ViewRootImpl$ViewRootHandler.handle$$anonymous$$essage (ViewRootImpl.java:4567) at android.os.Handler.dispatch$$anonymous$$essage (Handler.java:105) at android.os.Looper.loop (Looper.java:164) at android.app.ActivityThread.main (ActivityThread.java:6944) at java.lang.reflect.$$anonymous$$ethod.invoke (Native $$anonymous$$ethod) at com.android.internal.os.Zygote$$$anonymous$$ethodAndArgsCaller.run (Zygote.java:327) at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1374)
Answer by unity_xrPBQ-2zcfd-DA · Feb 14, 2019 at 07:07 AM
Hey, I am having the same issue did you solve this problem?
Your answer
Follow this Question
Related Questions
How to Make Application in Unity for Android 0 Answers
Running Unity3D with Awesomium an android device 1 Answer
I can't see light effects in Android AVD 0 Answers
Android - Failed to sign APK package: Unsupported major.minor version 52.0 {SOLVED} 1 Answer
Is it possible to display Unity 3D object on the video play screen ? 0 Answers