2 Android Apps

Oracle Mobile Cloud Enterprise (OMCe) provides an SDK for Android that makes it easy to use OMCe’s features.

Getting the SDK

To get the OMCe client SDK for Android, go to the Oracle Mobile Cloud Enterprise Downloads page on OTN.

Creating a Backend

You create a backend to serve as a secure gateway between your app and OMCe features, such as platform and custom APIs. For your app to access these resources, it authenticates with a backend.

  1. Click icon to open the side menu to open the side menu and select Mobile Apps > Backends.

  2. Click New Backend.

  3. Once you complete the dialog and the backend is created, keep the Settings page open.

    You’ll need to configure your app with some of this information.

Adding the SDK

Assuming a basic app setup, without intervening frameworks, here’s what you would do to add the Android client SDK to an app

  1. If you haven’t already done so, unzip the Android client SDK zip.

  2. Copy the SDK jars into the libs folder in your app's project. If this folder doesn't exist, create it at the same level in your hierarchy as your src and build folders.

  3. Import the IDMMobileSDK.jar into the project. (In Android Studio, select File > New > New Module, click Import .JAR/.AAR Package, click Next, select IDMMobileSDK.jar and click Next.)

  4. In the source tree for the application, create a folder called assets (at the same level as the java and res folders).

  5. In the SDK bundle, locate the oracle_mobile_cloud_config.xml file and copy it to the assets folder.

  6. In your app's build.gradle file, make sure the following are among the dependencies registered so that the SDK libraries are available to the app.

    dependencies {
        compile fileTree(dir: 'libs', include: ['*.jar'])
        compile 'com.squareup.okhttp3:okhttp:3.9.0'
        compile 'org.slf4j:slf4j-jdk14:1.7.13'
        //to enable the app to receive notifications, include the following:
        compile 'com.google.firebase:firebase-messaging:11.0.2'
    }
  7. Open assets/oracle_mobile_cloud_config.xml and fill in the environment details for the mobile backend that the app will be using.

Configuring SDK Properties

To use the client SDK in an Android app, you need to add a oracle_mobile_cloud_config.xml configuration file to the app and fill it in with environment details for your backend in OMCe. In turn, the SDK classes use this information to construct HTTP headers for REST calls made to OMCe.

You package the configuration file in your app’s main bundle in the assets folder at the same level as the java and res folders. For example, in the sample GettingStarted app, it’s in /GettingStarted/src/main/assets.

The file is essentially divided into the following parts:

  • The mobileBackend element and its contents.

    You include this part if you are using a backend with the app. The SDK classes use the environment and authentication details you specify there to access the backend and construct HTTP headers for REST calls made to APIs.

  • Elements that apply to the configuration as a whole, such as logLevel and oAuthTokenEndpoint. These elements generally, but don’t have to, appear at the top of the file.

The following code sample shows the structure of a oracle_mobile_cloud_config.xml file.

