سبد (0)

دریافت پیام از سرویسهای Cloud اندروید

آموزش دریافت پیام از سرویسهای Cloud در آندروید

این فصل روش نشاندن (push) اطلاعات از یک سرور به دستگاه گوگل را برای شما تشریح می کند.

فهرست محتوا

1. Cloud to device messaging (پیام رسانی از cloud به دستگاه)

Polling (ممیزی یا نظارت) در مقابل push (نشاندن)

Cloud service (رایانش ابری)

ابزار لازم برای استفاده از C2DM

مجوزهای لازم برای استفاده از C2DM

receiver intent

2. مراحل پیاده سازی

ثبت سرور برنامه (application server registration)

دریافت شناسه ی ثبت (registration ID) برای برنامه ی موبایل

ثبت و تخصیص گیرنده برای پیام های C2DM

ارسال پیام

3. ثبت و دستگاه

4. آموزش ایجاد برنامه هایی که قابلیت C2DM در برنامه فعال سازی شده باشد

طرح بندی و پروژه

ایجاد receiver ها و activity ها

ثبت برنامه

5. آموزش استفاده از ابزار خط فرمان Curl برای شبیه سازی سرور

6. آموزش ایجاد برنامه ی سرور

1. Cloud to device messaging (پیام رسانی از cloud به دستگاه)

Polling (ممیزی یا نظارت) در مقابل push (نشاندن)

بیشتر برنامه های موبایل ملزم به دانلود و دریافت داده از اینترنت هستند. یکی از روش های بروز رسانی اطلاعات برنامه ی مورد نظر، polling (نظارت) است که طی آن برنامه های موبایل در فواصل معین سرور را برای اطلاعات جدید بررسی می کند. در صورت نبود داده های مورد نیاز استفاده از این روش پهنای باند شبکه و باتری موبایل را بی هیچ دلیل معینی مصرف کرده است.

روش دیگری که می توان از آن بهره برد، این است که خود سرویس دهنده یا سرور به محض اینکه داده های جدید عرضه شد با دستگاه موبایل ارتباط برقرار کرده وآن را از وجود اطلاعات جدید مطلع کند. به این فرایند push (نشاندن) می گویند. چنانچه اطلاعات یا داده ها به طور مداوم تغییر نمی کنند، Push روش ارجح تلقی می گردد.

Cloud service (رایانش ابری)

شما می توانید از طریق Google Play services اطلاعیه ها (notification) ها را در برنامه یا اپلیکیشن خود بنشانید. برای این منظور باید Google Cloud Messaging for Androidرا در Google API Console فعال سازی کنید.

در C2DM سه گروه مختلف شرکت دارند. سرور برنامه (app server) که پیام ها را به دستگاه اندروید ارائه داده و یا پیام های نام برده را در آن می نشاند، سرورهای C2DM گوگل و دیگری برنامه ی اندروید. برنامه ی موجود در سرور برنامه ممکن است به هر زبان برنامه نویسی نوشته شده باید مانند Python، Java و PHP.

زمانی که سرور برنامه، پیامی را به اپلیکیشن مربوطه اندروید ارائه می دهد (push)، در واقع پیام ذکر شده را از طریقHTTP POST  به سرورهای C2DM گوگل ارسال می کند.

سرورهای C2DM پیام مورد نظر را به دستگاه می فرستند. اگر دستگاه به اینترنت وصل نباشد، پیام مربوطه زمانی که دستگاه آنلاین شد به آن تحویل داده می شود. پس از اینکه پیغام توسط دستگاه مورد نظر دریافت گردید، گیرنده ی intent ایجاد می گردد. برنامه ی موبایل یک intent receiver ویژه ی این Broadcast ثبت می کند. در مرحله ی بعد برنامه اجرا شده و پیغام مربوطه توسط Intent Receiver پردازش می شود.

حجم پیام های C2DM محدود به 1024 بایت می باشد و وظیفه ی آن ها تنها اطلاع دادن به دستگاه است و نه انتقال داده ها. گردش کار (workflow) متداول این است که خود سرورهای C2DM گوگل به اپلیکیشن اطلاع می دهند که اطلاعات جدیدی ویژه ی آن برنامه عرضه شده است. سپس اپلیکیشن اندروید داده ها را از سرور دیگری واکشی می کند.

دستگاه های اندروید با سرور Android play مداوم ارتباط دارند. C2DM از این ارتباط یا اتصال موجود با سرورهای گوگل استفاده می کند. این اتصال به گونه ای بهینه سازی شده است که مصرف پهنای باند و باتری به کمترین حالت ممکن برسد.

البته C2DM هم اکنون در مرحله ی آزمون بتا به سر می برد، برای استفاده از آن باید درخواست بدهید. C2DM روزانه اجازه ی ارسال تنها 200، 000 پیام به ازای هر فرستنده را می دهد و در حال حاضر خدمت رسانی آن رایگان می باشد.

ابزار لازم برای استفاده از C2DM

C2MD برای نخستین بار در اندروید 2.2 در دسترس قرار گرفت و لازمه ی استفاده از آن نصب برنامه ی Android Play بر روی دستگاه می باشد.

