مطورو Unity معتادون بالفعل على إدارة تدفقات الألعاب والخدمات على منصات مثل iOS و Android. ومع ذلك ، بعد ظهور خدمات Huawei المحمولة في النظام البيئي ، تحتاج الآن إلى دعم إصدار آخر من اللعبة إذا كنت تريد الوصول إلى اللاعبين الذين لديهم أجهزة Huawei.
تتناول هذه المقالة فقط كيفية إدارة التبعيات بين العديد من خدمات Android و Huawei المحمولة في قاعدة بيانات واحدة بأقل جهد.
الشكل 1. الفرق بين دعم الأنظمة الأساسية المختلفة وخدمات الهاتف المحمول
كما ترى في الشكل أعلاه ، تستخدم هواتف Huawei المحمولة نظام التشغيل Android ، لذلك يجب أن يستخدمه مشروع Unity عند إنشاء أجهزة من هذه الشركة. ومع ذلك ، أنت الآن بحاجة إلى تطوير ملفي APK مختلفين لنظام Android أو حزمة منفصلة لـ Huawei AppGallery.
ما الفرق بين ملفات APK هذه؟
الاختلاف الأول والأهم هو خدمات الهاتف المحمول. هذه خدمات مثل عمليات الشراء داخل التطبيق ، والإعلان ، وخدمات الألعاب ، والتحليلات ، وما إلى ذلك. لا يمكنك استخدام GMS على أجهزة Huawei المحمولة. لهذا السبب ، يصبح من الضروري إنشاء ملفي APK: للإصدار في Huawei AppGallery و Google Play.
الاختلاف الثاني الذي لا يقل أهمية هو اسم الحزمة. نظرًا لأن كلا النظامين البيئيين يعملان على Android ، لتجنب التناقضات والتجاوزات ، فإن معرض تطبيقات Huawei لديه قاعدة تقضي بأن اسم الحزمة الخاص بك يجب أن ينتهي بـ .huawei أو .HUAWEI. يستخدم هذا الأسلوب لفصل إصدارات Huawei عن جميع أجهزة Android الأخرى.
لكن لا تقلق: يمكننا التعامل مع هذه الاختلافات في قاعدة بيانات واحدة.
فيما يلي حيلتان صغيرتان للمساعدة في حل هذه المشكلات.
1. هل سمعت من قبل عن #defines؟
بفضل التعريفات ، يمكننا التحكم في خيوطنا في وقت الإنشاء ، وبفضل بيئة تطوير واحدة - وأثناء الترميز.
ما هي الجداول التي نتحدث عنها؟
تخيل أنك بحاجة إلى تشغيل نوعين من خدمات الألعاب: Google Play و Huawei. لإنشاء تطبيق لهم في رمز واحد ، يمكنك فصله باستخدام التعريفات. لنلق نظرة على مثال صغير:
internal static class GameServiceFactory
{
public static IGameServiceProvider CreateGameServiceProvider()
{
#if HMS_BUILD
return new HMSGameServiceProvider();
#else
return new GooglePlayGameServiceProvider();
#endif
}
}
إذا قمت بإضافة الكلمة الأساسية "HMS_BUILD" إلى قائمة التعريفات الخاصة بك ، فستقوم اللعبة باستدعاء HMSGameServiceProvider. بهذه الطريقة يمكننا إدارة خيوطنا في كود واحد.
يمكنك استخدام البرنامج النصي أدناه لإدارة التعريفات قبل الإنشاء. بعد تغيير DefineKeywords وحفظها ، سيقوم IDE بتحديث تدفق التعليمات البرمجية بناءً على الكلمات الرئيسية التي حددتها.
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. البرامج النصية قبل وبعد
الإنشاء (ما قبل الإنشاء وما بعد الإنشاء ) لذلك ، كما ذكرنا سابقًا ، نحتاج إلى تغيير اسم حزمة لعبتنا لإصدار Huawei AppGallery.
ومع ذلك ، إذا كنت تستخدم خدمات Google Play في نفس الوقت ، فسيتم ربط جميع التكوينات باسم الحزمة الحالية وسيؤثر تغييرها على التكوين. بالإضافة إلى ذلك ، سيحذرك محرر الوحدة في نافذة منبثقة من وقت لآخر لتصحيح اسم حزمة التطبيق ، لأن اسم الحزمة وتكوين خدمة الجوال مختلفان الآن. إغلاق هذه النافذة المنبثقة مرارًا وتكرارًا أمر شاق للغاية.
لحل هذه المشكلة وإدارة اسمين مختلفين للحزم في نفس الوقت ، يمكن استخدام حل بديل مع البرامج النصية سابقة الإنشاء وما بعد الإنشاء مع التعريفات.
ألق نظرة على هذا الرمز:
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
}
}
كما ترى ، كل شيء بسيط. بمساعدة التعريفات ، يمكننا تغيير اسم الحزمة أثناء الإنشاء المسبق لـ HMS_BUILD فقط. بعد ذلك ، بعد البناء ، يمكنك إعادة اسم الحزمة إلى الاسم الأصلي ، وبعد ذلك لن تحذرنا الوحدة من عدم تطابق اسم الحزمة.
هذا كل شئ. نحن الآن جاهزون لتطوير لعبة برمز واحد لهواوي وجوجل بلاي في نفس الوقت.
مثال على تطوير التطبيق
لننشئ تطبيقًا في نفس قاعدة الشفرة لأجهزة Android و Huawei ، والذي يتضمن خدمات الألعاب وعمليات الشراء داخل اللعبة والإعلانات.
لن نقوم بتنفيذ جميع الوظائف لكل خدمة لأن هذا مجرد عرض توضيحي. يمكنك تمديد كل ميزة ووظيفة بنفسك.
هيكل وحدة الخدمة
الشكل 2. مخطط تشغيل وحدات
الخدمة لكل خدمة سيكون لدينا خاصتنا ؛
- مدير : تتضمن هذه الفئة منطق اللعبة للخدمات وتدير الوظائف العامة. قد تحتاج الألعاب المختلفة إلى تغيير هذه الفئة لتناسب متطلباتك.
- فئة المصنع (المصنع) : تتضمن هذه الفئة منطق اختيار المزود. في نهجنا ، سوف نستخدم التعريفات ، ولكن يمكنك تغيير آلية اختيار المزود حسب رغبتك.
- مزود : لكل خدمة ، نحتاج إلى إنشاء مزود خاص به. يجب أن تظل جميع التبعيات بين مشروعك وخدمات الهاتف المحمول ضمن هذه الفئة.
- واجهة الموفر : لتوحيد استخدام مختلف خدمات الهاتف المحمول ، نحتاج إلى مزودين مشتركين ، ولهذا الغرض ، يتم إنشاء واجهات مزود. وفقًا لمتطلبات لعبتك ، تحتاج إلى تحديد جميع الأساليب التي ستستخدمها في لعبتك من خدمات الهاتف المحمول.
إذا لزم الأمر ، يمكنك أيضًا تمكين:
- الكيانات العامة : قد تحتاج إلى كيانات عامة لاستخراج بعض الخدمات من لعبتك. للاحتفاظ بالتبعية على فئات الموفر فقط ، يمكنك استخدام الكيانات العامة وفقًا لمتطلباتك.
- المستمعين العامين: على غرار الكيانات العامة ، إذا كنت تريد مستمعين عامين ، فيمكنك إنشاء هؤلاء أيضًا.
الشكل 3. مثال على هيكل لوحدة خدمة لعبة
الآن دعونا نلقي نظرة على الأمثلة ونحاول فهم ما يمكننا فعله بالطريقة الموضحة في المقالة.
لاستخراج خدمات الهاتف المحمول من منطق اللعبة ، سنستخدم المديرين. يتواصل المديرون مع مقدمي الخدمات من خلال الأقمشة. بهذه الطريقة يمكننا استخدام موفري الخدمة مثل المكونات الإضافية. إنهم بحاجة إلى تنفيذ واجهة مشتركة تحتوي على الأساليب التي نريد الوصول إليها.
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();
}
ثم نحتاج إلى مزود واحد على الأقل يقوم بتنفيذ واجهة الخدمة. كما ذكرنا سابقًا ، يجب أن تظل جميع التبعيات بين اللعبة وخدمات الهاتف المحمول التابعة لجهات خارجية ضمن هذه الفئة. لنقم بإنشاء مزودين اثنين: لهواوي وجوجل بلاي.
هذه بعض الأمثلة البرمجية. يمكنك العثور عليها في المشروع على GitHub في نهاية المقالة.
مزود خدمة ألعاب هواوي
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
public class GooglePlayGameServiceProvider : IGameServiceProvider
{
private static string TAG = "GooglePlayServiceProvider";
private PlayGamesPlatform _platform;
public CommonAuthUser commonAuthUser = null;
public void Init()
{
InitPlayGamesPlatform();
}
....
}
الآن نحن بحاجة إلى إنشاء مدير وفئة مصنع. ثم نحصل على المزود وفقًا لتعريفنا.
public class GameServiceManager : Singleton<GameServiceManager>
{
public IGameServiceProvider provider;
protected override void Awake()
{
base.Awake();
provider = GameServiceFactory.CreateGameServiceProvider();
}
.....
}
هذا ما تبدو عليه فئة المصنع:
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 ، تتغير وظائف تسجيل الدخول والخروج ولوحات المتصدرين والإنجازات وعمليات الشراء داخل اللعبة.
فيما يلي مقاطع فيديو قصيرة لكلا التجميعين.
في حالة "HMS_BUILD":
في حالة "GMS_BUILD":
يمكن العثور على مشروع تجريبي وملفات APK مُعدة لـ HMS و GMS على الرابط الموجود على GitHub .