«

»

Dec 21

GCM

GCM

 
 

רקע תאורטי:

 

ה Google Cloud Messaging הוא שירות שמאפשר שליחת מידע משרת למכשירים ספציפיים שמותקן בהם האפליקציה דרך שרת ה GCM.

 

התהליך זה עובד כך:

 

1. אנחנו רושמים את השרת שלנו לשירות ה GCM ומקבלים את ה API-Key.

 

2. האפליקציה שולחת בקשה לשרת ה GCM להרשם לשירות ה GCM ומעבירה לו את הקבוע של ה API-KEY של השרת שלנו.

 

3. שרת ה GCM מחזיר מזהה regId שהוא מזהה חד-חד ערכי למכשיר הספציפי שמריץ את האפליקציה ולשרת שאליו הוא נרשם.

 

4. אנו שולחים את המזהה הזה לשרת שלנו וזה המזהה שבעזרתו השרת יכול לשלוח הודעות למכשיר הספציפי. (בשליחת המזהה לשרת נשלח גם פרמטרים שמזהים את המכשיר, כמו userId).

 

5. השרת שולח את הודעה למכשירים שהוא מעוניים לעדכן אותם ב push. ההודעה חייבת להיות מוגבלת בגודל של עד 4kb. ולמעשה אמורה להכיל מידע למכשיר שיפנה לשרת לקבל את העדכון.

 

6. המכשיר מקבל את ההודעה (גם אם האפליקציה סגורה) ופונה לשרת לקבל את העדכון.

 

בזמן קבלת ההודעה:

 

אם האפליקציה במצב foreground – ז.א. שהמשתמש רואה ומשתמש בה כרגע, היא תוכל להציג שינויים מהשרת בזמן אמת למשתמש.

 

אם האפליקציה במצב background – ז.א. המשתמש השתמש באפליקציה אבל כרגע לא רואה ומשתמש בה והיא עברה ל background. עדיין היא תקבל מידע ותפעל לפיו.

 

אם היא סגורה אבל המכשיר פעיל – ה broadcast receiver שמוגדר ל GCM יקרא והאפליקציה תפעל לפי המידע המתקבל ותעבור למצב background.

 

ההודעות שנשלחות מהשרת לאפליקציה יכולות להיות בגודל של עד 4kb.
זאת בשביל שיהיה אפשר לשלוח מידע כמו הודעות טקסט ולהציג במיידית ללא צורך בפניה לשרת שלך מהאפליקציה. ולא לאפשר לאנשים להשתמש בשירות הזה בשביל לשלוח תמונות או מידע כבד שיעמיס על שרתים Google.
אלא לשלוח לאפליקציה הודעה שיש תמונה חדשה בשרת שלך ושהיא יכולה ליזום פניה לשרת שלך (ברגע קבלת ההודעה) ולהוריד את התמונה.

 

התהליך הזה מתאפשר מכיוון שברגע שהמכשיר פועל הוא יוצר Background Service שאחראי שיהיה קשר תמידי לשרת ע”י יצירת TCP Session, קישור TCP/IP לשרת ה GCM.
לשרת של ה GCM יש יכולת פיקוח על תקינות הקשר עם המכשיר ובמקרה שהמכשיר אינו מוכן לקבל הודעות (לדוגמא כאשר הוא מכובה), שרת ה GCM ישמור אותן במסד נתונים אצלו וישלח אותם במועד מאוחר יותר כאשר המכשיר ידלק.
אפשר להגדיר בשליחת ההודעה שהמכשיר לא יקבל (או יקבל) את העדכונים כאשר המסך מכובה (המכשיר ב Sleep), זה נשלט ע”י פרמטר שמגדירים delay_while_idle. וזה אפשרי מכיוון שהמכשיר מדווח לשרתי גוגל כאשר המסך נכבה ונדלק.
השרת ידע שהמכשיר נדלק ומוכן לקבל הודעות מכיוון שהמכשיר שולח הודעות Heart Beats לשרת כל כמה זמן ש Google קבעו. (את הזמן הזה Google לא מפרסמים) ואז שהוא יחזור הוא יודיע לשרת שהוא מוכן לקבל הודעות, השרת ישלח אותן ויוכל למחוק אותן ממסד הנתונים שלו.

 