<config>

  <!--This value is required if you are using OAuth to authenticate against the mobile backend-->
  <oAuthTokenEndPoint>YOUR_OAUTH_TOKEN_END_POINT<oAuthTokenEndPoint>
  <!--Set to true if you want to get logging information-->
  <enableLogger>true</enableLogger>
  <logLevel>DEBUG</logLevel>
  <!--Whether to log HTTP call request and response bodies and headers-->
  <logHTTP>true</logHTTP>

  <!-- Include the mobileBackend element and its sub-elements if you are going 
       to be using a backend to access custom and platform APIs.-->
  <mobileBackend>
    <name>MBE_NAME</name>
    <baseUrl>BASE_URL</baseUrl>
    <enableAnalytics>true</enableAnalytics>
    <authentication>
      <!--possible values for type are [oauth, basic, facebook, tokenExchange ]-->
      <type>AUTH_TYPE</type>
      <oauth>
        <clientId>CLIENT_ID</clientId>
        <clientSecret>CLIENT_SECRET</clientSecret>
        <enableOffline>true</enableOffline>
      </oauth>
      <basic>
        <mobileBackendId>MOBILE_BACKEND_ID</mobileBackendID>
        <anonymousKey>ANONYMOUS_KEY</anonymousKey>
        <enableOffline></enableOffline>
      </basic>
      <facebook>
        <appId>FACEBOOK_APP_ID</appId>
        <scopes>public_profile,user_friends,email,user_location,user_birthday</scopes>
        <basic>
          <mobileBackendId>MOBILE_BACKEND_ID</mobileBackendID>
          <anonymousKey>ANONYMOUS_KEY</anonymousKey>
        </basic>
      </facebook>
      <tokenExchange>
        <! tokenExchange can contain an 'oauth' sub-element or a 'basic' sub-element.
        <oauth>
          <clientId>CLIENT_ID</clientId>
          <clientSecret>CLIENT_SECRET</clientSecret>
        </oauth>
        <basic>
          <mobileBackendId>MOBILE_BACKEND_ID</mobileBackendID>
          <anonymousKey>ANONYMOUS_KEY</anonymousKey>
        </basic>
      <tokenExchange>
    </authentication>
    <!-- additional properties go here -->
  </mobileBackend>

</config>

The values that you need to fill in for a given backend can be found on the Settings and App Profile pages for that mobile backend.

Here are some more notes on the file’s elements.

  • oAuthTokenEndPoint — The URL of the OAuth server from where your application gets its authentication token. This key needs to be provided for all apps that rely on OAuth to authenticate. You get this from the backend’s Settings page.

  • logLevel — Determines how much SDK logging is displayed in the app’s console. The default value is ERROR. Other possible values (in increasing level of detail) are WARNING, INFO, and DEBUG. It is also possible to specify NONE.

  • enableAnalytics — When set to true, analytics are collected for system and custom events that were defined with the legacy Mobile Cloud Service analytics features. This option has no impact on the current analytics features.

  • enableLogger — When set to true, logging is included in your app.

  • logHTTP — When set to true, the SDK logs the HTTP and HTTPS headers in requests and responses.

  • mobileBackend — An element containing authentication details for your backend and other optional details, such as synchronization properties.

    You get the authentication details, such as the OAuth and HTTP credentials, from the backend’s Settings page.

  • mobileBackend/baseUrl — The base URL for all APIs that you call through the backend. You get this from the backend’s Settings page.

  • mobileBackend/authentication — Contains the following sub-elements:

    • The type sub-element, with possible values of oauth, basic, facebook, and tokenExchange.

    • One or more sub-elements for authentication types, each containing authentication credentials.

      You can also add the offlineEnabled key and set its value to true.

    See Authentication Properties for examples of each authentication type.

  • enableOffline — If set to true, offline login will be allowed. This applies only to the Basic and OAuth login types. For this to work, you also need to add the following to the app’s AndroidManifest.xml file:
    <receiver android:name="oracle.cloud.mobile.network.NetworkHelper"
      <intent-filter>
        <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
      </intent-filter>
    </receiver>

Authentication Properties

The contents and sub-elements of authentication depend on what kind of authentication the app will be using.

OAuth
  • Set the value of the <type> element to oauth.

  • Fill in the clientID and clientSecret  credentials provided by the backend.

  • Optionally, if you want to disable offline authentication, add the enableOffline element and set it to false.

  • At the top level of the file, supply the oAuthTokenEndPoint value.

The resulting authentication element might look something like this:

<oAuthTokenEndPoint>http://oam-server.oracle.com/oam/oauth2/tokens</oAuthTokenEndPoint>

<authentication>
  <type>oauth</type>
  <oauth>
    <clientId>f2d3ca5c-7e6f-4d1c-aabc-a2f3caf7ec4e</clientId>
    <clientSecret>vZMRkgniIbhNUiPnSRT2</clientSecret>
    <enableOffline>false</enableOffline>
  </oauth>
