Для Unity-разработчиков уже привычно управление игровыми потоками и сервисами на таких платформах, как iOS и Android. Однако после того, как в экосистеме появились мобильные сервисы Huawei, теперь нужно поддерживать и еще одну версию игры, если вы хотите охватить игроков, у которых есть девайсы этой фирмы.
Эта статья — как раз о том, как минимальными усилиями управлять зависимостями между несколькими мобильными сервисами Android и Huawei в одной кодовой базе.
Рисунок 1. Разница между поддержкой разных платформ и мобильных сервисов
Как видно на рисунке выше, мобильные телефоны Huawei используют операционную систему Android, так что и ваш Unity-проект должен использовать ее же при сборке для девайсов этой фирмы. Однако теперь вам нужно разработать 2 разных APK на Android или же отдельный пакет для Huawei AppGallery.
В чем разница между этими APK?
Первое и главное различие — мобильные сервисы. Речь идет о таких сервисах, как внутриигровые покупки, реклама, игровые сервисы, аналитика и т. д. Вы не можете использовать GMS в мобильных устройствах Huawei. Из-за этого возникает необходимость в создании двух APK: для релиза в Huawei AppGallery и в Google Play.
Второе не менее важное отличие — имя пакета. Поскольку обе экосистемы работают на Android, чтобы избежать несогласованности и переопределения, в Huawei App Gallery заведено правило: имя вашего пакета должно заканчиваться на .huawei или .HUAWEI. Такой подход используется для отделения сборок для Huawei от всех остальных девайсов на Android.
Но не волнуйтесь: мы можем справиться с этими различиями в одной кодовой базе.
Расскажем о двух небольших приемах, которые помогут решить эти проблемы.
1. Вы когда-нибудь слышали о #defines?
Благодаря определениям (defines) мы можем управлять нашими потоками во время сборки, а благодаря единой среде разработки — и во время кодирования.
О каких потоках речь?
Представьте, что вам нужно оперировать двумя видами игровых сервисов: Google Play и Huawei. Чтобы создать для них приложение в одном коде, можно разделить его при помощи определений (defines). Рассмотрим небольшой пример:
internal static class GameServiceFactory { public static IGameServiceProvider CreateGameServiceProvider() { #if HMS_BUILD return new HMSGameServiceProvider(); #else return new GooglePlayGameServiceProvider(); #endif } }
Если вы добавите ключевое слово «HMS_BUILD» в ваш список определений, игра вызовет HMSGameServiceProvider. Так мы сможем управлять нашими потоками в одном коде.
Для управления определениями перед сборкой можно использовать приведенный ниже скрипт. После изменения и сохранения DefineKeywords интегрированная среда разработки обновит поток кода в соответствии с заданными ключевыми словами.
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. Скрипты до и после сборки (pre-build и post-build)
Итак, как уже упоминалось ранее, нам нужно изменить имя пакета нашей игры для версии Huawei AppGallery.
Однако, если вы в то же время используете сервисы Google Play, все конфигурации будут привязаны к вашему существующему имени пакета, и его изменение повлияет на конфигурацию. Кроме того, редактор Unity во всплывающем окне будет из раза в раз предупреждать вас об исправлении имени пакета приложения, ведь теперь имя пакета и конфигурация мобильного сервиса отличаются. Закрывать это всплывающее окно снова и снова очень утомительно.
Чтобы решить эту проблему и управлять двумя разными именами пакетов одновременно, можно использовать обходной путь с помощью pre-build и post-build сценариев с определениями.
Взгляните на этот код:
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 } }
Как видите, все просто. С помощью определений мы можем изменить имя пакета во время pre-build только для HMS_BUILD. Затем после сборки можно снова вернуть имя пакета к исходному, и тогда Unity больше не будет предупреждать нас о несовпадении имени пакета.
Вот и все. Теперь мы готовы разрабатывать игру в одном коде для Huawei и Google Play одновременно.
Пример разработки приложения
Создадим приложение в одной кодовой базе для Android и Huawei, включающее в себя игровые сервисы, внутриигровые покупки и рекламу.
Мы не будем реализовывать все функции для каждого сервиса, поскольку это всего лишь демонстрационный пример. Каждую фичу и функциональность вы можете расширить самостоятельно.
Структура сервисных модулей
Рисунок 2. Схема работы сервисных модулей
Для каждого сервиса у нас будут свои;
- Менеджер (Manager): этот класс включает в себя игровую логику для сервисов и управляет общими функциональностями. Для разных игр может потребоваться изменение этого класса в соответствии со своими требованиями.
- Фабричный класс (Factory): этот класс включает в себя логику выбора провайдера. В нашем подходе мы будем использовать определения, но вы можете изменить механизм выбора провайдера на свой вкус.
- Провайдер (Provider): для каждого сервиса нам нужно создать свой провайдер. Все зависимости между вашим проектом и мобильными сервисами должны оставаться в рамках этого класса.
- Интерфейс провайдера (Provider Interface): для унификации использования различных мобильных сервисов нам нужны общие провайдеры, и с этой целью заводятся интерфейсы провайдеров. В соответствии с требованиями вашей игры вам нужно определить все методы, которые вы будете использовать в своей игре из мобильных сервисов.
При необходимости можно еще включить:
- Общие сущности (entities): для абстрагирования некоторых сервисов от вашей игры вам могут понадобиться общие сущности. Чтобы сохранить зависимость только от классов провайдеров, можно использовать общие сущности в соответствии с вашими требованиями.
- Общих слушателей (listeners): аналогично общим сущностям, если вам нужны общие слушатели, вы можете создать и их.
Рисунок 3. Пример структуры для модуля игрового сервиса
Теперь давайте рассмотрим примеры и попытаемся понять, что мы можем сделать с помощью описанного в статье метода.
Чтобы абстрагировать мобильные сервисы от игровой логики, мы будем использовать менеджеров. Менеджеры связываются с провайдерами через fabrics. Таким образом, мы можем использовать провайдеров как плагины. Им необходимо реализовать общий интерфейс, содержащий методы, к которым мы хотим получить доступ.
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(); }
Затем нам понадобится хотя бы один провайдер, реализующий интерфейс сервиса. Как уже говорилось ранее, все зависимости между игрой и сторонними мобильными сервисами должны оставаться в пределах этого класса. Создадим два провайдера: для Huawei и Google Play.
Приведем примеры кода. Их вы можете найти в проекте на GitHub в конце статьи.
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(); } .... }
Теперь нам нужно создать менеджер и класс factory. Тогда мы получим провайдера в соответствии с нашим определением.
public class GameServiceManager : Singleton<GameServiceManager> { public IGameServiceProvider provider; protected override void Awake() { base.Awake(); provider = GameServiceFactory.CreateGameServiceProvider(); } ..... }
Так выглядит наш класс factory:
internal static class GameServiceFactory { public static IGameServiceProvider CreateGameServiceProvider() { #if HMS_BUILD return new HMSGameServiceProvider(); #else return new GooglePlayGameServiceProvider(); #endif } }
Вот и все: теперь у нас есть класс GameManager, который может управлять функциями игрового сервиса с несколькими провайдерами.
Чтобы инициализировать GameServices, используем приведенные ниже строки кода там, где это нужно:
public class MainSceneManager : MonoBehaviour { void Start() { GameServiceManager.Instance.Init(); .... } .... private void OnClickedScoreBoardButton() { GameServiceManager.Instance.provider.ShowLeaderBoard(); } private void OnClickedAchievementButton() { GameServiceManager.Instance.provider.ShowAchievements(); } .... }
Не будем вдаваться в работу каждого сервисного модуля, поскольку все они имеют одинаковую логику и структуру. Посмотреть на них в деле можно, скопировав код из проекта на GitHub.
Кроме того, если вам нужно руководство по настройке плагина Huawei в Unity, это описано в данном посте.
Перейдем к выводам.
С помощью изменения определений между HMS_BUILD и GMS_BUILD в DefineConfig.cs:
- мы можем получить два разных APK или пакета для Huawei AppGallery и Google Play;
- между HMS и GMS меняются функции входа и выхода (Login&Logout), доски лидеров, достижения, внутриигровые покупки.
Ниже приведены короткие видеозаписи обеих сборок.
В случае «HMS_BUILD»:
В случае «GMS_BUILD»:
Демо-проект и подготовленные APK для HMS и GMS можно найти по ссылке на GitHub.
ссылка на оригинал статьи https://habr.com/ru/company/pixonic/blog/532496/
Добавить комментарий