📱 دليل دمج لعبة الفواكه (WebView) مع تطبيقات الموبايل

هذا الدليل مخصص لمطوري تطبيقات الموبايل (Flutter, Android, iOS) لربط السوكت الحقيقي (WebSocket) الخاص بالتطبيق بواجهة اللعبة (WebView)، لضمان سرعة اللعب وتوفير موارد السيرفر وتقليل الضغط.

🎯 الفكرة العامة (The Concept)

بدلاً من أن تقوم اللعبة (WebView) بفتح اتصال Socket جديد، أو تعتمد على طلبات متكررة (HTTP Polling) تضغط على السيرفر، تم تصميم اللعبة لتكون "مستمعة" (Listener).

التطبيق الأساسي (الذي يمتلك الاتصال الأصلي بالسيرفر Swoole) هو من يتلقى أحداث اللعبة، ومهمة مبرمج الموبايل الوحيدة هي تمرير هذه الأحداث إلى الـ WebView عبر الـ JavaScript Bridge (window.postMessage).

ميزة "Smart Polling" المُدمجة باللعبة:

اللعبة تبدأ بطلب احتياطي (Request) كل 4 ثوانٍ تحسباً لأي طارئ. ولكن بمجرد استلام أول رسالة من تطبيق الموبايل، ستكتشف اللعبة أن الربط نجح، وستقوم بإيقاف الطلبات الاحتياطية نهائياً (0 RPS) لتعتمد كلياً على التطبيق!

🛠️ شكل البيانات المطلوب تمريرها (JSON Payload)

يجب أن يكون الـ JSON الممرر من التطبيق للـ WebView مطابقاً للرسالة التي أرسلها سيرفر Swoole. ويجب أن يحتوي الكائن (Object) على الأقل على القيم التالية لكي تتعرف عليه اللعبة:

{
  "type": "multiplier_game",
  "event": "game_started", 
  "game_data": {
    "round_id": 125,
    "remaining_seconds": 27,
    "status": "betting"
  }
}

(يتغير قيمة event و game_data حسب كل حدث يأتي من السيرفر: game_started، betting_closed، game_spinning، game_completed).

💙 أولاً: الدمج مع تطبيق Flutter

بناءً على المكتبة المستخدمة لفتح الـ WebView، الكود بسيط جداً وهو عبارة عن دالة حقن الجافاسكريبت.

1. باستخدام مكتبة webview_flutter (الإصدار 4+)

import 'dart:convert';
import 'package:webview_flutter/webview_flutter.dart';

// 1. تعريف الكنترولر
final WebViewController controller = WebViewController()
  ..setJavaScriptMode(JavaScriptMode.unrestricted)
  ..loadRequest(Uri.parse('رابط اللعبة الخاص بك'));

// 2. عندما يصلك تنبيه السوكت من (Swoole) بخصوص اللعبة
void onSocketMessageReceived(Map socketData) {
  // التأكد أن الرسالة تخص اللعبة
  if (socketData['type'] == 'multiplier_game') {
    String jsonData = jsonEncode(socketData);
    
    // 3. تمرير الحدث للـ WebView
    controller.runJavaScript("window.postMessage($jsonData, '*');");
  }
}

2. باستخدام مكتبة flutter_inappwebview

import 'dart:convert';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';

InAppWebViewController? webViewController;

// ... داخل InAppWebView widget ...
onWebViewCreated: (controller) {
  webViewController = controller;
},

// ... في مكان استقبال السوكت ...
void onSocketMessageReceived(Map socketData) {
  if (socketData['type'] == 'multiplier_game' && webViewController != null) {
    String jsonData = jsonEncode(socketData);
    
    // حقن الرسالة في الـ WebView
    webViewController!.evaluateJavascript(source: "window.postMessage($jsonData, '*');");
  }
}

🤖 ثانياً: الدمج مع تطبيق Android (Kotlin)

إذا كان التطبيق مبرمجاً بالـ Native Android:

// عند استقبال بيانات السوكت من السيرفر كـ JSON String
fun onSocketMessageReceived(jsonData: String) {
    // حقن البيانات في الـ WebView
    runOnUiThread {
        webView.evaluateJavascript("window.postMessage($jsonData, '*');", null)
    }
}

🍎 ثالثاً: الدمج مع تطبيق iOS (Swift)

إذا كان التطبيق مبرمجاً بالـ Native iOS باستخدام WKWebView:

// عند استقبال بيانات السوكت من السيرفر كـ JSON String
func onSocketMessageReceived(jsonData: String) {
    let jsCode = "window.postMessage(\(jsonData), '*');"
    
    DispatchQueue.main.async {
        self.webView.evaluateJavaScript(jsCode, completionHandler: nil)
    }
}

✅ كيف تتأكد من نجاح الدمج؟

  • قم بفتح اللعبة داخل التطبيق (Flutter/Android/iOS).
  • يجب أن تتلقى رسائل أحداث اللعبة وتبدأ العجلة بالدوران متزامنةً مع التطبيق.
  • إذا قمت بفحص الـ Logs أو سيرفر الـ API، ستلاحظ أن طلبات الـ /state توقفت تماماً، مما يثبت أن التطبيق يتخاطب الآن حصرياً عبر الـ Socket Bridge بنجاح! 🚀