ارسال الاشعارات في تطبيقات اندرويد برمجياً باستخدام GCM

بسم الله الرحمن الرحيم

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

كما أحب أن أذكر قبل أن ابدأ في كتابة هذا الموضوع, إن الأمر يعتمد بشكل أكبر على لغات اخرى للتعامل مع قواعد البيانات, لذلك شرحي يحتمل الخطأ ولكن سوف يعطي نتيجة جيدة, لأنني أحاول أن اجمع أكبر عدد من الامثلة والشروحات عن هذا الموضوع وأحاول تبسيطه قدر الإمكان. ومع إعطاء الشروحات المتنوعة ودراستها .. تزداد خبرتي والتي سوف تمدني بالطاقة لتقديم المزيد والمزيد.

هذا الموضوع اعتبره كبير وضخم, فئة سوف يدخلون هذا الموضوع وينسخون الأكواد ولصقها, وفئة حقاً سوف تستفيد من خلال مراجعة الموضوع أكثر من مرة والتعمق بالموضوع أكثر بالقراءة عنه.

لتعرف ما الذي نتكلم عنه راجع : مقدمة لاستخدام GCM ببرمجة تطبيقات الاندرويد + تجهيزها
ويجب قرائته لمعرفة كيفية تجهيز مشروع والحصول على مفتاح API.

** من المزايا التي يدعمها GCM هي : إنك ترسل اشعار من الخادم إلى سيرفر GCM إلى التطبيق, وفي حال لا يوجد اتصال لدى المستخدم, تبقى الرسالة في قائمة الانتظار .. حال وجود انترنت في جهاز المستخدم تصله هذه الرسالة.

الرجاء ثم الرجاء ثم الرجاء قراءة التالي قبل متابعة وقراءة هذا الموضوع. هذا الدرس هو مثال او شرح مبسط نوعاً ما لاستخدام gcm لارسال اشعار من السيرفر الى التطبيق, وهو يعتبر تجربة .. لأنه يسجل تطبيق واحد فقط .. والسبب لا يوجد قاعدة بيانات لتقوم بتخزين جميع المستخدمين .. لذلك هذا التطبيق لجهاز جوال واحد .. لتأخذ خلفية عن الموضوع .. و أوعدكم إن شاء الله لنا دروس قادمة في كيفية ربط تطبيق الويب بقاعدة بيانات لتسجيل جميع المستخدمين وارسال رسائل لهم جميعاً .. او ارسال رسائل لفئة معينة, ان كانت بالعمر او الدولة .. وغيرها من الدروس .. وبدعمكم ان شاء الله نعطي المزيد والمزيد ..

معاينة سريعة من اليوتيوب لدرس اليوم :

ما سوف نتعلمه في هذا الدرس :

* برمجة تطبيق اندرويد ويحتوي على نموذج تسجيل بواسطة ايميل المستخدم فقط, لكي يحصل جهازه على id خاص فيه.
* تطبيق جداً بسيط, لمعرفة او كيفية ارسال اشعارات لجميع الاجهزة المسجلة اشعاراً او رسالة نصية قصيرة.
* بعد حصول المستخدم على الاشعار يضغط عليه وينتقل الى اكتفتي داخل التطبيق لرؤية هذه الرسالة.

تطبيق اليوم يحتوي على قسمين مهمين :

– تطبيق ويب Server Application / مبرمج بلغة php لارسال رسالة للمستخدمين.

– تطبيق اندرويد Client Application / لاستقبال هذه الرسالة.

# تجهيز تطبيق الويب : (يجب ان يكون لديك سيرفر لقراءة ملفات php )

سوف اعمل على السيرفر الداخلي الاباتشي .. appserv

قم بإنشاء ملف جديد بصيغة php واسمه gcm.php داخل مجلد اسمه gcm ,داخل ملفات السيرفر وضع فيه الكود التالي : – لا تغير اسم الملف والمجلد إلا اذا كانت لديك الخبرة بتعديل الكود –

<?php
	//Generic php function to send GCM push notification
   function sendMessageThroughGCM($registatoin_ids, $message) {
		//Google cloud messaging GCM-API url
        $url = 'https://android.googleapis.com/gcm/send';
        $fields = array(
            'registration_ids' => $registatoin_ids,
            'data' => $message,
        );
		// Update your Google Cloud Messaging API Key - لا تنسى قم باستبدال API Key بالموجود عندك
		define("GOOGLE_API_KEY", "API_SERVER_KEY"); 	 	
        $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);
        return $result;
    }