המידע שעובר בין המכשיר לשרת הוא מאובטח ב SSL.

 

ההודעות לא חייבות להגיע באותו סדר שבו הן נשלחו.

 

ה GCM תומך רק בגרסאות Froyo ומעלה ולכן צריך שהאפליקציה שלכם לא תהיה זמינה למכשירים שגרסאתם קטנה מ 8 (Froyo).

 
 
———————————————————————————–
 

ההגדרות שצריך לעשות לפני בשביל לקבל projectid לשרת:

 

אם אתה לא מתכנת גם את צד השרת ויש לך מישהו שכבר עשה זאת והביא לך projectid, אין צורך לקרוא את זה. במאמר הזה אני לא מרחיב על צד השרת אבל כן בחרתי להסביר פה איך להשיג את ה projectid בצד השרת בשביל לקבל הבנה של מה זה.

 

1. ראשית צריך ליצור פרוייקט ב Google APIs Console Page
ללחוץ על הטאב של API Project וללחוץ על Create לפרוייקט משלך.

 

 

 

 

 
 
 
 
 
 
 
 
 
 
 
 

לאחר היצירה, ה project id שיצרת הוא המספר שמוצג ב url של הדף.
במקרה הזה ה project id הוא 123454789123.

כעת יש להפעיל את השירות הזה, ללחוץ על services ואז יש להעביר ל on את ה Google Cloud Messaging for android. (אתה תצטרך להסכים לתנאי ההצטרפות של Google).

 
 
 
 

ללחוץ על ה API Access וליצור Server key חדש. ה API key שתשתמש בו בשביל ה GCM יוצג לך.

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
———————————————————————————–
 
 

דוגמא והסבר:

 

1. הורדת ה SDK של ה GCM: בשביל להשתמש ב API של ה GCM ראשית נתקין אותו מה Android SDK Manager ב extras ונתקין את Google Cloud Messaging for Android Library.

 
 
 
 
 
 

2. הוספת ה jar: נצרף את ה gcm.jar שנמצא ב
Android\sdk\android-sdk\extras\google\gcm\gcm-client\dist
לאפליקציה שלנו.

 

3. הגדרות ב Manifest:
בגלל שה GCM נתמך רק מ Froyo ומעלה נגדיר ב Manifest את ה uses-sdk שה minSdkVersion יהיה 8.
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="<Your target API level>" />

 

הוספת הרשאות לקבלת הודעות מה GCM לאפליקציה:

<permission
android:name="<This App Package Name>.permission.C2D_MESSAGE"
android:protectionLevel="signature" />

<uses-permission android:name="<This App Package Name>.permission.C2D_MESSAGE" />
מי שרוצה ללמוד יותר על הרשאות ומה זה אומר permission/uses-permission (שני מושגים עם משמעות שונה לגמרי) יכול לקרוא את המאמר שלי על הרשאות באנדרואיד.
נוסיף הרשאות שמאפשרות שימוש ב GCM:

 

לקבלת הודעות
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />

 

לגישה לאינטרנט

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

ל Google Accounts

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

 

שאם הודעה מגיעה להשאיר את המעבד ער.

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

 

נוסיף הגדרה ל Broadcast Receiver של ה GCM של גוגל שיהיה אחראי לתפיסת 2 intents שנשלחים מה GCM ומגדירים אותם ב Manifest (ולא דרך הקוד) בשביל שה intents יתפסו ע”י ה Broadcast Receiver גם שהאפליקציה סגורה.
מגינים על ה Broadcast Receiver ע”י ה permission: “com.google.android.c2dm.permission.SEND” שאומר שרק intents שנשלחים ע”י ה GCM system framework יהיה להם הרשאות לשלוח אליו.
יש להחליף את ה android:name לשם של ה package שלך ב category.
<receiver
    android:name="com.google.android.gcm.GCMBroadcastReceiver"
    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="co.il.lior.gcmtest" />
    </intent-filter>
