Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 30 additions & 13 deletions Assets/AirConsole/scripts/Runtime/AirConsole.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2248,27 +2248,22 @@ private void CreateAndroidWebview(string connectionUrl) {
_pluginManager.InitializeOfflineCheck();
}

string url;
string baseUrl;
if (IsAndroidRuntime) {
string urlOverride = AndroidIntentUtils.GetIntentExtraString("base_url", string.Empty);
url = !string.IsNullOrEmpty(urlOverride) ? urlOverride : Settings.AIRCONSOLE_BASE_URL;
baseUrl = !string.IsNullOrEmpty(urlOverride) ? urlOverride : Settings.AIRCONSOLE_BASE_URL;
AirConsoleLogger.LogDevelopment(() => $"BaseURL Override: {urlOverride}");
} else {
url = Settings.AIRCONSOLE_BASE_URL;
}

url += connectionUrl;
if (IsAndroidRuntime) {
url += $"&bundle-version={GetAndroidBundleVersionCode()}";
baseUrl = Settings.AIRCONSOLE_BASE_URL;
}

androidGameVersion = AndroidIntentUtils.GetIntentExtraString("game_version", androidGameVersion);

url += "&game-id=" + Application.identifier;
url += "&game-version=" + androidGameVersion;
url += "&unity-version=" + Application.unityVersion;
bool nativeSizingSupported = ResolveNativeGameSizingSupport(nativeGameSizingSupported);
url += nativeSizingSupported ? "&supportsNativeGameSizing=true" : "&supportsNativeGameSizing=false";

string url = BuildWebviewUrl(
baseUrl, connectionUrl, IsAndroidRuntime,
IsAndroidRuntime ? GetAndroidBundleVersionCode() : 0, Application.version,
Application.identifier, androidGameVersion, Application.unityVersion, nativeSizingSupported);

defaultScreenHeight = Screen.height;
_webViewOriginalUrl = url;
Expand Down Expand Up @@ -2307,6 +2302,28 @@ private static bool ResolveNativeGameSizingSupport(bool fallback) {
return settings ? settings.NativeGameSizingSupported : fallback;
}

/// <summary>
/// Assembles the query string appended to the AirConsole webview URL.
/// Pure and free of device dependencies so both the Android and Web paths are unit-testable:
/// the caller passes device-derived values (bundle version code, app version, ...).
/// The <c>bundle-version</c> and <c>androidAppVersion</c> parameters are only added on the Android runtime.
/// </summary>
internal static string BuildWebviewUrl(string baseUrl, string connectionUrl, bool isAndroidRuntime,
int bundleVersionCode, string appVersion, string gameId, string gameVersion, string unityVersion,
bool nativeSizingSupported) {
string url = baseUrl + connectionUrl;
if (isAndroidRuntime) {
url += $"&bundle-version={bundleVersionCode}";
url += $"&androidAppVersion={appVersion}";
}

url += "&game-id=" + gameId;
url += "&game-version=" + gameVersion;
url += "&unity-version=" + unityVersion;
url += nativeSizingSupported ? "&supportsNativeGameSizing=true" : "&supportsNativeGameSizing=false";
return url;
}