جهت استفاده از C2MD بر روی شبیه ساز (EMULATOR) باید از یک دستگاه گوگل که API آن حداقل 8 و یا بالاتر است بهره گرفته و یک حساب کاربری گوگل نیز از طریق Settings برای خود ایجاد کنید.

مجوزهای لازم برای استفاده از C2DM

به منظور استفاده از C2DM در برنامه ی خود لازم است مجوزهای ذیل را رجیستر / ثبت کنید.

com.google.android.c2dm.permission.RECEIVE

android.permission.INTERNET

برنامه ی شما همچنین باید مجوز "applicationPackage + ".permission.C2D_MESSAGE" را با "android:protectionLevel" of "signature" اعلان کند تا از این طریق اپلیکیشن های دیگر نتوانند پیام های برنامه ی مربوطه را ثبت و دریافت کنند. android:protectionLevel="signature" ایجاب می کند که برنامه ی درخواست کننده ی مجوز با همان گواهی یا مجوزی (certificate) که برنامه ی اعلان کننده ی مجوز با آن امضاء شده، نشان گذاری شده باشد. در غیر این صورت مجوز به آن برنامه داده نخواهد شد.

receiver intent

برنامه ی شما باید یک گیرنده ی intent برای دو intent زیر ثبت کند.

com.google.android.c2dm.intent.REGISTRATION

com.google.android.c2dm.intent.RECEIVE

receiver ویژه ی "com.google.android.c2dm.intent.RECEIVE" به محض دریافت پیغام جدید، فراخوانده می شود، در حالی که گیرنده ی (مختص)"com.google.android.c2dm.intent.REGISTRATION" تنها زمانی صدا زده می شود که کد ثبت / registration code برنامه ی مورد نظر دریافت شده باشد.

2. مراحل پیاده سازی

ثبت سرور برنامه (application server registration)

سرور برنامه باید خود را برای سرورهای C2DM احراز هویت کند (بشناساند). با ارسال درخواستHTTP POST  به C2DM، توکن یا نشانه ی شناسایی امنیتی (authentication token) توسط یک پست الکترونیکی و رمزعبور مشخص می گردد. توکن در برنامه ی سمت سرور (app server) ذخیره گشته، سپس از این توکن برای شناسایی برنامه ی تحت سرور (app server) به سرورهای C2DM، به مجرد ارسال پیام ها، استفاده می شود.

مثال

با استفاده از کد زیر می توان توکن ایمیل و پسورد ثبت شده را دریافت کرد.


package de.vogella.java.c2dm.server.util;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
public class AuthenticationUtil {
  private AuthenticationUtil() {
    // Util class cannot get instanziated
  }
  public static String getToken(String email، String password)
          throws IOException {
    // create the post data
    // Requires a field with the email and the password
    StringBuilder builder = new StringBuilder();
    builder.append("Email=").append(email);
    builder.append("&Passwd=").append(password);
    builder.append("&accountType=GOOGLE");
    builder.append("&source=MyLittleExample");
    builder.append("&service=ac2dm");
    // Setup the Http Post
    byte[] data = builder.toString().getBytes();
    URL url = new URL("https://www.google.com/accounts/ClientLogin");
    HttpURLConnection con = (HttpURLConnection) url.openConnection();
    con.setUseCaches(false);
    con.setDoOutput(true);
    con.setRequestMethod("POST");
    con.setRequestProperty("Content-Type"،
            "application/x-www-form-urlencoded");
    con.setRequestProperty("Content-Length"، Integer.toString(data.length));
    // Issue the HTTP POST request
    OutputStream output = con.getOutputStream();
    output.write(data);
    output.close();
    // read the response
    BufferedReader reader = new BufferedReader(new InputStreamReader(con.getInputStream()));
    String line = null;
    String auth_key = null;
    while ((line = reader.readLine()) != null) {
      if (line.startsWith("Auth=")) {
        auth_key = line.substring(5);
      }
    }
    // Finally get the authentication token
    // To something useful with it
    return auth_key;
  }
}

مثال فوق با زبان برنامه نویسی جاوا نوشته شده است. می توان توکن را با استفاده از دیگر ابزار http یا زبان های برنامه نویسی دریافت کرد. برای مثال می توان با استفاده از ابزار خط فرمان curl (= یک ابزار خط فرمان که به منظور ارسال و دریافت فایل ها به وسیله ی ترکیب نحوی URL مورد استفاده قرار می گیرد) سرور را شبیه سازی کرد.

دریافت شناسه ی ثبت (registration ID) برای برنامه ی موبایل

به منظور رجیستر کردن برنامه ی اندروید برای بهره گرفتن از خدمت رسانی C2DM، یک registration intent "com.google.android.c2dm.intent.REGISTER". اجرا (fire) کنید. این کار با راه اندازی یک سرویس در نهایت registration را به سرورهای C2DM ارسال می کند.

Intent نام برده دربردارنده ی یک extra با کلید "sender" و آدرس ایمیل است که در ابتدای امر برای سرویس C2DM ثبت شده بود. این intent همچنین باید حامل یک Pendingintent با "app" extra باشد. PendingIntent درباره ی برنامه ی جاری اطلاعاتی را به سیستم اندروید ارائه می دهد. مقدار برای "sender" آدرس ایمیلی است که تحت آن C2DM message service خود را رجیستر کردید. در مثال زیر این آدرس ایمیل توسط spambots حفاظت می شود. برای دیدن شما نیاز به جاوا اسکریپت دارید را با ایمیل خود جایگزین کنید.

 