?>
<?php
	
	//Post message to GCM when submitted
	$pushStatus = "حالة الرسالة سوف تظهر هنا";	
	if(!empty($_GET["push"])) {	
		$gcmRegID  = file_get_contents("GCMRegId.txt");
		$pushMessage = $_POST["message"];	
		if (isset($gcmRegID) && isset($pushMessage)) {		
			$gcmRegIds = array($gcmRegID);
			$message = array("m" => $pushMessage);	
			$pushStatus = sendMessageThroughGCM($gcmRegIds, $message);
		}		
	}
	
	//Get Reg ID sent from Android App and store it in text file
	if(!empty($_GET["shareRegId"])) {
		$gcmRegID  = $_POST["regId"]; 
		file_put_contents("GCMRegId.txt",$gcmRegID);
		echo "Done!";
		exit;
	}	
?>
<html dir="rtl">
    <head>
        <title>Test GCM in PHP</title>
		<style>
			div#formdiv, p#status{
			text-align: center;
			background-color: #fff;
			border: 2px solid #37B8EB;
			padding: 10px;
			}
			textarea{
			border: 2px solid #37B8EB;
			margin-bottom: 10px;			
			text-align: center;
			padding: 10px;
			font-size: 25px;
			font-weight: bold;
			}
			input{
			background-color: #37B8EB;
			border: 5px solid #37B8EB;
			padding: 10px;
			cursor: pointer;
			color: #fff;
			font-weight: bold;
			}
			 
		</style>
		<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
		<meta http-equiv="Content-Language" content="ar-sa">
		<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
		<script>
		$(function(){
			$("textarea").val("");
		});
		function checkTextAreaLen(){
			var msgLength = $.trim($("textarea").val()).length;
			if(msgLength == 0){
				alert("حقل الرسالة فارغ ؟!");
				return false;
			}else{
				return true;
			}
		}
		</script>
    </head>
	<body>
		<div id="formdiv">
		<h1 dir="rtl">تجربة <span lang="en-us">GCM </span>تطبيق ويب بلغة
		<span lang="en-us">PHP</span></h1>	
		<form method="post" action="/gcm/gcm.php/?push=true" onsubmit="return checkTextAreaLen()">					                                                      
				<textarea rows="5" name="message" cols="45" placeholder="اكتب هنا رسالتك"></textarea> <br/>
				<input type="submit"  value="ارسال اشعار للمستخدمين" />
				<p style="text-align: left"><b><font color="#0000FF" size="2">
				<span lang="en-us"><a href="https://andrody.com/">By: 
				www.AndRody.com</a></span></font></b></p>
		</form>
		</div>
		<p id="status">
		<?php echo $pushStatus; ?>
		</p>        
    </body>
</html>

ملف الويب هذا هو مبرمج بلغة php لذلك من لديه خبرة يستطيع برمجة نموذج كما يريد, وبشكل يخدمه.

# تجهيز تطبيق الاندرويد :

– قم بإنشاء مشروع جديد, سبق تم شرح كيفية إنشاء مشروع على اندرويد ستوديو. اضغط هنا

– الاستعانة بمكتبة الدعم Android Asynchronous Http Client وهي مكتبة مشهورة ولها خصائص عديدة ويستخدم هذه المكتبة اشهر التطبيقات منها, Instagram,Pinterest,Heyzap,Pose وغيرها .. للتحميل اضغط هنا.
بعد التحميل ملف jar توضع في مجلد libs ضمن مجلدات التطبيق app.

– إعداد خدمات جوجل في مشروعك Google Play Services, في البداية تأكد من وجودها من خلال الذهاب إلى حزمة الـ SDK , في مجلد Extras > Google Play services تأكد من تحميلها .. ثم الذهاب إلى ملف build.gradle داخل ملفات تطبيقك من برنامج الاندرويد ستوديو وقم بفتحه وإضافة السطر التالي :

compile 'com.google.android.gms:play-services:7.3.0'

أو تستطيع استخدام من خدمات جوجل فقط خدمة التراسل السحابية GCM :

compile 'com.google.android.gms:play-services-gcm:7.3.0'

يضاف السطر ضمن dependencies, لا تنسى بعد الاضافة الضغط على مزامنة Sync Project with Gradle Files.

# برمجة وتصميم التطبيق – اندرويد -:

في البداية أصدقائي لكي اسهل عليكم, يوجد لدينا في المشروع التالي : ( قم بإنشائه بنفسك )

Two Package :
* Main Package: com.andrody.testandrody // أجعل فيها الاكتفتي المستخدمة لتطبيقك
* gcm Package: com.andrody.testgcm // سوف أضع فيها فقط الاكتفتي الداعمة لخدمة التراسل السحابية gcm

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

Two class inside Main Package :
* Main_Activity // الاكتفتي الرئيسية التي تعمل ببداية تشغيل التطبيق, وفيها يتم تسجيل ايميل المستخدم وتعمل فقط مرة واحدة لتسجيل الايميل .. من بعدها سوف تظهر اكتفتي هوم هي الرئيسية بشكل دائم لأن الايميل يتسجل لمرة واحدة.
* Home_Activity // الاكتفتي الرئيسية من بعد تسجيل ايميل المستخدم, وفيها سوف يتم اظهار الايميل المسجل للمستخدم, وهي الاكتفتي التي يتم فتحها عن الضغط على الاشعار لإظهار الرسالة التي تصل من السيرفر داخلها.

