عام

GCM بالـعربية – الدرس الثانى

فى الدرس السابق GCM بالـعربية الدرس الأول تعلمنا كيفية إنشاء Service أطلقنا عليها اسم Registration Service تتلخص مهمتها الحصول على token خاص بالـ device وإرساله للسيرفر الخاص بنا وتسجيله فى قاعدة البيانات حيث ان اى جهاز موبايل  يتم  تثبيت التطبيق الخاص  بنا فيه اول مرة يقوم بفتح التطبيق  سيتم تشغيل هذه الـ service وانشاء token للجهاز بواسطة  InstanceID الخاص بجوجل ونرسله للسيرفر الخاص بنا ليتم تسجيله فى جدول الـ tokens فى قاعدة البيانات .

 

وبشكل عام فإن الـ GCM يحتاج منا الى تكويد جزء خاص بالاندرويد وجزء خاص بالسيرفر سواء كان php ام nodejs او اى شىء اخر تستخدمه جهة السيرفر لكن سنركز على الـ php هنا .

 

إرسال التنبيهات عبر GCM

اذا اردت ارسال التنبيهات الى احد الاجهزة فإنى استخدم الـ php فى ملف موضوع على السيرفر الخاص بى  فى التواصل مع سيرفر الـ GCM الخاص بجوجل ويقوم هو بدوره بارسال التنبيه للجهاز المقصود او مجموعة الاجهزة التى نريد توصيل الاشعارات اليها .

على سبيل المثال :

الكود التالى (سنشرحه لاحقا ) بمجرد تشغيله سوف يتواصل مع GCM ويخبره اننا نريد ارسال اشعار للجهاز صاحب التوكن dEUAZsn5Avo:APA…….
وهو التوكن الخاص بجهازى والذى تم تسجيله فى السيرفر فى الدرس السابق

<?php
       $url = 'https://android.googleapis.com/gcm/send';
       $message=array('message'=>'life is nothing without eating indomi and drink coffee !');
       $fields = array(
           'to' => 'dEUAZsn5Avo:APA91bGntZQvagkCB4BnBweoxKQ9xVj6jtY-EelNUmKSluq9vVyjuakZ1DnrQEo7Vc7VOsTJ2F4xFxcDIl_BswOgvG2_VQfoZrETR59O3GAgrA3xqSlFvZh6Zepau-jyye7-yqe110ks',
           'data' => $message,
       );
       // Google API Key
       define("GOOGLE_API_KEY", "AIzaSyC-dDYU5MbF4CFY6yuBS-vS-xIXxU4YKOQ");
       $headers = array(
           'Authorization: key=' . GOOGLE_API_KEY,
           'Content-Type: application/json'
       );
       $ch = curl_init();
       curl_setopt($ch, CURLOPT_URL, $url);
       curl_setopt($ch, CURLOPT_POST, true);
       curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
       curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
       curl_setopt ($ch, CURLOPT_SSL_VERIFYHOST, 0);
       curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
       curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($fields));
       $result = curl_exec($ch);
       if ($result === FALSE) {
           die('Curl failed: ' . curl_error($ch));
       }
       curl_close($ch);
       echo $result;