</authentication>
HTTP Basic
  • Set the value of the type element to basic.

  • Fill in the mobileBackendID and anonymousKey that are provided by the backend.

  • Optionally, if you want to disable offline authentication, add the enableOffline sub-element and set it to false.

The resulting authentication element might look something like this:

<authentication>
  <type>basic</type>
  <basic>
    <mobileBackendID>6d3744b8-cab2-479c-998b-ebba2c31560f</mobileBackendID>
    <anonymousKey>UFJJTUVfREVDRVBUSUNPTl9NT0JJTEVfQU5PTll</anonymousKey>
    <enableOffline>false</enableOffline>
  </basic>
</authentication>
Token Exchange

If you are authenticating using a third-party token, do the following:

  • Set the value of the <type> element to tokenExchange.

  • Create a <basic> sub-element and fill in the OAuth Consumer credentials provided by the backend.

The resulting authentication element might look something like this:

<authentication>
  <type>tokenExchange</type>
    <basic>
      <mobileBackendID>6d3744b8-cab2-479c-998b-ebba2c31560f</mobileBackendID>
      <anonymousKey>UFJJTUVfREVDRVBUSUNPTl9NT0JJTEVfQU5PTll</anonymousKey>
    </basic>
  <tokenExchange>
</authentication>
Facebook Login

For Facebook login:

  • Set the value of the <type> property to facebook.

  • Create a <facebook> sub-element.

  • Fill in the <appID> for the Facebook app.

  • Fill in <scopes> with any relevant Facebook permissions (optional).

  • Within <facebook>, created a <basic> element and fill in the HTTP Basic credentials provided by the backend.

The resulting authentication element might look something like this:

<authentication>
  <type>facebook</type>
  <facebook>
    <basic>
      <mobileBackendId>MOBILE_BACKEND_ID</mobileBackendId>
      <anonymousKey>ANONYMOUS_KEY</anonymousKey>		
    </basic>
    <appID>123456789012345</appId>
    <scopes>public_profile,user_friends,email,user_location,user_birthday</scopes>
  </facebook>
<authentication>

Configuring Your Android Manifest File

Permissions for operations such as accessing the network and finding the network state are controlled through permission settings in your application's manifest file, AndroidManifest.xml. These permissions are required:

  • permission.INTERNET — Allows your app to access open network sockets.

  • permission.ACCESS_NETWORK_STATE — Allows your app to access information about networks.

Other permissions are optional. For example, there are a number of permissions necessary for the app to be able to receive notifications. For a rundown on the available permissions, see Android Manifest Permissions in the Google documentation.

Add the permissions at the top of your AndroidManifest.xml file, as shown in the following example:

<?xml version="1.0" encoding="UTF-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="oracle.cloud.mobile.sample" >
  <uses-permission android:name="android.permission.INTERNET" />
  <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
  <uses-permission android:name="android.permission.WRITE_INTERNAL_STORAGE"/>
  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
  <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
  <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

  <application>
    <receiver android:name="oracle.cloud.mobile.network.NetworkHelper"
      <intent-filter>
        <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
      </intent-filter>
    </receiver>

    (.....)
  </application>
</manifest>

Adding the client SDK to your application may require you to configure your AndroidManifest.xml file to add new permissions or activities. For example, if you add the Notifications individual SDK library, you may also need to add a new broadcast receiver. For more information, see Setting Up a Mobile App for Notifications.

Calling Mobile APIs

In OMCe, a backend is a logical grouping of custom APIs, storage collections, and other resources that you can use in your apps. The backend also provides the security context for accessing those resources.

Here are the general steps for using a backend in your Android app:

  1. Add the client SDK to your app.

  2. Fill in the oracle_mobile_cloud_config.xml with environment and authentication details for the backend.

  3. Add an SDK call to your app to load the configuration info.

  4. Add an SDK call to your app to handle authentication.

  5. Add any other SDK calls that you want to use.

Loading the Backend's Configuration