Two class & One interface inside gcm Package :
* Gcm_Application_Constants // انترفيس يتصل بمشروعك على جوجل لتسجيل الاي دي الخاص بالمستخدم وجلب الرسالة من السيرفر.
* Gcm_Broadcast_Receiver // بإمكانك اعتبار هذا الاكتفتي البسيط انه جهاز استقبال للاشارة في حال وجود رسالة من السيرفر يلتقطها ويمررها لـ انتنت سيرفس من اجل معالجتها وارسالها للاكتفتي الهوم لعرضها
* Gcm_Notification_Intent_Service // يتعامل مع الرسالة التي تاتي من السيرفر ويرسل الاشعار وبعد الضغط عليه ياخذك للهوم اكتفتي لعرض هذه الرسالة

Two Layout :
* main.xml // context for “.Main_Activity”
* home.xml // context for “.Home_Activity”

حسناً أصدقائي بينا ما الذي نقوم بإنشائه, و الآن سوف أدرج لكم الأكواد .. وهي طويلة بعض الشيء لذلك سوف أجعل فيها سطور التعليقات لتوضيح بعض الأمور. ” سطور التعليقات كثيرة بالعربية والانجليزية ” الانجليزية تم اقتباسها من نفس موقع الرسمي مطوريين اندرويد.

# Layout :

main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="#ff8b0000"
    android:gravity="center"
    android:orientation="vertical"
    android:padding="15dp"
    tools:context=".Main_Activity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="40dp"
        android:text="Test GCM App"
        android:textColor="#fff"
        android:textSize="35sp"
        android:textStyle="bold" />


    <EditText
        android:id="@+id/email"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:background="#ffff00"
        android:hint="Your Email"
        android:padding="15dp"
        android:singleLine="true"
        android:textColor="#FF0000" />

    <Button
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="25dp"
        android:background="#fdfdfd"
        android:onClick="RegisterUser"
        android:text="Register"
        android:textColor="#000"
        android:textSize="20sp" />
</LinearLayout>

home.xml

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:background="#ff8b0000"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_centerInParent="true"
        android:padding="15dp"
        android:gravity="center"
        android:orientation="vertical"
    tools:context=".Home_Activity">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Welcome My Friend"
            android:textColor="#fff"
            android:textSize="25sp"
            android:textStyle="bold" />
        <TextView
            android:id="@+id/usertitle"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginBottom="40dp"
            android:textColor="#fff"
            android:textSize="20sp"
            android:textStyle="bold" />

        <TextView
            android:id="@+id/message"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_marginBottom="10dp"
            android:background="#fff"
            android:hint="سوف تظهر هنا الرسالة التي سوف يتم ارسالها المبرمج من السيرفر"
            android:padding="10dp"
            android:textColor="#000"
            android:textSize="20dp" />

    </LinearLayout>

# Activity :

رسائل التوست كثيرة وذلك لتخبرك كمبرمج ماذا يحدث الان .. في حال بناء التطبيق تستطيع الاستغناء عنها, أغلب الأكواد واضحة, عن طريق اندرويد ستوديو تستطيع متابعة كل متغير ومن أي أتى, ومنها تعرف ما وظيفته.

Main_Activity.java

package com.andrody.testandrody;


import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.AsyncTask;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;

import com.andrody.testgcm.Gcm_Application_Constants;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.gcm.GoogleCloudMessaging;
import com.loopj.android.http.AsyncHttpClient;
import com.loopj.android.http.AsyncHttpResponseHandler;
import com.loopj.android.http.RequestParams;

import java.io.IOException;

public class Main_Activity extends Activity {
    ProgressDialog prgDialog;
    RequestParams params = new RequestParams();
    GoogleCloudMessaging gcmObj;
    Context applicationContext;
    String regId = "";

    private final static int PLAY_SERVICES_RESOLUTION_REQUEST = 9000;


    public static final String REG_ID = "regId"; // تسجيل معرف الجهاز
    public static final String EMAIL_ID = "eMailId"; // الايميل الذي يدخله المستخدم
    EditText emailET;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        applicationContext = getApplicationContext();
        emailET = (EditText) findViewById(R.id.email);

        prgDialog = new ProgressDialog(this);
        // Set Progress Dialog Text
        prgDialog.setMessage("Please wait...");
        // Set Cancelable as False
        prgDialog.setCancelable(false);

