Android chat in the cloud
-
Upload
firenze-gtug -
Category
Technology
-
view
13.613 -
download
0
description
Transcript of Android chat in the cloud
Alfredo MorresiDeveloper Relations @ Google
Android chat in the cloudRESTful APIs, authentication, push notifications and some additional goodies
ROLE
Developer Relations Program Manager
COUNTRY
Italy
PASSIONS
Community, Development, Snowboarding, Tiramisu'
REACH ME
[email protected]/+AlfredoMorresi@rainbowbreeze
Alfredo Morresi
Who I am
Download from https://play.google.com/store/apps/details?id=org.alexismp.cloud.backend
Let’s start with the chat demo app
In less than 40 minutes?
Forget about the backend!
Use Google Cloud Platform + Mobile Backend Starter
Optional server-side coding: Control your cloud service using Android and iOS client libraries.
Cloud Datastore: Store millions of objects in the cloud and manage them from your app.
Push Notifications: Send and broadcast objects as messages via Apple Push Notifications and Google Cloud Messaging.
Event Driven Programming: Create real-time interactive user experiences using Continuous Queries.
User authentication: Authenticate users using Google Accounts and control access on private data.
Built to scale: Mobile backend runs on App Engine infrastructure to scale to millions of users within hours.
https://developers.google.com/cloud/samples/mbs
Create your backend
Create your backend
Create your backend
Create your backend
http://goo.gl/0FLRPp
Download Android app source code
Change● PROJECT_ID● PROJECT_NUMBER● WEB_CLIENT_ID
Set some values in the source and you’ve done!
Step 1Accessing to the APIs
Google Cloud Endpoints: generate APIs from annotations
https://developers.google.com/appengine/docs/java/endpoints/
Explore the APIs:http://<YOUR_PROJECT_ID>.appspot.com/_ah/api/explorer
Explore the backend APIs
Set Open authentication in the backend
Set the Consts.IS_AUTH_ENABLED to false
Set the Consts.PROJECT_ID to
Access to RESTful APIs, no authentication
It was easy!
Google Cloud Endpoints automatically generates the Android code required to access the backend APIs
Mobilebackend.Builder builder = new Mobilebackend.Builder( AndroidHttp.newCompatibleTransport(), new GsonFactory(), null);
Mobilebackend backend = builder.setRootUrl(Consts.ENDPOINT_ROOT_URL).build();
Access to RESTful APIs, no authentication
Insert a new CloudEntity in the backend
CloudEntity post = new CloudEntity("Guestbook");post.put("message", "Your message here...");
EntityDto resultEntityDto = backend.endpointV1() .insert(post.getKindName(), post.getEntityDto()).execute();
CloudEntity resultCo = CloudEntity.createCloudEntityFromEntityDto(resultEntityDto);
Log.i(Consts.TAG, "insert: inserted: " + resultCo);
Access to RESTful APIs, no authentication
Step 2Accessing to the APIs with authentication
Restrict the API access only to your application(s).
ANDROID Client_ID: identifies your app in unique way (package name + SHA1 of signing key of the app)
WEB Client_ID: establishes that the client and the server are from the same developer so the standard OAuth2 prompt is avoided (no 3rd party app). It’s a shared token.
https://developers.google.com/appengine/docs/java/endpoints/auth
Authenticated access to the APIs
Generate Android Client ID
Generate Android Client ID
Generate Web Client ID
Generate Web Client ID
Set Android and Web Client IDs in the backend
Set the Consts.IS_AUTH_ENABLED to true
Set the Consts.WEB_CLIENT_ID to Web Client ID
Authenticated access to the APIs
GoogleAccountCredential credential = GoogleAccountCredential.usingAudience( getActivity(), Consts.AUTH_AUDIENCE);
if (credential.getSelectedAccountName() == null) { startActivityForResult( credential.newChooseAccountIntent(), REQUEST_ACCOUNT_PICKER);
String accountName = data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME);credential.setSelectedAccountName(accountName);
https://developers.google.com/appengine/docs/java/endpoints/consume_android#Java_Making_authenticated_calls
The Android client provides credentials!
Inject the credential in the backend manager class
// check if credential has account namefinal GoogleAccountCredential gac = credential == null || credential.getSelectedAccountName() == null ? null : mCredential;
// create HttpRequestInitializerHttpRequestInitializer httpRequestInitializer = new HttpRequestInitializer() { @Override public void initialize(HttpRequest request) throws IOException { if (gac != null) { gac.initialize(request); } }};
Authenticated access to the APIs
Mobilebackend.Builder builder = new Mobilebackend.Builder( AndroidHttp.newCompatibleTransport(), new GsonFactory(), httpRequestInitializer);
Mobilebackend backend = builder.setRootUrl(Consts.ENDPOINT_ROOT_URL).build();
… Now the API backend framework automatically authenticates the user and enforces the authorized clientIds whitelist, ultimately by supplying a valid User to the API parameters.
Authenticated access to the APIs
Step 3Add push notifications
Google Cloud Messaging for Android
http://developer.android.com/google/gcm/index.html
Enable GCM in the project
Generate a Server API Key
Generate a Server API Key
Enable GCM in the backend
Set the Consts.PROJECT_NUMBER to
Enable GCM in the client
http://developer.android.com/google/gcm/client.html
Register your app and store registration ID
String regId = getRegIdFromPref();if (registrationId.isEmpty()) { regid = GoogleCloudMessaging.getInstance(context) .register(PROJECT_ID); storeRegIdToPref(regId);}
A look into GCM client code
@Overridepublic void onReceive(Context context, Intent intent) { // Explicitly specify that GcmIntentService will handle the intent ComponentName comp = new ComponentName( context.getPackageName(), GCMIntentService.class.getName()); // Start service, keeping the device awake while it is launching startWakefulService(context, (intent.setComponent(comp))); setResultCode(Activity.RESULT_OK);}
Create a BroadcastReceiver to receive push messages
protected void onHandleIntent(Intent intent) { Bundle extras = intent.getExtras(); GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(this); String msgType = gcm.getMessageType(intent);
if (extras.isEmpty()) { // has effect of unparcelling Bundle … } if (GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE.equals(messageType)) { … } // Release the wake lock provided by the WakefulBroadcastReceiver. GCMBroadcastReceiver.completeWakefulIntent(intent);}
Handle the message with a Service
And remember to...
App registration is a network operation
Bonus StepApp internal architecture
EntityDto resultEntityDto = backend.endpointV1() .insert(post.getKindName(), post.getEntityDto()).execute();
Because API calls are slow...
Never forget!
// create a response handler that will receive the result or an errorCloudCallbackHandler<List<CloudEntity>> handler = new CloudCallbackHandler<List<CloudEntity>>() { @Override public void onComplete(List<CloudEntity> results) { ... }
@Override public void onError(IOException exception) { ... }
CloudBackendASync extends CloudBackend
// execute the query with the handlermProcessingFragment.getCloudBackend().listByKind( "Guestbook", CloudEntity.PROP_CREATED_AT, Order.DESC, 50, Scope.FUTURE_AND_PAST, handler);
CloudBackendASync extends CloudBackend
Why these two classes?
Separate the logic (CloudBackend) from the sync management (CloudBackendAsync) makes the code more testable!
// Check to see if we have retained the fragment which handles asynchronous backend callsmProcessingFragment = (CloudBackendFragment) mFragmentManager. findFragmentByTag(PROCESSING_FRAGMENT_TAG);// If not retained (or first time running), create a new oneif (mProcessingFragment == null) { mProcessingFragment = new CloudBackendFragment(); mProcessingFragment.setRetainInstance(true); fragmentTransaction.add(mProcessingFragment, PROCESSING_FRAGMENT_TAG);}…// execute the insertion with the handlermProcessingFragment.getCloudBackend().insert(newPost, handler);mMessageTxt.setEnabled(false);mSendBtn.setEnabled(false);
Activity lifecycle (you can do better!)
CloudEntity post = new CloudEntity("Guestbook");post.put("message", "Your message here...");post.put("alf_property", "Custom property value here...");
EntityDto resultEntityDto = backend.endpointV1() .insert(post.getKindName(), post.getEntityDto()).execute();
CloudEntity resultCo = CloudEntity.createCloudEntityFromEntityDto(resultEntityDto);
Extends the data
https://developersitalia.blogspot.com
Curious about Google dev initiatives and event in Italy?
Thank you!http://developers.google.com
Alfredo Morresiplus.google.com/+AlfredoMorresi@rainbowbreeze