اذا قمنا بتنفيذ الكود السابق فلن يحدث أى شىء ولن يتم ارسال الاشعار وهذا بسبب أن الاشعار او الرسالة ارسلت من GCM للموبايل لكن لم يستمع اليها الموبايل ولم يعرها أى انتباه ابدا .. اذكر فى احد المرات عندما كنت اقرأ كتاب “كيف تفكر كعالم كمبيوتر” ذكر المؤلف ان الكمبيوتر غبى وينفذ فقط ما يملى عليه تماما لذلك عندما تنسى سيمى كولن فى php فانه لا يفهم انه بحاجه اليها ويقوم بادخالها تلقائيا وتشغيل الكود فكل شىء يجب عمله بنفسك عندما يتعلق الامر بالبرمجة  لذلك فى حالتنا هنا لن يعرف التطبيق من نفسه بل  يجب ان نقوم  بكتابة كود يقوم بتنفيذ امر ما عندما يأتى تنبيه من GCM سواء اظهار Notification على شاشة المستخدم او مثلا اظهار اشعار جديد فى ايقونة الاشعارات وهو يتصفح التطبيق او شىء اخر نريده يحدث عندما يستمع الموبايل ويأتيه تنبيه من GCM   لذلك سنقوم الان بكتابة كلاس GCM Listener فى التطبيق لتقوم بالاستماع الى الـ GCM وتنفيذ عملية ظهور النوتيفيكشن فى حالة ما اذا اتى اشعار جديد للموبايل ! .

 

كلاس GCMListener

نقوم بإنشاء كلاس جديدة نسميها GCMListener  وسترث من كلاس GCMListener Service وهى سيرفس تابعة للاندرويد والتى يتواصل معها الـ GCM عندما يتم الطلب منه سواء من خلال سيرفر تطبيقك او تطبيقات اخرى ويقوم بايصال الرسالة الى الجهاز المطلوب ايصال الرسالة او الاشعار اليه .

 

public class GCMListener extends GcmListenerService {


}

 

يوجد ميثود اسمها onMesseageReceived وهى تستدعى عند وصول اى اشعار من GCM خاص بهذا الجهاز ومتعلق بهذا التطبيق  سوف نقوم الان بعمل override لها .

public class GCMListener extends GcmListenerService {

    @Override
    public void onMessageReceived(String from, Bundle data) {
        
    }
}

 

سوف نقوم بعمل override لميثود تسمى onMessageReceived والتى تستدعى عندما يتم ارسال notification

سوف نقوم بإنشاء ميثود لاظهار النوتيفيكشن ولن اقوم بشرحها هنا فهى ليس لها علاقة بـ GCM بشكل مباشر ربما يتم شرحها فى تدوينة خاصة عن الـ Notifications نفسها كمكون من مكونات الـ UI  لكن فى الشائع انه عندما يأتى تنبيه من GCM نقوم باظهار Notification للمستخدم يحتوى على الرسالة ليصبح الكود الان كالتالى :

public class GCMListener extends GcmListenerService {

    @Override
    public void onMessageReceived(String from, Bundle data) {
        super.onMessageReceived(from, data);
        String message = data.getString("message");
        sendNotification(message);
    }


