How to run PHP on Android with PeachPie

One of the key advantages of PeachPie over its predecessor, Phalanger, is that we can also target .NET Core in addition to the full .NET Framework. This allows PeachPie-compiled PHP apps to run on all platforms .NET Core supports, which makes for some pretty funky possibilities.

The Idea

Nowadays, we can easily build a .NET application for mobile phones, e.g. on Android. And running 3D graphics using OpenGL under them is no problem either. So why not take this a step further with a technology that is not designed for running on a mobile environment at all?

Our plan is to create a simple app with OpenGL graphics, written in PHP, using Xamarin and PeachPie Compiler, and to run it on an Android-powered device, and the end result should look something like this:

To accomplish this, we need quite a few technologies cooperating together, so let’s get started. The backbone of our endeavor is PeachPie Compiler.

PeachPie is a second-generation PHP compiler and runtime under .NET & .NET Core, capable of turning PHP into CIL bytecode that is both-way interoperable with any .NET language. Besides the frequently mentioned performance, security and interoperability benefits, this technology also offers some completely whacky possibilities that are otherwise closed for PHP devs, e.g. running their apps on phones.

Edit: It has just become significantly easier to achieve this with the implementation of .NET generics. Check out this blog post.

Requirements

To accomplish our objective of running PHP on Android, the tools we need and recommend are:

Installation

To make the whole stack of technologies work, we need to install a few additional tools essential for compiling PHP code to the .NET environment, and running a .NET Core application with OpenGL on an Android device. These tools are:

PeachPie Compiler – PHP compiler for .NET
PeachPie is our Roslyn-based PHP compiler and runtime for .NET Core that lets us transfer PHP code into the modern .NET world. You can learn how to set up the initial PHP project here.

In our case, we will be creating a library project instead of web or console app. That can be done simply by running the following two commands:

dotnet new -i Peachpie.Templates::*
dotnet new classlib -lang PHP

The first one will install the PeachPie project templates on your computer using the .NET Core SDK. The second command will create a template project, which will create the .msbuildproj project file for you, so you don’t have to create it manually.

dotnet restore (runs automatically upon every build) will then install all the packages necessary – both .NET and PeachPie.

UrhoSharp – 3D game engine (OpenGL support)
UrhoSharp is a multi-platform 3D game engine for Xamarin and .NET, featuring pretty much everything you need for mobile game development, including both OpenGL and Direct3D support. We will use it to simplify working with 3D graphics. UrhoSharp is distributed as a NuGet package, so its installation could not be easier. In VS, go to Tools -> Extensions and Updates, and search for UrhoSharp Templates online. Install those, and you should find the option to create an UrhoSharp project for Android in the New Project dialog. Create this templated project, and NuGet Restore will take care of the rest of the installation upon building the new project for you.


Getting Started with Xamarin

There is a nice tutorial about how to get quick-started with Xamarin available from Microsoft under this link. However, there was one point I felt this tutorial didn’t elaborate on: Setting up the emulator.

Emulator – Virtual Machine Problems
To run and test the Android application on a windows computer, we need to emulate the android environment. It gets installed in the Android SDK under Visual Studio, as per the Microsoft tutorial. The Android emulator uses Intel’s HAXM virtual machine. To use it on the Windows operating system, we must disable all of Microsoft’s virtual machine managers. What you can read in the official guide is to disable all Hyper-V features in the “Turn Windows Features On and Off” dialog. However, even after doing that and making sure all else was fine, I still could not run the emulator. The reason was another Windows virtual machine manager – “Windows Hypervisor Platform”, which also needed to be disabled to run HAXM without issues.

After disabling both and reinstalling the emulator from the Android SDK manager in VS2017, the emulator should be available to run. Besides the emulator, you also need to install the Intel HAXM and Google USB Debugging Tools from Tools -> Android SDK Manager.

Checking the Intel x86 Emulator Accelerator (HAXM) only downloads the installer, but you need to run the downloaded installer manually afterwards, if not installed already on your system. More specific instructions on this can be found in intel’s tutorial here.

