Invoking Liferay Services in Your Android App

Once the appropriate Mobile SDKs are set up in your Android project, you can access and invoke Liferay Portal’s services in your app. This tutorial takes you through the steps you must follow to invoke these services:

  1. Create a session.
  2. Import the Liferay Portal services you need to call.
  3. Create a service object and call the service methods.

Since some service calls require special treatment, this tutorial also shows you how to handle them. But first, you’ll learn about securing Liferay Portal’s JSON web services in the portal.

Securing JSON Web Services

The Liferay Mobile SDK calls Liferay Portal’s JSON web services, which are enabled by default. The web services you call via the Mobile SDK must remain enabled for those calls to work. It’s possible, however, to disable the web services that you don’t need to call. For instructions on this, see the tutorial Portal Configuration of JSON Web Services.

Step 1: Create a Session

A session is a conversion state between the client and server, that consists of multiple requests and responses between the two. You need a session to pass requests between your app and the Mobile SDK. In most cases, sessions need to be created with user authentication. The imports and code required to create a session are shown here:

import com.liferay.mobile.android.auth.basic.BasicAuthentication;
import com.liferay.mobile.android.service.Session;
import com.liferay.mobile.android.service.SessionImpl;
...
Session session = new SessionImpl("http://10.0.2.2:8080", 
    new BasicAuthentication("test@liferay.com", "test"));

The arguments to SessionImpl are used to create the session. The first parameter is the URL of the Liferay instance you’re connecting to. If you’re running your app on Android Studio’s emulator, http://10.0.2.2:8080 is equivalent to http://localhost:8080. Be sure to replace this with the correct address for your server.

The second parameter creates a new BasicAuthentication object containing the user’s credentials. Depending on the authentication method used by your Liferay instance, you need to provide the user’s email address, screen name, or user ID. You also need to provide the user’s password. The BasicAuthentication object tells the session to use Basic Authentication to authenticate each service call. The Mobile SDK also supports OAuth authentication, as long as the OAuth Provider portlet is deployed to your Liferay instance. To learn how to use OAuth authentication with the Mobile SDK, see the OAuth sample app.

If you’re building a sign in view for your app, you can use the SignIn utility class to check if the credentials given by the user are valid.

import com.liferay.mobile.android.auth.SignIn;
...
SignIn.signIn(session, new JSONObjectAsyncTaskCallback() {

    @Override
    public void onSuccess(JSONObject userJSONObject) {
        System.out.println("Successful sign-in, user details: " + userJSONObject)
    }

    @Override
    public void onFailure(Exception e) {
        e.printStackTrace();
    }

});

Note that the Mobile SDK doesn’t keep a persistent connection or session with the server. Each request is sent with the user’s credentials (except when using OAuth). However, the SignIn class provides a way to return user information after a successful sign-in.

Next, you’re shown how to create an unauthenticated session in the limited cases where this is possible.

Creating an Unauthenticated Session

In some cases, it’s possible to create a Session instance without user credentials. However, most Liferay remote methods don’t accept unauthenticated remote calls. Making a call with an unauthenticated session generates an Authentication access required exception in most cases.

Unauthenticated service calls only work if the remote method in the portal or your plugin has the @AccessControlled annotation. This is shown here for the hypothetical class FooServiceImpl and its method bar:

import com.liferay.portal.security.ac.AccessControlled;
...
public class FooServiceImpl extends FooServiceBaseImpl {
...
    @AccessControlled(guestAccessEnabled = true)
    public void bar() { ... }
...

To make such a call, you need to use the constructor that accepts the server URL only:

Session session = new SessionImpl("http://10.0.2.2:8080");

Fantastic! Now that you have a session, you can use it to call Liferay’s services.

Step 2: Import the Liferay Services You Need

First, you should determine the Liferay services you need to call. You can find the available portal and plugin services at http://localhost:8080/api/jsonws. Be sure to replace http://localhost:8080 in this URL with your server’s address.

Add the imports for the services you need to call. For example, if you’re building a blogs app, you can import BlogsEntryService:

import com.liferay.mobile.android.v62.blogsentry.BlogsEntryService;

Note that the Liferay version (.v62) is used in the package namespace. Since the Mobile SDK is built for a specific Liferay version, service classes for different Liferay versions are separated by their package names. In this example, the Mobile SDK classes use the .v62 package, which means this Mobile SDK is compatible with Liferay 6.2. This namespacing lets your app support multiple Liferay versions.

Step 3: Create a Service Object and Call its Service Methods

Once you have a session and the required imports, you’re ready to make the service call. This is done by creating a service object for the service you want to call, and then calling its service methods. For example, if you’re creating a blogs app, you need to use BlogsEntryService to get all the blogs entries from a site. This is demonstrated by the following code:

BlogsEntryService service = new BlogsEntryService(session);

JSONArray jsonArray = service.getGroupEntries(10184, 0, 0, -1, -1);

This fetches all blog entries from the Guest site. In this example, the Guest site’s groupId is 10184. Note that many service methods require groupId as a parameter. You can get the user’s groups by calling the getUserSites() method from GroupService.

Service method return types can be void, String, JSONArray, or JSONObject. Primitive type wrappers can be Boolean, Integer, Long, or Double.

This BlogsEntryService call is a basic example of a synchronous service call; the method only returns after the request finishes. However, Android doesn’t allow network communication from an app’s main UI thread. Service calls issued from the main UI thread need need to be asynchronous. For instructions on doing this, see the tutorial Invoking Services Asynchronously from Your Android App.

Great! Now you’re familiar with the basics of accessing Liferay services through the Mobile SDK. However, there are some special cases you may run into when making service calls from your app. These are discussed in the following sections.

Non-Primitive Arguments

There are some special cases in which a service method’s arguments aren’t primitives. In these cases, you should use JSONObjectWrapper. For example:

JSONObjectWrapper wrapper = new JSONObjectWrapper(new JSONObject());

You must pass a JSON containing the object properties and their values. On the server side, your object is instantiated and setters for each property are called with the values from the JSON you passed.

There are other cases in which service methods require interfaces or abstract classes as arguments. Since it’s impossible for the SDK to guess which implementation you want to use, you must initialize JSONObjectWrapper with the class name. For example:

JSONObjectWrapper wrapper = new JSONObjectWrapper(className, new JSONObject());

The server looks for the class name in its classpath and instantiates the object for you. It then calls setters, as in the previous example. The abstract class OrderByComparator is a good example of this. This is discussed next.

OrderByComparator

On the server side, OrderByComparator is an abstract class. You must therefore pass the name of a class that implements it. For example:

String className = "com.liferay.portlet.bookmarks.util.comparator.EntryNameComparator";

JSONObjectWrapper orderByComparator = new JSONObjectWrapper(className, new JSONObject());

If the service you’re calling accepts null for a comparator argument, pass null to the service call.

You may want to set the ascending property for a comparator. Unfortunately, as of Liferay 6.2, most Liferay OrderByComparator implementations don’t have a setter for this property and it isn’t possible to set from the Mobile SDK. Future portal versions will address this. However, you may have a custom OrderByComparator that has a setter for ascending. In this case, you can use the following code:

String className = "com.example.MyOrderByComparator";

JSONObject jsonObject = new JSONObject();
jsonObject.put("ascending", true);

JSONObjectWrapper orderByComparator = new JSONObjectWrapper(className, jsonObject);

For more examples, see the test case OrderByComparatorTest.java.

ServiceContext

Another non-primitive argument is ServiceContext. It requires special attention because most Liferay service methods require it. However, you aren’t required to pass it to the SDK; you can pass null instead. The server then creates a ServiceContext instance for you, using default values.

If you need to set properties for ServiceContext, you can do so by adding them to a new JSONObject and then passing it as the ServiceContext argument:

JSONObject jsonObject = new JSONObject();
jsonObject.put("addGroupPermissions", true);
jsonObject.put("addGuestPermissions", true);

JSONObjectWrapper serviceContext = new JSONObjectWrapper(jsonObject);

For more examples, see the test case ServiceContextTest.java.

Binaries

Some Liferay services require argument types such as byte arrays (byte[]) and Files (java.io.File).

The Mobile SDK converts byte arrays to strings before sending the POST request. For example, "hello".getBytes("UTF-8") becomes a JSON array such as "[104,101,108,108,111]". The Mobile SDK does this for you so you don’t have worry about it; you only need to pass the byte array to the method.

However, you need to be careful when using such methods. This is because you’re allocating memory for the whole byte array, which may cause memory issues if the content is large.

Other portal service methods require java.io.File as an argument. In these cases, the Mobile SDK requires InputStreamBody instead. To accomodate this, you need to create an InputStream and pass it to the InputStreamBody constructor, along with the file’s mime type and name. For example:

InputStream is = context.getAssets().open("file.png");
InputStreamBody file = new InputStreamBody(is, "image/png", "file.png");

The Mobile SDK sends a multipart form request to the portal. On the server side, a File instance is created and sent to the service method you’re calling.

It’s also possible to cancel or monitor service calls that upload data to Liferay. Every service that uploads data returns an AsyncTask instance. You can use it to cancel the upload if needed. If want to listen for upload progress to create a progress bar, you can create an UploadProgressAsyncTaskCallback callback and set it to the current Session object. Its onProgress method is called for each byte chunk sent. It passes the total number of uploaded bytes so far. For example:

session.setCallback(

    new UploadProgressAsyncTaskCallback<JSONObject>() {

        (...)

        public void onProgress(int totalBytes) {
            // This method will be called for each byte chunk sent.
            // The totalBytes argument will contain the total number
            // of uploaded bytes, from 0 to the total size of the
            // request.
        }

        (...)

    }
);

For more examples on this subject, see the aadFileEntry* methods in DLAppServiceTest.java.

As you can see, the Mobile SDK does a great deal of work for you even when special service method arguments are required.

Invoking Services Asynchronously from Your Android App

Building Mobile SDKs

Creating iOS Apps that Use Liferay

Service Builder and Services

« Making Liferay and Custom Portlet Services Available in Your Android AppInvoking Services Asynchronously from Your Android App »
Was this article helpful?
0 out of 0 found this helpful