Lab 3A - Android Add push notifications to your Android app
by user
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