بسم الله الرحمن الرحيم
بالتأكيد أحاول قدر الإمكان مساعدة الجميع للوصول إلى أعلى مستوى ممكن في برمجة تطبيقات الاندرويد لذلك سوف أضع لكم هذا الدرس والذي هو مهم نوعاً ما لفئة من المستخدمين.
كما أحب أن أذكر قبل أن ابدأ في كتابة هذا الموضوع, إن الأمر يعتمد بشكل أكبر على لغات اخرى للتعامل مع قواعد البيانات, لذلك شرحي يحتمل الخطأ ولكن سوف يعطي نتيجة جيدة, لأنني أحاول أن اجمع أكبر عدد من الامثلة والشروحات عن هذا الموضوع وأحاول تبسيطه قدر الإمكان. ومع إعطاء الشروحات المتنوعة ودراستها .. تزداد خبرتي والتي سوف تمدني بالطاقة لتقديم المزيد والمزيد.
هذا الموضوع اعتبره كبير وضخم, فئة سوف يدخلون هذا الموضوع وينسخون الأكواد ولصقها, وفئة حقاً سوف تستفيد من خلال مراجعة الموضوع أكثر من مرة والتعمق بالموضوع أكثر بالقراءة عنه.
لتعرف ما الذي نتكلم عنه راجع : مقدمة لاستخدام 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
** من يسئل لماذا العنوان هكذا والمضمون لا يلبي ماذا يحتاج الجميع .. ما أقوله ان هذا الدرس هو البداية و الباقي معتمد عليه .. يستفيد من الدرس من هم في الطبقة المتوسطة وأعلى, لمعرفة كيفية تعديل الأكواد للحصول على النتيجة المطلوبة, تستطيع من هذه الأكواد مثلاً إنشاء تطبيق كامل .. وفي حال يوجد تحديث جديد للتطبيق تخبرهم بذلك برسالة توضح رابط التحميل واهم المزايا .. ويوجد له استخدامات اخرى.
أصدقائي أحب أن أذكر إن الدرس بالكامل مجهود شخصي, شرحته على حسب فهمي له لذلك كل السموحة والمعذرة عن أي خطأ .. وفي حال اكتشاف اي خطأ سوف يتم التعديل بالاستعانة بالله ثم بكم, وهذا من أكثر المواضيع او الدروس التي أخذت مني وقت ومجهود في تجهيزها, ونرحب بكل تعليقاتكم .. نرجوا دعمكم والدعاء لنا بالتوفيق .. والى اللقاء في درس آخر .. والسلام عليكم 🙂
شكرا إلك ♥
اهلا وسهلا ~
انا عندى مشكلة ..الكود بيتم تنفيذة بشكل كويس
ولكن لما احط اللينك بتاع السيرفر بتاعى
وال project _ID
بيرجعلى انه تم تسجيله
لكن لما بفتح مش بلاقيه سجل ؟؟
وضبطت الـ api key ? ..
حضرتك انا عملت كل الخطوات بس ظهرلى الخطأ ده
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/
حمل اخر اصدارات .. و فعل خدمات جوجل بلاي في مشروعك .. ومن ثم قم بتطبيق الدرس .. وراجع الدروس السابقة لانها مكملة لبعضها 🙂
شكرا جزيلا
العفو واهلا وسهلا بك اخي ..
الله ** ** ** تعبك
يعني مفكر نفسك فهمان وبتمنع النسخ
يعني انت بتعمل زي الي بيقول عندي ميا بس لاتشربوا
روح شوف موقع عبدالله عيد كل شيء متاح مجانا ً
شوف موقع بشير شلاح كل الاكواد مجاناً
.
الله وكيلك كرهتني موقعك وكرهتني ادخل عليه
ولا زر ولا ماوس بتشتغل
اهلا وسهلا بك .. تشرفنا 🙂
بالحقيقة الكلام البذيء عادة لا ارد عليه ..
لكنك لو كنت فعلاً مهتم لرأيت ان النسخ مفتوح للاكواد .. ولكن لم تجرب 🙂 وحصل ذلك مع الكثير ..
عموماً السيد المحترم تستطيع الضغط على اعلى الكود يوجد فتح الكود في نافذة صغيرة لنسخه ..
وعدم نسخ النصوص ذلك لأمر .. وليس بالداعي ان اوضحه لك .. بالتوفيق واهلا وسهلا مرة اخرى 🙂
مرحبا طبقت المكتوب تمام و اشتغل التطبيق و طلب مني في الأندرويد اسجل ايمل سجلت و حكالي انو سجل بس ملف النوت باد GSMRegId ما اجا في مجلد ال gcm الي ع السيرفر xampp و بس اكتب رسالة في الموقع و اعمل ارسال بضهري السطر التالي في مكان حالة الرسالة !!!!
{“multicast_id”:5731427341574576584,”success”:0,”failure”:1,”canonical_ids”:0,”results”:[{“error”:”InvalidRegistration”}]}
اهلا .. لما تدخل السيرفر المحلي xampp من جوالك بيفتح بالمتصفح بشكل طبيعي ؟! ..
واذا لم يعمل معك, جرب تشغيله على اي استضافة مجانية ..
السلام عليكم
أنا عندي تطبيق باصات
المطلوب انه كيف ارسل اشعار للطالب أو الطالبة أنه الباص قرب من البيت أو هو وصل بالقعل ؟
هل هذا الكود ينفعني ؟