Dynamics 365 for Finance and Operations is built on open standards like OAuth 2.0, OData v4 and RESTful JSON Web service APIs, which makes it possible for us to integrate our business apps with many different platforms and environments. One of these possibilities is integration with the popular mobile development platform of Android.

Microsoft already has open source libraries and tools to integrate Android with Azure hosted services and in this example, we will see how to integrate Android mobile platform with Dynamics 365 for Finance and Operations:

(Note : video demo below is only available in original blog post in devblog.sertanyaman.com)

The example project in D365FO

Capture3.JPG

Our example project (exported from platform update 15) includes a simple D365FO web API service which sends customer visit registrations for a worker on certain set of dates. You simply enter the worker, customer and date of the visit in the “AndVisitSchedule” form and these new records are picked up by the web service. The export file for this D365 project is included in the root of my GitHub project, which I give a link below, named as “AndroidTest.axpp”.

Capture4
Capture2.JPG

The following D365FO service operation code is used to pick up new records for the Worker, and flags them as “Sent” so they are not sent again. To reset the “Sent” flags on the records, and send them again to the device, you can use the menu button on the “AndVisitSchedule” form called “Re-initialize”:


[AifCollectionTypeAttribute('return', Types::Class, classStr(AndVisitScheduleDataContract))]
public List getNewTasks(HcmPersonnelNumberId _worker)
{
List tasks = new List(Types::Class);
AndVisitScheduleDataContract task;
AndVisitScheduleEntity entity;
AndVisitSchedule schedule;

ttsbegin;

while select entity where entity.Sent == NoYes::No && entity.PersonnelNumber == _worker
{
task = AndVisitScheduleDataContract::construct();

task.parmLineNum(entity.LineNum);
task.parmCustAccount(entity.CustAccount);
task.parmWorker(entity.PersonnelNumber);
task.parmVisitDateTime(entity.VisitDateTime);
task.parmCustName(entity.CustName);
task.parmWorkerName(entity.WorkerName);
task.parmAddress(entity.Address);

tasks.addEnd(task);

update_recordset schedule setting Sent = NoYes::Yes where schedule.LineNum == entity.LineNum;
}

ttscommit;

return tasks;

}

Android part of the project

Screenshot_1539781324

The Android part of the project, exported from Android Studio 3.2, is available on the GitHub project folder, and free to use. In this blog post I will not get into the details of the Android programming part, but I will certainly mention the methods and libraries I used for integration with D365FO.

To be able to connect D365FO from Android, you first need to authorize your application in Azure Active Directory and get a valid authorization token from AAD token service. By providing this token in the HTTP request header of the RESTful D365FO webAPI service call (with a key of “Authorization” and token in the value with a prefix of “Bearer “), you can successfully get authorized and receive a response from this service. The Azure authentication process for D365FO, based on OpenAuth 2.0 is shown below :

services-authentication.png

Microsoft provides open source libraries for azure authentication on different platforms. For Java/Android there are two libraries provided :

ADAL:

https://github.com/AzureAD/azure-activedirectory-library-for-android

This library is the special one for Android mobile platform development and uses a graphical user interface to provide authorization for your application. Therefore, you have to pass a launching activity to the library to redirect the user to a predefined Azure AD login page:

screenshot

In our example we will use this library to authorize our application with Azure. This library is directly available in Android native repository and can be added to your Gradle depencies as :

implementation("com.microsoft.aad:adal:1.15.+")

ADAL4J:

https://github.com/AzureAD/azure-activedirectory-library-for-java

This library is the one for legacy java and provides Azure AD authorization without the need for a login page or UI element. Therefore you can provide username and password directly in the parameters of the method that acquires a token. This library is not available directly for Android repository but available in Maven repository. I was not able to add this library myself from Maven to Android Studio because the library is compiled with another Java compiler than Android Studio one, so I am not sure if it works together with Android.

Steps for Azure AD authorization

To be able to communicate with Azure services, applications must first be registered in Azure AD settings in your cloud subscription. For more information on how to register an application on AAD, you can check the following page from Microsoft :

https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-v1-add-azure-ad-app

Register your example application here as a native client application and make sure you grant full “Delegated Permissions” for “Microsoft Dynamics ERP” API here inside your application registration settings. Copy the application ID here and use it in your application’s settings screen for client ID.

screenshot (3).png

Also fill in the URL of your D365 FO launch page and the worker id (personnel number) you want to receive updates for.