public void register(View view) {
        Intent intent = new Intent("com.google.android.c2dm.intent.REGISTER");
        intent.putExtra("app"،PendingIntent.getBroadcast(this، 0، new Intent()، 0));
        intent.putExtra("sender"، "این آدرس ایمیل توسط spambots حفاظت می شود. برای دیدن شما نیاز به جاوا اسکریپت دارید");
        startService(intent);
        }

سرویس به طور ناهمگام با Google رجیستر (ثبت) شده و در صورت موفقیت عملیات ثبت intent "com.google.android.c2dm.intent.REGISTRATION" را ارسال می کند. اپلیکیشن شما باید یک Broadcast receiver ویژه ی intent مذکور ثبت کند (یک broadcast receiver به آن تخصیص دهد). برای این امر نیز به یک مجوز مبتنی بر پکیج نیاز است، زیرا که سیستم اندروید آن را از داخل بررسی می کند.

 

package de.vogella.android.c2dm.simpleclient;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
public class C2DMRegistrationReceiver extends BroadcastReceiver {
  @Override
  public void onReceive(Context context، Intent intent) {
    String action = intent.getAction();
    Log.w("C2DM"، "Registration Receiver called");
    if ("com.google.android.c2dm.intent.REGISTRATION".equals(action)) {
      Log.w("C2DM"، "Received registration ID");
      final String registrationId = intent
             .getStringExtra("registration_id");
      String error = intent.getStringExtra("error");
      Log.d("C2DM"، "dmControl: registrationId = " + registrationId
              + "، error = " + error);
      // TODO Send this to my application server
    }
  }
}

فایل AndroidManifest.xml آن به ترتیب زیر است. در صورت استفاده از پکیج دیگر باید کدنویسی را متناسب آن پکیج اصلاح کنید.

 

<?xml version="1.0" encoding="utf-8" ?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android"

          package="de.vogella.android.c2dm.simpleclient"

          android:versioncode="1"

          android:versionname="1.0">

    <uses-sdk android:minsdkversion="8" />

    <permission android:name="de.vogella.android.c2dm.simpleclient.permission.C2D_MESSAGE"

                android:protectionlevel="signature" />

    <uses-permission android:name="de.vogella.android.c2dm.simpleclient.permission.C2D_MESSAGE" />

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

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

 

    <application android:icon="@drawable/icon"

                 android:label="@string/app_name">

        <activity android:label="@string/app_name"

                  android:name=".C2DMClientActivity">

            <intent-filter>

                <action android:name="android.intent.action.MAIN" />

 

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

            </intent-filter>

        </activity>

 

        <receiver android:name=".C2DMRegistrationReceiver"

                  android:permission="com.google.android.c2dm.permission.SEND">

            <intent-filter>

                <action android:name="com.google.android.c2dm.intent.REGISTRATION">

                </action>

 

                <category android:name="de.vogella.android.c2dm.simpleclient" />

            </intent-filter>

        </receiver>

    </application>

 

</manifest>

اینتنت "com.google.android.c2dm.intent.REGISTRATION" حاوی یک شناسه ی ثبت (registration ID) است. هر شناسه ی ثبت نشان دهنده ی دستگاه معینی است، به عنوان مثال هر گوشی اندرویدی کد ثبت مختص به خود را دریافت می کند.

C2DM ممکن است این شناسه ی ثبت را در بازه هایی معین بازسازی (refresh) کند، اما تا یک بازسازی دیگر برنامه ی مورد نظر باید این شناسه را برای استفاده در آینده ذخیره کند.

پس از اینکه برنامه ی اندروید شناسه ی ثبت را دریافت کرد، باید این اطلاعات دریافتی را به سرور برنامه ارسال کند. سرور برنامه می تواند از شناسه ی ثبت استفاده کرده و از طریق سرورهای C2DM به دستگاه پیام ارسال کند.

به عنوان مثال کد زیر deviceId و registrationId را به یک سرور ارسال می کند.

 

// Better do this in an asynchronous thread
public void sendRegistrationIdToServer(String deviceId، String registrationId) {
        Log.d("C2DM"، "Sending registration ID to my application server");
        HttpClient client = new DefaultHttpClient();
        HttpPost post = new HttpPost("http://your_url/register");
        try {
        List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(1);
        // Get the deviceID
        nameValuePairs.add(new BasicNameValuePair("deviceid"، deviceId));
        nameValuePairs.add(new BasicNameValuePair("registrationid"، registrationId));
        post.setEntity(new UrlEncodedFormEntity(nameValuePairs));
        HttpResponse response = client.execute(post);
        BufferedReader rd =
        new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
        String line = "";
        while ((line = rd.readLine()) != null) {
        Log.e("HttpResponse"، line);
        }
        } catch (IOException e) {
        e.printStackTrace();
        }
        }

ثبت و تخصیص گیرنده برای پیام های C2DM