        SharedPreferences prefs = getSharedPreferences("UserDetails",
                Context.MODE_PRIVATE);
        String registrationId = prefs.getString(REG_ID, "");
        if (!TextUtils.isEmpty(registrationId)) {
            Intent i = new Intent(applicationContext, Home_Activity.class);
            i.putExtra("regId", registrationId);
            startActivity(i);
            finish();
        }
    }

    public void RegisterUser(View view) {
        String emailID = emailET.getText().toString();

        if (!TextUtils.isEmpty(emailID)) {
            if (checkPlayServices()) {
                registerInBackground(emailID);
            }
        }
        // إذا كان الحقل النصي فارغ الخاص بكتابة البريد الالكتروني
        else {
            Toast.makeText(applicationContext, "Please enter valid email",
                    Toast.LENGTH_LONG).show();
        }

    }

    private void registerInBackground(final String emailID) {
        new AsyncTask<Void, Void, String>() {
            @Override
            protected String doInBackground(Void... params) {
                String msg = "";
                try {
                    if (gcmObj == null) {
                        gcmObj = GoogleCloudMessaging
                                .getInstance(applicationContext);
                    }
                    regId = gcmObj
                            .register(Gcm_Application_Constants.GOOGLE_PROJ_ID);
                    msg = "Registration ID :" + regId;

                } catch (IOException ex) {
                    msg = "Error :" + ex.getMessage();
                }
                return msg;
            }

            @Override
            protected void onPostExecute(String msg) {
                if (!TextUtils.isEmpty(regId)) {
                    storeRegIdinSharedPref(applicationContext, regId, emailID);
                    Toast.makeText(
                            applicationContext,
                            "Registered with GCM Server successfully.\n\n"
                                    + msg, Toast.LENGTH_SHORT).show();
                } else {
                    Toast.makeText(
                            applicationContext,
                            "Reg ID Creation Failed.\n\nEither you haven't enabled Internet or GCM server is busy right now. Make sure you enabled Internet and try registering again after some time."
                                    + msg, Toast.LENGTH_LONG).show();
                }
            }
        }.execute(null, null, null);
    }

    private void storeRegIdinSharedPref(Context context, String regId,
                                        String emailID) {
        SharedPreferences prefs = getSharedPreferences("UserDetails",
                Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = prefs.edit();
        editor.putString(REG_ID, regId);
        editor.putString(EMAIL_ID, emailID);
        editor.commit();
        storeRegIdinServer();

    }

    private void storeRegIdinServer() {
        prgDialog.show();
        params.put("regId", regId);
        // Make RESTful webservice call using AsyncHttpClient object
        AsyncHttpClient client = new AsyncHttpClient();
        client.post(Gcm_Application_Constants.APP_SERVER_URL, params,
                new AsyncHttpResponseHandler() {
                    // When the response returned by REST has Http
                    // response code '200'
                    @Override
                    public void onSuccess(String response) {
                        // Hide Progress Dialog
                        prgDialog.hide();
                        if (prgDialog != null) {
                            prgDialog.dismiss();
                        }
                        Toast.makeText(applicationContext,
                                "Reg Id shared successfully with Web App ",
                                Toast.LENGTH_LONG).show();
                        Intent i = new Intent(applicationContext,
                                Home_Activity.class);
                        i.putExtra("regId", regId);
                        startActivity(i);
                        finish();
                    }

                    // When the response returned by REST has Http
                    // response code other than '200' such as '404',
                    // '500' or '403' etc
                    @Override
                    public void onFailure(int statusCode, Throwable error,
                                          String content) {
                        // Hide Progress Dialog
                        prgDialog.hide();
                        if (prgDialog != null) {
                            prgDialog.dismiss();
                        }
                        // When Http response code is '404'
                        if (statusCode == 404) {
                            Toast.makeText(applicationContext,
                                    "Requested resource not found",
                                    Toast.LENGTH_LONG).show();
                        }
                        // When Http response code is '500'
                        else if (statusCode == 500) {
                            Toast.makeText(applicationContext,
                                    "Something went wrong at server end",
                                    Toast.LENGTH_LONG).show();
                        }
                        // When Http response code other than 404, 500
                        else {
                            Toast.makeText(
                                    applicationContext,
                                    "Unexpected Error occcured! [Most common Error: Device might "
                                            + "not be connected to Internet or remote server is not up and running], check for other errors as well",
                                    Toast.LENGTH_LONG).show();
                        }
                    }
                });
    }

    // فحص الجهاز هل يحتوي على خدمات جوجل بلاي
    private boolean checkPlayServices() {
        int resultCode = GooglePlayServicesUtil
                .isGooglePlayServicesAvailable(this);
        if (resultCode != ConnectionResult.SUCCESS) {
            if (GooglePlayServicesUtil.isUserRecoverableError(resultCode)) {
                GooglePlayServicesUtil.getErrorDialog(resultCode, this,
                        PLAY_SERVICES_RESOLUTION_REQUEST).show();
            } else {
             /*   Toast.makeText(
                        applicationContext,
                        "This device doesn't support Play services, App will not work normally",
                      Toast.LENGTH_LONG).show();
                      */
                finish();
            }
            return false;
        } else {
            /*Toast.makeText(
                    applicationContext,
                    "This device supports Play services, App will work normally",
                    Toast.LENGTH_LONG).show();
                    */
        }
        return true;
    }

    @Override
    protected void onResume() {
        super.onResume();
        checkPlayServices();
    }
}