Make sure your AAD login has necessary rights in D365 and has default company set to the company you want to test your app. Finally test if your D365 web api service is deployed and accessible by adding ‘/api/services/AndroidTests/AndVisitSchedule/getNewTasks’ at the end of your D365 URL and getting the JSON service definition.

Acquiring an authentication token from AAD

The method for acquiring an authentication token using ADAL library for Android is the one below. You first create an AuthenticationContext object, which tracks the complete authentication process, and then request a token using ‘aadContext.acquireToken’ method. This method will show you an Azure AD login screen if called for the first time and get an authorization token from the AAD server in an async manner.

You may notice that I do not do a silent authentication call before the interactive “acquireToken” call as suggested in the Github documentation of the library (and many of the sample code). I did so previously but realized that the “acquireToken” call below does a silent call itself when it is needed, and also keeps track of the token expiry and token refresh tasks automatically. So I removed my manual calls for a silent authentication using “acquireTokenSilentAsync” from my final code :

private void getAccessToken(Activity activity) throws NullPointerException
{
    if(isConnected(activity)) {
        //Create context
        if (aadContext == null) {
            aadContext = new AuthenticationContext(activity.getApplicationContext(), AAD_END_POINT, false);
        }
        curToken = "";
        try
        {
            aadContext.acquireToken(activity, axUrl, clientId, axUrl, PromptBehavior.Auto, authCallback);
        }
        catch (Exception exception) {
            Log.e("Azure AAD :", "Authorization failed!");
            exception.printStackTrace();
            onAuthorizationResult.onAuthorizationFail();
        }
    }
    else
    {
        snackIt(activity, "Not connected to internet");
        onAuthorizationResult.onAuthorizationFail();
    }
}

Once you acquire your token using this code, you can use it in your REST call for the web api service.

Calling the D365FO Web API Service and receiving data

In Android platform you have so many different open source libraries and tools for calling a REST api and getting JSON data from it. In this example I have decided to use google’s “Volley” library, but you are free to pick up any favourite library of yours. In any library you use, you need to include the token you acquired in your AAD authorization in the header of the HTTP request like shown below :

@Override
public Map<String, String> getHeaders() {
    Map<String, String> headers = new HashMap<>();
    headers.put("Authorization", "Bearer " + aadHelper.getCurToken());
    return headers;
}

Then you can do your call using POST method and adding your service operation parameters (method parameters of D365 service) as a single JSON object containing them:

VolleyJsonRequestExtension request = new VolleyJsonRequestExtension(Request.Method.POST, uriGetTasks.toString(), jsonObject,new Response.Listener<JSONArray>() {...}</pre>

You may notice that here I have created an overload (in D365FO terms, an ‘Extension’) for the default Volley library for their request method. The reason is, in the time of writing, Volley has either JsonObject(parm)>JsonObject(return) or JsonArray(parm)>JsonArray(return) request methods and no JsonObject(parm)>JsonArray(return) method as used in D365FO Web API services.

After the service call is done and JSON response is received, it is automatically saved into the model class using Google’s Gson library and then to the SQLite database as permanent storage.

Showing the task on the map

If you click on the RecyclerView item in the main screen of the application, a map is shown with the pointer of the address received from D365FO. To show this map successfully in the demo app, you first need to get an API key from google and declare it in the “google_maps_api.xml” file of the project (under “res\values\”).

Screenshot_1539788647.png

But be aware of something before you test your customer addresses with this Google maps geolocator; D365FO uses 3 digit ISO country codes whereas Google geocoder uses the two digit ISO ones, and for some countries, google refuses to decode three digit  country codes!. At the time of writing, there is no easy way to show 2 digit ISO codes instead of 3 digit ones in default D365FO addressing, but to overcome this problem, you can include full country names in your D365FO addressing setup, by checking the “Extract” option on address part for country codes.

Notifications?

And how to get notifications on notification bar of Android when there are new tasks available for our worker? This is not done on the Android side like the example here, but the other way around. For notifications, you need to utilize a trusted Android messaging service, such as “Firebase Cloud Messaging”. Then from D365FO, you need to create a batch job which periodically checks for new Tasks, and notifies the messaging service if there are new ones. Then you implement a Receiver on your Android project to receive that message and show notifications.

This process is not included in my example since it is not quite about D365FO integration but this is simply how it is done in Android platform.

Github link for the complete project :

https://github.com/sertanyaman/native-android-integration-example-for-dynamics-365fo

 

Leave a Reply