</receiver>

להכריז על ה intent service בשם GCMIntentService בתיקייה של ה package name.

<service android:name=".GCMIntentService" />

 

שימו לב!
חייבים לשמור את ה GCMIntentService שלנו בתיקיית הבסיס, ב packagename שלנו. מכיוון שה GCMBroadcastReceiver של גוגל פונה אליה בברירת המחדל. אם אכפת לכם ממבנה תיקיות נכון ולא רוצים לשים את ה GCMIntentService שלכם בתקיית הבסיס אפשר לעקוף את זה.

 

בשביל לקבוע מיקום משלנו ל intent service:

3.1. יש ליצור BroadcastReceiver משלנו שמרחיב את ה GCMBroadcastReceiver ונדרוס את מתודת ה getGCMIntentServiceClassName בשביל להחזיר את השם המלא (כולל התיקיות של ה intent Service שלנו). בנוסף נשנה ב Manifest במקום להגדיר שה GCMBroadcastReceiver יתפוס את הודעות ה GCM, ה BroadcastReceiver שאנחו יצרנו יתפוס. כמו שמימשתי בפרוייקט הדוגמא: הגדרת ה BroadcastReceiver שלנו:

public class MyGCMBroadcastReceiver extends GCMBroadcastReceiver {

	@Override
	protected String getGCMIntentServiceClassName(Context context) {

		String gcmIntentServiceName = GCMIntentService.class.getName();
		return gcmIntentServiceName;

	}

}

3.2. ההכרזה ב Manifest במקום ההכרזה של ה GCMBroadcastReceiver:

<receiver
        android:name=".gcm.MyGCMBroadcastReceiver"
        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="co.il.lior.gcmtest" />
        </intent-filter>
</receiver>

 
 

4. שינויים בקוד:

 

1. נכתוב את ה intent service:

הוא יהיה אחראי לטיפול בהודעות משרת ה GCM. שרת ה GCM ישלח intents ל GCMBroadcastReceiver שמוגדר ב gcm.jar והוא יקרא למתודות ב intent service שלנו.

public class GCMIntentService extends GCMBaseIntentService{

 

onError – נקרא כאשר המכשיר ניסה להרשם או לבטל הרשמה אבל ה GCM החזיר שגיאה. אין יותר מידיד מה לעשות בשביל לטפל בשגיאה.

	@Override
	protected void onError(Context context, String errorId) {

	}

 

onMessage – נקרא כאשר השרת שלנו שולח הודעה ל GCM וה GCM שולח את ההודעה למכשיר שלנו היא מתקבלת במתודה שלנו פה. אם להודעה יש payload אפשר להשיג את המידע מה extras של ה intents. אפשר גם לפנות עכשיו ישירות לשרת שלנו כי אנחנו יודעים שיש הודעה שמחכה למכשיר שלנו ולהתעדכן מול השרת בשינוי שצריך לבקש ממנו.

	@Override
	protected void onMessage(Context context, Intent intent) {

	}

 

onRegistered – נקרא כאשר שרת ה GCM קיבל מהמכשיר שלנו את ה intent שהמכשיר רוצה לקבל מהשרת שלנו (לפי ה projectid שהועבר) עדכונים. ה GCM מעביר למתודה הזאת את ה regId שזה הפרמטר ששרת ה GCM הקצה בשביל לזהות באופן חד-חד ערכי את המכשיר.

נעביר לשרת את ה regId ולפיו השרת ידע לשלוח למכשיר הספציפי הזה הודעות דרך שרת ה GCM..

	@Override
	protected void onRegistered(Context context, String regId) {

	}

 

onUnregistered – נקרא כאשר המכשיר ביקש להפסיק להרשם להודעות ה GCM. מומלץ לשלוח את ה regId הזה לשרת שלנו בשביל שהוא יוריד את המכשיר מרשימת ההודעות לשליחה.