Home_Activity.java

package com.andrody.testandrody;

import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.widget.TextView;
import android.widget.Toast;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesUtil;

/**
 * Created by Abboudi_Aliwi on 10/05/2015.
 */
public class Home_Activity extends Activity {
    TextView msgET, usertitleET;

    private final static int PLAY_SERVICES_RESOLUTION_REQUEST = 9000;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.home);

        // Intent Message sent from Broadcast Receiver
        String str = getIntent().getStringExtra("msg");

        // Get Email ID from Shared preferences
        SharedPreferences prefs = getSharedPreferences("UserDetails",
                Context.MODE_PRIVATE);
        String eMailId = prefs.getString("eMailId", "");
        // Set Title
        usertitleET = (TextView) findViewById(R.id.usertitle);

        // Check if Google Play Service is installed in Device
        // Play services is needed to handle GCM stuffs
        if (!checkPlayServices()) {
            Toast.makeText(
                    getApplicationContext(),
                    "This device doesn't support Play services, App will not work normally",
                    Toast.LENGTH_LONG).show();
        }

        usertitleET.setText("your email:" + eMailId); // الرسالة التي تظهر بجانب الايميل الذي يدخله المستخدم
        // When Message sent from Broadcase Receiver is not empty
        if (str != null) {
            // Set the message
            msgET = (TextView) findViewById(R.id.message);
            msgET.setText(str);
        }
    }

    // Check if Google Playservices is installed in Device or not
    private boolean checkPlayServices() {
        int resultCode = GooglePlayServicesUtil
                .isGooglePlayServicesAvailable(this);
        // When Play services not found in device
        if (resultCode != ConnectionResult.SUCCESS) {
            if (GooglePlayServicesUtil.isUserRecoverableError(resultCode)) {
                // Show Error dialog to install Play services
                GooglePlayServicesUtil.getErrorDialog(resultCode, this,
                        PLAY_SERVICES_RESOLUTION_REQUEST).show();
            } else {
                Toast.makeText(
                        getApplicationContext(),
                        "This device doesn't support Play services, App will not work normally",
                        Toast.LENGTH_LONG).show();
                finish();
            }
            return false;
        } else {
            Toast.makeText(
                    getApplicationContext(),
                    "This device supports Play services, App will work normally",
                    Toast.LENGTH_LONG).show();
        }
        return true;
    }

    // When Application is resumed, check for Play services support to make sure
    // app will be running normally
    @Override
    protected void onResume() {
        super.onResume();
        checkPlayServices();
    }
}

Gcm_Application_Constants.java

package com.andrody.testgcm;

/**
 * Created by Abboudi_Aliwi on 10/05/2015.
 */
public interface Gcm_Application_Constants {
    // رابط صفحة الربط مع السيرفر لتسجيل الاي دي
    static final String APP_SERVER_URL = "http://192.168.1.10/gcm/gcm.php?shareRegId=true"; // غير الرابط حسب الموجود لديك

    // رقم المشروع على جوجل
    static final String GOOGLE_PROJ_ID = "71439801010"; // غير الرقم إلى رقم المشروع الذي أنشتئه
    // الرسالة التي تأتي من السيرفر
    static final String MSG_KEY = "m"; //

}

Gcm_Broadcast_Receiver.java

package com.andrody.testgcm;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.support.v4.content.WakefulBroadcastReceiver;

/**
 * Created by Abboudi_Aliwi on 10/05/2015.
 */
public class Gcm_Broadcast_Receiver extends WakefulBroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        // Explicitly specify that GcmIntentService will handle the intent.
        ComponentName comp = new ComponentName(context.getPackageName(),
                Gcm_Notification_Intent_Service.class.getName());
        // Start the service, keeping the device awake while it is launching.
        startWakefulService(context, (intent.setComponent(comp)));
        setResultCode(Activity.RESULT_OK);
    }
}

Gcm_Notification_Intent_Service.java

package com.andrody.testgcm;

import android.app.IntentService;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.NotificationCompat;

import com.andrody.testandrody.Home_Activity;
import com.andrody.testandrody.R;
import com.google.android.gms.gcm.GoogleCloudMessaging;

/**
 * Created by Abboudi_Aliwi on 10/05/2015.
 */
public class Gcm_Notification_Intent_Service extends IntentService {
    // يحدد اي دي للاشعارات
    public static final int notifyID = 9001;