درست مشابه تخصیص یک registration receiver، شما باید یک گیرنده ی پیغام (message receiver) پیکربندی و تنظیم کنید. این می تواند دقیق همان registration receiver باشد یا یک گیرنده ی به طور کامل متفاوت باشد. نمونه ی زیر مثالی از یک گیرنده ی پیغام مجزا می دهد.


package de.vogella.android.c2dm.simpleclient;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;

public class C2DMMessageReceiver extends BroadcastReceiver {
  @Override
  public void onReceive(Context context، Intent intent) {
    String action = intent.getAction();
    Log.w("C2DM"، "Message Receiver called");
    if ("com.google.android.c2dm.intent.RECEIVE".equals(action)) {
      Log.w("C2DM"، "Received message");
      final String payload = intent.getStringExtra("payload");
      Log.d("C2DM"، "dmControl: payload = " + payload);
      // Send this to my application server
    }
  }
}

علاوه بر آن، لازم است گیرنده ی پیغام (message receiver) خود را در فایل AndroidManifest.xmlثبت کنید.

 

<receiver android:name=".C2DMMessageReceiver"
   android:permission="com.google.android.c2dm.permission.SEND">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE"></action>
<category android:name="de.tahlildadeh.android.c2dm.simpleclient" />
</intent-filter>
</receiver>

ارسال پیام

در این مرحله، سرور برنامه و اپلیکیشن اندروید هر دو آماده ی استفاده از C2DM هستند. سرور توکن امنیتی (authentication token) و شناسه ی ثبت برنامه ی مورد نظر را داشته و اپلیکیشن موبایل نیز یک Broadcast receiver ویژه ی دریافت پیغام ها ثبت کرده است.

جهت ارسال یک پیغام به دستگاه، سرور اپلیکیشن یک درخواست HTTP POST به سرورهای C2DM گوگل ارسال می کند. این درخواست HTTP GET حاوی شناسه ی ثبت ویژه ی این دستگاه و توکن امنیتی است (برای اینکه به گوگل اطلاع دهد که این سرور مجوز ارسال پیغام را دارد).

 

package de.vogella.java.c2dm.server.util;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URL;
import java.net.URLEncoder;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLSession;
public class MessageUtil {
  private final static String AUTH = "authentication";
  private static final String UPDATE_CLIENT_AUTH = "Update-Client-Auth";
  public static final String PARAM_REGISTRATION_ID = "registration_id";
  public static final String PARAM_DELAY_WHILE_IDLE = "delay_while_idle";
  public static final String PARAM_COLLAPSE_KEY = "collapse_key";
  private static final String UTF8 = "UTF-8";
  public static int sendMessage(String auth_token، String registrationId،
        String message) throws IOException {
    StringBuilder postDataBuilder = new StringBuilder();
    postDataBuilder.append(PARAM_REGISTRATION_ID).append("=")
    .append(registrationId);
  postDataBuilder.append("&").append(PARAM_COLLAPSE_KEY).append("=")
          .append("0");
  postDataBuilder.append("&").append("data.payload").append("=")
           .append(URLEncoder.encode(message، UTF8));
    byte[] postData = postDataBuilder.toString().getBytes(UTF8);
    // Hit the dm URL.
    URL url = new URL("https://android.clients.google.com/c2dm/send");
    HttpsURLConnection
           .setDefaultHostnameVerifier(new CustomizedHostnameVerifier());
    HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
    conn.setDoOutput(true);
    conn.setUseCaches(false);
    conn.setRequestMethod("POST");
    conn.setRequestProperty("Content-Type"،
            "application/x-www-form-urlencoded;charset=UTF-8");
    conn.setRequestProperty("Content-Length"،
            Integer.toString(postData.length));
    conn.setRequestProperty("Authorization"، "GoogleLogin auth="
            + auth_token);
    OutputStream out = conn.getOutputStream();
    out.write(postData);
    out.close();
    int responseCode = conn.getResponseCode();
    return responseCode;
  }
  private static class CustomizedHostnameVerifier implements HostnameVerifier {
    public boolean verify(String hostname، SSLSession session) {
      return true;
    }
  }
}

پس از اینکه سرور پیغام ها را به سرور C2DM فرستاد، سرویس دهنده پیام ها را صف بندی کرده و به محض در دسترس بودن دستگاه آن ها را برای شما نمایش می دهد. پیام مذکور به عنوان یک broadcast به دستگاه مربوط ارسال می گردد. برنامه ی شما باید برای این رخداد broadcast ثبت نام کرده تا پیام را دریافت کند.

پیغام دریافت شده به broadcast receiver ثبت شده برای "com.google.android.c2dm.intent.RECEIVE". ارسال می گردد. داده ها را می توان از intent به وسیله ی تابع getExtras() دریافت کرد. کلیدهای موجود نیز عبارتند از "payload"، "from"،"collapse_key" . داده ی واقعی داخل "payload" گنجانده شده است. گیرنده / receiver خود قادر است این اطلاعات را استخراج کرده و به آن واکنش نشان دهد.

3. ثبت و دستگاه

در حال حاضر C2DM در مرحله ی آزمایشی بتا به سر می برد. برای دسترسی و استفاده از آن باید درخواست دهید. با مراجعه به این لینک می توانید برای استفاده از آن ثبت نام کنید : link to the signup form.

