Skip to content
This repository has been archived by the owner on Sep 17, 2022. It is now read-only.

Commit

Permalink
Browse files Browse the repository at this point in the history
sync up docs with android studio docs
  • Loading branch information
etanshaul committed Mar 7, 2016
1 parent 7d87f62 commit 04d7f57
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 160 deletions.
193 changes: 33 additions & 160 deletions GcmEndpoints/README.md
Expand Up @@ -7,7 +7,9 @@ This backend template employs [Google Cloud Endpoints](https://developers.google

# 1. Adding a backend in Android Studio

To add the backend to your existing Android app from this backend template, open Android Studio ([installation instructions](https://developer.android.com/sdk/installing/studio.html)) and navigate to "File → New Module..." or right-click on your project and choose "New → Module".
This guide builds on top of the [GCM sample Quickstart app](https://github.com/googlesamples/google-services/tree/master/android/gcm). If you already have an existing application, then you can reference the Quickstart app as a guide to setting the GCM client code.

To add the backend to your existing Android app from the GCM backend template, open [Android Studio](https://developer.android.com/sdk/installing/studio.html) and navigate to "File → New Module..." or right-click on your project and choose "New → Module".

![New → Module](/doc/img/add-app-engine-backend-menu-scaled.png)

Expand All @@ -19,7 +21,7 @@ Then choose "App Engine Backend with Google Cloud Messaging".

![App Engine GCM Module](/doc/img/gcm2.png)

Enter the module/package names for your new backend, and choose the "client" module in your project which contains your Android app. The client module will be set up to call your newly generated backend. Module name which you've entered above (marked with red **1**) will be used in your Android Studio project. Package name (marked with red **2**) will be used for all classes imported from this template and (reversed) for [Endpoints API namespaces](https://developers.google.com/appengine/docs/java/endpoints/annotations#apinamespace). In turn, Endpoints API namespaces will be used to derive the name of the autogenerated Android client libraries, hence this ensures that the names of generated client libraries will match your package name.
Enter the module/package names for your new backend, and choose the "client" module in the project which contains your Android app. The client module will be set up to call your newly generated backend. The module name which you've entered above (marked with red **1**) will be used in your Android Studio project. The package name (marked with red **2**) will be used for all classes imported from this template and (reversed) for [Endpoints API namespaces](https://developers.google.com/appengine/docs/java/endpoints/annotations#apinamespace). In turn, Endpoints API namespaces will be used to derive the name of the autogenerated Android client libraries. This ensures that the names of generated client libraries will match your package name.

![Added "GcmEndpoints" backend. Red numbers 1 and 2 indicate that the module name and the package names came from "New App Engine Module" dialog](/doc/img/added-backend-gcm.png)

Expand All @@ -31,31 +33,15 @@ As soon as the backend module is added to your project and Gradle sync finishes,

Rebuild your project (via "Build → Rebuild Project") and launch this run configuration. It will invoke `appengineRun` task in [Gradle plug-in for App Engine](https://github.com/GoogleCloudPlatform/gradle-appengine-plugin), which in turn will start the local App Engine [Java development server](https://developers.google.com/appengine/docs/java/tools/devserver).

To ensure that your backend started successfully, navigate to [http://localhost:8080](http://localhost:8080). If everything went well, you should see the following page:
Navigate to [http://localhost:8080](http://localhost:8080). You should see the following page:

!["HelloWorld" backend running in local Java development server](/doc/img/devappserver-gcm.png)

# 2. Connecting your Android app to the backend

## 2.1. Obtaining Google Cloud Messaging API key

Before testing the application, you will need to obtain a Google Cloud Messaging API key. Open the `<backend>/src/main/webapp/WEB-INF/appengine-web.xml` file (it should have been opened by default when you generated the backend), and navigate to this link: [https://console.developers.google.com/flows/enableapi?apiid=googlecloudmessaging&keyType=SERVER_SIDE&r=0.0.0.0/0](https://console.developers.google.com/flows/enableapi?apiid=googlecloudmessaging&keyType=SERVER_SIDE&r=0.0.0.0/0).

![Project creation in Google Developers Console](/doc/img/dev-console-gcm-register.png)

Choose a "Create a new project" option to create a new [Google Developers Console](https://console.developers.google.com) project (or choose an existing project, if you have one already), and click "Continue".

Read the Terms of Service and assuming that you agree, check the checkbox to indicate that you have read them and click "Accept".

Once you select or create a project, it will have "Google Cloud Messaging for Android" API enabled automatically. In the following configuration dialog, you can use the supplied "0.0.0.0/0" IP address for testing purposes.

![Creating a new server key in Google Developers Console](/doc/img/dev-console-server-key.png)

Click "Create" to get the API key for server applications generated for you.

![Server applications API key in Google Developers Console](/doc/img/dev-console-key-view.png)

Copy the generated [API key](http://developer.android.com/google/gcm/gcm.html#apikey) (in a red rectangle, starts with `AIza...`) back into `appengine-web.xml` file, replacing
To test the application, you need a Google Cloud Messaging API key. Follow the [instructions](https://developers.google.com/cloud-messaging/android/client) to create a `google-services.json` configuration file and API key. Open the `<backend>/src/main/webapp/WEB-INF/appengine-web.xml` file (it should have been opened by default when you generated the backend), and copy the generated API key into `appengine-web.xml` file, replacing
```xml
<property name="gcm.api.key" value="YOUR_KEY_HERE"/>
```
Expand All @@ -64,10 +50,6 @@ with
<property name="gcm.api.key" value="AIza..."/>
```

Finally, go back to your project's overview in [Google Developers Console](https://console.developers.google.com) and note down the project number (in red rectangle below): this will be your Google Cloud Messaging [sender ID](http://developer.android.com/google/gcm/gcm.html#senderid) in the next step.

![Project number in Google Developers Console](/doc/img/dev-console-project-overview.png)

## 2.2. Registering devices with Google Cloud Messaging backend

Before any messages can be sent from a Google Cloud Messaging backend to the devices, these devices need to be registered with a GCM backend.
Expand All @@ -76,26 +58,14 @@ When you added this backend module to your project, the [required permissions, n

Furthermore, a `RegistrationEndpoint` [Cloud Endpoints API](https://developers.google.com/appengine/docs/java/endpoints/) has been automatically generated for you, so that you could start calling this endpoint from your Android app to register devices with your new Google Cloud Messaging backend.

Here is an example code snippet which illustrates how to create an [AsyncTask](http://developer.android.com/reference/android/os/AsyncTask.html) to register the user's device with your new backend:

```java
class GcmRegistrationAsyncTask extends AsyncTask<Void, Void, String> {
private static Registration regService = null;
private GoogleCloudMessaging gcm;
private Context context;
Set up your [Google Cloud Messaging Client](https://developers.google.com/cloud-messaging/android/client). Follow the guide to obtain a registration token, register the user's device with your new backend, and set up the listener services to show push notifications from the GCM backend.

// TODO: change to your own sender ID to Google Developers Console project number, as per instructions above
private static final String SENDER_ID = "1234567890123";
To send your newly obtained GCM registration token to the server, use the following code snippet which you should invoke from the `RegistrationIntentService` you created when setting up the client:

public GcmRegistrationAsyncTask(Context context) {
this.context = context;
}

@Override
protected String doInBackground(Void... params) {
if (regService == null) {
Registration.Builder builder = new Registration.Builder(AndroidHttp.newCompatibleTransport(),
new AndroidJsonFactory(), null)
```java
private void sendRegistrationToServer(String token) throws IOException {
Registration.Builder builder = new Registration.Builder(AndroidHttp.newCompatibleTransport(),
new AndroidJsonFactory(), null)
// Need setRootUrl and setGoogleClientRequestInitializer only for local testing,
// otherwise they can be skipped
.setRootUrl("http://10.0.2.2:8080/_ah/api/")
Expand All @@ -106,136 +76,34 @@ class GcmRegistrationAsyncTask extends AsyncTask<Void, Void, String> {
abstractGoogleClientRequest.setDisableGZipContent(true);
}
});
// end of optional local run code

regService = builder.build();
}

String msg = "";
try {
if (gcm == null) {
gcm = GoogleCloudMessaging.getInstance(context);
}
String regId = gcm.register(SENDER_ID);
msg = "Device registered, registration ID=" + regId;

// You should send the registration ID to your server over HTTP,
// so it can use GCM/HTTP or CCS to send messages to your app.
// The request to your server should be authenticated if your app
// is using accounts.
regService.register(regId).execute();

} catch (IOException ex) {
ex.printStackTrace();
msg = "Error: " + ex.getMessage();
}
return msg;
Registration regService = builder.build();
regService.register(token).execute();
}

@Override
protected void onPostExecute(String msg) {
Toast.makeText(context, msg, Toast.LENGTH_LONG).show();
Logger.getLogger("REGISTRATION").log(Level.INFO, msg);
}
}
```

Don't forget to replace `SENDER_ID` in the snippet above with your actual Google Developers Console project number!

To make the actual registration call from your app, invoke this AsyncTask from one of your Android activities. For example, to execute it from `MainActivity` class, add the following code snippet to `MainActivity.onCreate` method:

```java
new GcmRegistrationAsyncTask(this).execute();
```

## 2.3. Testing device registration in an emulator

If you have added an `GcmRegistrationAsyncTask` invokation to one of your Android app activities as per steps above (and replaced `SENDER_ID` with your actual Google Developers Console project number), you should be all set to test the device registration with your backend locally!
If you have added a `RegistrationIntentService` invocation to one of your Android app activities (as demonstrated in the Quickstart app), and set up the `google-services.json` configuration file containing your Google Developers Console project number, you are ready to test the device registration with your backend locally.

To begin with, make sure that your Android Virtual Device is using Google APIs System Image as illustrated in the screenshot below.
First, make sure that your Android Virtual Device is using Google APIs System Image as illustrated in the screenshot below.

![Android Virtual Device configuration containing Google APIs System Image Target](/doc/img/avd-manager-google-api-image.png)

Then, launch your backend locally as described in section 1.1. and ensure that you can access it via [http://localhost:8080](http://localhost:8080). If you can access the backend locally, change the run configuration back to your Android app and run the Android emulator.
Next, launch your backend locally as described in section 1.1 and ensure that you can access it via [http://localhost:8080](http://localhost:8080). If you can access the backend locally, change the run configuration back to your Android app and run the Android emulator.

If everything goes well, you should see the following toast in your app:
You should see the following in your GCM Quickstart app:

![Emulator successfully registered with "GcmEndpoints" backend](/doc/img/emulator-gcm.png)

## 2.4. Showing push notifications from GCM backend

In order to show the push notifications coming from the generated backend, you need to add two more simple classes into your Android client: `GcmIntentService` and `GcmBroadcastReceiver`.

Here is the source code for `GcmIntentService.java`:

```java
public class GcmIntentService extends IntentService {

public GcmIntentService() {
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);

if (extras != null && !extras.isEmpty()) { // has effect of unparcelling Bundle
// Since we're not using two way messaging, this is all we really to check for
if (GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE.equals(messageType)) {
Logger.getLogger("GCM_RECEIVED").log(Level.INFO, extras.toString());

showToast(extras.getString("message"));
}
}
GcmBroadcastReceiver.completeWakefulIntent(intent);
}

protected void showToast(final String message) {
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG).show();
}
});
}
}
```

Similarly, here is the source code for `GcmBroadcastReceiver.java`:
You should now be set up to receive push notifications coming from the generated backend. To test this out, ensure your GCM backend is running locally as described in section 1.1, enter a test message, and send:

```java
public class GcmBroadcastReceiver extends WakefulBroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
// Explicitly specify that GcmIntentService will handle the intent.
ComponentName comp = new ComponentName(context.getPackageName(),
GcmIntentService.class.getName());
// Start the service, keeping the device awake while it is launching.
startWakefulService(context, (intent.setComponent(comp)));
setResultCode(Activity.RESULT_OK);
}
}
```
![Send message from GCM backend](/doc/img/backend-message.png)

After adding these classes to your Android application, register them by adding the following snipped into your `AndroidManifest.xml` file (inside `<application>` tag).

```xml
<receiver
android:name=".GcmBroadcastReceiver"
android:permission="com.google.android.c2dm.permission.SEND" >
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<category android:name="MY_PACKAGE" />
</intent-filter>
</receiver>
<service android:name=".GcmIntentService" />
```
You should see a notification arrive in your device emulator:

Do not forget to replace `MY_PACKAGE` in the snippet above with your package name.
![Receive notification in device emulator](/doc/img/backend-notification.png)

## 2.5. Deploying the backend live to App Engine

Expand Down Expand Up @@ -263,20 +131,25 @@ sign-in with your Google Account. Choose an account and sign in.<br>

## 2.6. Testing against a deployed backend

Once you have deployed your backend to App Engine, you can connect your Android app to it by modifying `GcmRegistrationAsyncTask` class defined in section 2 above. In particular, replace the lines
Once you have deployed your backend to App Engine, you can connect your Android app to it by modifying the `RegistrationIntentService` class explained in section 2 above. In particular, replace the lines
```java
Registration.Builder builder = new Registration.Builder(AndroidHttp.newCompatibleTransport(), new AndroidJsonFactory(), null)
.setRootUrl("http://10.0.2.2:8080/_ah/api/") // 10.0.2.2 is localhost's IP address in Android emulator
Registration.Builder builder = new Registration.Builder(AndroidHttp.newCompatibleTransport(),
new AndroidJsonFactory(), null)
// Need setRootUrl and setGoogleClientRequestInitializer only for local testing,
// otherwise they can be skipped
.setRootUrl("http://10.0.2.2:8080/_ah/api/")
.setGoogleClientRequestInitializer(new GoogleClientRequestInitializer() {
@Override
public void initialize(AbstractGoogleClientRequest<?> abstractGoogleClientRequest) throws IOException {
public void initialize(AbstractGoogleClientRequest<?> abstractGoogleClientRequest)
throws IOException {
abstractGoogleClientRequest.setDisableGZipContent(true);
}
});
```
with these two lines
with these lines
```java
Registration.Builder builder = new Registration.Builder(AndroidHttp.newCompatibleTransport(), new AndroidJsonFactory(), null)
Registration.Builder builder = new Registration.Builder(AndroidHttp.newCompatibleTransport(),
new AndroidJsonFactory(), null)
.setRootUrl("https://android-app-backend.appspot.com/_ah/api/");
```
where `android-app-backend` corresponds to your own Project ID created in section 2.5.
Expand Down
Binary file added doc/img/backend-message.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/img/backend-notification.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified doc/img/emulator-gcm.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 04d7f57

Please sign in to comment.