    private void sendNotification(String message) {
        
        Intent intent = new Intent(this, MainActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        
        PendingIntent pendingIntent = PendingIntent.getActivity(this,0, intent,
                PendingIntent.FLAG_ONE_SHOT);
        
        Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
        
        NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
                .setSmallIcon(R.mipmap.ic_launcher)
                .setContentTitle("HelloGCM")
                .setContentText(message)
                .setAutoCancel(true)
                .setSound(defaultSoundUri)
                .setContentIntent(pendingIntent);
        
        NotificationManager notificationManager =
                (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        
        notificationManager.notify(0, notificationBuilder.build());
    }
}

ولاحظ أن البيانات الاتية من السيرفر تأتى فى bundel قد يكون هناك اشياء اخرى غير الـ message لكن هنا نستخدم ابسط شىء وهو message والتى سوف نحددها فى ملف php الذى سيكون مسؤولا عن إرسال طلب التنبيه الى الـ GCM والذى يستيجب له GCM ويرسل لأجهزة الأندرويد.

 

رائع ! الان لدينا كلاس مهمته الاستماع الى GCM وتنبيهاته وتنفيذ امر بناءا عليها والذى هو فى هذه الحالة اظهار تنبيه للمستخدم كـ Notification يحتوى على الرسالة القادمة لكن يجب أن نقوم بإعطاء هذه الـ Service الصلاحية بالاستماع للـ GCM  وذلك عن طريق الـ Manifest بداخل intent filter وعلاوة على ذلك اعطاء التطبيق نفسه صلاحية الاستماع للـ GCM  كمال فى الكود التالى :

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.hendiware.hellogcm">
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

        <receiver
            android:name="com.google.android.gms.gcm.GcmReceiver"
            android:exported="true"
            android:permission="com.google.android.c2dm.permission.SEND">
            <intent-filter>
                <action android:name="com.google.android.c2dm.intent.RECEIVE" />
                <category android:name="com.hendiware.hellogcm" />
            </intent-filter>
        </receiver>

        <activity
            android:name=".MainActivity"
            android:label="@string/app_name"
            android:theme="@style/AppTheme.NoActionBar">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <service
            android:name=".GCMListener"
            android:exported="false">
            <intent-filter>
                <action android:name="com.google.android.c2dm.intent.RECEIVE" />
            </intent-filter>
        </service>
        
        <service
            android:name=".RegistrationService" />

    </application>

</manifest>

لاحظ أننا اضفنا reciver الخاص بـ GCM فى السطر 13-21 واسم الباكيدج الخاصة بالتطبيق فى السطر 19 .

 

الى الان اذا انتقلنا الى php وكتبنا كود السيرفر سيعمل بشكل ممتاز لكن سريعا سنقوم بعمل الكلاس GCMInstacneIDListener  والذى اتفقنا سابقا على انه كلاس يستجيب للـ GCM عند تحديث التوكن فاذا تم تحديث التوكن الخاص بالجهاز لاسباب امنية من جوجل أو لاى اسباب اخرى فسنحتاج  الى تشغيل سيرفسRegisterationService مرة أخرى للحصول على الـ token جديد وإرساله  للسيرفر الخاص بنا ويعتبر اصغر كلاس سنقوم ببرمجته حيث تكمن مهمته فى بدء سيرفس RegisterationService فقط كالتالى

 

 

GCMInstanceIDListener

سننشىء كلاس جديد باسم GCMInstanceIDListener  ترث من InstanceIDListenerService

public class GCMInstanceIDListener extends InstanceIDListenerService {
    
    
}

 

نقوم بعمل Override للميثود onTokenRefresh  وهى التى تستدعى اذا ما حدث Refresh للتوكن وسنضع بداخلها الكود الذى سنقوم بوضع قيمة false فى  قيمة token_sent فى shardPreferences  اى ان التوكن لم يرسل للسيرفر  لذلك تبدأ RegisterationService فى العمل والحصول على الـ token وارساله للسيرفر مرة أخرى

public class GCMInstanceIDListener extends InstanceIDListenerService {
    SharedPreferences preferences;
    SharedPreferences.Editor prefEditor;

    @Override
    public void onTokenRefresh() {
        preferences = PreferenceManager.getDefaultSharedPreferences(this);
        prefEditor = preferences.edit();
        prefEditor.putBoolean("token_sent", false).apply();
        startService(new Intent(this, RegistrationService.class));
 
    }
}

 

 

الان انتهينا من الجزء الخاص بأندرويد وسننتقل للجزء الخاص بالـ php .

 

GCM Server Side

فى الكود الذى ذكرناه فى اول التدوينة اذا قمت بكتابة فى ملف php ووضع الـ token الخاص بجهازك مكان الخاص بى سوف تستقبل الـ notification بمجرد تشغيل الملف لكن فى اغلب الاحيان تحتاج الى ارسال الاشعار الى كل المستخدمين وهذا ما يفعله هذا الملف التالى :

 

<?php
include 'DB.php';
$db = DB::getInstance();
$tokens = $db->table('users_tokens')->select('tokens')->get();

$tokens_arr = [];
foreach ($tokens as $key => $token) {
    array_push($tokens_arr, $token['tokens']);
}

$message = array('message' => 'Hendiware Team last news ');

sendMessageThroughGCM($tokens_arr, $message);


function sendMessageThroughGCM($registatoin_ids, $message)
{
    $url = 'https://android.googleapis.com/gcm/send';
    $fields = array(
        'registration_ids' => $registatoin_ids,
        'data' => $message,
    );
    define("GOOGLE_API_KEY", "AIzaSyC-dDYU5MbF4CFY6yuBS-vS-xIXxU4YKOQ");
    $headers = array(
        'Authorization: key=' . GOOGLE_API_KEY,
        'Content-Type: application/json'
    );
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($fields));
    $result = curl_exec($ch);
    if ($result === FALSE) {
        die('Curl failed: ' . curl_error($ch));
    }
    curl_close($ch);
    echo $result;
}


ما هذا ؟

 

السطر 3,2 : نقوم بعمل include و inite لـ Marei DB  والتى شرحناها سابقا واستخدمناها فى الدرس السابق من السلسلة .

السطر  4 : تنفيذ امر select لتحديد الـ tokens من جدول الـ user_tokens الذى أنشأناه الدرس السابق .

السطر 6 : إنشاء php Array جديدة باسم $tokens_arr والتى سنضع بها جميع الـ tokens لكى نمررها للـ GCM ليرسل الاشعار لهذه الـ tokens .

السطر 7-9 : نقوم بعمل foreach على الناتج من الـ select للحصول على الـ tokens فقط وتخزينها بالتتابع فى $tokens_arr.

السطر 11: تجهيز message التى سنرسلها فى الإشعار  عبر GCM  والتى سيستقبلها المستخدمون .

السطر 13 : استخدام الميثود sendMessageThroughGCM وإعطائها الـ tokens التى سيرسل اليها الاشعار وكذلك الـ message التى سوف ترسل .

السطر 16-42 : ميثود او دالة sendMessageThroughGCM حيث عندنا فى الجافا نعرف الـ Method داخل Object عن طريق public void or type  وبعدها اسم المثيود لكن هنا فى php نكتب فقط كلمة function

السطر 18 : رابط ارسال الاوامر الى الـ GCM  .

السطر 19-22 : مصفوفة php اسمها fileds التى ستحتوى على الـ tokens وعلى الـ messages والتى سنرسلها للـ gcm فى array واحده.

السطر 23 : تعريف ثابت فى php للـ Google API Key فعندنا فى الجافا نعرف الثابت public static final xxxxx فى php عندما تعرف ثابت تستخدم الميثود define وتأخذ بارامترين الاول هو الـ key والباراميتر الثانى هو الـ value الذى احتفظنا به من الدرس السابق وهو الـ server key من جوجل .

السطر 24-27 : انشاء array ووضع عناصر بها لترسل مع الطلب الى gcm من خلال الـ header الخاص بالـ http Requst  الذى سنرسله للgcm  اذا لم تفهم ما هو الـ header راجع تدوينة ما يجب أن يعرفه كل مبرمج عن الـ Http .

السطر 28-40 : نستخدم cUrl وهى مكتبة php تسمح لك باستخدام الـ cURl داخل الكود وبالتأكيد ان كنت تستخدم نظام ماك او لينكس فانت تعرف ما هو الـ cURL او سمعت عنه واذا كنت احد مستخدمى الويندوز فلتعلم ان هذا الامر يستخدم من خلال الـ terminal (الشاشة السودة الى بتشوفها فى الافلام الهاكرز بيستخدموها وبيتكتبوا فيها سطور كتير تحت بعض دى ) ويسمح لك بعمل request لاى url وهنا فى php المكتبة الخاصة به تسمح لنا من داخل كود php التواصل مع لينك معين وهو لينك GCM للإرسال (السطر 18 ) وستجد اننا قمنا بعمل init له ثم جعل الريكوست نوعه POST وارفاق الheader وارفاق الـ feildes ثم اذا حدث خطأ قم بطباعته او عد بالنتائج او رد السيرفر علينا الذى اتصلنا به .

 

قم بوضع محتوى الملف السابق فى ملف php خاص بك  مع تعديل الـ Google APi KEY  الى الخاص بك ورفعه على السيرفر  وجرب ان تستدعيه فى المتصفح وستجد أن الـ Notification تعمل بشكل صحيح ^ـ^

 

 

ملحوظة : لا تستطيع ارسال أكتر من 1000 token فى المرة الواحده للـ GCM ليرسل لهم الاشعارات سيتم تحديث هذا المقال بعد شرح تدوينة الـ paginition لتتعلم كيف يمكنك ارسال جميع الـ Tokens عندك الى GCM مهما كان عددهم او يمكنك عمل for loop بنفسك وإرسال الف بالف  . 

 

الخلاصة :

نقوم بعمل Service للحصول على token وارساله للسيرفر الخاص بنا عن طريق ريكوست الى  ملف php  .

نقوم بعمل Service للاستماع للـ GCM واشعارته وبداخله ننفذ الكود الذى نريد .

نقوم بعمل Service اذا ما تم تحديث الـ token يتم تشغيلها لتشغيل Service الاولى للحصول على الـ token الجديد وإرساله للسيرفر .

نقوم بعمل ملف php خاص بارسال الاشعارات يستخدم cUrl ويقوم بالتواصل مع رابط GCM وارسال الـ API Key والـرسالة والـ tokens له ويقوم الـ GCM بالتنفيذ وارسال الاشعارات للاجهزة صاحبة هذه الـ Tokens .

 

اى اخلال باى خطوة من الخطوات التى تحدثنا بها فى السابق يمكن ان لا يعمل الكود لذلك ركز وراجع خطواتك .

بالتأكيد ليس هذا كل شىء عن GCM يوجد مواضيع أخرى ممتعة متعلقة به سنتحدث عنها فى تدوينات لاحقة مثل موضوع الـ Topics لكن لن يكون فى هذه الفترة .

اى سؤال أو استفسار قم بسؤاله فى الجروب الخاص بالدعم  Hendiware Developers وستجد هناك الشباب يقومون بمساعدتك والاجابة على استفساراتك .