    public Gcm_Notification_Intent_Service() {
        super("GcmIntentService");
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        Bundle extras = intent.getExtras();
        GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(this);
// The getMessageType() intent parameter must be the intent you received
        // in your BroadcastReceiver.
        String messageType = gcm.getMessageType(intent);
        /*
             * Filter messages based on message type. Since it is likely that GCM
             * will be extended in the future with new message types, just ignore
             * any message types you're not interested in, or that you don't
             * recognize.
             */
        if (!extras.isEmpty()) { // بعض منها غير مستخدمة ولكن من أجل استخدامها في حال تم تطوير الاكواد بشكل اكبر
            // has effect of unparcelling Bundle
            if (GoogleCloudMessaging.MESSAGE_TYPE_SEND_ERROR // يوجد خطأ اثناء ارسال الرسالة
                    .equals(messageType)) {
                sendNotification("" + extras.toString());
            } else if (GoogleCloudMessaging.MESSAGE_TYPE_DELETED // رسالة تم حذفها
                    .equals(messageType)) {
                sendNotification(""
                        + extras.toString());
            } else if (GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE // الرسالة سليمة
                    .equals(messageType)) {
                sendNotification("" + extras.get(Gcm_Application_Constants.MSG_KEY)); // الرسالة اذا كانت سليمة من السيرفر وهو متغير سترنج لذلك يوجد علامات التنصيص تستطيع كتابة ما تريد اي جملة وسوف تظهر مع النص المرسل من السيرفر
            }
        }
        // Release the wake lock provided by the WakefulBroadcastReceiver.
        Gcm_Broadcast_Receiver.completeWakefulIntent(intent);
    }

    private void sendNotification(String msg) {
        Intent resultIntent = new Intent(this, Home_Activity.class);
        resultIntent.putExtra("msg", msg);
        PendingIntent resultPendingIntent = PendingIntent.getActivity(this, 0,
                resultIntent, PendingIntent.FLAG_ONE_SHOT);

        NotificationCompat.Builder mNotifyBuilder;
        NotificationManager mNotificationManager;

        mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

        mNotifyBuilder = new NotificationCompat.Builder(this)
                .setContentTitle("رسالة جديدة") // العنوان الذي يظهر الاشعار
                .setSmallIcon(R.mipmap.ic_launcher); // ايقونة الاشعار
        // Set pending intent
        mNotifyBuilder.setContentIntent(resultPendingIntent);

        // Set Vibrate, Sound and Light
        int defaults = 0;
        defaults = defaults | Notification.DEFAULT_LIGHTS;
        defaults = defaults | Notification.DEFAULT_VIBRATE;
        defaults = defaults | Notification.DEFAULT_SOUND;

        mNotifyBuilder.setDefaults(defaults);
        // Set the content for Notification
        mNotifyBuilder.setContentText("لديك رسالة جديدة من السيرفر"); // الرسالة التي تظهر في الاشعار
        // Set autocancel
        mNotifyBuilder.setAutoCancel(true);
        // Post a notification
        mNotificationManager.notify(notifyID, mNotifyBuilder.build());
    }
}

** أرجوا أن تكون واضحة وفي حال أي شيء مبهم تستطيع استخدام صندوق التعليقات في الأسفل.

# تجهيز ملف AndroidManifest.xml :

الصلاحيات المطلوبة والمستخدمة في هذا الدرس : (المقصود فيها صلاحيات التطبيق في جهاز المستخدم)

– android.permission.INTERNET
اذن للتطبيق بالاتصال بالانترنت من أجل تسجيل رقم الاي دي للجهاز في السيرفر.

– android.permission.GET_ACCOUNTS -غير مطلوب , للاحتياط-
اذن للوصول الى حساب الـ gmail, حيث يشترط على الاجهزة القديمة ان يكون يجد بالجهاز حساب gmail ولكن بالاجهزة الحديثة لا مشكلة.

– android.permission.WAKE_LOCK
اذن بالاستيقاظ في حال كان جهازك في حال سبات ” اطفاء الشاشة ” لتلقي الرسالة.

– permission.C2D_MESSAGE + اسم الحزمة
اذن لمنع التطبيقات الاخرى من استلام الرسائل الموجهة لهذا التطبيق, والفرق بين : uses-permission & permission واحدة للاذن من المستخدم وصلاحية للتطبيق والاخرى استخدام هذا الاذن.

– com.google.android.c2dm.permission.RECEIVE
اذن لتمكين التطبيق من استقبال وتسجيل الرسائل.

– android.permission.ACCESS_NETWORK_STATE
اذن مشابه تقريباً لصلاحية دخول التطبيق للانترنت permission.INTERNET ولكن أحداها للاتصال بالانترنت والاخرى لمعرفة حالة الاتصال.

– android.permission.VIBRATE
اذن لاستخدام التطبيق لخاصية الاهتزاز.

– com.google.android.gms.version
بإمكانك اعتباره ضمان لتشغيل خدمات جوجل بشكل سليم.

– com.google.android.c2dm.permission.SEND
صعب شرحها نوعاً ما , ولكن هي أسفل الاكتفتي المشتقة من WakefulBroadcastReceiver , كإننا نخبره فقط سيرفر GCM هو من يستقبل الاشعارات لهذا الاكتفتي ” التطبيق “.

