[Unity 5.6] WebGL Login Facebook by Popup Dialog using JavaScript in HTML

I was working on EatMe.io, making new version for WebGL and upload to hosting server. The game required Facebook Login in order to play directly via web browser, and for some reason the Facebook Login for WebGL is not using Facebook SDK but Popup Window instead. And it was supposed to start loading the game after success to login Facebook via Popup Window.

However, it doesn’t have any response for some reason, it just closed the popup and do nothing after login facebook, i even doesn’t know it is success to login or not, but i guess it is success login, should be something wrong about callback handling after facebook login.

I had traced code and found that we are using a plugin, kind of .jslib file to open that popup window with the redirectUrl that pointing to response.html, but i can’t found any html in Unity Project, it there just have index.html generated by Unity. Finally, i found that file from hosting server and wonder what is it :

public void PopupLoginFacebook()
{
#if UNITY_WEBGL
string appID = "<FB_APP_ID>";
string redirectUrl = Application.absoluteURL + "/response.html";
string scope = "email,user_friends,public_profile,publish_actions";

openWindow("https://www.facebook.com/dialog/oauth?client_id=" + appID + "&redirect_uri=" + redirectUrl + "&response_type=token,granted_scopes&scope=" + scope + "&display=popup");
#endif
}

#if UNITY_WEBGL
[DllImport("__Internal")]
private static extern void openWindow(string url);
#endif

OpenWindow.jslib

var OpenWindowPlugin = {  
openWindow: function(link)
{
var url = Pointer_stringify(link);
document.onmouseup = function()
{
window.open(url, 'Facebook Login Window', 'height=500,width=670');
document.onmouseup = null;
}
}
};

mergeInto(LibraryManager.library, OpenWindowPlugin);

response.html

<!DOCTYPE html>
<html>
<body>
<h1 id="header">Please wait...</h1>
<script>
var timer = setTimeout(updateMessage, 100);

function updateMessage()
{
var url = document.URL;
var Url = url.includes("access_token");

if(Url)
{
var element = document.getElementById("header");
element.innerHTML = "Success.";
var name = "Facebook";
document.cookie = name + "=" + "Success" + ";" + " path=/";
window.close();
}

Url = url.includes("error=access_denied");
if(Url)
{
var element = document.getElementById("header");
element.innerHTML = "Access Denied.";
window.close();
}
}

updateMessage();
</script>
</body>
</html>

I am not familiar in HTML and JavaScript, but it looks like only write cookie after login facebook success. So i started checking the index.html and found out that the old one has some JavaScript and SendMessage back to unity :

JaveScript ( NOT WORKING | OLD VERSION CODE FROM UNITY 5.4 )

var timer;

function getRandomInt(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min)) + min;
}


function readCookie(name) {
var name = "Facebook" + "=";
var ca = document.cookie.split(';');
for(var i = 0; i <ca.length; i++) {
var c = ca[i];
while (c.charAt(0)==' ') {
c = c.substring(1);
}
if (c.indexOf(name) == 0) {
return c.substring(name.length,c.length);
}
}
return "";
}

function updateMessage()
{
timer = setTimeout(updateMessage, 100);
if(readCookie("Facebook") != "")
{
if(readCookie("Facebook") == "Success")
{
var name = "Facebook";
document.cookie = name + "=" + getRandomInt(100000, 1000000) + ";" + " path=/";

// NAME_OF_GAMEOBJECT : Just use the name of gameObject if it is root object
// if gameObject have any parent, use '/' divide just like a full path :
// <ROOT_GAMEOBJECT_NAME>/<PARENT_GAMEOBJECT_NAME>/<GAMEOBJECT_NAME>
SendMessage ('<FULL_PATH_OF_GAMEOBJECT>', '<PUBLIC_FUNCTION_NAME>');
}
}
}

updateMessage();

and the new index.html just have the gameInstance without any action :

index.html ( NOT WORKING AFTER FACEBOOK LOGIN )