 المشروع على Github 

السابق
كلاس Marei DB للتعامل مع قواعد بيانات MySQL بسهولة
التالي
الـ Tasks والـ BackStack

7 تعليقات

أضف تعليقا

  1. ِAli Hassan قال:

    احسنت احسنت احسنت

  2. Ahmed Ali قال:

    شرح اكتر من رائع مشكور جدا وكنت منتظرها تخلص 😀
    بس هل GCM بتستخدم برضو لل Chat Apps ؟
    مشكورين 🙂

    1. اة في ناس بتسدخمها لكن الافضل منها فى ال chats شىء يعرف ب xmpp اكيد هيتم شرحها قريب

  3. محمد جمال قال:

    بجد مشكووووووووووووورين جداااااا علي تعبكم دا
    في انتظار الدروس القادمه

  4. علي قال:

    لكم جزيل الشكر
    كم انا سعيد بناجحي بتطبيق الدرس
    بحثت كثير و لم اجد شرح بهذه البساطة و التفصيل المبسط الرائع
    تحياتي لكم

  5. ESSRA قال:

    جميل جدا
    جزاك الله خيرا على المجهود المبذول

    لكن لدى مشكلة عند جعل نص الـ message باللغة العربية فإن الـ notification تصل فارغة إلى الموبيل
    علما بأني استخدم لغة Asp في الجزء الخاص بالتحكم بالـ server

  6. mon قال:

    لو سمحت انا عاوز ابعت الاشعار من التطبىق نفسه مثلا لو المستخد عمل click على button ابعت اشعار للمستخدمىن
    ىا رىت ضرورى (مشروع تخرج)

اترك تعليقاً

هذا الموقع يستخدم Akismet للحدّ من التعليقات المزعجة والغير مرغوبة. تعرّف على كيفية معالجة بيانات تعليقك.