– تسجيل اكتفتي service
وهي الاكتفتي المشتقة من IntentService, التي تمر بالاكتفتي المشتقة من WakefulBroadcastReceiver لكي تتعامل مع الرسالة التي تأتي من السيرفر GCM , تستطيع التعامل مع الرسالة في BroadcastReceiver ولكن الاغلب يستخدم IntentService.

** بالنسبة لتوضيح بعض الخصائص في الاعلى, أقول الاكتفتي والمشتقة .. لأن اسم الاكتفتي يختلف على حسب مزاج المبرمج وما يقوم بتسمية هذه الاكتفتي وأقصد بمشتقة “extends”.

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.andrody.testandrody">

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.GET_ACCOUNTS" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />

    <permission
        android:name="com.andrody.testandrody.permission.C2D_MESSAGE"
        android:protectionLevel="signature" />

    <uses-permission android:name="com.andrody.testandrody.permission.C2D_MESSAGE" />

    <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.VIBRATE" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme">
        <meta-data
            android:name="com.google.android.gms.version"
            android:value="@integer/google_play_services_version" />

        <activity
            android:name=".Main_Activity"
            android:label="@string/app_name"
            android:noHistory="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:name=".Home_Activity"
            android:configChanges="orientation|keyboardHidden"
            android:label="@string/app_name"
            android:noHistory="true"></activity>

        <receiver
            android:name="com.andrody.testgcm.Gcm_Broadcast_Receiver"
            android:permission="com.google.android.c2dm.permission.SEND">
            <intent-filter>
                <action android:name="com.google.android.c2dm.intent.RECEIVE" />
                <action android:name="com.google.android.c2dm.intent.REGISTRATION" />

                <category android:name="com.andrody.testandrody" />
            </intent-filter>
        </receiver>

        <service android:name="com.andrody.testgcm.Gcm_Notification_Intent_Service" />

    </application>

</manifest>

التعديلات المطلوبة منك :
داخل gcm.php لوضع رقم API Key الذي أنشئناه في الدرس السابق. ( وصلة الموضوع في الاعلى).
+ في اكتفتي Gcm_Application_Constants تقوم بوضع رقم مشروعك على جوجل + مسار ملف gcm.php.

إضافة للمشروع : وهي ( لا يستطيع المستخدم التسجيل بغير الاحرف الانجليزية ووضع بريد الكتروني صحيح )
من دون هذه الاضافة يستطيع كتابة اي كلام عربي او احرف ويتم تسجيله المهم ان لا يكون الحقل فارغ.

نقوم بإضافة كلاس جديد بإسم : Utility.java ونقوم بوضع داخل الكود التالي :

package com.andrody.testgcm;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Created by Semon on 11/05/2015.
 */
public class Utility {
    private static Pattern pattern;
    private static Matcher matcher;
    //Email Pattern
    private static final String EMAIL_PATTERN =
            "^[_A-Za-z0-9-\\+]+(\\.[_A-Za-z0-9-]+)*@"
                    + "[A-Za-z0-9-]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$";

    /**
     * Validate Email with regular expression
     *
     * @param email
     * @return true for Valid Email and false for Invalid Email
     */
    public static boolean validate(String email) {
        pattern = Pattern.compile(EMAIL_PATTERN);
        matcher = pattern.matcher(email);
        return matcher.matches();
    }
}

