This open source Java library allows you to integrate ACS into your Android application. Except as otherwise noted, the ACS Android SDK is licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0.html) **Note**: The ACS iOS SDK is no longer being developed or maintained. Please consider using the [Appcelerator Platform Services SDK for iOS](http://docs.appcelerator.com/cloud/latest/#!/guide/ios) instead (Platform subscription required).LICENSE ------ This project is open source and provided under the Apache Public License (version 2). Please make sure you see the LICENSE file included in this distribution for more details on the license. (C) Copyright 2012-2014, Appcelerator Inc. All Rights Reserved.Getting Started: Using the Android SDK
The ACS Android SDK allows you to integrate Appcelerator Cloud Services into your Android application.
Setting up your environment
The ACS Android SDK works in any Android development environment. The following steps assume you are using Eclipse.
The first step is to clone the ACS Android SDK from GitHub.
Clone the ACS Android SDK:
git clone git@github.com:appcelerator/acs-android-sdk.gitNext, you'll create a new project in Eclipse for the ACS SDK.
Create a new project for the ACS SDK:
- In Eclipse, select File > New > Project.
- Select Android Project from Existing Code from the Android category, and click Next.
- Select the acs-android-sdk/acs directory. You should see the project properties populated.
- Click Finish.
- Open the Properties dialog for the project and select the Android category.
- In the Library section, enable the Is Library option. {@img is_library.png}
- Click OK
Now you can add the ACS project as a library of an existing project.
Add the SDK to an existing project
Once you've created the Android project for the SDK in your workspace, you can include the SDK as a library of an existing project.
To add the ACS Android SDK to an existing project:
- In the same workspace that contains the ACS Android SDK library project, open the Properties dialog for the project.
- Select the Android category.
- In the Library section, click Add.
- In the Project Selection dialog, select the ACS Android SDK library project. {@img add-library-dialog.png}
- Click OK.
You're now ready to use the SDK in your application.
Initialization and authorization
You use the `com.appcelerator.cloud.sdk.ACSClient` class to make API calls. First, you must import the ACSClient library into your application:
import com.appcelerator.cloud.sdk.ACSClient;You need to authorize your application with Appcelerator Cloud Services using either an application key, or your OAuth consumer key/secret.
ACSClient sdk = new ACSClient("<app key>");ACSClient sdk = new ACSClient("<OAuth consumer key>", "<OAuth secret>");The ACS Android SDK also provides ability to store user session data in the device's local storage. This allows the application to restore a session after it is has been closed and then restarted. To enable this feature, pass an instance of the application's
android.content.Context
to theACSClient
constructor method as an additional parameter. You use thegetApplicationContext()
to get the application context.If you are using an OAuth consumer key and secret:
ACSClient sdk = new ACSClient("<OAuth consumer key>", "<OAuth secret>", "<app. context>");Or if you are using an application key to authorize:
ACSClient sdk = new ACSClient("<app key>", "<app. context>");Session Management
As mentioned previously, when you create an ACSClient instance, lets you optionally store your application's session status in the device's local storage. The client also holds an instance of
com.appcelerator.cloud.sdk.CCUser
that contains the currently logged in user's information. TheCCUser
class has the following definition:public class CCUser { public String getObjectId(); //id public Date getCreatedDate(); //created date public Date getUpdatedDate(); //updated date public String getFirst(); //first name public String getLast(); //last name public String getEmail(); //email public String getUserName(); //user name }You get an instance of this class by calling the
getCurrentUser()
method of the ACSClient class. If there is no current session or "logout" is called, the return value will be null.Call the
getCurrentUser()
method of theACSclient
class; if there is no active session, orlogoutUser()
was called, the return value will benull
.Making API calls
The SDK provides thesendRequest()
method to make synchronized REST calls to the ACS server easier. It has the following signature:public CCResponse sendRequest(String url, CCRequestMethod method, Map<String, Object> data, boolean useSecure) throws ACSClientErrorParameters
url
The request API URL, which is a shortened version of the full REST URL. For instance, with the REST API you use http://api.cloud.appcelerator.com/v1/users/create.json to create a new user. In this case, you would use the value users/create.json for the
url
parameter.method
Specifies the REST-ful method to use when making the method call. Accepts one of the following four objects from class
com.appcelerator.cloud.sdk.CCRequestMethod
as its value:
- CCRequestMethod.GET
- CCRequestMethod.POST
- CCRequestMethod.PUT
- CCRequestMethod.DELETE
data
An instance of
Map<String, Object>
which contains the parameters to pass. The key is the name of the passing parameter, and the value is the value of the passing parameter. For example, using the user login API:Map<String, Object> data = new HashMap<String, Object>(); data.put("login", "test@appcelerator.com"); data.put("password", "test");useSecure
Indicates whether the client should use SSL for HTTP communication. Set to true to use SSL, or false to a non-SSL connection.
Handling server responses
Server response are contained in an instance of
com.appcelerator.cloud.sdk.CCResponse
returned by thesendRequest()
method. The CCResponse class has the following definition:public class CCResponse { public CCMeta getMeta(); public JSONObject getResponseData(); }The
getMeta()
method returns an instance ofcom.appcelerator.cloud.sdk.CCMeta
which contains all metadata returned by server. Here is the CCMeta's class definition:public class CCMeta { public String getStatus(); public int getCode(); public String getMessage(); public String getMethod(); }The
getResponseData()
method returns an instance of classorg.json.JSONObject
which contains all of the response data returned by server. The ACS Android SDK uses the standardJSONObject
class to wrap the returned JSON data.Example of accessing a response object
The code below demonstrates how to handle an array users returned by the `users/search.json` method :CCResponse response = sdk.sendRequest("users/search.json", CCRequestMethod.GET, null, false); JSONObject responseJSON = response.getResponseData(); JSONArray users = responseJSON.getJSONArray("users"); for (int i=0;i<users.length();i++) { JSONObject user = usersArr.getJSONObject(i); System.out.println("User: " + user); }Push Notifications
ACS supports Google Cloud Messaging (GCM) for sending notifications to Android clients. This section describes how to integrate GCM notifications into your Android application with ACS.Obtaining a Google API key and GCM sender ID
To use GCM in your Android application, you need to create a Google API project, enable its GCM service, and obtain the API project's Google API key and GCM sender ID. For steps on obtaining these items see Setting up Google Cloud Messaging.Setup the Android Project
Next you need to add the ACS `PushService` service to your Android project's manifest file.
- Open your project's AndroidManifest.xml file.
- Add following to the
<application>
section:<service android:name="com.appcelerator.cloud.push.PushService" />- Add following to the
<manifest>
section:<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <uses-permission android:name="android.permission.READ_PHONE_STATE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.VIBRATE" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />- Save your changes to AndroidManifest.xml.
Device Token
A device token is a unique identifier for an Android device. The push notification server can locate and push the desired notifications to the right device. You request a device token from the Appcelerator Cloud Services push notification server by calling one of following methods from the
com.appcelerator.cloud.push.CCPushService
class:public static String getDeviceToken(final Context androidContext, final String appKey); public static void getDeviceTokenAsnyc(final Context androidContext, final String appKey, final DeviceTokenCallback callback);As their method names suggest, the difference between these methods is that
getDeviceToken()
operates synchronously, where thegetDeviceTokenAsnyc()
is asynchronous.
- androidContext -- The instance of
android.context.Context
from your app- appKey -- The app's key of your Appcelerator Cloud Services app
- callback -- An instance of
com.appcelerator.cloud.push.DeviceTokenCallback
for which whenever a device token is available, itsreceivedDeviceToken
will be called.Once you get the device token, you may proceed to subscribe the device by using the {@link PushNotifications#subscribe} API. This starts the push notification service and gets the Android device ready to receive push notifications.
Note: once device token is successfully acquired, it will be stored on the device's local storage, and next time when getting device token, it will return from reading local storage instead of communicating with server. So it is safe to request device token multiple times if necessary.
Push Notification Service
The push notification service is a standard Android service that keeps a persistent connection to the push notification server. Once the service is started, the device is ready to receive push notifications. The service continues running as a background process even if app is not actively running. The class
com.appcelerator.cloud.push.CCPushService
is a utility for starting and stopping the push notification service.To start or stop the push notification service:
/* Start push notification service */ CCPushService.getInstance().startService(context); /* Stop push notification service */ CCPushService.getInstance().stopService(context);The
context
is the instance ofandroid.content.Context
which belongs to your Android app.Please be noted that you need to get device token before starting the push notification service on your device, otherwise, there will be an exception thrown when trying to start push notification service without having a valid device token.
Receiving push notifications
Once your application has acquired the device token, and started the push notification service, the device is ready to receive push notifications. When a push notification arrives, there will be an application-wide broadcast containing the notification payload.
To process a push notification, your application must implement an Android receiver to receive the payload, and register the receiver in your project's AndroidManifest.xml file.
Below is an example of a receiver. The payload is a string that's passed to your receiver as an extra data field in the
Intent
parameter.import com.appcelerator.cloud.push.PushService; public class CustomReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { if(intent == null || context == null) return; if (intent.getAction().equals(PushService.ACTION_MSG_ARRIVAL)) { String payloadString = intent.getStringExtra("payload"); // Covert payload from String to JSONObject JSONObject payload = null; try { payload = new JSONObject(payloadString); } catch (JSONException ex) { //error } ... } } }You must also register the receiver in the
<application>
section of your project's AndroidManifest.xml:<receiver android:name="com.your.app.CustomReceiver" > <intent-filter> <action android:name="com.appcelerator.cloud.push.PushService.MSG_ARRIVAL" /> <category android:name="android.intent.category.HOME" /> </intent-filter> </receiver>Using the default broadcast receiver
The ACS Android SDK includes a fully-featured notification receiver that you can use in your project, instead of creating your own from scratch. The default notification receiver can take one of the following actions when a notififcation arrives:
- Show a custom alert
- Display custom title
- Display custom icon
- Display custom badge
- Play a custom sound
- Vibrate the device
Your application can invoke any of these actions simply by setting specifically named fields in the notification's JSON payload. First, you must register the default notification recevier in the
<application>
section of your project's AndroidManifest.xml file, as shown below.<receiver android:name="com.appcelerator.cloud.push.PushBroadcastReceiver" > <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED" /> <action android:name="android.intent.action.USER_PRESENT" /> <action android:name="com.appcelerator.cloud.push.PushService.MSG_ARRIVAL" /> <category android:name="android.intent.category.HOME" /> </intent-filter> <meta-data android:name="com.appcelerator.cloud.push.BroadcastReceiver.ArrivalActivity" android:value="com.yourorganization.pushnotifications.ArrivalActivity" /> </receiver>When the device receives a push notification and has been processed by the default receiver, the ACSClient needs an
Activity
from your application to hand processing control to. The<meta-data/>
element registers your customActivity
. The name attribute of the<meta-data/>
section must be com.appcelerator.cloud.push.BroadcastReceiver.ArrivalActivity for the receiver to locate your activity, and its value attribute must point to your customActivity
.The complete payload is passed to your
Activity
so that your application still further process the payload data, as necessary. Below is an example of an custom activity getting access to the notification payload:public class ArrivalActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.arrival); Intent intent = getIntent(); String payload = intent.getExtras().getString("payload"); ... } }To invoke the desired behavior of the default receiver, the JSON notification payload must use certain reserved keywords, defined in the following table.
Key Value type Comments alert
String Content of the notification item to be displayed in notification center. title
String Title of the notification item to be displayed in notification center. icon
String The icon's file name without extension. This icon will be used to show in notification bar and be used as icon of notification item in the notification center. The file must be located in your project's res/drawable
directory. If an icon file is not specified, or the specified file cannot be located, then app's default icon is used instead.badge
Number The number to display as the badge of the application icon. sound
String The sound's file name. The file should be located under app's assets/sound
directory. If the sound file is not reachable, no sound will be played.vibrate
Boolean If the value is true, then the device will vibrate for 1 second. Below an example JSON payload including all the reserved keywords with custom content:
{ "title": "Example", "alert": "Sample alert", "icon": "little_star", "badge": 3, "sound": "door_bell.wav", "vibrate": true, "score": 51, "custom_field": { "headlines": "Appcelerator Cloud Services Rocks!" } }It's recommended to only have one push notification receiver registered at a time. Registering multiple receivers at the same time may cause conflicts.
Extending the default ACS receiver
You can extend the default notification's receiver implementation with your own functionality. To do this, you create your own broadcast receiver, as explained in the "Receiving push notifications" section above. In your custom receiver's
onReceive()
handler, extract the JSON payload and pass it to the ACSClient'sshowNotification()
method to invoke the default receiver's behavior (for example, playing an audio file or displaying a message).There are two versions of the
showNotification()
method. One takes two parameters: the Android application context and the JSON payload. The second version takes these two parameters and a notification ID (an integer) that lets you control how or if multiple notifications are merged into a single item in the Android notification center.protected void showNotification(Context context, JSONObject payload); protected void showNotification(Context context, JSONObject payload, int notificationId);Parameters
context
-- Theandroid.content.Context
that belongs to your app.payload
-- TheJSONObject
containing the notification payload.notificationId
-- An integer that identifies the notification. Notifications that share the same ID are merged into a single item in the Android notification center.Remember to remove the default receiver from the AndroidManifest if you register your own receiver.
Photo Uploads
To upload a photo with the Android ACS SDK you create an instance of
java.io.File
, then pass the instance as an item of thedata
to thesendRequest()
method.The File instance must be initialized with an existing file.
Here is an example of uploading a local image file to ACS server through Android SDK:
1. Create a File instance:
// Create a File instance File file = new File("/photos/profile.gif"); // Upload the image file by callingsendRequest
: ACSClient sdk = new ACSClient('vw1G7wq6KTKd52m76XwjvoiIhxeHxeXG'); Map<String, Object> data = new HashMap<String, Object>(); data.put("photo", file); sdk.sendRequest("photos/create.json", CCRequestMethod.POST, data, false);It is the client code's responsibility to make sure the instance of
File
is initialized with an existing local image file before passing to SDK, otherwise, the upload won't be succeed.Example
Below is an example of creating a user by using the ACS Android SDK with a profile photo.
First, prepare the data object to pass to the sendRequest() method.
// Prepare new user data: Map<String, Object> data = new HashMap<String, Object>() data.put("email", "test@appcelerator.com"); data.put("first_name", "test_firstname"); data.put("last_name", "test_lastname"); data.put("password", "test_password"); data.put("password_confirmation", "test_password"); // Prepare new user profile image: File file = new File("/photos/profile.gif"); data.put("photo", file);Next, create an ACSClient instance and send the request.
ACSClient sdk = new ACSClient('vw1G7wq6KTKd52m76XwjvoiIhxeHxeXG'); CCResponse response = sdk.sendRequest("users/create.json", URLRequestMethod.POST, data, false);When the
sendRequest()
method returns, process the server response. In this case, the new user's information is logged to the system console.JSONObject responseJSON = response.getResponseData(); //CCResponse response CCMeta meta = response.getMeta(); if("ok".equals(meta.getStatus()) && meta.getCode() == 200 && "createUser".equals(meta.getMethod())) { JSONArray users = responseJSON.getJSONArray("users"); JSONObject user = users.getJSONObject(0); StringBuffer sb = new StringBuffer(); sb.append("Create user successful!\n"); sb.append("id:" + user.getString("id") + "\n"); sb.append("first name:" + user.getString("first_name") + "\n"); sb.append("last name:" + user.getString("last_name") + "\n"); sb.append("email:" + user.getString("email") + "\n"); System.out.println(sb.toString()); }Run the ACS Demo sample application
Below are instructions for creating and running the Demo sample using Eclipse. The sample application uses the Google Maps v2 API to display location data. To build the application you will need to install Google Play services and add it to your project as a library. You'll also need to generate an API key for the Google Maps Android API v2 service.
Importing and setting up the Demo application:Run the application:
- In Eclipse, select File > Import....
- Select Existing Android Code into Workspace from the Android category folder and click Next.
- Click Browse... and select the acs-android-sdk/examples/Demo folder.
- Click Finish.
- Open the Properties dialog for the project and, in the Android section, add Google Play Services as a library. {@img play-services-lib.png}
- Click OK to apply your changes.
- Open examples/Demo/res/layout/main.xml.
- Locate the
<com.google.android.maps.MapView/>
section of the file update theandroid:apiKey
with your Google Maps API key, for example:android:apiKey="1234567890abcdefghijklmnop"- Open DemoApplications.java located in the
src/
folder.- Locate the
APP_ID
constant and assign to it your ACS application ID, for example:public static final String APP_ID = "7YGry9R7abckXFG3ZYPAvQtA3TVBRH4T";- In the
initialize()
method, uncomment the following line to construct the ACSClient usingAPI_ID
.sdk = new ACSClient(APP_ID, appContext);- Save your changes.
- Create an appropriate Android virtual device (AVD):
- Open the Android Virtual Device Manager.
- Click New.
- From the Target menu select Google APIs - API Level 13.
- Click OK.
- In Eclipse, create a Android run configuration that targets the AVD you created.
- Launch the run configuration to run the application in the simulator.
3-Legged OAuth process
Android SDK 2.1.1 and later supports interactions with Authorization Server. It provides APIs for Android application developers to sign in/sign up/sign out users with Authorization Server. For signing-in and signing-up the SDK uses a webview to load pages from Authorization Server.
1. Create a ACSClient object
To create a ACSClient object use one of the following constructors:
ACSClient sdk = new ACSClient(appConsumerKey); ACSClient sdk = new ACSClient(appConsumerKey, appContext); ACSClient sdk = new ACSClient(appConsumerKey, appContext, APIhost); ACSClient sdk = new ACSClient(appConsumerKey, appConsumerSecret); ACSClient sdk = new ACSClient(appConsumerKey, appConsumerSecret, appContext); ACSClient sdk = new ACSClient(appConsumerKey, appConsumerSecret, appContext, APIhost);If appConsumerSecret is not passed in the SDK will fail to sign requests. appContext is an android.content.Context object. APIhost is used to specify the ACS API server. The default is api.cloud.appcelerator.com/v1/.To use 3-Legged OAuth you need to call the following method of the sdk object after it's created.
sdk.useThreeLegged(true);Once get the sdk object you may call the following method to set the Authorization Server host other than the default.sdk.setAuthHost("<AUTH HOST OTHER THAN DEFAULT>");2. Check Session Status
The SDK doesn't take care of saving token information. Application Developers need to take care of saving token information somewhere and set it (and check its validity) to the sdk object upon application restart.
3. Sign in
Use one of the following methods to sign an user in.
sdk.authorize(Activity activity, String action, final DialogListener listener); sdk.authorize(Activity activity, String action, final DialogListener listener, boolean useSecure);activity: (android.app.Activity) The Android activity relevant.
action: (String) Should be ACSClient.ACTION_LOGIN.
useSecure: (Boolean) Specify if HTTPS should be used for sending request. If not specified default to false.
listener: (com.appcelerator.cloud.sdk.oauth2.DialogListener) The listener object is used to provide various callbacks to the signing-in process. Please refer to the Listener for more detail. The most significant callback method is onComplete(Bundle values) where you can get token information by calling the following methods and save them as you want.sdk.getAccessToken(); sdk.getAccessExpires();The following code from the demo application shows a call to this method.
sdk.authorize(UserView.this, ACSClient.ACTION_LOGIN, new LoginDialogListener(), false);4. Sign up
Use one of the following methods to sign an user up.
sdk.authorize(Activity activity, String action, final DialogListener listener); sdk.authorize(Activity activity, String action, final DialogListener listener, boolean useSecure);activity: (android.app.Activity) The Android activity relevant.
action: (String) Should be ACSClient.ACTION_SINGUP.
useSecure: (Boolean) Specify if HTTPS should be used for sending request. If not specified default to false.
listener: (com.appcelerator.cloud.sdk.oauth2.DialogListener) The listener object is used to provide various callbacks to the signing-up process. Please refer to the Listenr class for more detail. The most significant callback method is onComplete(Bundle values) where you can get token information by calling the following methods and save them as you want.sdk.getAccessToken(); sdk.getAccessExpires();The following code from the demo application shows a call to this method.
sdk.authorize(UserView.this, ACSClient.ACTION_SINGUP, new LoginDialogListener());5. Sign out
Signing-out should be done the same way as before. That is calling sdk.sendRequest to send a request to users/logout.json.
6. Login to API Server directly
To use the new authorization flow, you need to configure your app on Apps page. If an app is configured to use Authorization Server for user authentication, it's not possible to log-in/sign-up to API server directly.7. Customize webview
The webview is used to show pages loaded from Authorization Server. It's possible to customize it. The SDK has the following method to accept a com.appcelerator.cloud.sdk.oauth2.DlgCustomizer object to support customization.sdk.setDlgCustomizer(new MyDlgCustomizer());For example, the following code snippet from the demo application implements a DlgCustomizer named MyDlgCustomizer.public class MyDlgCustomizer implements DlgCustomizer { static final int FB_BLUE = 0xFF6D84B4; static final int MARGIN = 4; static final int PADDING = 2; public float[] getPortraitDimensions() { return new float[]{320, 420}; } public float[] getLandscapeDimensions() { return new float[]{460, 260}; } public TextView setUpTitle(Context context) { Drawable icon = context.getResources().getDrawable(R.drawable.application_icon); TextView title = new TextView(context); title.setText("ACS - To be customized"); title.setTextColor(Color.WHITE); title.setTypeface(Typeface.DEFAULT_BOLD); title.setBackgroundColor(FB_BLUE); title.setPadding(MARGIN + PADDING, MARGIN, MARGIN, MARGIN); title.setCompoundDrawablePadding(MARGIN + PADDING); title.setCompoundDrawablesWithIntrinsicBounds(icon, null, null, null); return title; } }Have Fun!