How to get Stadia running on iOS

Jason Meulenhoff
ITNEXT
Published in
4 min readSep 15, 2020

--

Photo by Cristiano Pinto on Unsplash

Everyone is pretty frustrated that Apple doesn’t allow services like Stadia on the Appstore. It’s a nice service that should be allowed to run everywhere.

Luckily I have found a workaround to get Stadia running on your iOS device. Today I will explain how it works and provide you guys with a sample project that you can tinker with.

It’s also possible to create a custom controller overlay so you can play on the device without a controller.

Note: this source is not pretty. It serves as a proof of concept for others to build upon.

But first, we need to overcome these main challenges;

  • We can access stadia only from specific browsers so we need to alter our user-agent so we can access the stadia service.
  • We need someway to login to our Google Account and redirect to stadia
  • WKWebView has crappy controller support its a hit or miss situation, we need to come up with a “better” way to support the Gamepad API.

The first problem is easily solvable we check the user-agent of a device that is allowed to visit stadia.google.com and we copy that specific user-agent in our browser.

The controller was a hard problem. Safari on iOS supports the Gamepad API natively but on my device, it would never connect; and if it did it would stop working randomly.

My current solution is to provide the data to javascript myself and hijack the Navigators.getGamepads() function and emulate a controller so we can decide when it is connected/disconnected.

Taking Control

First, we will make a model so that we can represent the controller as the Navigator.getGamepads() function would normally do.

You can find the official spec here

We can now build our custom controller script. We can read our controllers using GameController framework provided by Apple. We then parse that into our models. Since the buttons need to be in a certain order we construct it in the following way.

*We assume that we want to take control over the first connected controller, we also only support one controller.

This code will benefit from some error handling ❤

In my testing, the timestamp isn’t needed so I left it blank. Feel free to create the implementation to fully emulate the official API. We have our controller data ready all that’s left is create a bridge of communication between our iOS app and a WKWebView that runs Stadia.

Using WKWebView in iOS14, we can add an addScriptMessageHandler this allows us to communicate with Javascript and return a Promise this will help us in hijacking the Navigators.getGamepads() function and return our custom data.

Using the following javascript we can emulate a fake controller. We hijack the method. Every time it’s accessed we call a messageHandler that will give us our controller data over a Promise and override the last known state. (This means that we are out of sync for one frame but we won’t notice this in-game)

Thanks to my friend Stephan Mantel for helping me figuring it out

We will create a class with a method that can load up a file (as String) and a method that can setup a WKWebView so that it can run our custom code

This code will benefit from error handling ❤

Generally what happens is whenever we call setup(webview: WKWebView) we execute the javascript we wrote earlier overriding the Navigators.getGamepads() function. Whenever this function is called we now call our app code and land in the usercontentController callback where we return our current controller state.

Voila, we should have a consistent working controller in any WKWebView.

Yaay for controller support

Back to Stadia

Getting Stadia to work now isn’t a lot of work anymore we first start by creating a UIViewController with a WKWebView. In my tests we need to have a valid iOS user-agent to login our Google account. Using a custom agent only is needed to access Stadia. Luckily WKWebView has us covered.

Do you want to test out the controller? uncomment the line and call controller.setup(webview) before loading the request!

We create a custom configuration adding our controller as a ScriptMessageHandler make sure that the name cross matches with the name used in our javascript script earlier!

Using the WKNavigationDelegate we can check if we are currently logged in or that we are currently still busy trying to login.

Yes this isn’t pretty i know it works for this POC

Whenever we are logged in we navigate to Stadia automatically, if we are on our destination we start the javascript magic and voila stadia runs in full screen on iOS with controller support.

Playing Hitman on the go ❤

There you have it a working solution on playing your Stadia games right on iOS device. There are some things that could be done to make it nicer but the core functionality is there.

This touches a different subject than I normally do on Medium. It was a fun problem to figure out.

I opened up the repo here: https://github.com/Plnda/Gradia please submit any PR’s if you’d like so we can collaborate together on this app

Here at Pinch, we experiment to make our apps even better. Do you have any questions or remarks? Let us know in the comments.

--

--