Pages

Tuesday, 15 March 2016

A splash screen for Unity application(Only useful with personal or free edition) on Android platform

I always wanted to display my own splash screen as the first thing in my applications. And I was looking for a solution for this with
Unity personal edition. And I found one myself, well not a complete one!

With personal edition, unity displays its logo when the application is launched. You cannot suppress it from displaying
it, but what you can do is display a splash screen with your logo first and then let unity display its logo.

To accomplish this what we do is, before starting the UnityPlayerActivity we will start our activity which displays our the splash screen.

Lets go and create this activity.

To make the splash screen configurable, the splash screen activity will accept, splash screen image, splash screen duration and the activity to start once the splash screen is expired.

These configuration values needs to be specified in the AndroidManifest.xml file under the splash screen activity section.

A sample splash screen activity declaration in the manifest file is shown below,
 <activity android:label="@string/app_name"
    android:screenOrientation="portrait"
    android:launchMode="singleTask"
    android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
    android:name="com.example.unitysplash.android.SplashScreen">
      <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
      </intent-filter>
  
  <!--
  Activity com.unity3d.player.UnityPlayerActivity will be launched once the splash screen completes
  -->
      <meta-data android:name="activityToStart" android:value="com.unity3d.player.UnityPlayerActivity" />
  
  <!--
  splash screen displays @drawable/splash_screen image resource
  this image can be kept at, <Unity Project>\Assets\Plugins\Android\res\drawable-nodpi\
  -->
  <meta-data android:name="splashImage" android:resource="@drawable/splash_screen" /> 
  
  <!-- splash screen expires after 1000 milli seconds -->
  <meta-data android:name="duration" android:value="1000" />
  
    </activity>


Path for the AndroidManifest file is <Unity Project>\Assets\Plugins\Android.

If you do not have the AndroidManifest.xml file then you can generate one if you export your project. You can export the project from build settings.
After exporting add the above activity declaration and make sure that default activity's name is changed to "com.unity3d.player.UnityPlayerActivity".

If you are using custom activity for Unity then give its name for activityToStart.

Now lets go and create the activity. We will keep our activity in a jar file, so create and android library project.

Once the project is created add the class SplashScreen which derives from Activity.

In the onCreate of this activity, first retrieve the meta-data as,
        try {
            ActivityInfo ai = getPackageManager().getActivityInfo(this.getComponentName(), PackageManager.GET_META_DATA);
            Bundle bundle = ai.metaData;

            mActivityToStart = bundle.getString("activityToStart", mActivityToStart);
            mSplashImage = bundle.getInt("splashImage", mSplashImage);
            mDuration = bundle.getInt("duration", mDuration);

        } catch (PackageManager.NameNotFoundException e) {
            Log.d(SplashScreen.class.getName(), e.getMessage());
        }

Now create an ImageView and set the specified image resource to this View.
            LinearLayout layout = new LinearLayout(this);
            layout.setOrientation(LinearLayout.HORIZONTAL);

            ImageView splashImage = new ImageView(this);
            splashImage.setImageResource(mSplashImage);
            splashImage.setScaleType(ImageView.ScaleType.FIT_XY);
            layout.addView(splashImage, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));

            setContentView(layout, new  ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));


To handle the time-out add a Handler implementation,
    private Handler mSplashTimeoutHandler = new Handler() {

        @Override
        public void handleMessage(Message msg) {
            if (msg.what == SplashTimeoutMessage) {
                try {
                    Intent i = new Intent(SplashScreen.this, Class.forName(mActivityToStart));
                    startActivity(i);
                    SplashScreen.this.finish();
                } catch (ClassNotFoundException e) {
                    Log.d(SplashScreen.class.getName(), e.getMessage());
                }
            }
            super.handleMessage(msg);
        }
    };


In the onResume post the handler with delay as the duration mentioned.
        mSplashTimeoutHandler.sendMessageDelayed(mSplashTimeoutHandler.obtainMessage(SplashTimeoutMessage), mDuration);

In case user presses the back key before the splash screen is finished do not launch the final activity. To do this implement onBackPressed as,
        mSplashTimeoutHandler.removeMessages(SplashTimeoutMessage);

Now we are done with SplashScreen activity. Now create a jar out of it and copy it to <Unity Project>\Assets\Plugins\Android

Now if you launch the application splash screen should be the first activity displayed.


Please find a complete example at https://github.com/trsquarelab/unityexamples/tree/master/UnitySplashScreen

2 comments:

  1. Hello, would it be possible to create a custom frame layout with an ImageView over the UnityPlayer that gets removed from the layout, if the scenes is started?

    ReplyDelete
    Replies
    1. Yes, you should be able to do it. You can always add the your views to by adding it to the UnityPlayerActivity.

      Delete