For any calls to OMCe APIs using the Android client SDK to successfully complete, you need to have the backend’s configuration loaded from the app’s oracle_mobile_cloud_config.xml file. You do this using the MobileManager class:

MobileManager.getManager().getMobileBackend(this)

Authenticating and Logging In

Here is some sample code that you can use for authentication through OMCe in your Android apps.

OAuth Consumer

First you initialize the authorization agent and set the authentication type to OAUTH:

private AuthorizationAgent mAuthorization; 
private MobileBackend mobileBackend; 

try {
  mobileBackend = MobileManager.getManager().getMobileBackend(this);
} catch (ServiceProxyException e) {
      e.printStackTrace();
}

mAuthorization = mobileBackend.getAuthorization(AuthType.OAUTH);

Then you use the authenticate method to attempt authentication. The call includes parameters for Android context, user name, password, and a callback that completes the authorization process:

TextView username, password; 
username = (TextView) findViewById(R.id.username);
password = (TextView) findViewById(R.id.password); 
String userName = username.getText().toString(); 
String passWord = password.getText().toString();
mAuthorization.authenticate(mCtx, userName, passWord, mLoginCallback); 

Here’s the definition for the callback:

AuthorizationCallback mLoginCallback = new AuthorizationCallback() {
   @Override
   public void onCompletion(ServiceProxyException exception) {
     Log.d(TAG, "OnCompletion Auth Callback");
      if (exception != null) {
        Log.e(TAG, "Exception while receiving the Access Token", exception);
     } else {
        Log.e(TAG, "Authorization successful");
     }
   }
 }

SSO with a Third-Party Token

First, your app needs to get a token from the third-party token issuer. The way you can obtain the token varies by issuer. For detailed information on obtaining third-party tokens and configuring identity providers in OMCe, see Third-Party SAML and JWT Tokens.

Once you have the token, initialize the authorization agent and use the token in your authorization call.

private AuthorizationAgent mAuthorization; 
private MobileBackend mobileBackend; 
Context mCtx = getApplicationContext();

try {
  mobileBackend = MobileManager.getManager().getMobileBackend(this);
} catch (ServiceProxyException e) {
      e.printStackTrace();
}

mAuthorization = mobileBackend.getAuthorization(AuthType.TOKENEXCHANGE);

Then you use the authenticateUsingTokenExchange method to attempt authentication.

mAuthorization.authenticateUsingTokenExchange(mCtx, token, false, mLoginCallback);

Here’s the callback:

AuthorizationCallback mLoginCallback = new AuthorizationCallback() {
    @Override
    public void onCompletion(ServiceProxyException exception) {
        if (exception == null) {
            //redirect to another Activity after login
            Intent intent = new Intent(mCtx, ContentActivity.class);
            startActivity(intent);
  
        } else {
            Log.e(TAG, "Exception during token exchange:", exception);
            finish();
        }
    }
};

Note:

The default expiration time for storing a third-party token in OMCe is 6 hours. You can adjust this time by changing the Security_TokenExchangeTimeoutSecs policy. See Modifying Policies in Administering Oracle Mobile Cloud, Enterprise.

SSO with a Third-Party Token — Staying Logged In

You can also code the app to keep the user logged in, even when closing and restarting the app.

In the above example, the authenticateUsingTokenExchange() method is called with the third parameter (storeToken) set to false. If you set this parameter to true and the token exchange is successful, the MCS token is stored in a secure store and the user remains logged in until the token expires.

You can then use the loadSSOTokenExchange method on the Authorization object to load the stored token. If a token can’t be retrieved from the secure store, the method returns false.

Here’s some code that tries to load a saved token and, if it fails, restarts the authentication process:

