...

Lab 3A - Android Add push notifications to your Android app

by user

on
Category: Documents
17

views

Report

Comments

Transcript

Lab 3A - Android Add push notifications to your Android app
IBM Mobile Cloud Development Workshop
Lab 3A - Android
Add push notifications to your Android app
12/2015
COPYRIGHT IBM CORPORATION 2015. ALL RIGHTS RESERVED.
LAB 3A
PAGE 1 OF 21
IBM Mobile Cloud Development Workshop
Introduction:
Have you ever gone to the grocery store and forgotten the exact ingredient your
spouse needed for that fabulous soufflé recipe? Or the lunch box dessert the kids
had requested for the next day?
What if they all could enter their requests into a shared grocery list, and you could
receive push notifications alerting you to the updates?
This simple application will be used during the workshop and enhanced by adding
several IBM Bluemix Cloud services such as Mobile Data, Push Notifications and
Security.
Description:
In this lab we extend the Android BlueList application built in Lab 2 (data backend
built in Lab 1) with IBM Bluemix Push notifications.
Objective:
At the end of the lab you should be able to use the IBM Bluemix MBaaS Push Notification service.
COPYRIGHT IBM CORPORATION 2015. ALL RIGHTS RESERVED.
LAB 3A
PAGE 2 OF 21
IBM Mobile Cloud Development Workshop
Procedure:
Note: The prerequisite for the following steps is the completion of
SECTION 1 in Lab 1 and Lab 2A of this workshop. A completed version of
Lab 2 (except the Bluemix app values for app route, app secret and app
id you can clone with the following command:
git clone https://hub.jazz.net/git/mobilecloud/bluelist-mobiledata
A completed version of this lab you can clone with the following command.
git clone https://hub.jazz.net/git/mobilecloud/bluelist-push
SECTION 1: GET YOUR GOOGLE API PROJECT NUMBER AND GCM API KEY NEEDED
FOR PUSH
Step 1 Open the Google Developers Console
http://console.developer.google.com
Step 2 Click CREATE PROJECT, enter a Project name and click Create.
Step 3 Open the Project just created.
Step 4 Copy the Project Number from the top of the page. This is your GCM
Sender Id (Google API Project Number). You'll need this later!
Step 5 From the Menu
in the top left corner select the API Manager
Step 6 Turn ON Google Cloud Messaging for Android
COPYRIGHT IBM CORPORATION 2015. ALL RIGHTS RESERVED.
LAB 3A
PAGE 3 OF 21
IBM Mobile Cloud Development Workshop
Step 7 In the API Manager menu, click Credentials
Step 8 From Add credentials click API key
Step 9 Click Server key.
Step 10 Name the key f.e. BlueList and Click Create.
Step 11 Copy the API key from the Public API access section. This is your Sender
Auth Token (GCM API Key). You'll need this later.
SECTION 2: ADD THE REQUIRED SERVICES LIBRARIES TO YOUR PROJECT
Step 1 In your Android Studio project open the gradle.build file in the Gradle
Scripts section.
Step 2 In the dependencies section add the following for the Google Play Services:
// Google Play services jar
compile 'com.google.android.gms:play-services:+'
COPYRIGHT IBM CORPORATION 2015. ALL RIGHTS RESERVED.
LAB 3A
PAGE 4 OF 21
IBM Mobile Cloud Development Workshop
Step 3 Add and the entries to support the IBM Bluemix Push Notification service:
compile 'com.ibm.mobile.services:ibmpush:1.+'
compile 'com.ibm.mobile.services:ibmcloudcode:1.+'
Step 4 On the Android Studio menu click Build → Rebuild Project to add the required libraries to your project.
Step 5 Add a reference to the google-play-services version at your application's
AndroidManifest.xml as the first child of the <application> element.
<meta-data
android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version" />
SECTION 3: ADD THE GOOGLE API PROJECT NUMBER AND THE GCM API KEY INTO
YOUR APPLICATION IN BLUEMIX
Step 1 Log in to Bluemix.
Step 2 Click your Application in the Bluemix Dashboard.
Step 3 Click the Push service.
Step 4 Under the Configuration tab of the Push service, click EDIT under Google
Cloud Messaging.
Step 5 Fill in the GCM API Key and the Google API Project Number you got earlier
from Google, and click SAVE. (You can fill both, Sandbox and Production
configuration).
COPYRIGHT IBM CORPORATION 2015. ALL RIGHTS RESERVED.
LAB 3A
PAGE 5 OF 21
IBM Mobile Cloud Development Workshop
SECTION 4: MODIFY THE SERVER-SIDE NODE.JS CODE DEPLOYED IN LAB 1
In Lab 1 we have already created a node.js application that provides Create, Read,
Update, and Delete operations for our web application. An explanation of this can be
found in SECTION 3 of Lab 1.
We now expand this code to also provide IBM Bluemix Push notifications. In contrast
to our Android mobile app we use the Node.js JavaScript version of the IBM Bluemix
APIs. With this we can also use the notifyOtherDevices method from the iOS
version of the app that will be created in another lab series.
Step 1 Open package.json in
<Workshop folder>/bluelist/bluelist-web
Step 2 In the “dependencies”: section add ibmpush.
"ibmpush": "latest",
Step 3 Open app.js in
<Workshop folder>/bluelist/bluelist-web
Step 4 Add the module dependency for ibmpush.
ibmpush = require('ibmpush');
COPYRIGHT IBM CORPORATION 2015. ALL RIGHTS RESERVED.
LAB 3A
PAGE 6 OF 21
IBM Mobile Cloud Development Workshop
Step 5 Initialize the ibmpush service after the ibmdata service
req.ibmpush = ibmpush.initializeService(req);
Step 6 Implement the POST request for the notification of other devices.
Insert the code after the appContext.delete(..) function.
// create resource URIs
// endpoint: https://mobile.ng.bluemix.net/${appHostName}/v1/apps/${applicationId}/notifyOtherDevices/
appContext.post('/notifyOtherDevices', function(req,res) {
var results = 'Sent notification to all registered devices successfully.';
console.log("Trying to send push notification via JavaScript Push SDK");
var message = { "alert" : "The BlueList has been updated.",
"url": "http://www.google.com"
};
req.ibmpush.sendBroadcastNotification(message,null).then(f u n c t i o n (response) {
console.log("Notification sent successfully to all devices.", response);
res.send("Sent notification to all registered devices.");
}, function(err) {
console.log("Failed to send notification to all devices.");
console.log(err);
res.send(400, {reason: "An error occurred while sending the Push
notification.", error: err});
});
});
Step 7 Save and close all files you have changed.
COPYRIGHT IBM CORPORATION 2015. ALL RIGHTS RESERVED.
LAB 3A
PAGE 7 OF 21
IBM Mobile Cloud Development Workshop
Step 8 Deploy your app to Bluemix.
See Lab 1, Section 2, Step 5
Step 9 The app should still serve the web client from Lab 1.
COPYRIGHT IBM CORPORATION 2015. ALL RIGHTS RESERVED.
LAB 3A
PAGE 8 OF 21
IBM Mobile Cloud Development Workshop
SECTION 5: MAKE SOME CLIENT-SIDE CODE CHANGES TO INTERACT WITH THE PUSH AND
THE NODE.JS SERVICE YOU JUST SET UP
Step 1 In Android Studio in your cradle.build file you should adjust the values for
compileSdkVersion and buildToolsVersion to what you have installed in your
SDK. On the menu click Tools → Android → SDK Manager
Step 2 In Android Studio in your bluelist-android application, open AndroidManifest.xml.
Step 3 Update the permissions and activity sections as shown below. Add the new
GCM Intent Service and intent-filters for RECEIVE and REGISTRATION after the last activity section. Lines to be added in blue.
<!-- Push Permission -->
<permission
android:name="com.ibm.bluelist.permission.C2D_MESSAGE"
android:protectionLevel="signature" />
<!-- Permissions -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.USE_CREDENTIALS" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<!-- Push Permissions -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="com.ibm.bluelist.permission.C2D_MESSAGE" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<activity
android:name="com.ibm.bluelist.MainActivity"
android:label="@string/app_name"
android:configChanges="keyboardHidden|orientation">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<!-- Push Settings Start -->
<!-- Notification Intent -->
<intent-filter>
<action android:name="com.ibm.bluelist.BlueList.IBMPushNotification" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<!-- Push Settings End -->
</activity>
COPYRIGHT IBM CORPORATION 2015. ALL RIGHTS RESERVED.
LAB 3A
PAGE 9 OF 21
IBM Mobile Cloud Development Workshop
<activity
android:name="com.ibm.bluelist.EditActivity"
android:label="@string/title_activity_edit"
android:configChanges="keyboardHidden|orientation">
</activity>
<!-- Push Settings Start -->
<!-- Add GCM Intent Service and intent-filters for RECEIVE and REGISTRATION of
notifications -->
<activity android:name="com.ibm.mobile.services.push.IBMUIActivity" />
<service android:name="com.ibm.mobile.services.push.IBMPushIntentService" />
<receiver android:name="com.ibm.mobile.services.push.IBMPushBroadcastReceiver"
android:permission="com.google.android.c2dm.permission.SEND">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<category android:name="com.ibm.mbaas.push.sdk.client.android.sample" />
</intent-filter>
<intent-filter>
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<category android:name="com.ibm.mbaas.push.sdk.client.android.sample" />
</intent-filter>
</receiver>
<!-- Push Settings End -->
COPYRIGHT IBM CORPORATION 2015. ALL RIGHTS RESERVED.
LAB 3A
PAGE 10 OF 21
IBM Mobile Cloud Development Workshop
Step 4 Open BlueListApplication.java
Step 5 Create an IBMPush service and Activity variable for later use. Create
Strings for the deviceAlias and consumerID. Additionally, create variables
for the IBMPush service, IBMPushNotificationListener, and the Activity.
public final class BlueListApplication extends Application {
public static final int EDIT_ACTIVITY_RC = 1;
public static IBMPush push = null;
private Activity mActivity;
private static final String deviceAlias = "TargetDevice";
private static final String consumerID = "MBaaSListApp";
private static final String CLASS_NAME = BlueListApplication.class.getSimpleName();
private static final String APP_ID = "applicationID";
private static final String APP_SECRET = "applicationSecret";
private static final String APP_ROUTE = "applicationRoute";
private static final String PROPS_FILE = "bluelist.properties";
private IBMPushNotificationListener notificationListener = null;
List<Item> itemList;
Resolve the import for IBMPush and IBMPushNotificationListener with
alt+Enter
COPYRIGHT IBM CORPORATION 2015. ALL RIGHTS RESERVED.
LAB 3A
PAGE 11 OF 21
IBM Mobile Cloud Development Workshop
Step 6 Track the activity status within four of the ActivityLifecycleCallbacks.
public BlueListApplication() {
registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
@Override
public void onActivityCreated(Activity activity,Bundle savedInstanceState) {
Log.d(CLASS_NAME, "Activity created: " + activity.getLocalClassName());
//Track activity
mActivity = activity;
}
@Override
public void onActivityStarted(Activity activity) {
Log.d(CLASS_NAME, "Activity started: " + activity.getLocalClassName());
//Track activity
mActivity = activity;
}
@Override
public void onActivityResumed(Activity activity) {
Log.d(CLASS_NAME, "Activity resumed: " + activity.getLocalClassName());
//Track activity
mActivity = activity;
}
@Override
public void onActivitySaveInstanceState(Activity activity,Bundle outState) {
Log.d(CLASS_NAME, "Activity saved instance state: "
+ activity.getLocalClassName());
}
@Override
public void onActivityPaused(Activity activity) {
Log.d(CLASS_NAME, "Activity paused: " + activity.getLocalClassName());
//Track activity
if (activity != null && activity.equals(mActivity))
mActivity = null;
}
@Override
public void onActivityStopped(Activity activity) {
Log.d(CLASS_NAME, "Activity stopped: " + activity.getLocalClassName());
}
@Override
public void onActivityDestroyed(Activity activity) {
Log.d(CLASS_NAME, "Activity destroyed: " + activity.getLocalClassName());
}
});
}
COPYRIGHT IBM CORPORATION 2015. ALL RIGHTS RESERVED.
LAB 3A
PAGE 12 OF 21
IBM Mobile Cloud Development Workshop
Step 7 When the application is created, initialize the Push service, register the device with the service and define the IBMPushResponseListener. You are
adding the existing service initialization calls here. Your updated onCreate
method should look like this.
@Override
public void onCreate() {
super.onCreate();
itemList = new ArrayList<Item>();
//Read from properties file
Properties props = new java.util.Properties();
Context context = getApplicationContext();
try {
AssetManager assetManager = context.getAssets();
props.load(assetManager.open(PROPS_FILE));
Log.i(CLASS_NAME, "Found configuration file: " + PROPS_FILE);
} catch (FileNotFoundException e) {
Log.e(CLASS_NAME, "The bluelist.properties file was not found.", e);
} catch (IOException e) {
Log.e(CLASS_NAME, "The bluelist.properties file could not be read properly.",
e);
}
Log.i(CLASS_NAME, "Application ID is: " + props.getProperty(APP_ID));
// initialize the IBM core backend-as-a-service
IBMBluemix.initialize(this, props.getProperty(APP_ID), props.getProperty(APP_SE CRET),
props.getProperty(APP_ROUTE));
// initialize the IBM Data Service
IBMData.initializeService();
// register Item Specialization here
Item.registerSpecialization(Item.class);
// initialize IBM Push service
IBMPush.initializeService();
// retrieve instance of the IBM Push service
push = IBMPush.getService();
// register the device with the IBM Push service
push.register(deviceAlias, consumerID).continueWith(new Continuation<String, Void>()
{
@Override
public Void then(Task<String> task) throws Exception {
if (task.isFaulted()) {
Log.e(CLASS_NAME, "Exception : " + task.getError().getMessage());
return null;
}
Log.d(CLASS_NAME, "Device Successfully Registered");
return null;
}
});
}
Note: When the Organize Imports does not resolve an error on push.register(....) then you have to import the following manually:
import bolts.Continuation;
import bolts.Task;
COPYRIGHT IBM CORPORATION 2015. ALL RIGHTS RESERVED.
LAB 3A
PAGE 13 OF 21
IBM Mobile Cloud Development Workshop
Step 8 When an activity is created, define the IBMPushNotificationListener. Your
new onActivityCreated method should look like this:
public void onActivityCreated(Activity activity,Bundle savedInstanceState) {
Log.d(CLASS_NAME, "Activity created: " + activity.getLocalClassName());
mActivity = activity;
//Define IBMPushNotificationListener behavior on push notifications
notificationListener = new IBMPushNotificationListener() {
@Override
public void onReceive(final IBMSimplePushNotification message) {
mActivity.runOnUiThread(new Runnable(){
@Override
public void run() {
Class<? extends Activity> actClass = mActivity.getClass();
if (actClass == MainActivity.class) {
((MainActivity)mActivity).listItems();
Log.e(CLASS_NAME, "Notification message received: " + message.toString());
//present the message when sent from Push notification console.
if(!message.getAlert().contains("ItemList was updated")){
mActivity.runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(mActivity, "ItemList was updated", Toast.LENGTH_LONG).show();
}
});
}
}
}
});
}
};
}
COPYRIGHT IBM CORPORATION 2015. ALL RIGHTS RESERVED.
LAB 3A
PAGE 14 OF 21
IBM Mobile Cloud Development Workshop
Step 9 Check for push when the activity is resumed or paused. Your new
onActivityResumed methodand onActivityPaused method should look
like this:
public void onActivityResumed(Activity activity) {
Log.d(CLASS_NAME, "Activity resumed: " + activity.getLocalClassName());
//Track activity
mActivity = activity;
if (push != null) {
push.listen(notificationListener);
}
}
public void onActivityPaused(Activity activity) {
if (push != null) {
push.hold();
}
Log.d(CLASS_NAME, "Activity paused: " + activity.getLocalClassName());
if (activity != null && activity.equals(mActivity))
mActivity = null;
}
COPYRIGHT IBM CORPORATION 2015. ALL RIGHTS RESERVED.
LAB 3A
PAGE 15 OF 21
IBM Mobile Cloud Development Workshop
Step 10 In MainActivity.java, add a call to updateOtherDevices on edit, create, and
delete of an item. Add the new updateOtherDevices method, which will
make a call to the IBM Cloud Code hosted Node.js application (app.js) that
you previously uploaded to your application.
/*
* Send a notification to all devices whenever the BlueList is modified (create, update, or delete)
*/
private void updateOtherDevices() {
// initialize and retrieve an instance of the IBM CloudCode service
IBMCloudCode.initializeService();
IBMCloudCode myCloudCodeService = IBMCloudCode.getService();
JSONObject jsonObj = new JSONObject();
try {
jsonObj.put("key1", "value1");
} catch (JSONException e) {
e.printStackTrace();
}
// Call the node.js application hosted in the IBM Cloud Code service
// with a POST call, passing in a non-essential JSONObject
// The URI is relative to, appended to, the BlueMix context root
myCloudCodeService.post("notifyOtherDevices",
jsonObj).continueWith(new Continuation<IBMHttpResponse, Void>() {
@Override
public Void then(Task<IBMHttpResponse> task) throws Exception {
if (task.isFaulted()) {
Log.e(CLASS_NAME, "Exception : " + task.getError().getMessage());
return null;
}
InputStream is = task.getResult().getInputStream();
try {
BufferedReader in = new BufferedReader(new InputStreamReader(is));
String responseString = "";
String myString = "";
while ((myString = in.readLine()) != null)
responseString += myString;
in.close();
Log.i(CLASS_NAME, "Response Body: " + responseString);
} catch (IOException e) {
e.printStackTrace();
}
Log.i(CLASS_NAME, "Response Status from notifyOtherDevices: " +
task.getResult().getHttpResponseCode());
return null;
}
});
}
Resume all unresolved messages with alt+Enter.
COPYRIGHT IBM CORPORATION 2015. ALL RIGHTS RESERVED.
LAB 3A
PAGE 16 OF 21
IBM Mobile Cloud Development Workshop
public void onActivityResult(int requestCode, int resultCode, Intent data) {
. . .
/*if an edit has been made, notify that the data set has changed.*/
case BlueListApplication.EDIT_ACTIVITY_RC:
// Call updateOtherDevices to invoke Cloud functions
updateOtherDevices();
sortItems(itemList);
lvArrayAdapter.notifyDataSetChanged();
break;
}
public void createItem(View v) {
. . . → in the else { ...
// If the result succeeds, load the list
if (!isFinishing()) {
listItems();
// Call updateOtherDevices to invoke Cloud functions
updateOtherDevices();
}
. . .
}
public void deleteItem(Item item) {
. . . → in the else { ...
// If the result succeeds, reload the list
if (!isFinishing()) {
runOnUiThread(new Runnable() {
public void run() {
// Call updateOtherDevices to invoke Cloud functions
updateOtherDevices();
lvArrayAdapter.notifyDataSetChanged();
}
});
}
. . .
}
COPYRIGHT IBM CORPORATION 2015. ALL RIGHTS RESERVED.
LAB 3A
PAGE 17 OF 21
IBM Mobile Cloud Development Workshop
Step 11 Run the App
a) On an emulator make sure you have one with Google APIs installed.
b) Click the Run
click OK.
button and select the appropriate device or emulator and
COPYRIGHT IBM CORPORATION 2015. ALL RIGHTS RESERVED.
LAB 3A
PAGE 18 OF 21
IBM Mobile Cloud Development Workshop
Step 12 When the app is started you see the list of items entered in the previous
labs.
Step 13 Add, delete or change (long press on item) some items.
A push notification will be sent and an updated list is displayed.
COPYRIGHT IBM CORPORATION 2015. ALL RIGHTS RESERVED.
LAB 3A
PAGE 19 OF 21
IBM Mobile Cloud Development Workshop
SECTION 6: TEST SENDING NOTIFICATIONS FROM BLUEMIX
Step 1 Log in to Bluemix, if not already done so.
Step 2 From the Dashboard view, click you application.
Step 3 Click the Push service icon.
Step 4 Click the Notification tab.
Step 5 Enter a message and click NEXT
Step 6 Select All registered mobile devices and click SEND.
COPYRIGHT IBM CORPORATION 2015. ALL RIGHTS RESERVED.
LAB 3A
PAGE 20 OF 21
IBM Mobile Cloud Development Workshop
Step 7 Watch as your mobile device receives a push notification. Either inside the
app or outside in the notification area.
Conclusion
Extending your app using the Push and Node.js server-side services available in
IBM Bluemix should give you a sense of how easy it is to consume and integrate mobile data capabilities using mobile cloud services. So far in this series, you've used
the MobileData service to store, delete, update, and query a list of objects stored on
the cloud. You've also used the Push and Node.js server-side services to refresh the
list on all devices and send notifications when one of the devices updates the list in
some way.
COPYRIGHT IBM CORPORATION 2015. ALL RIGHTS RESERVED.
LAB 3A
PAGE 21 OF 21
Fly UP