Os desenvolvedores do Unity já estão acostumados a gerenciar fluxos de jogos e serviços em plataformas como iOS e Android. No entanto, depois que os serviços móveis da Huawei apareceram no ecossistema, agora você precisa oferecer suporte a outra versão do jogo se quiser alcançar jogadores que tenham dispositivos Huawei.
Este artigo é apenas sobre como gerenciar dependências entre vários serviços móveis Android e Huawei em uma base de código com o mínimo de esforço.
Figura 1. A diferença entre o suporte para diferentes plataformas e serviços móveis
Como você pode ver na figura acima, os telefones celulares Huawei usam o sistema operacional Android, portanto, seu projeto Unity deve usá-lo ao construir para dispositivos desta empresa. No entanto, agora você precisa desenvolver 2 APKs diferentes para Android ou um pacote separado para Huawei AppGallery.
Qual é a diferença entre esses APKs?
A principal diferença são os serviços móveis. Estes são serviços como compras no aplicativo, publicidade, serviços de jogos, análises, etc. Você não pode usar o GMS em dispositivos móveis Huawei. Por isso, torna-se necessário criar dois APKs: para lançamento no Huawei AppGallery e no Google Play.
A segunda diferença igualmente importante é o nome do pacote. Como os dois ecossistemas são executados no Android, para evitar inconsistências e substituições, a Huawei App Gallery tem uma regra de que o nome do seu pacote deve terminar em .huawei ou .HUAWEI. Essa abordagem é usada para separar os builds da Huawei de todos os outros dispositivos Android.
Mas não se preocupe: podemos lidar com essas diferenças em uma base de código.
Aqui estão dois pequenos truques para ajudar a resolver esses problemas.
1. Você já ouviu falar em #defines?
Graças a define, podemos controlar nossos threads em tempo de construção e graças a um único ambiente de desenvolvimento - e durante a codificação.
De que streams estamos falando?
Imagine que você precise operar dois tipos de serviços de jogos: Google Play e Huawei. Para criar um aplicativo para eles em um código, você pode separá-lo usando definições. Vejamos um pequeno exemplo:
internal static class GameServiceFactory
{
public static IGameServiceProvider CreateGameServiceProvider()
{
#if HMS_BUILD
return new HMSGameServiceProvider();
#else
return new GooglePlayGameServiceProvider();
#endif
}
}
Se você adicionar a palavra-chave "HMS_BUILD" à sua lista de definições, o jogo chamará HMSGameServiceProvider. Desta forma, podemos gerenciar nossos threads em um código.
Você pode usar o script abaixo para gerenciar as definições antes de construir. Depois de alterar e salvar o DefineKeywords, o IDE atualizará o fluxo de código com base nas palavras-chave que você especificou.
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. Scripts antes e depois da compilação (pré-compilação e pós-compilação)
Portanto, como mencionado anteriormente, precisamos alterar o nome do pacote do nosso jogo para a versão Huawei AppGallery.
No entanto, se você estiver usando o Google Play Services ao mesmo tempo, todas as configurações serão associadas ao nome do seu pacote existente e alterá-lo afetará a configuração. Além disso, o editor do Unity em uma janela pop-up irá avisá-lo de vez em quando para corrigir o nome do pacote do aplicativo, porque agora o nome do pacote e a configuração do serviço móvel são diferentes. Fechar este pop-up repetidamente é muito tedioso.
Para resolver este problema e gerenciar dois nomes de pacote diferentes ao mesmo tempo, uma solução alternativa pode ser usada com scripts de pré-construção e pós-construção com definições.
Dê uma olhada neste código:
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
}
}
Como você pode ver, tudo é simples. Com a ajuda de definições, podemos alterar o nome do pacote durante a pré-construção apenas para HMS_BUILD. Então, após a construção, você pode retornar o nome do pacote ao original e o Unity não nos avisará mais sobre a incompatibilidade do nome do pacote.
Isso é tudo. Agora estamos prontos para desenvolver um jogo em um código para Huawei e Google Play ao mesmo tempo.
Exemplo de desenvolvimento de aplicativo
Vamos criar um aplicativo na mesma base de código para Android e Huawei, que inclui serviços de jogo, compras no jogo e publicidade.
Não implementaremos todas as funcionalidades para cada serviço, pois esta é apenas uma demonstração. Você mesmo pode estender cada recurso e funcionalidade.
Estrutura do módulo de serviço
Figura 2. Esquema de funcionamento dos módulos de serviço
Para cada serviço teremos o nosso;
- Gerente : Esta classe inclui a lógica do jogo para os serviços e gerencia a funcionalidade geral. Jogos diferentes podem precisar mudar esta classe para atender às suas necessidades.
- Classe de fábrica (fábrica) : esta classe inclui a lógica para escolher um provedor. Em nossa abordagem, usaremos definições, mas você pode alterar o mecanismo de seleção de provedor de acordo com sua preferência.
- Provedor : para cada serviço, precisamos criar seu próprio provedor. Todas as dependências entre seu projeto e os serviços móveis devem permanecer dentro desta classe.
- Interface do provedor : Para unificar o uso de vários serviços móveis, precisamos de provedores comuns e, para isso, são criadas interfaces de provedor. De acordo com os requisitos do seu jogo, você precisa definir todos os métodos que usará em seu jogo nos serviços móveis.
Se necessário, você também pode ativar:
- Entidades genéricas : você pode precisar de entidades genéricas para abstrair alguns serviços do seu jogo. Para manter a dependência apenas nas classes de provedor, você pode usar entidades genéricas de acordo com sua necessidade.
- Ouvintes genéricos : semelhantes a entidades genéricas, se desejar ouvintes genéricos, você também pode criá-los.
Figura 3. Um exemplo de estrutura para um módulo de serviço de jogo
Agora, vamos examinar os exemplos e tentar entender o que podemos fazer com o método descrito no artigo.
Para abstrair os serviços móveis da lógica do jogo, usaremos gerentes. Os gerentes se comunicam com os fornecedores por meio de tecidos. Dessa forma, podemos usar provedores como plug-ins. Eles precisam implementar uma interface comum contendo os métodos que queremos acessar.
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();
}
Então, precisamos de pelo menos um provedor que implemente a interface de serviço. Conforme mencionado anteriormente, todas as dependências entre o jogo e os serviços móveis de terceiros devem permanecer dentro desta classe. Vamos criar dois provedores: para Huawei e Google Play.
Aqui estão alguns exemplos de código. Você pode encontrá-los no projeto no GitHub no final do artigo.
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();
}
....
}
Provedor de serviços de jogos do Google
public class GooglePlayGameServiceProvider : IGameServiceProvider
{
private static string TAG = "GooglePlayServiceProvider";
private PlayGamesPlatform _platform;
public CommonAuthUser commonAuthUser = null;
public void Init()
{
InitPlayGamesPlatform();
}
....
}
Agora precisamos criar um gerente e uma classe de fábrica. Então obtemos o provedor de acordo com nossa definição.
public class GameServiceManager : Singleton<GameServiceManager>
{
public IGameServiceProvider provider;
protected override void Awake()
{
base.Awake();
provider = GameServiceFactory.CreateGameServiceProvider();
}
.....
}
Esta é a aparência de nossa classe de fábrica:
internal static class GameServiceFactory
{
public static IGameServiceProvider CreateGameServiceProvider()
{
#if HMS_BUILD
return new HMSGameServiceProvider();
#else
return new GooglePlayGameServiceProvider();
#endif
}
}
É isso: agora temos uma classe GameManager que pode gerenciar a funcionalidade de um serviço de jogo com vários provedores.
Para inicializar GameServices, use as seguintes linhas de código quando apropriado:
public class MainSceneManager : MonoBehaviour
{
void Start()
{
GameServiceManager.Instance.Init();
....
}
....
private void OnClickedScoreBoardButton()
{
GameServiceManager.Instance.provider.ShowLeaderBoard();
}
private void OnClickedAchievementButton()
{
GameServiceManager.Instance.provider.ShowAchievements();
}
....
}
Não entraremos no trabalho de cada módulo de serviço, pois todos possuem a mesma lógica e estrutura. Você pode vê-los em ação copiando o código do projeto para o GitHub.
Além disso, se você precisar de orientação sobre como configurar o plugin Huawei no Unity, isso é descrito neste post .
Vamos passar às conclusões.
Alterando as definições entre HMS_BUILD e GMS_BUILD em DefineConfig.cs:
- podemos obter dois APKs ou pacotes diferentes para Huawei AppGallery e Google Play;
- entre HMS e GMS, funções de Login e Logout, tabelas de classificação, conquistas e compras no jogo estão mudando.
Abaixo estão vídeos curtos de ambas as assembleias.
No caso de "HMS_BUILD":
No caso de "GMS_BUILD":
Projeto de demonstração e APKs preparados para HMS e GMS podem ser encontrados no link no GitHub .