You can then create and manage your emulators under Tools->Android->Android Device Manager.

Debugging and Deploying on an Android Device

There are basically two options to deploy Xamarin applications onto your Android device. The first one is the Xamarin Live Player. This is quite a powerful tool allowing quick-start debugging right on the device. However, it has some limitations as to which functionality is accessible, which would constrict us in the 3G graphics area. That is why I chose to use the second approach: to debug directly on the device.

To do this, you need to have your device connected to the computer via a USB cable, and have the USB debugging option checked in your android phone settings. Then you can build and deploy your code onto your android device directly from Visual Studio. You can read more on how to set up your device for development on the Microsoft sites.

Targeting and Project structure

Under Xamarin, there still needs to be a project targeting the specific Android platform (even though as advertised by Xamarin, virtually all the code can be shared in the joint .NET standard project). As we currently cannot target this directly from a PHP project, we need separate projects. It is also useful to separate the PHP and C# code.
We can follow the same design as done by the Xamarin Forms template solution. We have the small project targeting the specific Android platform that is used to start up our application and can possibly contain some low-level API code, if necessary, written in C#.

And then we have the actual PHP project, the core of our solution. We basically replace the shared library C# project with our new PHP library project we created previously. This way, all the logic can be written in PHP, using the Android project only to be able to deploy on the device.

We can add the reference to this project directly in VS, or by running the following command from our UrhoSharp project directory:

dotnet add reference ../<PHPLibName>/<PHPLibName>.csproj

We also created a third project, holding some static C# utility tools, which are shared, and it seems like a better design to keep them separated from the specific Android project. They are mostly methods for instantiating generic classes. More on this can be read in the next section.

Once again, we can add a reference in VS, or from the PHP library project directory, assuming both projects are under the same root, running the command:

dotnet add reference ../<PHPUtilityLibName>/<PHPUtilityLibName>.csproj

After this, our project structure is ready and prepared to be built. All the parts we use will be constructed upon building the primary UrhoSharp project, or the whole solution.

Generics

PHP currently doesn’t support generic classes, so its syntax doesn’t either. However, a lot of popular C# libraries, including UrhoSharp we are using to empower OpenGL, make extensive use of generics. So, as the generic class, when given a template type, is compiled into a regular CIL object, we can subsequently use it from our PHP code. Then only issue is to declare and instantiate it.

The way around this is to use a kind of factory method in C#, called from PHP. We create these factory methods in our C# utility class, which we reference from the PHP library. Then we can call these methods to take care of instantiating the Generic types for us. Ones they are created, we can use them as any other object in PHP code. Here’s an example of such a method:

public static class UtilityFunctions
    	{
       	public static Sphere CreateSphereComponent(Node node)
       	{
        		return node.CreateComponent<Sphere>();
        	}
}

A future version of PeachPie Compiler will offer an extended syntax (similar to the Hack language) for working with generic classes. Keep an eye out for an announcement about this and follow our documentation!

Edit: .NET generics have been implemented in PeachPie 0.9.17. Check out this blog post.

Time to Code

So, finally we are ready to write some code that actually does something (or, to be totally honest, “rewrite” would be more accurate). We take the sample UrhoSharp application and rewrite the logic into PHP.