اگر مثال زیر را روی شبیه ساز تست می کنید باید توجه داشته باشید که API گوگل آن نسخه ی 8 یا بالاتر باشد. همچنین باید یک کاربر گوگل در محیط شبیه ساز ثبت کنید. این کار را می توان با مراجعه به Settings → Accounts Syncاین انجام داد. در صورت امتحان کردن این مثال روی دستگاه واقعی اندروید، باید از نصب Android Market بر روی دستگاه اطمینان کسب کنید.

4. آموزش ایجاد برنامه هایی که قابلیت C2DM در برنامه فعال سازی شده باشد.

طرح بندی و پروژه

پروژه ی اندروید "de.vogella.android.c2dm.simpleclient" همراه با اکتیویتی "C2DMClientActivity" را ایجاد کنید. طرح کلی  main.xml را ایجاد کنید.

 

<?xml version="1.0" encoding="utf-8" ?>

<linearlayout xmlns:android="http://schemas.android.com/apk/res/android"

              android:layout_width="match_parent"

              android:layout_height="match_parent"

              android:orientation="vertical">

 

    <button android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:onclick="register"

            android:text="Register"></button>

 

    <button android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:onclick="showRegistrationId"

            android:text="Show"></button>

 

</linearlayout>

همچنین طرح کلی "activity_result.xml" را ایجاد کنید، از این layout در result activity های خود استفاده می کنیم.

 

<?xml version="1.0" encoding="utf-8" ?>

<linearlayout xmlns:android="http://schemas.android.com/apk/res/android"

              android:layout_width="match_parent"

              android:layout_height="match_parent"

              android:orientation="vertical">

 

    <textview android:id="@+id/result"

              android:layout_width="match_parent"

              android:layout_height="match_parent"

              android:layout_gravity="center"

              android:text="No info."

              android:textappearance="?android:attr/textAppearanceLarge">

    </textview>

 

</linearlayout>

ایجاد receiver ها و activity ها

اکنون کلاس های "C2DMReceiverReceiver" و "C2DMMessageReceiver" را بسازید، این دو کلاس را بعد به عنوان گیرنده برای registration intent و message intent ثبت می کنیم.

 

package de.vogella.android.c2dm.simpleclient;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.preference.PreferenceManager;
import android.provider.Settings.Secure;
import android.util.Log;
public class C2DMRegistrationReceiver extends BroadcastReceiver {
  @Override
  public void onReceive(Context context، Intent intent) {
    String action = intent.getAction();
    Log.w("C2DM"، "Registration Receiver called");
    if ("com.google.android.c2dm.intent.REGISTRATION".equals(action)) {
      Log.w("C2DM"، "Received registration ID");
      final String registrationId = intent
             .getStringExtra("registration_id");
      String error = intent.getStringExtra("error");
      Log.d("C2DM"، "dmControl: registrationId = " + registrationId
              + "، error = " + error);
      String deviceId = Secure.getString(context.getContentResolver()،
              Secure.ANDROID_ID);
      createNotification(context، registrationId);
      sendRegistrationIdToServer(deviceId، registrationId);
      // Also save it in the preference to be able to show it later
      saveRegistrationId(context، registrationId);
    }
  }
  private void saveRegistrationId(Context context، String registrationId) {
    SharedPreferences prefs = PreferenceManager
           .getDefaultSharedPreferences(context);
    Editor edit = prefs.edit();
    edit.putString(C2DMClientActivity.AUTH، registrationId);
    edit.commit();
  }
  public void createNotification(Context context، String registrationId) {
    NotificationManager notificationManager = (NotificationManager) context
           .getSystemService(Context.NOTIFICATION_SERVICE);
    Notification notification = new Notification(R.drawable.icon،
            "Registration successful"، System.currentTimeMillis());
    // hide the notification after its selected
    notification.flags |= Notification.FLAG_AUTO_CANCEL;

    Intent intent = new Intent(context، RegistrationResultActivity.class);
    intent.putExtra("registration_id"، registrationId);
    PendingIntent pendingIntent = PendingIntent.getActivity(context، 0،
       intent، 0);
    notification.setLatestEventInfo(context، "Registration"،
      "Successfully registered"، pendingIntent);
    notificationManager.notify(0، notification);
  }
  // incorrect usage as the receiver may be canceled at any time
  // do this in an service and in an own thread
  public void sendRegistrationIdToServer(String deviceId،
  String registrationId) {
    Log.d("C2DM"، "Sending registration ID to my application server");
    HttpClient client = new DefaultHttpClient();
    HttpPost post = new HttpPost("http://tahlildadeh.com/register");
    try {
      List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(1);
      // Get the deviceID
      nameValuePairs.add(new BasicNameValuePair("deviceid"، deviceId));
      nameValuePairs.add(new BasicNameValuePair("registrationid"،
      registrationId));
      post.setEntity(new UrlEncodedFormEntity(nameValuePairs));
      HttpResponse response = client.execute(post);
      BufferedReader rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
      String line = "";
      while ((line = rd.readLine()) != null) {
        Log.e("HttpResponse"، line);
      }
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
}
package de.vogella.android.c2dm.simpleclient;
        import android.app.Notification;
        import android.app.NotificationManager;
        import android.app.PendingIntent;
        import android.content.BroadcastReceiver;
        import android.content.Context;
        import android.content.Intent;
        import android.util.Log;
public class C2DMMessageReceiver extends BroadcastReceiver {
  @Override
  public void onReceive(Context context، Intent intent) {
    String action = intent.getAction();
    Log.w("C2DM"، "Message Receiver called");
    if ("com.google.android.c2dm.intent.RECEIVE".equals(action)) {
      Log.w("C2DM"، "Received message");
      final String payload = intent.getStringExtra("payload");
      Log.d("C2DM"، "dmControl: payload = " + payload);
      // TODO Send this to my application server to get the real data
      // Lets make something visible to show that we received the message
      createNotification(context، payload);
    }
  }
  public void createNotification(Context context، String payload) {
    NotificationManager notificationManager = (NotificationManager) context
           .getSystemService(Context.NOTIFICATION_SERVICE);
    Notification notification = new Notification(R.drawable.icon،
            "Message received"، System.currentTimeMillis());
    // hide the notification after its selected
    notification.flags |= Notification.FLAG_AUTO_CANCEL;
    Intent intent = new Intent(context، MessageReceivedActivity.class);
    intent.putExtra("payload"، payload);
    PendingIntent pendingIntent = PendingIntent.getActivity(context، 0،
            intent، PendingIntent.FLAG_CANCEL_CURRENT);
    notification.setLatestEventInfo(context، "Message"،
            "New message received"، pendingIntent);
    notificationManager.notify(0، notification);
                          }
                         }

همچنین دو activity زیر را ایجاد کنید که در مراحل بعدی جهت مشاهده ی نتایج از آن ها استفاده می کنیم.

 

package de.vogella.android.c2dm.simpleclient;
import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;
public class RegistrationResultActivity extends Activity {
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    setContentView(R.layout.activity_result);
    Bundle extras = getIntent().getExtras();
    if (extras != null) {
      String registrationId = extras.getString("registration_id");
      if (registrationId != null && registrationId.length() > 0) {
        TextView view = (TextView) findViewById(R.id.result);
        view.setText(registrationId);
      }
    }
    super.onCreate(savedInstanceState);
  }
}
package de.vogella.android.c2dm.simpleclient;

