Monday, August 31, 2015

Candy Kid Android Port

In the previous post, we introduced Candy Kid: a simple maze chase video game re-written in XNA 4.0.
The game targets WP7 by default but we would like to port to other mobile platforms e.g. iOS / Android.

MonoGame implements XNA 4.0 API and can be used to port C#/.NET code: On Windows PC, MonoGame integrates directly in Visual Studio 2012. On Mac OS/X, MonoGame integrates well with Xamarin Studio.
 Machine  Platform  IDE  Framework  Language 
 Windows PC WP7 Visual Studio 2010 XNA 4.0 C#/.NET
 Windows PC Android Visual Studio 2012 MonoGame C#/.NET
 Mac OS/X iOS Xamarin Studio MonoGame C#/.NET

This post outlines the main tasks to port Candy Kid to Android platform; the next post will focus on iOS.

Let's check it out!

Setup
This post assumes you have the Android SDK installed and C:\Android\sdk\platform-tools\ added to the Windows PC Environment path. Also, all Android devices should be setup for USB Debugging enabled.

MonoGame
Download and install MonoGame for Visual Studio. Here is tutorial to create cross platform MonoGame.

Xamarin Studio
Download and install Xamarin Studio. Setup an account; a trial version can be used just to get started!
Launch Xamarin Studio | Click Login. Enter your email + password and click the "Create Account" link.

From here you will be prompted to create a Xamarin account: enter name, email address and password. Check "Start 30-day Xamarin trial immediately". Click Accept. Log in to Xamarin Studio to activate a/c.

Visual Studio
Launch Visual Studio 2012. File | New | Project. Expand Templates | Visual C# | MonoGame.
Choose MonoGame Android Project. Name: CandyKid.Android. Choose project Location. OK.
Build solution. Error: Your app is too large to be developed with Xamarin Android Starter edition.
Choose Begin a Trial from popup. Xamarin then activates the trial version. Rebuild solution fine.

Before writing any new code or porting any existing, ensure the following tasks are completed:
  • Rename Game1.cs to AnGame.cs
  • Rename all references from Game1 to AnGame
  • Use default root namespace of WindowsGame
  • Update Activity1.cs to construct new AnGame
  • Update Activity attribute: set Label="Candy Kid"
Libraries
Candy Kid references the following libraries: Ninject for IoC Container and Xml.Linq for Serialization.
Note: MonoGame Android Project should automatically add reference to System.Xml.Linq by default.

In Visual Studio 2012, right click CandyKid.Android project References | Manage NuGet Packages
Enter "Portable Ninject" into Search bar top right | Select "Ninject for Portable Class Libraries"
Click Install button

Project Properties
Right click CandyKid.Android project. Choose Properties. Ensure the following options are set on tabs:

Application
 Assembly Name WindowsGame
 Default namespace WindowsGame
 Compile using Android version API Level 17 (Xamarin.Android v4.2 Support)
 Minimum Android to target Use Compile using SDK version
 Target Android version Use Compile using SDK version

Android Manifest
 Application name Candy Kid
 Package name Enter bundle identifier
 Application icon @drawable/Icon
 Version number 1
 Version name 1.0.0

Version number is the Version code on the Google Play Developer console. This value must be unique.
Version name is the build version. This value does not need to be unique but it's best practice to do so.

Why? Because Version name is visible on the Google Play Store whereas Version code is not (internal).
Also, update AssemblyInfo.cs file under Properties folder. Synchronize "1.0.0" as the AssemblyVersion.

Build
 Conditional compilation symbmols ANDROID
Repeat all settings for both Debug and Release build configurations!

Xamarin Studio
Note: if you are using Xamarin Studio to build and deploy then make subtle Project Properties changes:

Right click Project | Options | Build section | General | Set Target framework: Android 4.2 (Jelly Bean).
At the time of this writing, Android 4.2 (Jelly Bean) is the lowest API version that will build and deploy.
Also, right click Project | Options | Build section | Android Application. Set the following Android versions:
Minimum: Android 2.3 (API level 10) and also Target: Automatic - use target framework version (API 17)

Code
Import all C#/.NET code from original XNA 4.0 project. When game exits, ensure this code is added:
Otherwise Android process will not be killed when you close the game and therefore cannot re-launch.
#if ANDROID
  Android.OS.Process.KillProcess(Android.OS.Process.MyPid());
  System.Environment.Exit(0);
#endif
Also, if you'd like to upsell full version of your game to unlock then open the url in the native browser:
#if ANDROID
  string url = @"Enter URL to full version of game";
  var intent = new Android.Content.Intent(Android.Content.Intent.ActionView, Android.Net.Uri.Parse(url));

  intent.SetFlags(Android.Content.ActivityFlags.NewTask);
  Android.App.Application.Context.StartActivity(intent);
