如何使用 Android Studio 为 Android 实施 GCM Hello World

How to implement a GCM Hello World for Android using Android Studio

几天来我一直在寻找如何为 Android 实施 Google 云消息传递,但我对此有一些严重的怀疑。

我的意思是,显然 Google 在网上发布了一些很好的信息,例如 here and here,但我对所有逻辑感到困惑。一页讨论客户端,另一页讨论服务器端。太好了,但我如何将所有这些绑定在一起?我如何实施 HTTP and/or XMPP 协议来与 GCM 连接服务器通信?

我想为 GCM 实现一个基本的 HelloWorld,它可以通过以下步骤工作:

1. App send a message (say "HelloWorld") to GCM;
2. Receive that message from GCM and add it to a TextView.

实现这个基本应用程序需要哪些步骤?

谢谢,

如果您已经阅读问题中的两个链接并了解 GCM 关键概念,那么您可以参考以下示例代码:

当然,假设你已经完成了:

  • Google Developers Console
  • 处创建项目及其服务器 API 密钥
  • 像这样在您的 AndroidManifest 文件中设置权限 <uses-permission android:name="android.permission.INTERNET" />

服务器端:

public class MainActivity extends AppCompatActivity {

    private TextView mTextView;

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

        mTextView = (TextView) findViewById(R.id.textView);

        new GCMRequest().execute();
    }

    ...    

    private class GCMRequest extends AsyncTask<Void, Void, String> {

        @Override
        protected String doInBackground(Void... voids) {

            final String API_KEY = "..."; // An API key saved on the app server that gives the app server authorized access to Google services
            final String CLIENT_REG_ID = "..."; //An ID issued by the GCM connection servers to the client app that allows it to receive messages
            final String postData = "{ \"registration_ids\": [ \"" + CLIENT_REG_ID + "\" ], " +
                    "\"delay_while_idle\": true, " +
                    "\"data\": {\"tickerText\":\"My Ticket\", " +
                    "\"contentTitle\":\"My Title\", " +
                    "\"message\": \"Test GCM message from GCMServer-Android\"}}";

            try {                        
                URL url = new URL("https://android.googleapis.com/gcm/send");
                HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
                urlConnection.setDoInput(true);
                urlConnection.setDoOutput(true);
                urlConnection.setRequestMethod("POST");
                urlConnection.setRequestProperty("Content-Type", "application/json");
                urlConnection.setRequestProperty("Authorization", "key=" + API_KEY);

                OutputStream outputStream = new BufferedOutputStream(urlConnection.getOutputStream());
                BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream, "utf-8"));
                writer.write(postData);
                writer.flush();
                writer.close();
                outputStream.close();

                int responseCode = urlConnection.getResponseCode();
                InputStream inputStream;
                if (responseCode < HttpURLConnection.HTTP_BAD_REQUEST) {
                    inputStream = urlConnection.getInputStream();
                } else {
                    inputStream = urlConnection.getErrorStream();
                }
                BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
                String temp, response = "";
                while ((temp = bufferedReader.readLine()) != null) {
                    response += temp;
                }
                return response;
            } catch (IOException e) {
                e.printStackTrace();
                return e.toString();
            }
        }

        @Override
        protected void onPostExecute(String message) {
            super.onPostExecute(message);

            if (mTextView != null) {
                try {
                    JSONObject jsonObject = new JSONObject(message);
                    mTextView.setText(jsonObject.toString(5));
                } catch (JSONException e) {
                    e.printStackTrace();
                    mTextView.setText(e.toString());
                }
            }
        }
    }
}

客户端:

MainActivity.java:

public class MainActivity extends AppCompatActivity {

    private final Context mContext = this;
    private final String SENDER_ID = "..."; // Project Number at https://console.developers.google.com/project/...
    private final String SHARD_PREF = "com.example.gcmclient_preferences";
    private final String GCM_TOKEN = "gcmtoken";    
    public static TextView mTextView;

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

        SharedPreferences appPrefs = mContext.getSharedPreferences(SHARD_PREF, Context.MODE_PRIVATE);
        String token = appPrefs.getString(GCM_TOKEN, "");
        if (token.isEmpty()) {
            try {
                getGCMToken();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        mTextView = (TextView) findViewById(R.id.textView);
    }

    ...    

    private void getGCMToken() {
        new AsyncTask<Void, Void, Void>() {
            @Override
            protected Void doInBackground(Void... params) {
                try {
                    InstanceID instanceID = InstanceID.getInstance(mContext);
                    String token = instanceID.getToken(SENDER_ID, GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);
                    if (token != null && !token.isEmpty()) {
                        SharedPreferences appPrefs = mContext.getSharedPreferences(SHARD_PREF, Context.MODE_PRIVATE);
                        SharedPreferences.Editor prefsEditor = appPrefs.edit();
                        prefsEditor.putString(GCM_TOKEN, token);
                        prefsEditor.apply();
                    }
                    Log.i("GCM", token);
                } catch (IOException e) {
                    e.printStackTrace();
                }
                return null;
            }
        }.execute();
    }
}

GcmService.java:

public class GcmService extends GcmListenerService {

    @Override
    public void onMessageReceived(String from, Bundle data) {
        JSONObject jsonObject = new JSONObject();
        Set<String> keys = data.keySet();
        for (String key : keys) {
            try {
                jsonObject.put(key, data.get(key));
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }
        try {
            sendNotification("Received: " + jsonObject.toString(5));
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onDeletedMessages() {
        sendNotification("Deleted messages on server");
    }

    @Override
    public void onMessageSent(String msgId) {
        sendNotification("Upstream message sent. Id=" + msgId);
    }

    @Override
    public void onSendError(String msgId, String error) {
        sendNotification("Upstream message send error. Id=" + msgId + ", error" + error);
    }

    private void sendNotification(final String msg) {
        Handler handler = new Handler(Looper.getMainLooper());
        handler.post(new Runnable() {
            @Override
            public void run() {                    
                if (MainActivity.mTextView != null) {
                    MainActivity.mTextView.setText(msg);
                }
            }
        });
    }
}

AndroidManifest.xml:

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

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

    <permission android:name="com.example.gcm.permission.C2D_MESSAGE"
        android:protectionLevel="signature" />
    <uses-permission android:name="com.example.gcm.permission.C2D_MESSAGE" />

    <application
        android:allowBackup="true"
        android:fullBackupContent="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >

        <receiver
            android:name="com.google.android.gms.gcm.GcmReceiver"
            android:exported="true"
            android:permission="com.google.android.c2dm.permission.SEND" >
            <intent-filter>
                <action android:name="com.google.android.c2dm.intent.REGISTRATION" />
                <action android:name="com.google.android.c2dm.intent.RECEIVE" />
                <category android:name="com.example.gcm" />
            </intent-filter>
        </receiver>
        <service android:name=".GcmService" android:exported="false">
            <intent-filter>
                <action android:name="com.google.android.c2dm.intent.RECEIVE" />
            </intent-filter>
        </service>

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

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

</manifest>