        import android.app.Activity;
        import android.os.Bundle;
        import android.widget.TextView;
public class MessageReceivedActivity extends Activity {
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    setContentView(R.layout.activity_result);
    Bundle extras = getIntent().getExtras();
    if (extras != null) {
      String message = extras.getString("payload");
      if (message != null && message.length() > 0) {
        TextView view = (TextView) findViewById(R.id.result);
        view.setText(message);
      }
    }
    super.onCreate(savedInstanceState);
  }
}

حال فایل AndroidManifest.xmlزیر را ایجاد کنید. فایل گفته شده Intent Receiver ها، Activity ها، درخواست ها و مجوزهای لازم را به ثبت می رساند.

 

<?xml version="1.0" encoding="utf-8" ?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android"

          package="de.vogella.android.c2dm.simpleclient"

          android:versioncode="1"

          android:versionname="1.0">

 

    <uses-sdk android:minsdkversion="8" />

 

    <permission android:name="de.vogella.android.c2dm.simpleclient.permission.C2D_MESSAGE"

                android:protectionlevel="signature" />

 

    <uses-permission android:name="de.vogella.android.c2dm.simpleclient.permission.C2D_MESSAGE" />

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

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

 

    <application android:icon="@drawable/icon"

                 android:label="@string/app_name">

        <activity android:label="@string/app_name"

                  android:name=".C2DMClientActivity">

            <intent-filter>

                <action android:name="android.intent.action.MAIN" />

 

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

            </intent-filter>

        </activity>

 

        <receiver android:name=".C2DMRegistrationReceiver"

                  android:permission="com.google.android.c2dm.permission.SEND">

            <intent-filter>

                <action android:name="com.google.android.c2dm.intent.REGISTRATION">

                </action>

 

                <category android:name="de.vogella.android.c2dm.simpleclient" />

            </intent-filter>

        </receiver>

        <receiver android:name=".C2DMMessageReceiver"

                  android:permission="com.google.android.c2dm.permission.SEND">

            <intent-filter>

                <action android:name="com.google.android.c2dm.intent.RECEIVE">

                </action>

 

                <category android:name="de.vogella.android.c2dm.simpleclient" />

            </intent-filter>

        </receiver>

 

        <activity android:name="RegistrationResultActivity">

        </activity>

        <activity android:name="MessageReceivedActivity">

        </activity>

    </application>

</manifest>

کلاس "C2DMClientActivity" را به ترتیب زیر اصلاح کنید.

 