ونذهب لاستخدام هذا الكلاس في خانة الحقل النصي لاضافة الايميل .. في داخل اكتفتي Main_Activity, ابحث عن السطر :

        if (!TextUtils.isEmpty(emailID)) {

وقم باستبداله إلى :

        if (!TextUtils.isEmpty(emailID)&& Utility.validate(emailID)) {

*** انتهى ***

لمعرفة المزيد وبشرح أدق .. راجع التالي >

*https://developer.android.com/google/gcm/client.html
*http://developer.android.com/reference/com/google/android/gms/gcm/GoogleCloudMessaging.html
*https://developer.android.com/google/gcm/gcm.html

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

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

عن عبدالقادر عليوي

مواليد 1996 , سوري الجنسية, طالب علم, لدي شغوف كبير في تعلم كل ما يتعلق بالانترنت من تطوير وحماية, أحب القراءة كثيراً .. هدفي نشر العلم بشتى أنواعه ومجالاته, متابع من الدرجة الأولى لـ الدكتور ابراهيم الفقي و الشيخ أحمد ديدات - رحمهم الله -.

شاهد أيضاً

التقنيات التي نستطيع برمجة تطبيقات والعاب الاندرويد بها

هل أنت محتار من أين تريد البدأ في مجال برمجة التطبيقات للهواتف الذكية أو الألعاب عالية الاداء ؟ تعرف في هذا المقال عن اللغات والتقنيات واختر منها ما يناسبك لدخول هذا المجال

تعلم برمجة تطبيق اندرويد لمدونتك البلوجر (1)

هل لديك تدوينة أو موقع إخباري ؟ أو معرض يعرض الكثير من البيانات من وسائط ؟ وبحاجة لعرضها في تطبيق اندرويد ؟ هذه فرصتك من هنا وللمبتدئين تعلم برمجة تطبيق لمدونتك

عرض صورة في التطبيق من فايربيس

بسم الله الرحمن الرحيم اليوم سيكون شرحنا عن كيفية عرض صورة  في التطبيق من قاعدة …

15 تعليقات

  1. شكرا إلك ♥

  2. انا عندى مشكلة ..الكود بيتم تنفيذة بشكل كويس
    ولكن لما احط اللينك بتاع السيرفر بتاعى
    وال project _ID

    بيرجعلى انه تم تسجيله

    لكن لما بفتح مش بلاقيه سجل ؟؟

  3. حضرتك انا عملت كل الخطوات بس ظهرلى الخطأ ده

    Error:Execution failed for task ‘:app:processDebugManifest’.
    > Manifest merger failed : uses-sdk:minSdkVersion 8 cannot be smaller than version 9 declared in library C:\testandrody\app\build\intermediates\exploded-aar\com.google.android.gms\play-services-gcm\7.3.0\AndroidManifest.xml
    Suggestion: use tools:overrideLibrary=”com.google.android.gms.gcm” to force usage

    مش عارف ال http://schemas.android.com/apk/res/android مش راضيه تتظبط

    • كم رقم الاصدار الذي تعمل عليه ؟! .. وما هو اقل اصدار لحزمة sdk ?! ..

      و بالنسبة لـ تفعيل خدمات جوجل بلاي .. الان احدث اصدار 7.5.0

      أين مكانها الذي لا تضبط فيه !؟ .. ممكن صورة من الخطأ او الكود الذي عليه الخطأ .. لافهمك بشكل اوضح ~

      • الاصدار الذى اعمل عليه من اندرويد استوديو 1.2,1,1
        التطبيق لما انشأته كان على بيئة froyo
        جوجل بلاي منزلها من ال sdk ومتحدثه
        بس سؤالى هل فيه اي حاجه اعملها تانى غير انى احدثها من ال sdk
        ولا لازم مثلا اعملها استيراد وكده

        انا مبتدى ولسه مش عارف قوى فى المواضيع دى

    • افتح الحزمة SDK و حمل المطلوب منك فيها .. من خلال مراجعت للدرس التالي :
      https://andrody.com/2015/02/before_programming_begins_android_studio/

      حمل اخر اصدارات .. و فعل خدمات جوجل بلاي في مشروعك .. ومن ثم قم بتطبيق الدرس .. وراجع الدروس السابقة لانها مكملة لبعضها 🙂

  4. نواف الرشيدي

    شكرا جزيلا

  5. الله ** ** ** تعبك
    يعني مفكر نفسك فهمان وبتمنع النسخ
    يعني انت بتعمل زي الي بيقول عندي ميا بس لاتشربوا
    روح شوف موقع عبدالله عيد كل شيء متاح مجانا ً
    شوف موقع بشير شلاح كل الاكواد مجاناً

    .
    الله وكيلك كرهتني موقعك وكرهتني ادخل عليه
    ولا زر ولا ماوس بتشتغل

    • اهلا وسهلا بك .. تشرفنا 🙂

      بالحقيقة الكلام البذيء عادة لا ارد عليه ..

      لكنك لو كنت فعلاً مهتم لرأيت ان النسخ مفتوح للاكواد .. ولكن لم تجرب 🙂 وحصل ذلك مع الكثير ..

      عموماً السيد المحترم تستطيع الضغط على اعلى الكود يوجد فتح الكود في نافذة صغيرة لنسخه ..

      وعدم نسخ النصوص ذلك لأمر .. وليس بالداعي ان اوضحه لك .. بالتوفيق واهلا وسهلا مرة اخرى 🙂

  6. مرحبا طبقت المكتوب تمام و اشتغل التطبيق و طلب مني في الأندرويد اسجل ايمل سجلت و حكالي انو سجل بس ملف النوت باد GSMRegId ما اجا في مجلد ال gcm الي ع السيرفر xampp و بس اكتب رسالة في الموقع و اعمل ارسال بضهري السطر التالي في مكان حالة الرسالة !!!!

    {“multicast_id”:5731427341574576584,”success”:0,”failure”:1,”canonical_ids”:0,”results”:[{“error”:”InvalidRegistration”}]}

    • اهلا .. لما تدخل السيرفر المحلي xampp من جوالك بيفتح بالمتصفح بشكل طبيعي ؟! ..

      واذا لم يعمل معك, جرب تشغيله على اي استضافة مجانية ..

  7. السلام عليكم
    أنا عندي تطبيق باصات
    المطلوب انه كيف ارسل اشعار للطالب أو الطالبة أنه الباص قرب من البيت أو هو وصل بالقعل ؟
    هل هذا الكود ينفعني ؟

ضع بصمتك بتعليق يعبر عن امتنانك

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