<!DOCTYPE html>
<html lang="en-us">
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Unity WebGL Player | EatMe.io</title>
<link rel="shortcut icon" href="TemplateData/favicon.ico">
<link rel="stylesheet" href="TemplateData/style.css">
<script src="TemplateData/UnityProgress.js"></script>
<script src="Build/UnityLoader.js"></script>
<script>
var gameInstance = UnityLoader.instantiate("gameContainer", "Build/WebGL.json", {onProgress: UnityProgress});
</script>
</head>
<body>
<div class="webgl-content">
<div id="gameContainer" style="width: 960px; height: 600px"></div>
<div class="footer">
<div class="webgl-logo"></div>
<div class="fullscreen" onclick="gameInstance.SetFullscreen(1)"></div>
<div class="title">EatMe.io</div>
</div>
</div>
</body>
</html>

I tried copy the above JavaScript and paste into new index.html, however it wasn’t work and throwing exception that ‘SendMessage is not defined’. And luckily that i found the answer from Unity Doc :

at the bottom of this doc :

var gameInstance = UnityLoader.instantiate("gameContainer", 
"Build/build.json",
{onProgress: UnityProgress});

Then you can send a message to the build using gameInstance.SendMessage(),or access the build Module object like this gameInstance.Module.

so finally i made that work by modify JavaScript as below :

index.html ( WORK )

<!DOCTYPE html>
<html lang="en-us">
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Unity WebGL Player | EatMe.io</title>
<link rel="shortcut icon" href="TemplateData/favicon.ico">
<link rel="stylesheet" href="TemplateData/style.css">
<script src="TemplateData/UnityProgress.js"></script>
<script src="Build/UnityLoader.js"></script>
<script>
var gameInstance = UnityLoader.instantiate("gameContainer", "Build/WebGL.json", {onProgress: UnityProgress});

//==== ADDED by Calvin in order to make it work ====
updateMessage();

function updateMessage() {
timer = setTimeout(updateMessage, 100);
if(readCookie("Facebook") != "")
{
if(readCookie("Facebook") == "Success")
{
var name = "Facebook";
document.cookie = name + "=" + getRandomInt(100000, 1000000) + ";" + " path=/";
gameInstance.SendMessage ('<FULL_PATH_GAMEOBJECT>', '<PUBLIC_FUNCTION>');
}
}
}

function getRandomInt(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min)) + min;
}

function readCookie(name) {
var name = "Facebook" + "=";
var ca = document.cookie.split(';');
for(var i = 0; i <ca.length; i++) {
var c = ca[i];
while (c.charAt(0)==' ') {
c = c.substring(1);
}
if (c.indexOf(name) == 0) {
return c.substring(name.length,c.length);
}
}
return "";
}
//==== END OF CODE BY CALVIN ====

</script>
</head>
<body>
<div class="webgl-content">
<div id="gameContainer" style="width: 960px; height: 600px"></div>
<div class="footer">
<div class="webgl-logo"></div>
<div class="fullscreen" onclick="gameInstance.SetFullscreen(1)"></div>
<div class="title">EatMe.io</div>
</div>
</div>
</body>
</html>

FLOW CHAT

Basically index.html will call UpdateMessage() on awake and it will keep calling itself in a loop and checking if have any cookie about facebook login success as if a gate to check you have passport or ticket to move forward.

At the same time, Facebook Login Dialog shown to process login, and will be redirected to response.html with access token if login success.

response.html will call UpdateMessage() on awake and keep calling itself in a loop, to check if any access token exists, then will write cookie as if putting passport or ticket to somewhere so that index.html can find it and move forward.

Once index.html got the cookie, it will fire event by loop of UpdateMessage() to unity for start loading game via gameInstance.SendMessage().

Special Thanks : @benben13891

Like what you read? Give Calvin Chan a round of applause.

From a quick cheer to a standing ovation, clap to show how much you enjoyed this story.