Skip to content

Commit

Permalink
fix: Network discovery blocked on Android-based devices
Browse files Browse the repository at this point in the history
  • Loading branch information
SoftwareGuy committed Feb 20, 2022
1 parent 9b21830 commit 711e921
Show file tree
Hide file tree
Showing 4 changed files with 203 additions and 7 deletions.
8 changes: 8 additions & 0 deletions Assets/Discovery/Android.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

123 changes: 123 additions & 0 deletions Assets/Discovery/Android/AndroidManifestHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
// 2022-02-20: Modified version of AndroidManifestHelper by Clancey (see Mirror PR #2887)
// Modifications made by Coburn (SoftwareGuy).

// This helper script should only used on Android build targets.
#if UNITY_EDITOR && UNITY_ANDROID
using System.Xml;
using System.IO;

using UnityEditor;
using UnityEditor.Android;
using UnityEditor.Build;
using UnityEditor.Build.Reporting;
using UnityEngine;

[InitializeOnLoad]
public class AndroidManifestHelper : IPreprocessBuildWithReport, IPostprocessBuildWithReport, IPostGenerateGradleAndroidProject
{
public int callbackOrder { get { return 99999; } }

public void OnPostGenerateGradleAndroidProject(string path)
{
string manifestFolder = Path.Combine(path, "src/main");
string sourceFile = manifestFolder + "/AndroidManifest.xml";

// Load android manfiest file
var doc = new XmlDocument();
doc.Load(sourceFile);

string androidNamepsaceURI;
var element = (XmlElement)doc.SelectSingleNode("/manifest");
if (element == null)
{
Debug.LogError("Could not find the manifest tag in android manifest.");
return;
}

// Get android namespace URI from the manifest
androidNamepsaceURI = element.GetAttribute("xmlns:android");
if (string.IsNullOrEmpty(androidNamepsaceURI))
{
Debug.LogError("Could not find the Android Namespace in manifest.");
return;
}

// As the name suggests, add or remove the required things.
AddOrRemoveTag(doc,
androidNamepsaceURI,
"/manifest",
"uses-permission",
"android.permission.CHANGE_WIFI_MULTICAST_STATE",
true,
false);
AddOrRemoveTag(doc,
androidNamepsaceURI,
"/manifest",
"uses-permission",
"android.permission.INTERNET",
true,
false);

// Finally, save it.
doc.Save(sourceFile);
}

private static void AddOrRemoveTag(XmlDocument doc, string @namespace, string path, string elementName, string name, bool required, bool modifyIfFound, params string[] attrs) // name, value pairs
{
XmlNodeList nodes = doc.SelectNodes(path + "/" + elementName);
XmlElement element = null;
foreach (XmlElement e in nodes)
{
if (name == null || name == e.GetAttribute("name", @namespace))
{
element = e;
break;
}
}

if (required)
{
if (element == null)
{
XmlNode parent = doc.SelectSingleNode(path);
element = doc.CreateElement(elementName);
element.SetAttribute("name", @namespace, name);
parent.AppendChild(element);
}

for (int i = 0; i < attrs.Length; i += 2)
{
if (modifyIfFound || string.IsNullOrEmpty(element.GetAttribute(attrs[i], @namespace)))
{
if (attrs[i + 1] != null)
{
element.SetAttribute(attrs[i], @namespace, attrs[i + 1]);
}
else
{
element.RemoveAttribute(attrs[i], @namespace);
}
}
}
}
else
{
if (element != null && modifyIfFound)
{
element.ParentNode.RemoveChild(element);
}
}
}

public void OnPostprocessBuild(BuildReport report)
{
// Unused.
}

public void OnPreprocessBuild(BuildReport report)
{
// Unused.
}

}
#endif
11 changes: 11 additions & 0 deletions Assets/Discovery/Android/AndroidManifestHelper.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

68 changes: 61 additions & 7 deletions Assets/Discovery/NetworkDiscoveryBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@
// forked from https://github.com/in0finite/MirrorNetworkDiscovery
// Both are MIT Licensed

// Updated 2022-02-20 by Coburn (SoftwareGuy)
// This update has changes integrated from the Mirror PR #2887
// PR author: Clancey; 22 Aug 2021
// Source: https://github.com/vis2k/Mirror/pull/2887/

namespace Mirage.Discovery
{
/// <summary>
Expand Down Expand Up @@ -81,6 +86,12 @@ void OnApplicationQuit()

void Shutdown()
{
#if UNITY_ANDROID
// If we're on Android, then tell the Android OS that
// we're done with multicasting and it may save battery again.
EndMulticastLock();
#endif

if (serverUdpClient != null)
{
try
Expand All @@ -89,7 +100,7 @@ void Shutdown()
}
catch (Exception)
{
// it is just close, swallow the error
// If it's already closed, then just swallow the error. There's no need to show it.
}

serverUdpClient = null;
Expand All @@ -103,7 +114,7 @@ void Shutdown()
}
catch (Exception)
{
// it is just close, swallow the error
// Again, if it's already closed, then just swallow the error.
}

clientUdpClient = null;
Expand Down Expand Up @@ -137,6 +148,11 @@ public void AdvertiseServer()

public async UniTask ServerListenAsync()
{
#if UNITY_ANDROID
// Tell Android to allow us to use Multicasting.
BeginMulticastLock();

#endif
while (true)
{
try
Expand All @@ -145,12 +161,12 @@ public async UniTask ServerListenAsync()
}
catch (ObjectDisposedException)
{
// socket has been closed
// This socket's been disposed, that's okay, we'll handle it
break;
}
catch (Exception)
{
// if we get an invalid request, just ignore it
// Invalid request or something else. Just ignore it.
}
}
}
Expand Down Expand Up @@ -224,9 +240,47 @@ protected virtual void ProcessClientRequest(Request request, IPEndPoint endpoint
/// <returns>The message to be sent back to the client or null</returns>
protected abstract Response ProcessRequest(Request request, IPEndPoint endpoint);

#endregion
#endregion

#region Android specific functions for Multicasting support

#if UNITY_ANDROID
AndroidJavaObject multicastLock;
bool hasMulticastLock;

void BeginMulticastLock() {
if (hasMulticastLock)
return;

if (Application.platform == RuntimePlatform.Android)
{
using (AndroidJavaObject activity = new AndroidJavaClass("com.unity3d.player.UnityPlayer").GetStatic<AndroidJavaObject>("currentActivity"))
{
using (AndroidJavaObject wifiManager = activity.Call<AndroidJavaObject>("getSystemService", "wifi"))
{
multicastLock = wifiManager.Call<AndroidJavaObject>("createMulticastLock", "lock");
multicastLock.Call("acquire");
hasMulticastLock = true;
}
}
}
}

void EndMulticastLock()
{
// Don't have a multicast lock? Short-circuit.
if (!hasMulticastLock)
return;

// Release the lock.
multicastLock?.Call("release");
hasMulticastLock = false;
}
#endif

#endregion

#region Client
#region Client

/// <summary>
/// Start Active Discovery
Expand Down Expand Up @@ -359,6 +413,6 @@ async Task ReceiveGameBroadcastAsync(UdpClient udpClient)
/// <param name="endpoint">Address of the server that replied</param>
protected abstract void ProcessResponse(Response response, IPEndPoint endpoint);

#endregion
#endregion
}
}

0 comments on commit 711e921

Please sign in to comment.