package de.vogella.android.c2dm.simpleclient;
import android.app.Activity;
import android.app.PendingIntent;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.View;
import android.widget.Toast;
public class C2DMClientActivity extends Activity {
  public final static String AUTH = "authentication";
  // Example Activity to trigger a request for a registration ID to the Google
  // server
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
  }
  public void register(View view) {
    Log.w("C2DM"، "start registration process");
    Intent intent = new Intent("com.google.android.c2dm.intent.REGISTER");
    intent.putExtra("app"،
            PendingIntent.getBroadcast(this، 0، new Intent()، 0));
    // Sender currently not used
    intent.putExtra("sender"، "این آدرس ایمیل توسط spambots حفاظت می شود. برای دیدن شما نیاز به جاوا اسکریپت دارید");
    startService(intent);
  }
  public void showRegistrationId(View view) {
    SharedPreferences prefs = PreferenceManager
           .getDefaultSharedPreferences(this);
    String string = prefs.getString(AUTH، "n/a");
    Toast.makeText(this، string، Toast.LENGTH_LONG).show();
    Log.d("C2DM RegId"، string);
  }
}

متدهای داخل activity ها به وسیله ی خصوصیت (property) onclick به دکمه ها متصل هستند. دکمه ی اول درخواست برای شناسه ی ثبت را راه اندازی می کند و دکمه ی دوم کلید ثبت (registration key) ذخیره شده را نشان می دهد. همچنین شناسه ی ثبت را در LogCat view رایت کنید.

اکنون یک کپی از شناسه ی ثبت LogCat view تهیه کرده تا در آینده بتوانید آن را در پیاده سازی سرور خود بکار ببرید.

ثبت برنامه

برنامه ی خود را اجرا کرده و کاربر ثبت نام شده را نگه دارید، سپس دکمه ی مربوط را بزنید. LogCat را برای شناسه ی ثبت بررسی کنید.

در صورت مشاهده ی پیغام زیر، مطمئن شوید که از دستگاه گوگل استفاده کرده و همچنین یک کاربر گوگل روی دستگاه مورد نظر ثبت کرده اید.

 

Unable to start service Intent
  {act=com.google.android.c2dm.intent.REGISTER... }: not found

. آموزش استفاده از ابزار خط فرمان Curl برای شبیه سازی سرور

در صورت راه اندازی سیستم لینوکس، می توانید به راحتی سرویس را روی خط فرمان تست کنید. با استفاده از curlروی خط فرمان می توان کلید شناسایی / احراز هویت (authentication key) را درخواست کرد. از پاسخ دریافتی بخش پس از "Auth=" را دریافت کرده و بکار ببرید.

 

curl https://www.google.com/accounts/ClientLogin -d
        Email=your_user -d "Passwd=your_password" -d accountType=GOOGLE
        -d source=Google-cURL-Example -d service=ac2dm

با استفاده از این بخش و کد ثبت (registration code) می توان پیغام به دستگاه ارسال کرد.

 

curl --header "Authorization: GoogleLogin auth=your_authenticationid"
        "https://android.apis.google.com/c2dm/send" -d registration_id=your_registration
        -d "data.payload=payload" -d collapse_key=0

. آموزش ایجاد برنامه ی سرور

همان طور که پیشتر توضیح داده شد، سرور برنامه باید از طریق HTTPS یک کلید احراز هویت دریافت کند. پس از این مرحله، سرور برنامه باید پیام های مورد نظر را از طریق HTTP با ارائه ی کلید احراز هویت و شناسه ی ثبت به دستگاه مربوطه ارسال کنید.

با بهره گیری از یک برنامه ی جاوا سرویس دهنده را شبیه سازی می کنیم. شناسه ی ثبت دستگاه داخل اپلیکیشن hard-code (وابسته به مقادیر موجود در متن برنامه / source code و نه مقادیری که توسط کاربر وارد می گردد) می شود، زیرا که امکان دستیابی به برنامه از طریق http وجود ندارد.

جهت ثبت و ذخیره ی اعتبارنامه (credentials) خود، کلاس زیر را بکار ببرید.

 

package de.vogella.java.c2dm.server.secret;
public class SecureStorage {
  public static final String USER = "your_registeredUser";
  public static final String PASSWORD = "your_password";
}

یک پروژه جدید جاوا "de.tahlildadeh.java.c2dm.server" ایجاد کنید. حال کلاس زیر را بسازید. کلاس مزبور در واقع به عنوان یک کلاس خدماتی / utility class (کلاسی که یک مجموعه متد ویژه اجرای توابع متداول که مدام مورد استفاده ی مجدد قرار ی گیرند، تعریف می کند) عمل می کند که توکن یا نشانه ی امنیتی (authentication token) را از سرور گوگل دریافت می کند.

 

package de.vogella.java.c2dm.server.util;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
public class AuthenticationUtil {
  private AuthenticationUtil() {
    // Util class cannot get instanziated
  }
  public static String getToken(String email، String password)
          throws IOException {
    // create the post data
    // Requires a field with the email and the password
    StringBuilder builder = new StringBuilder();
    builder.append("Email=").append(email);
    builder.append("&Passwd=").append(password);
    builder.append("&accountType=GOOGLE");
    builder.append("&source=MyLittleExample");
    builder.append("&service=ac2dm");
    // Setup the Http Post
    byte[] data = builder.toString().getBytes();
    URL url = new URL("https://www.google.com/accounts/ClientLogin");
    HttpURLConnection con = (HttpURLConnection) url.openConnection();
    con.setUseCaches(false);
    con.setDoOutput(true);
    con.setRequestMethod("POST");
    con.setRequestProperty("Content-Type"،
            "application/x-www-form-urlencoded");
    con.setRequestProperty("Content-Length"، Integer.toString(data.length));
    // Issue the HTTP POST request
    OutputStream output = con.getOutputStream();
    output.write(data);
    output.close();
    // read the response
    BufferedReader reader = new BufferedReader(new InputStreamReader(con.getInputStream()));
    String line = null;
    String auth_key = null;
    while ((line = reader.readLine()) != null) {
      if (line.startsWith("Auth=")) {
        auth_key = line.substring(5);
      }
    }
    // Finally get the authentication token
    // To something useful with it
    return auth_key;
  }
}