	@Override
	protected void onUnregistered(Context context, String regId) {

	}

 

onRecoverableError – נקרא כאשר המכשיר ניסה להרשם או לבטל הרשמה אבל שרתי ה GCM לא זמינים. לא חייבים לדרוס את המתודה הזאת ואז ההודעה תשלח במועד מאוחר יותר כאשר השרתים יהיו זמינים. אם נדרוס בכל זאת, נוכל להציג למשתמש הודעה שהשרת לא זמין ושינסה שוב או יבטל. אם נחזיר true אז ההודעה תשלח במועד מאוחר יותר. אם נחזיר false אז ההודעה לא תשלח.

	@Override
	protected boolean onRecoverableError(Context context, String regId) {

		return true;

	}

}

 

המתודות הללו מתבצעות בהתליכון ה worker של ה intent service ולכן אפשרת לעשות בהם פעולות UI (כמו לגשת לאינטרנט) אבל יש לקחת בחשבון שב intent service יש רק תליכון worker אחד ולכן אם עושים פעולות ארוכות אז שאר המתודות יהיו blocked (יחכו עד שהתליכון יסיים את פעולתו) ולכן עדיף ליצור בכל זאת תליכון אחר שיבצע את הפעולות הארוכות.

 

2. נגדיר את שליחת בקשת הרישום ב Activity:
נקרא למתודה הבאה ב onCreate של ה Activity:
checkDevice – מוודאת שהמכשיר תומך ב GCM.
checkManifest – בודק שהגדרנו את קובץ ה manifest.xml נכון. אפשר למחוק את השורה הזאת לפני שמפרסמים את האפליקציה.
/**
* Sends a registration request to GCM
*/
private void sendRegistrationRequest() {

	try {

		GCMRegistrar.checkDevice(this);
		GCMRegistrar.checkManifest(this); 
		final String regId = GCMRegistrar.getRegistrationId(this);

 
regId – זה ה regId שה GCM קבע שהוא משייך למכשיר ולשרת-לפרוייקט שהוא נרשם אליו. בפעם הראשונה שנקרא ל getRegistrationId תחזור מחרוזת ריקה ונקרא ל register. אז בפעם הבאה שנקרא ל getRegistrationId כבר נקבל את ה regId שמשוייך למכשיר ולפרוייקט, אותו regId שנשלח למתודת ה onRegister ב IntentService.

		if (regId.equals("")) {

			GCMRegistrar.register(this, "");

		} else {

			Log.d("Text", "Lior: GCMActivity: Already registered");

		}

	} catch(Exception e) {

		Log.e("Text", "Lior: Device does not support GCM");

	}

}

 

3. נגדיר את ה Server-Side:
על זה אני לא אפרט, מכיוון שזה צד השרת ולא קשור לצד ה Client של התכנות לאנדרואיד. זה קשור לקנפוג השרת והשגת ה projectid.

 

4. קבלת ההודעות:
זהו עכשיו השגנו קישור בין המכשיר לשרת שלנו דרך שירות ה GCM של גוגל ונוכל לשלוח את ההודעות מהשרת ולקבל אותם ב intent service שהגדרנו באפליקציה שלנו ב:
	@Override
	protected void onMessage(Context context, Intent intent) {

		Bundle extras = intent.getExtras();
		String extraMessage = extras.getString(EXTRA_MESSAGE);

	}

 

ההודעה מועברת ב key הקבוע מראש בשם
EXTRA_MESSAGE = “message”.
השרת יכול לשלוח לנו ב bundle של ה intent גם מידע נוסף עם ערכי key אחרים.

 
 

לינק להורדת הפרויקט לדוגמה

 

בהצלחה !

 

Leave a Reply

Your email address will not be published.

אתם יכולים להשתמש באפשרויות ותגי ה-HTMLהבאים: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>