We start by creating the App class with the necessary public fields (there are a few more than in the original C# app, because of the cooperation of the two app parts) and a constructor that is implicitly called.

class App
{
	public $helloText;
	public $scene;
 
	public $earthNode;
	public $rootNode;
	public $cloudsNode;
	public $cameraNode;
	public $lightNode;
 
	public function __construct(string $text) {
    		$this->myText = $text;
	}
}

Then we create the Start method inside our App class, which initializes the UrhoSharp scene. It creates the Hello World text in the foreground of the scene, the scene itself, and the Octree object used as a basis of the UrhoSharp scene. We use the static CreateOctree function here, which calls the generic CreateComponent function on the instance of the scene object.

After creating the Scene and Octree, we also create the first node of the scene, the RootNode. We can see how we call standard methods from the .NET library on the instantiated rootNode object:

public function Start()
{
    	// UI text
    	$this->helloText = new GuiText();
    	$this->helloText->Value = "Yaay, hello from php";
    	$this->helloText->HorizontalAlignment = GuiHorizontalAlignment::Center;
    	$this->helloText->VerticalAlignment = GuiVerticalAlignment::Top;
    	
    	$this->scene = new Scene();
    	UtilityFunctions::CreateOctree($this->scene);
 
    	$this->rootNode = $this->scene->CreateChild();
    	$this->rootNode->Position = new Vector3(0, 0, 20);
    	
    	createEarthNode();
}

As the last statement of the Start method, we call the createEarthNode method declared right after, which instantiates the object for Earth. We do this in the same way as the root node. Additionally, we are setting the rotation of the node. Note how we are using a .NET library class from our PHP code here.

// Create a node for the Earth
public function createEarthNode()
{
    	$this->earthNode = $this->rootNode->CreateChild();
    	$this->earthNode->SetScale(5);
    	$this->earthNode->Rotation = new Quaternion(0, 180, 0);
}

The following is a method responsible for creating the Earth’s texture. We need to load the texture from a .jpg file. We are using a static UrhoSharp function creating a material for that. We call this public method directly from the C# Start method, right after our PHP Start method.

// Create a static model component - Sphere:
public function createEarthTexture()
{
    	$earthSphere = UtilityFunctions::CreateSphereComponent($this->earthNode);
    	$earthSphere->SetMaterial(Material::FromImage("Textures/Earth.jpg"));
}

We can follow the same pattern of rewriting the App methods, and write the whole scene creation code into PHP in this way.

Casting CIL objects in C#

There is still one problem caused by the PHP object types. Although the underlying object data is created as a CIL object, the top level type of the instances created in PHP and compiled using PeachPie is always PhpValue. So in order to use their methods and normally interact with them in C#, we need to explicitly cast them to their actual types. This is achieved as follows:

         	
(Scene)phpApp.scene.AsObject()

In order not to do this every time we want to use these objects from C# code, we also declare these objects as members of our App class in C#, and create a function to assign their instances constructed in PHP with the correct type to these:

Text helloText;
Node rootNode, earthNode, cloudsNode, cameraNode;
Scene scene;
private void CreatePHPReferences()
{
	helloText = ((Text)phpApp.helloText.AsObject());
        scene = ((Scene)phpApp.scene.AsObject());
        rootNode = ((Node)phpApp.rootNode.AsObject());
        earthNode = ((Node)phpApp.earthNode.AsObject());
        cloudsNode = ((Node)phpApp.cloudsNode.AsObject());
        cameraNode = ((Node)phpApp.cameraNode.AsObject());
}

Now we can take virtually all the code from the original UrhoSharp C# application, and rewrite it in PHP. You can also use any of your current PHP code, write new code, and build a whole mobile game in PHP this way!

This is the subject of our future work on the PeachPie API; as a part of our extensions of PeachPie’s interoperability with C#, we are planning to publish an API for implicit type conversions and working with C# dynamics and DynamicMetaObject.

Building and Running

Now we can easily build, debug and deploy the Android project in Visual Studio just as any other .NET project. Alternatively, we can build only the PHP library, in the default configuration by simply running:

dotnet build

This also builds the referenced utility library. At the end, we have a beautiful 3D visualization of the Earth spinning, written in PHP, running on an Android device via Xamarin and UrhoSharp:

Wrapping up

By now, you should have a fully configured and ready-to-use basic solution for our Xamarin PHP application. It is running OpenGL, it is written in PHP, compiled by PeachPie Compiler into .NET, and deployed to your Android device. The path forward is now open to experiments as to what you can do with a technology stack like this.

Grab the solution GitHub:
https://github.com/jan-pavlovsky/UrhoPHPTest

Let us know what you think of this option!

Share this article:Share on FacebookShare on VKPin on PinterestShare on Google+Tweet about this on TwitterShare on LinkedInShare on Reddit
Posted on November 12, 2018, in category News, Tutorial, tags: , , , , , , , ,