try {
    mAuthorization = MobileManager.getManager().getMobileBackend(this).getAuthorization();
    if (!mAuthorization.loadSSOTokenExchange(mCtx)) {
        //user not logged in, so need to initiate login
        mAuthorization.authenticateUsingTokenExchange(mCtx, token, true, mLoginCallback);
    }

When you have the token stored in the secure store, it remains associated with the mobile backend that the app originally used. Therefore, if the app is updated to use a different mobile backend (or mobile backend version), you need to clear the saved token and re-authenticate.

mAuthorization.clearSSOTokenExchange(mCtx);
mAuthorization.authenticateUsingTokenExchange(mCtx, token, true, mLoginCallback);

HTTP Basic Authentication

The code for handling login with HTTP Basic is nearly the same as the code for OAuth.

First you initialize the authorization agent and set the authentication type to BASIC_AUTH:

private AuthorizationAgent mAuthorization; 
private MobileBackend mobileBackend; 

try {
  mobileBackend = MobileManager.getManager().getMobileBackend(this);
} catch (ServiceProxyException e) {
      e.printStackTrace();
}

mAuthorization = mobileBackend.getAuthorization(AuthType.BASIC_AUTH)

Then you use the authenticate method to attempt authentication. The call includes parameters for Android context, user name, password, and a callback that completes the authorization process.

TextView username, password; 
username = (TextView) findViewById(R.id.username);
password = (TextView) findViewById(R.id.password);
String userName = username.getText().toString(); 
String passWord = password.getText().toString();
mAuthorization.authenticate(mCtx, userName, passWord, mLoginCallback); 

Here’s the definition for the callback:

AuthorizationCallback mLoginCallback = new AuthorizationCallback() {
   @Override
   public void onCompletion(ServiceProxyException exception) {
     Log.d(TAG, "OnCompletion Auth Callback");
     if (exception != null) {
       Log.e(TAG, "Exception while receiving the Access Token", exception);
     } else {
   Log.e(TAG, "Authorization successful");
   }
  }
 }

Facebook

For Facebook login, you use classes in the oracle_mobile_android_social library.

First you initialize the authorization agent and set the authentication type to Facebook:

SocialAuthorizationAgent mAuthorization;
SocialMobileBackend socialMobileBackend;
try {
  socialMobileBackend = SocialMobileBackendManager.getManager().getMobileBackend(mCtx);
} catch(ServiceProxyException e){
    e.printStackTrace();
}
mAuthorization = socialMobileBackend.getSocialAuthorization(); mAuthorization.setAuthType(AuthType.FACEBOOK);


Using a CallbackManager object from Facebook’s SDK, initiate authentication.

private CallbackManager callbackManager;
mAuthorization.setup(getApplicationContext(), callback);
callbackManager = mAuthorization.getCallBackManager();
mAuthorization.authenticateSocial(mCtx);

Here’s code you can use for the callback that is passed above:

private FacebookCallback<LoginResult> callback = new FacebookCallback<LoginResult>() {
    @Override
    public void onSuccess(LoginResult loginResult) {
        Log.e(TAG, "facebook login successful.");
    }
    @Override
    public void onCancel() {
    }
    @Override
    public void onError(FacebookException e) {
    }
};

Override the onActivityResult() method to use the callback:

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    callbackManager.onActivityResult(requestCode, resultCode, data);

Calling Platform APIs

Once the mobile backend’s configuration info is loaded into the app, you can make calls to client SDK classes.

The root object in the Android SDK is MobileManager. The MobileManager object manages MobileBackend objects.

The MobileBackend object manages connectivity, authentication, and other transactions between your application and its associated backend, including calls to platform APIs and any custom APIs you have defined. It manages calls to platform APIs through instances of ServiceProxy such as Storage and Location.

Here’s an example of how you would use these classes to upload an image using the Storage API:

try {
    Storage storage = MobileManager.getManager().getMobileBackend(this).getServiceProxy(Storage.class);
    StorageCollection imagesCollection = storage.getStorageCollection("FIF_Images");
    StorageObject imageToUpload = new StorageObject(null, imageBytes, "image/jpeg");
    StorageObject uploadedImage = imagesCollection.post(imageToUpload);
} catch(ServiceProxyException e) {int errorCode = e.getErrorCode();
            ...
}

The ServiceProxy instance created there manages calls to the Storage platform API, including the constructing of the HTTP headers with the mobile backend credentials necessary to access the API.

And here’s how you could retrieve an image using the Storage API:

try {
    Storage storage = MobileManager.getManager().getMobileBackend(this).getServiceProxy(Storage.class);
    StorageCollection imagesCollection = storage.getStorageCollection("FIF_Images");
    StorageObject image = imagesCollection.get("3x4mp1e-st0r4g3-0bj3ct-k3y");byte[] imageBytes = image.getPayloadBytes();
} catch(ServiceProxyException e) {int errorCode = e.getErrorCode();
 ...
}

Calling Custom APIs

The client SDK provides the CustomHttpResponse class, the GenericCustomCodeClientCallBack interface, and the invokeCustomCodeJSONRequest method in the authorization classes to simplify the calling of custom APIs in OMCe. You can call a REST method (GET, PUT, POST, or DELETE) on an endpoint where the request payload is JSON or empty and the response payload is JSON or empty.

You use GenericCustomCodeClientCallBack to create a handler for the response (which is returned in the form of a CustomHttpResponse object.)

Then, to call the custom API, you call invokeCustomCodeJSONRequest(GenericCustomCodeClientCallBack restClientCallback, JSONObject data, String functionName, RestClient.HttpMethod httpMethod) on your Authorization object.

To make a call to a custom API endpoint, you could use something like this:

import org.json.JSONObject;
import oracle.cloud.mobile.customcode.CustomHttpResponse;
import oracle.cloud.mobile.customcode.GenericCustomCodeClientCallBack;
import oracle.cloud.mobile.mobilebackend.MobileManager;
.......
 
final GenericCustomCodeClientCallBack genericCustomCodeClientCallBack = new GenericCustomCodeClientCallBack() {
    @Override
    public void requestCompleted(CustomHttpResponse response, JSONObject data, Exception e) {
        boolean getResponse = (response.getHttpStatus() >=200 && response.getHttpStatus() <300);
                   
        // write any logic based on above response
    }
};
AuthorizationAgent authorization = MobileManager.getManager().getMobileBackend(this).getAuthorization();
            
authorization.authenticate(mActivity, "user1", "pass1", successCallback);

........
// after the user successfully authenticates, make a call to the custom API endpoint
authorization.invokeCustomCodeJSONRequest(genericCustomCodeClientCallBack, null, "TaskApi/tasks", RestClient.HttpMethod.GET);

Libraries and Dependencies

Libraries

The following SDK libraries (JAR files) are included in the Android client SDK:

  • omce-android-sdk-shared-<version-number>.jar - The base library for the SDK, including functionality required by the other libraries as well as utility classes for accessing and authenticating with mobile backends.

  • IDMMobileSDK.jar - The identity management library used by all applications.

  • omce-android-sdk-location-<version-number> - The Location library, which lets you access details about location devices that have been registered in OMCe and the places and assets they are associated with.

  • omce-android-sdk-notifications-<version-number>.jar - The Notifications library, which lets you set up your application to receive notifications sent from your mobile backend.

  • omce-android-sdk-social-<version-number> - The Social Login library, which allows you to set up your app to use Facebook login.

  • omce-android-sdk-storage-<version-number>.jar - The Storage library, which lets you write code to access storage collections that are set up with your mobile backend.

  • omce-android-sdk-sync-<version-number> - The Sync Client library, which allows you to cache application data when the device running your app is disconnected from the network, then sync up the data when the network connection is reestablished.

Dependencies

The SDK is modular, so you can package just the libraries that your app needs. Just be aware of the following dependencies:

  • Every Android application developed for OMCe must have the shared (oracle-mobile_android_shared-<version-number>.jar) and IDMMobileSDK.jar libraries.

  • If the Storage library is installed, the Sync Client library must also be installed.

Next Steps

Once you have the Android SDK set up, you can start using it to add OMCe features to your app.