Unity-Entwickler sind bereits daran gewöhnt, Spiel-Streams und -Dienste auf Plattformen wie iOS und Android zu verwalten. Nachdem die mobilen Dienste von Huawei im Ökosystem erschienen sind, müssen Sie jetzt eine andere Version des Spiels unterstützen, wenn Sie Spieler mit Huawei-Geräten erreichen möchten.
In diesem Artikel geht es nur darum, wie Sie Abhängigkeiten zwischen mehreren mobilen Android- und Huawei-Diensten in einer Codebasis mit minimalem Aufwand verwalten können.
Abbildung 1. Der Unterschied zwischen der Unterstützung für verschiedene Plattformen und mobile Dienste
Wie Sie in der obigen Abbildung sehen können, verwenden Huawei-Mobiltelefone das Android-Betriebssystem. Daher sollte Ihr Unity-Projekt es beim Erstellen von Geräten dieses Unternehmens verwenden. Jetzt müssen Sie jedoch 2 verschiedene APKs für Android oder ein separates Paket für Huawei AppGallery entwickeln.
Was ist der Unterschied zwischen diesen APKs?
Der wichtigste Unterschied sind mobile Dienste. Hierbei handelt es sich um Dienste wie In-App-Käufe, Werbung, Spieledienste, Analysen usw. Sie können das GMS nicht auf Huawei-Mobilgeräten verwenden. Aus diesem Grund müssen zwei APKs erstellt werden: für die Veröffentlichung in Huawei AppGallery und in Google Play.
Der zweite wichtige Unterschied ist der Paketname. Da beide Ökosysteme unter Android ausgeführt werden, gilt in der Huawei App Gallery die Regel, dass Ihr Paketname mit .huawei oder .HUAWEI enden muss, um Inkonsistenzen und Überschreibungen zu vermeiden. Dieser Ansatz wird verwendet, um Huawei-Builds von allen anderen Android-Geräten zu trennen.
Aber keine Sorge: Wir können diese Unterschiede in einer Codebasis behandeln.
Hier sind zwei kleine Tricks, um diese Probleme zu lösen.
1. Hast du jemals von #defines gehört?
Dank Defines können wir unsere Threads zur Erstellungszeit und dank einer einzigen Entwicklungsumgebung steuern - und während des Codierens.
Über welche Streams sprechen wir?
Stellen Sie sich vor, Sie müssen zwei Arten von Spielediensten betreiben: Google Play und Huawei. Um eine Anwendung für sie in einem Code zu erstellen, können Sie sie mithilfe von Definitionen trennen. Schauen wir uns ein kleines Beispiel an:
internal static class GameServiceFactory
{
public static IGameServiceProvider CreateGameServiceProvider()
{
#if HMS_BUILD
return new HMSGameServiceProvider();
#else
return new GooglePlayGameServiceProvider();
#endif
}
}
Wenn Sie das Schlüsselwort "HMS_BUILD" zu Ihrer Definitionsliste hinzufügen, ruft das Spiel HMSGameServiceProvider auf. Auf diese Weise können wir unsere Threads in einem Code verwalten.
Sie können das folgende Skript verwenden, um Definitionen vor dem Erstellen zu verwalten. Nachdem Sie die DefineKeywords geändert und gespeichert haben, aktualisiert die IDE den Codefluss gemäß den von Ihnen angegebenen Schlüsselwörtern.
public class ManageDefines : Editor
{
/// <summary>
/// Symbols that will be added to the editor
/// </summary>
public static readonly string [] DefineKeywords = new string[] {
//"TEST_VERSION",
"HMS_BUILD",
//"GMS_BUILD",
};
/// <summary>
/// Add define symbols as soon as Unity gets done compiling.
/// </summary>
static AddDefineSymbols ()
{
List<string> allDefines = new List<string>();
allDefines.AddRange ( DefineKeywords.Except ( allDefines ) );
PlayerSettings.SetScriptingDefineSymbolsForGroup (
EditorUserBuildSettings.selectedBuildTargetGroup,
string.Join ( ";", allDefines.ToArray () ) );
}
}
2. Skripte vor und nach dem Build (Pre-Build und Post-Build)
Wie bereits erwähnt, müssen wir den Paketnamen unseres Spiels für die Huawei AppGallery-Version ändern.
Wenn Sie jedoch gleichzeitig Google Play-Dienste verwenden, werden alle Konfigurationen an Ihren vorhandenen Paketnamen gebunden, und eine Änderung wirkt sich auf die Konfiguration aus. Darüber hinaus warnt Sie der Unity-Editor in einem Popup-Fenster von Zeit zu Zeit, den Anwendungspaketnamen zu korrigieren, da jetzt der Paketname und die Konfiguration des Mobilfunkdienstes unterschiedlich sind. Das Popup immer wieder zu schließen ist sehr mühsam.
Um dieses Problem zu lösen und zwei verschiedene Paketnamen gleichzeitig zu verwalten, kann eine Problemumgehung mithilfe von Skripten vor und nach dem Erstellen mit Definitionen durchgeführt werden.
Schauen Sie sich diesen Code an:
class MyCustomBuildProcessor : IPreprocessBuildWithReport, IPostprocessBuildWithReport
{
public int callbackOrder { get { return 0; } }
public void OnPostprocessBuild(BuildReport report)
{
PlayerSettings.SetApplicationIdentifier(BuildTargetGroup.Android, "your.package.name");
}
public void OnPreprocessBuild(BuildReport report)
{
#if HMS_BUILD
PlayerSettings.SetApplicationIdentifier(BuildTargetGroup.Android, "your.package.name.huawei");
#elif GMS_BUILD
PlayerSettings.SetApplicationIdentifier(BuildTargetGroup.Android, "your.package.name");
#endif
}
}
Wie Sie sehen können, ist alles einfach. Mit Definitionen können wir den Paketnamen nur während der Vorerstellung für HMS_BUILD ändern. Nach dem Erstellen können Sie den Paketnamen auf den ursprünglichen zurücksetzen. Unity warnt uns dann nicht mehr vor der Nichtübereinstimmung des Paketnamens.
Das ist alles. Wir sind jetzt bereit, ein Spiel in einem Code für Huawei und Google Play gleichzeitig zu entwickeln.
Anwendungsentwicklungsbeispiel
Lassen Sie uns eine Anwendung in derselben Codebasis für Android und Huawei erstellen, die Spieledienste, Einkäufe im Spiel und Werbung umfasst.
Wir werden nicht alle Funktionen für jeden Service implementieren, da dies nur eine Demo ist. Sie können jede Funktion selbst erweitern.
Struktur des Servicemoduls
Abbildung 2. Funktionsschema der Servicemodule
Für jeden Service haben wir unseren eigenen.
- Manager : Diese Klasse enthält Spielelogik für Dienste und verwaltet allgemeine Funktionen. Möglicherweise müssen verschiedene Spiele diese Klasse ändern, um Ihren Anforderungen zu entsprechen.
- Factory-Klasse (Factory) : Diese Klasse enthält die Logik zur Auswahl eines Anbieters. In unserem Ansatz werden Definitionen verwendet, aber Sie können den Anbieterauswahlmechanismus nach Ihren Wünschen ändern.
- Anbieter : Für jeden Dienst müssen wir einen eigenen Anbieter erstellen. Alle Abhängigkeiten zwischen Ihrem Projekt und mobilen Diensten müssen innerhalb dieser Klasse bleiben.
- Anbieterschnittstelle : Um die Nutzung verschiedener mobiler Dienste zu vereinheitlichen, benötigen wir gemeinsame Anbieter. Zu diesem Zweck werden Anbieterschnittstellen erstellt. Gemäß den Anforderungen Ihres Spiels müssen Sie alle Methoden definieren, die Sie in Ihrem Spiel von mobilen Diensten aus verwenden werden.
Bei Bedarf können Sie auch Folgendes aktivieren:
- Allgemeine Entitäten : Möglicherweise benötigen Sie generische Entitäten, um einige Dienste aus Ihrem Spiel zu abstrahieren. Um die Abhängigkeit nur von den Anbieterklassen beizubehalten, können Sie generische Entitäten gemäß Ihren Anforderungen verwenden.
- Generische Listener : Ähnlich wie bei generischen Entitäten können Sie auch generische Listener erstellen, wenn Sie generische Listener möchten.
Abbildung 3. Beispielstruktur für ein
Spieledienstmodul Schauen wir uns nun Beispiele an und versuchen zu verstehen, was wir mit der im Artikel beschriebenen Methode tun können.
Um mobile Dienste von der Spielelogik zu abstrahieren, werden wir Manager verwenden. Manager kommunizieren mit Anbietern über Stoffe. Auf diese Weise können wir Anbieter wie Plugins verwenden. Sie müssen eine gemeinsame Schnittstelle implementieren, die die Methoden enthält, auf die wir zugreifen möchten.
public interface IGameServiceProvider
{
void Init();
bool IsAuthenticated();
void SignOut();
void AuthenticateUser(Action<bool> callback = null);
void SendScore(int score, string boardId);
void ShowLeaderBoard(string boardId = "");
void ShowAchievements();
void UnlockAchievement(string key);
CommonAuthUser GetUserInfo();
}
Dann brauchen wir mindestens einen Anbieter, der die Service-Schnittstelle implementiert. Wie bereits erwähnt, müssen alle Abhängigkeiten zwischen dem Spiel und mobilen Diensten von Drittanbietern innerhalb dieser Klasse bleiben. Erstellen wir zwei Anbieter: für Huawei und Google Play.
Hier sind einige Codebeispiele. Sie finden sie im Projekt auf GitHub am Ende des Artikels.
Huawei Game Service Provider
public class HMSGameServiceProvider : IGameServiceProvider
{
private static string TAG = "HMSGameServiceProvider";
private HuaweiIdAuthService _authService;
private IRankingsClient _rankingClient;
private IAchievementsClient _achievementClient;
public AuthHuaweiId HuaweiId;
public CommonAuthUser commonAuthUser = null;
public void Init()
{
InitHuaweiAuthService();
}
....
}
Google Game Service Provider
public class GooglePlayGameServiceProvider : IGameServiceProvider
{
private static string TAG = "GooglePlayServiceProvider";
private PlayGamesPlatform _platform;
public CommonAuthUser commonAuthUser = null;
public void Init()
{
InitPlayGamesPlatform();
}
....
}
Jetzt müssen wir einen Manager und eine Fabrikklasse erstellen. Dann bekommen wir den Anbieter nach unserer Definition.
public class GameServiceManager : Singleton<GameServiceManager>
{
public IGameServiceProvider provider;
protected override void Awake()
{
base.Awake();
provider = GameServiceFactory.CreateGameServiceProvider();
}
.....
}
So sieht unsere Fabrikklasse aus:
internal static class GameServiceFactory
{
public static IGameServiceProvider CreateGameServiceProvider()
{
#if HMS_BUILD
return new HMSGameServiceProvider();
#else
return new GooglePlayGameServiceProvider();
#endif
}
}
Das war's: Wir haben jetzt eine GameManager-Klasse, die die Funktionalität eines Spieledienstes mit mehreren Anbietern verwalten kann.
Verwenden Sie zum Initialisieren von GameServices gegebenenfalls die folgenden Codezeilen:
public class MainSceneManager : MonoBehaviour
{
void Start()
{
GameServiceManager.Instance.Init();
....
}
....
private void OnClickedScoreBoardButton()
{
GameServiceManager.Instance.provider.ShowLeaderBoard();
}
private void OnClickedAchievementButton()
{
GameServiceManager.Instance.provider.ShowAchievements();
}
....
}
Wir werden nicht auf die Arbeit jedes Servicemoduls eingehen, da alle dieselbe Logik und Struktur haben. Sie können sie in Aktion sehen, indem Sie den Code aus dem Projekt nach GitHub kopieren.
Wenn Sie Anleitungen zum Einrichten des Huawei-Plugins in Unity benötigen, wird dies in diesem Beitrag beschrieben .
Kommen wir zu den Schlussfolgerungen.
Durch Ändern der Definitionen zwischen HMS_BUILD und GMS_BUILD in DefineConfig.cs:
- Wir können zwei verschiedene APKs oder Pakete für Huawei AppGallery und Google Play erhalten.
- Zwischen HMS und GMS ändern sich die Anmelde- und Abmeldefunktionen, Bestenlisten, Erfolge und Einkäufe im Spiel.
Unten finden Sie kurze Videos beider Baugruppen.
Bei "HMS_BUILD":
Bei "GMS_BUILD":
Demo-Projekt und vorbereitete APKs für HMS und GMS finden Sie unter dem Link auf GitHub .