الرسوم المتحركة المقدمة من الخادم في تطبيقات iOS



مرحبا بالجميع! منذ حوالي ستة أشهر ، أطلقنا واحدة من أكثر ميزات Badoo إثارة: البث المباشر . واحدة من وظائفها الرئيسية هي أن المشاهدين يمكنهم إرسال الهدايا إلى المقاطع المفضلة لديهم للتعبير عن تقديرهم. لقد أردنا أن نجعل الهدايا رائعة ومثيرة للاهتمام قدر الإمكان ، لذلك تقرر أن نجعل منها حية للغاية ، وأعني بذلك الرسوم المتحركة. ولإشراك الناس أكثر ، خططنا فريق Badoo لتحديث تلك الهدايا والرسوم المتحركة كل بضعة أسابيع.

كمهندس دائرة الرقابة الداخلية ، ربما كنت قد خمنت بالفعل التحدي الذي واجهناه هنا: الحاجة إلى إضافة رسوم متحركة جديدة وإزالة الصور القديمة ستحتاج إلى قدر لا بأس به من العمل من جانب العميل. سنحتاج إلى كلٍ من فرق تطوير Android و iOS لكل إصدار - والذي ، عندما يقترن مع مقدار الوقت الذي تستغرقه مراجعات متجر التطبيقات والموافقة عليه غالبًا ، قد يعني أنه قد يستغرق الأمر أيامًا قبل بدء التحديث. لكننا حل المشكلة ، وسأشرح لك كيف.

نظرة عامة على الحل


في هذه المرحلة ، عرفنا بالفعل كيفية تصدير الرسوم المتحركة لـ Adobe After Effects (AAE) إلى التنسيق الذي يمكن قراءته بواسطة تطبيق iOS الخاص بنا باستخدام مكتبة Lottie. هذه المرة ، ذهبنا أبعد من ذلك: قررنا إنشاء نوع من خدمات تخزين الرسوم المتحركة ، المتاحة عبر الإنترنت. بمعنى آخر ، سنقوم بتخزين جميع الرسوم المتحركة الفعلية على الخادم وتسليمها إلى تطبيقات العميل حسب الطلب:



إليك ما يبدو عليه الحل النهائي في محاكي iOS على جهاز المطور:


ومع ذلك ، في هذا المنشور ، المثال الذي سأستخدمه هو رسم بسيط للغاية أنشأته بنفسي. إنه ليس خياليًا مثل Badoo ، لكنه جيد بما يكفي لإظهار إمكانات النهج الموصوف.

تصدير الرسوم المتحركة


يمكن العثور على مشروع Adobe After Effects (AAE) للرسوم المتحركة التي أستخدمها هنا مع الملفات المصدر الأخرى على github . لذلك ، بعد فتح مشروع الرسوم المتحركة AAE الموجود في _raw/animations/Fancy/Fancy.aep ، سترى نافذة مثل هذا:



في هذه المرحلة ، لن أخوض في كيفية إنشاء الرسوم المتحركة في AEE ، لكن ما سأشرحه هو كيفية استيراد الرسوم المتحركة الموجودة بالفعل من AAE إلى تنسيق يمكن قراءته لتطبيق iOS باستخدام البرنامج المساعد Bodymovin .

بعد التأكد من تثبيت المكون الإضافي ، افتحه عن طريق تحديد خيار Window / Extensions / Bodymovin في القائمة:



الآن سترى نافذة Bodymovin حيث يمكنك تحديد الرسوم المتحركة التي ترغب في تصديرها ، وتحديد مسار ملف الإخراج ثم فتح إعدادات التصدير:



بعد تحديد إعدادات الرسوم المتحركة وفتحها ، يمكننا الآن مطالبة Bodymovin بتضمين الأصول في ملف JSON الناتج عن طريق تحديد الخيار Assets / Include in json :



أخيرًا ، يتم تصدير تركيبة الرسوم المتحركة المحددة وحفظها في الملف المحدد من خلال النقر فوق الزر Render .

تخزين الرسوم المتحركة على الخادم


لنفترض أننا قمنا بنقل ملفات JSON للرسوم المتحركة الخاصة بنا إلى خادم الويب المفضل لدينا عبر الإنترنت. في حالتنا ، من أجل البساطة ، قمت بتحميلها في مستودع جيثب لهذا المشروع. الرسوم المتحركة متوفرة هنا:


عنوان URL الأساسي: https://raw.githubusercontent.com/chupakabr/server-provided-animations/master/_raw/rendered-animations/

معرفات الرسوم المتحركة الخاصة:

  • clouds.json
  • fireworks.json

ملاحظة: هل تبحث عن خادم ويب لمزود الرسوم المتحركة مكتوب بـ Swift؟ ابحث عن الحل هنا على جيثب وشرح مفصل في هذه المقالة .
في هذه المرحلة ، لدينا خادم مزود للرسوم المتحركة يعمل بكامل طاقته ، لذلك حان الوقت للانتقال إلى الجزء الأكثر إثارة: تقديم الرسوم المتحركة لمستخدمينا.

جلب وتقديم الرسوم المتحركة


في هذه المرحلة ، أوصي بشدة بفتح مشروع تطبيق iOS الخاص بنا والموجود على Client/ServerProvidedAnimation.xcworkspace لأنه يحتوي بالفعل على جميع التعليمات البرمجية والتكوينات اللازمة للملف.

تحميل بيانات الرسوم المتحركة