#endif
Finally, you may like to create a splash screen activity as the main launcher to override default activity.
The benefit of this is that as soon as the player taps the game icon, the splash launches immediately.

Therefore, add the following file: SplashActivity.cs:
[Android.App.Activity(
  Label = "Candy Kid",
  MainLauncher = true,
  NoHistory = true,
  Icon = "@drawable/icon",
  Theme = "@style/Theme.Splash",
  AlwaysRetainTaskState = true,
  LaunchMode = Android.Content.PM.LaunchMode.SingleInstance
)]
public class SplashActivity : Android.App.Activity
{
  protected override void OnCreate(Android.OS.Bundle bundle)
  {
    base.OnCreate(bundle);
    StartActivity(typeof(Activity1));
  }
}
Update the default Activity1.cs file accordingly:
[Android.App.Activity(
  Label = "Candy Kid",
  NoHistory = true,
  Icon = "@drawable/icon",
  Theme = "@style/Theme.Splash",
  AlwaysRetainTaskState = true,
  LaunchMode = Android.Content.PM.LaunchMode.SingleInstance,
  ScreenOrientation = Android.Content.PM.ScreenOrientation.SensorLandscape
)]
public class Activity1 : Microsoft.Xna.Framework.AndroidGameActivity
{
  protected override void OnCreate(Android.OS.Bundle bundle)
  {
    base.OnCreate(bundle);
    var g = new AnGame();
    SetContentView((Android.Views.View)g.Services.GetService(typeof(Android.Views.View)));
    g.Run();
  }
}
Content
MonoGame Android Project templates add both an "Assets" folder and a "Content" folder by default.
However, all Content must live in "Content" subfolder under "Assets" when RootDirectory="Content";

Right click "Assets" folder | Add New Folder | "Content". Candy Kid uses the 4x following subfolders:

Data
Contains flat TXT + XML data files to be consumed by the game. Do not need to be built as XNB files!
Right click data file | Properties | Build Action: AndroidAsset | Copy to Output Directory: Do not copy
Fonts
Copy output from content pipeline XNB file built from spritefont file in the original XNA game project.
Right click font file | Properties | Build Action: AndroidAsset | Copy to Output Directory: Do not copy

Sound
Copy source MP3 files for Songs and WAV files for Sound Effects from the original XNA game project.
Right click sound file | Properties | Build Action: AndroidAsset | Copy to Output Directory: Do not copy

Textures
Copy all source texture images, for example: BMP, JPG, PNG files from the original XNA game project.
Right click texture | Properties | Build Action: AndroidAsset | Copy to Output Directory: Do not copy

Resources
Replace default Icon and Splash images located in Resources / Drawable folder with custom images:
 Icon.png 72x72
 Splash.png 800x480

MonoGame Pipeline
If you require MonoGame to build platform specific XNB content files then use the MonoGame Pipeline:
Start | run | Type MonoGame Pipeline. MonoGame Pipeline launches. Choose File | New. Save project.

Right click project | Add | Existing Item. Add an existing content file e.g. Emulogic.spritefont | Open.
Choose "Copy the file to the directory" | OK. Right click file | Rebuild. XNB file available in bin folder!

Deployment
Attach Android device to Windows PC. Choose Start | Run | cmd. Type "adb devices" shows device listed.

In Visual Studio 2012, select Android device from drop down list next to "Play" button. Hit F5 to Start.
Android device launches game as Built with evaluation software (this build will only work for 24 hours)

Alternative: switch to Release build Configuration. Right click project | Export Android Package (.apk)
Start | run | cmd. Navigate to bin / Release folder. Type "adb install Package-Signed.apk" to install.

Note: install "standard" .apk file generates Failure [INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION]

Deployment II
Attach Android device to Mac OS/X. Xamarin Studio, click arrow next to build configuration for device.
Click Play button. Android device launches game as "Evaluation Software". Build expires within 24hrs.

Alternative: right click CandyKid.Android project | Archive for Publishing. Click Sign + Distribute button.
Select Android Distribution Channel as "AdHoc" | Next. Create a New Key or Import an Existing Key.
Choose Next to Publish as Ad Hoc. Click Publish button. Choose Location | Save. Enter the key password.
Launch terminal window. Navigate to the saved folder. Type "adb install Package-Signed.apk" to install.

Summary
That concludes the Candy Kid port to Android platform. The next post will focus on Candy Kid port to iOS.