اکنون کلاس "GetAuthenticationToken" را ایجاد کنید. از این کلاس می توان برای دریافت نشانه ی امنیتی (authentication token) استفاده کرد.

 

ackage de.vogella.java.c2dm.server;
import java.io.IOException;
import de.vogella.java.c2dm.server.secret.SecureStorage;
import de.vogella.java.c2dm.server.util.AuthenticationUtil;
public class GetAuthenticationToken {
  public static void main(String[] args) throws IOException {
    String token = AuthenticationUtil.getToken(SecureStorage.USER،
            SecureStorage.PASSWORD);
    System.out.println(token);
  }
}

کلاس GetAuthenticationToken را اجرا کرده و به خاطر داشته باشید که باید نشانه ی احراز هویت (authentication token) و شناسه ی ثبت (registration id) خود را نگه دارید.

 

package de.vogella.java.c2dm.server;
public class ServerConfiguration {
  public static final String AUTHENTICATION_TOKEN = "your_token";
  public static final String REGISTRATION_ID = "registration_id_of_your_device";
}

همچنین لازم است کلاس خدماتی (utility class) زیر را ایجاد کنید. کلاس گفته شده به شما اجازه می دهد پیام ها را به دستگاه ارسال کنید.

 

package de.vogella.java.c2dm.server.util;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URL;
import java.net.URLEncoder;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLSession;
public class MessageUtil {
  private final static String AUTH = "authentication";
  private static final String UPDATE_CLIENT_AUTH = "Update-Client-Auth";
  public static final String PARAM_REGISTRATION_ID = "registration_id";
  public static final String PARAM_DELAY_WHILE_IDLE = "delay_while_idle";
  public static final String PARAM_COLLAPSE_KEY = "collapse_key";
  private static final String UTF8 = "UTF-8";
  public static int sendMessage(String auth_token، String registrationId،
      String message) throws IOException {
    StringBuilder postDataBuilder = new StringBuilder();
    postDataBuilder.append(PARAM_REGISTRATION_ID).append("=")
           .append(registrationId);
postDataBuilder.append("&").append(PARAM_COLLAPSE_KEY).append("=")
           .append("0");
    postDataBuilder.append("&").append("data.payload").append("=")
          .append(URLEncoder.encode(message، UTF8));
    byte[] postData = postDataBuilder.toString().getBytes(UTF8);
    // Hit the dm URL.
    URL url = new URL("https://android.clients.google.com/c2dm/send");
    HttpsURLConnection
           .setDefaultHostnameVerifier(new CustomizedHostnameVerifier());
    HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
    conn.setDoOutput(true);
    conn.setUseCaches(false);
    conn.setRequestMethod("POST");
    conn.setRequestProperty("Content-Type"،
            "application/x-www-form-urlencoded;charset=UTF-8");
    conn.setRequestProperty("Content-Length"،
            Integer.toString(postData.length));
    conn.setRequestProperty("Authorization"، "GoogleLogin auth="
            + auth_token);
    OutputStream out = conn.getOutputStream();
    out.write(postData);
    out.close();
    int responseCode = conn.getResponseCode();
    return responseCode;
  }
  private static class CustomizedHostnameVerifier implements HostnameVerifier {
    public boolean verify(String hostname، SSLSession session) {
      return true;
    }
  }
}

در مرحله ی آخر، کلاس "SendMessageToDevice" را ایجاد کنید، این کلاس نیز به شما اجازه می دهد پیام ها را به دستگاه خود بفرستید.

 

package de.vogella.java.c2dm.server;
import java.io.IOException;
import de.vogella.java.c2dm.server.util.MessageUtil;
public class SendMessageToDevice {
 public static void main(String[] args) throws IOException {
    // "Message to your device." is the message we will send to the Android app
    int responseCode = MessageUtil.sendMessage(ServerConfiguration.AUTHENTICATION_TOKEN،
ServerConfiguration.REGISTRATION_ID، "Message to your device.");
    System.out.println(responseCode);
  }
}

حال آن را اجرا کنید. باید پیغامی به دستگاه ارسال شده و کد بازگشتی  "200" را به شما ارائه دهد. روی دستگاه باید اطلاعیه ی مشاهده کنید، و در صورت آن باز کردن پیغامی برای شما به نمایش گذاشته شود.

تمامی محصولات و خدمات این وبسایت، حسب مورد دارای مجوزهای لازم از مراجع مربوطه می‌باشند و فعالیت‌های این سایت تابع قوانین و مقررات جمهوری اسلامی ایران است.
logo-samandehi مجوز نشر دیجیتال از وزرات فرهنگ و ارشاد اسلامی پرداخت آنلاین -  بانک ملت معرفی بیاموز در شبکه سه