نظرًا لأن نقاط نهاية واجهة برمجة تطبيقات REST للحصول على بيانات الرسوم المتحركة قيد التشغيل الآن ، فقد حان الوقت لتقديم بروتوكول موفر البيانات وإضافة تطبيق الخادم الخاص به:

 import Lottie protocol AnimationsProviderProtocol { typealias Completion = (_ animation: LOTComposition?) -> Void func loadAnimation(byId id: String, completion: @escaping Completion) } final class ServerAnimationProvider: AnimationsProviderProtocol { private let endpoint: URL init(endpoint: URL) { self.endpoint = endpoint } func loadAnimation(byId id: String, completion: @escaping Completion) { let path = "/\(id).json" guard let animationUrl = URL(string: path, relativeTo: self.endpoint) else { completion(nil) return } URLSession.shared.invalidateAndCancel() let task = URLSession.shared.dataTask(with: animationUrl) { (data, response, error) in guard error == nil, let data = data, let json = self.parseJson(from: data) else { completion(nil) return } let animation = LOTComposition(json: json) completion(animation) } task.resume() } private func parseJson(from data: Data?) -> [AnyHashable : Any]? { guard let data = data else { return nil } do { let json = try JSONSerialization.jsonObject(with: data, options: []) as? [AnyHashable : Any] return json } catch { return nil } } } 

تسمح لنا فئة موفر البيانات هذه بتحميل الرسوم المتحركة من الخادم بتنسيق JSON حسب الطلب والاحتفاظ بها في الذاكرة للتقديم على واجهة المستخدم. على افتراض أننا نتبع نموذج MVVM ، يمكن استخدامه بسهولة في كيان ViewModel بالطريقة التالية:

  // ... private let animationProvider: AnimationsProviderProtocol private(set) var animationModel: LOTComposition? // … func loadAnimation(byId animationId: String) {     self.animationProvider.loadAnimation(byId: animationId) { [weak self] (animationModel) in         self?.animationModel = animationModel     } } // ... 

يقوم ViewModel بتحديث خاصية بيانات الحركة المحددة عندما يتلقى استجابة HTTP صالحة من الخادم مع كائن JSON غير فارغ بداخله. يتم استخدام هذه البيانات بواسطة طبقة العرض التقديمي لجدولة عرض الرسوم المتحركة.

طبقة العرض


الآن يمكننا استخدام ViewModel الخاص بنا للوصول إلى بيانات الرسوم المتحركة وتقديمها عبر واجهة المستخدم في معالج الإجراءات "on the tap" المرفق بالزر:

 class ViewController: UIViewController {   // ...   @IBOutlet weak var animationContainer: UIView!   override func viewDidLoad() {       super.viewDidLoad()       // ...       self.animationView = {           let view = LOTAnimationView(frame: self.animationContainer.bounds)           self.animationContainer.addSubview(view)           return view       }()   }   @IBAction func onPlayAnimationAction(_ sender: Any) {       self.animationView.stop()       self.animationView.sceneModel = self.viewModel.animationModel       self.animationView.play()   } } 

في الأساس ، ما لدينا هنا هو معالج أزرار يقوم بتشغيل تحديث لمثيل LOTAnimationView مع أحدث بيانات الرسوم المتحركة الواردة من ViewModel .

إليك ما تبدو عليه النتيجة النهائية:


هذا الى حد كبير ذلك. يتم الآن تحميل الرسوم المتحركة من نقطة نهاية REST API المعدة وتقديمها على العميل عند الطلب.

نصائح والقيود


نصائح وحيل:

  • يسمح AAE باستخدام معظم أنواع الأصول بما في ذلك الرسومات النقطية والمتجهات ؛
  • يتيح Bodymovin إمكانية تضمين جميع الأصول في ملف JSON للرسوم المتحركة (باستخدام ترميز base64) - وهذا يعني أنه يمكننا تجنب تحميل الأصول بشكل منفصل على جانب العميل ؛
  • بالنسبة للرسوم المتحركة ، يمكنك الاختيار بين الرسم مباشرة في المتجه في AAE ، أو ببساطة استيراد رسومات Adobe Illustrator المتجهة.

لسوء الحظ ، ليس من الممكن حتى الآن استيراد رسومات SVG vector إلى AAE (لقد جربت!).

تم وصف المزيد من الحيل والمشاكل المحتملة في هذا المقال المذهل الذي كتبه زميلي رادوسلاف سيسيوا .

الاستنتاجات


لذا ، ما الذي يعطينا استخدام الرسوم المتحركة التي يوفرها الخادم؟ تتمثل الفائدة الأكثر وضوحًا لهذا النهج في القدرة على فصل جميع أصحاب المصلحة عن تدفق تحديث الرسوم المتحركة. بمعنى آخر ، لإطلاق رسم متحرك جديد ، يتوجب على جميع المصممين القيام به هو تقديم تمثيل JSON للرسوم المتحركة لفريق الخادم. ولإزالة واحدة ، يتعين على فريق الخادم إزالة تلك الرسوم المتحركة المحددة من خدمة الاكتشاف. لا تضيع الوقت!

شيء رائع آخر هو أنه يمكن تنفيذ نفس الوظيفة على جميع الأنظمة الأساسية للعميل المدعومة (iOS و Android و Web و ..) دون الحاجة إلى ضبط وظائف الخادم الحالية أو الرسوم المتحركة الأولية.

هذا كل شيء لهذا اليوم! شكرا للقراءة

الموارد


Source: https://habr.com/ru/post/ar439370/


All Articles