Errors managing the UnityPlayer lifecycle in a native android application

Ok, easy things first

W/libc(21095): pthread_create sched_setscheduler call failed: Operation not permitted

There is nothing you can do about it. You even get this when you compile directly from Unity for Android, so it's a problem inside the engine.

Basic Setup

The guide you linked is pretty outdated. You no longer need to copy files from various locations to create a simple Android project.

  1. Create a Android project by setting Build Settings -> Android -> Google Android project
  2. You now have a complete package ready to import into Eclipse or Android Studio
  3. Compile and deploy

Using UnityPlayer in a subactivity

The class UnityPlayerNativeActivity in your new Android project shows you how to setup the UnityPlayer and what events you need to forward. Here is the version used by Unity 4.3.4

package de.leosori.NativeAndroid;

import com.unity3d.player.*;
import android.app.NativeActivity;
import android.content.res.Configuration;
import android.graphics.PixelFormat;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;

public class UnityPlayerNativeActivity extends NativeActivity
{
    protected UnityPlayer mUnityPlayer;     // don't change the name of this variable; referenced from native code

    // 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.
    protected void onCreate (Bundle savedInstanceState)
    {
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        super.onCreate(savedInstanceState);

        getWindow().takeSurface(null);
        setTheme(android.R.style.Theme_NoTitleBar_Fullscreen);
        getWindow().setFormat(PixelFormat.RGB_565);

        mUnityPlayer = new UnityPlayer(this);
        if (mUnityPlayer.getSettings ().getBoolean ("hide_status_bar", true))
            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();
        setContentView(playerView);
        playerView.requestFocus();
    }
    protected void onDestroy ()
    {
        mUnityPlayer.quit();
        super.onDestroy();
    }

    // onPause()/onResume() must be sent to UnityPlayer to enable pause and resource recreation on resume.
    protected void onPause()
    {
        super.onPause();
        mUnityPlayer.pause();
    }
    protected void onResume()
    {
        super.onResume();
        mUnityPlayer.resume();
    }
    public void onConfigurationChanged(Configuration newConfig)
    {
        super.onConfigurationChanged(newConfig);
        mUnityPlayer.configurationChanged(newConfig);
    }
    public void onWindowFocusChanged(boolean hasFocus)
    {
        super.onWindowFocusChanged(hasFocus);
        mUnityPlayer.windowFocusChanged(hasFocus);
    }
    public boolean dispatchKeyEvent(KeyEvent event)
    {
        if (event.getAction() == KeyEvent.ACTION_MULTIPLE)
            return mUnityPlayer.onKeyMultiple(event.getKeyCode(), event.getRepeatCount(), event);
        return super.dispatchKeyEvent(event);
    }
}

Although UnityPlayerNativeActivity extends NativeActivity you can still extend from ActionBarActivity instead without any problems as far as I can tell. At least it worked during my experiments.

The most important part you are missing is the call to mUnityPlayer.quit() during onDestroy(). Trying to create a new instance of UnityPlayer while the old one is still running will lead to crashes, hanging activities and endless suffering.

Unexpected behavior of mUnityPlayer.quit()

Fixing that you may be surprised that now your whole App simply closes when you return from your UnityActivity. mUnityPlayer.quit() will kill the process it is running inside. Not a single method will execute after calling mUnityPlayer.quit(), not even the onDestroy() method will finish.

The path to victory is to start your UnityActivity as a new process by adding the parameter android:process=":UnityKillsMe to your activty inside your AndroidManifest.xml.

In your case it would look like this

<activity 
    android:name="com.package.example.UnityActivity" 
    android:label="@string/title_activity_unity" 
    android:screenOrientation="portrait" 
    android:launchMode="singleTask" 
    android:process=":UnityKillsMe"
    android:parentActivityName="com.package.example.MainActivity"
    android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale">
    <meta-data android:name="unityplayer.UnityActivity" android:value="true" />
    <meta-data android:name="unityplayer.ForwardNativeEventsToDalvik" android:value="false" />
</activity>

I'm not sure about the parameter unityplayer.ForwardNativeEventsToDalvik... The project created in the beginning sets it to false and the official (outdated) documentation mentions

Since touch/motion events are processed in native code, Java views would normally not see those events. There is, however, a forwarding mechanism in Unity which allows events to be propagated to the DalvikVM.

In my small example project I could not see a difference

The road ahead

You need to find a workflow to integrate your development with Unity with the Android project or vice versa. Exporting again with Unity would conflict with the changes you made in your Android project, so you would need to export into a separate folder and link to the Unity part from your Android project.

According to the aforementioned documentation you may be able to integrate your compiled Android classes and AndroidManifest.xml as plugins into Unity.

The resulting .class file(s) should be compressed into a .jar file and placed in the Assets->Plugins->Android folder. Since the manifest dictates which activity to launch it is also necessary to create a new AndroidManifest.xml. The AndroidManifest.xml file should also be placed in the Assets->Plugins->Android folder.

Good luck!


Question is two year ago, but I still struggled to find a detailed guide about it.

So I wrote one

The main Idea is to take the Unity project and use it as a library in the native android app.

I hope this guide will help someone.


well, i dont have clear answer for this but i have found couple of interesting psots

1- pthread_create warning on android talks about W/libc(21095): pthread_create sched_setscheduler call failed: Operation not permitted the post starts with After calling pthread_create function I receive next message: i quote from the post:

This error means, that the process trying to create the thread hasn't the appropriate privileges to set the scheduling priorty as specified.

and the post marked as answer have some good info to. have a look there but on your code you are NOT calling pthread_create() -- [1]

2- Meaning of Choreographer messages in Logcat W/Choreographer(20963): Already have a pending vsync event. There should only be one at a time i quote

Choreographer lets apps to connect themselves to the vsync, and properly time things to improve performance.

and

Yes, I am. I understand the Choreographer is probably the component that handles animations and when it doesn't get enough cpu cycles, it skips some frames and outputs this debug message so this is related to animation on UI ---[2]

so? based on [1] and [2]: its an issue with the animation generated by Unity, and its not under your control,

my own conclusion and opinion is: this is a Bug at the Unity code, that need to be fixed by Unity ? maybe?

sorry, if not helping but i have tried. i have never worked with Unity, but i tried to get conclusion from some other posts.

good luck