private static int GetAndroidBundleVersionCode() {
AndroidJavaObject ca = UnityAndroidObjectProvider.GetUnityActivity();
AndroidJavaObject packageManager = ca.Call<AndroidJavaObject>("getPackageManager");
Expand Down
97 changes: 97 additions & 0 deletions Assets/AirConsole/scripts/Tests/PlayMode/AndroidWebviewUrlTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
#if !DISABLE_AIRCONSOLE
using NUnit.Framework;

namespace NDream.AirConsole.PlayMode.Tests {
/// <summary>
/// Covers <see cref="AirConsole.BuildWebviewUrl"/>, the pure query-string builder behind the Android webview URL.
/// Exercises the Android vs Web runtime paths deterministically without a device: the Android-only parameters
/// (<c>bundle-version</c>, <c>androidAppVersion</c>) must appear only when <c>isAndroidRuntime</c> is true.
/// </summary>
public class AndroidWebviewUrlTests {
private const string BaseUrl = "https://www.airconsole.com/";

// Mirrors the real connection URL built in AirConsole.InitWebView: a path plus its own query start,
// e.g. "client?id=androidunity-2.62&runtimePlatform=android". The '?' is mid-string, not leading.
private const string ConnectionUrl = "client?id=androidunity-2.62&runtimePlatform=android";
private const string AppVersion = "1.2.3";
private const int BundleVersionCode = 42;
private const string GameId = "com.example.game";
private const string GameVersion = "7";
private const string UnityVersion = "2022.3.62f1";

private static string BuildAndroid() =>
AirConsole.BuildWebviewUrl(BaseUrl, ConnectionUrl, true, BundleVersionCode, AppVersion, GameId,
GameVersion, UnityVersion, true);

private static string BuildWeb() =>
AirConsole.BuildWebviewUrl(BaseUrl, ConnectionUrl, false, BundleVersionCode, AppVersion, GameId,
GameVersion, UnityVersion, true);

[Test]
public void AndroidPath_AddsAndroidAppVersion() {
StringAssert.Contains($"&androidAppVersion={AppVersion}", BuildAndroid());
}

[Test]
public void AndroidPath_AddsBundleVersion() {
StringAssert.Contains($"&bundle-version={BundleVersionCode}", BuildAndroid());
}

[Test]
public void WebPath_OmitsAndroidAppVersion() {
Assert.IsFalse(BuildWeb().Contains("androidAppVersion"),
"Web runtime URL must not carry the Android-only androidAppVersion parameter.");
}

[Test]
public void WebPath_OmitsBundleVersion() {
Assert.IsFalse(BuildWeb().Contains("bundle-version"),
"Web runtime URL must not carry the Android-only bundle-version parameter.");
}

[Test]
public void SharedParams_PresentOnBothPaths([Values(true, false)] bool isAndroidRuntime) {
string url = AirConsole.BuildWebviewUrl(BaseUrl, ConnectionUrl, isAndroidRuntime, BundleVersionCode,
AppVersion, GameId, GameVersion, UnityVersion, true);

StringAssert.Contains($"&game-id={GameId}", url);
StringAssert.Contains($"&game-version={GameVersion}", url);
StringAssert.Contains($"&unity-version={UnityVersion}", url);
StringAssert.Contains("&supportsNativeGameSizing=true", url);
}

[Test]
public void NativeGameSizing_ReflectsSupportFlag() {
string supported = AirConsole.BuildWebviewUrl(BaseUrl, ConnectionUrl, true, BundleVersionCode, AppVersion,
GameId, GameVersion, UnityVersion, true);
string unsupported = AirConsole.BuildWebviewUrl(BaseUrl, ConnectionUrl, true, BundleVersionCode, AppVersion,
GameId, GameVersion, UnityVersion, false);

StringAssert.Contains("&supportsNativeGameSizing=true", supported);
StringAssert.Contains("&supportsNativeGameSizing=false", unsupported);
}

[Test]
public void QueryString_IsWellFormed([Values(true, false)] bool isAndroidRuntime) {
string url = AirConsole.BuildWebviewUrl(BaseUrl, ConnectionUrl, isAndroidRuntime, BundleVersionCode,
AppVersion, GameId, GameVersion, UnityVersion, true);

StringAssert.StartsWith(BaseUrl + ConnectionUrl, url, "URL must begin with the base and connection URL unchanged.");
Assert.AreEqual(1, url.Split('?').Length - 1, "URL must contain exactly one '?' (the connection URL query start).");
Assert.IsFalse(url.Contains("&&"), "URL must not contain empty parameters (&&).");
Assert.IsFalse(url.Contains("=&"), "URL must not contain dangling parameters (=&).");
Assert.IsFalse(url.EndsWith("="), "URL must not end with a dangling '='.");
}

[Test]
public void AppVersion_IsSourceOfAndroidAppVersion_NotGameVersion() {
// Guards against wiring androidAppVersion to the wrong field (e.g. game-version).
string url = AirConsole.BuildWebviewUrl(BaseUrl, ConnectionUrl, true, BundleVersionCode, "9.9", GameId,
"1", UnityVersion, true);

StringAssert.Contains("&androidAppVersion=9.9", url);
StringAssert.Contains("&game-version=1", url);
}
}
}
#endif

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

1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ This includes security related updates like requiring fixed Unity versions and i
- **Unity API:** `OnMaximumVolumeChanged` event to notify when the games maximum volume must be changed.
- **Android:** After the last device disconnects, the webview is reset along the game state.
- **Android:** Add support to override the game version used in a previously built android game through intent extras with adb.
- **Android:** The Android application version is now reported to the platform through the webview URL.
- **Android:** The support for native game sizing is communicated
- **Android Audio Focus:** Improvements to match the expected behavior on Android Automotive.
- **Android Audio Focus:** Drive maximum volume based on Android system requirements to avoid pausing when losing audio focus.
Expand Down
4 changes: 2 additions & 2 deletions ProjectSettings/ProjectVersion.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
m_EditorVersion: 2022.3.62f2
m_EditorVersionWithRevision: 2022.3.62f2 (7670c08855a9)
m_EditorVersion: 2022.3.62f3
m_EditorVersionWithRevision: 2022.3.62f3 (96770f904ca7)
Loading