SOAP Client using ksoap2 in Android - Kotlin


Introduction:


SOAP stands for Simple Object Access Protocol. It is XML-based protocol that allows programs that run on different operating systems (like Windows, Linux, etc) to communicate using HTTP and XML.

Pros:

  • Security - SOAP provides its own security known as WS Security.
  • Platform Independent - SOAP web services can be written in any programming language and executed in any platform

Cons:

  • Slow - It uses XML format that must be parsed, to be read. It defines many standards to be followed while developing. So its slow and consumes more bandwidth and resource.
  • WSDL dependent - It uses WSDL mechanism and doesn't have any other mechanism to discover the service.

Things to know:

The following are the things we have to know before we proceed further:

                   URL - It is the URL of WSDL file.

                   NAMESPACE - It is targetNamespace in WSDL.
                   
                   METHOD_NAME - It is the methodName(function name) of web service. We can have any no. of methods.

                    SOAP_ACTION - Its nothing but, NAMESPACE+METHOD_NAME

Example:

The following image is request and response format of  SOAP url that I've used. (public sample one)


Here, the above image is request format. And you can see that the SOAPACTION is "http://tempuri.org/Add", so obviously, NAMESPACE is "http://tempuri.org/" and METHOD_NAME is "Add".

Also, it requires two parameters namely, <intA> and <intB> of type, Integer.

In the below image, you can see the response format. In this sample, the response is just an Integer of Result value. In most cases, it will be in JSON format(it depends).

Implementation:

To fetch and post data to Soap api, we can use ksoap2 library. Its simple to use as well. Let's see how to use that in step-by-step procedure.

AndroidManifest.xml

To initiate, first we need the INTERNET permission to be added in AndroidManifest.xml.


 <uses-permission android:name="android.permission.INTERNET" />
 <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

build.gradle

We can either add ksoap2 library into the project by adding JAR file or adding it via build.gradle. I found it easier to add using build.gradle. So I am posting code for it. If you are gonna add JAR file, then you skip this step and proceed next.


apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'

android {
    compileSdkVersion 27
    buildToolsVersion '27.0.3'
    defaultConfig {
        applicationId "com.yamikrish.soap_webservicesample"
        minSdkVersion 15
        targetSdkVersion 27
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }

        repositories {
            maven { url 'https://oss.sonatype.org/content/repositories/ksoap2-android-releases/' }
        }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])

    implementation 'com.android.support:appcompat-v7:27.1.1'
    implementation 'com.android.support.constraint:constraint-layout:1.1.0'
    implementation 'com.google.code.ksoap2-android:ksoap2-android:3.6.2'
    compile 'com.android.support:design:27.1.1'
    testImplementation 'junit:junit:4.12'
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
}
repositories {
    mavenCentral()
}

activity_soap.xml

Then, design the layout to get two integer inputs and a button and a textView. While clicking the button, those two input integers to be added using SOAP api and display the result in the textView below it.

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto">


    <android.support.design.widget.TextInputLayout
        android:id="@+id/inputLayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:layout_margin="15dp">

        <android.support.design.widget.TextInputEditText
            android:id="@+id/enterInput1"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:inputType="number"
            android:hint="@string/enter_input_1" />

    </android.support.design.widget.TextInputLayout>

    <android.support.design.widget.TextInputLayout
        android:id="@+id/input2Layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/inputLayout"
        android:layout_margin="15dp">

        <android.support.design.widget.TextInputEditText
            android:id="@+id/enterInput2"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:inputType="number"
            android:hint="@string/enter_input_2" />

    </android.support.design.widget.TextInputLayout>

    <TextView
        android:id="@+id/add"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/input2Layout"
        android:textAppearance="@style/TextAppearance.AppCompat.Medium"
        android:gravity="center"
        android:layout_margin="15dp"
        android:textColor="@color/colorWhite"
        android:background="@color/colorPrimary"
        android:text="@string/add"
        android:padding="10dp"/>
    <TextView
        android:id="@+id/resultValue"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/add"
        android:textAppearance="@style/TextAppearance.AppCompat.Small"
        android:layout_margin="15dp"
        android:padding="10dp"/>

</android.support.constraint.ConstraintLayout>


SoapActivity.kt

While clicking the button, 'add', we have to check whether the two inputs are entered or not. If it entered, we can call the SOAP api using AsyncTask and pass the two input values to it as well to process. For this process, another class, CallWebService is used. (I have written that class below.)

class SoapActivity : AppCompatActivity() {


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.new_layout)

        add.setOnClickListener {
            val input1 = enterInput1.text.toString().trim()
            val input2 = enterInput2.text.toString().trim()
            when {
                input1.length == 0 || input2.length == 0 -> Toast.makeText(this, getString(R.string.fill_field), Toast.LENGTH_SHORT).show()

                !Utils.isConnected(this@SoapActivity) -> Toast.makeText(this, getString(R.string.no_internet), Toast.LENGTH_SHORT).show()

                else -> getCitiesOfCountry().execute(input1,input2)
            }
        }
    }

    inner class getCitiesOfCountry : AsyncTask<String, String, String>() {

        override fun doInBackground(vararg params: String?): String {
            val response = CallWebService().callApi(Utils.METHOD_ADD, params[0], params[1])
            Log.v("response", "response==" + response)
            return response
        }

        override fun onPostExecute(result: String?) {
            super.onPostExecute(result)
            Log.v("response", "OnPostresponse==" + result)
            try {
                resultValue.text = getString(R.string.result)+" "+result
            } catch (e: Exception) {
                e.printStackTrace()
            }

        }
    }
}

CallWebService.kt

This class is to process SOAP API. Note that we have added the parameters intA and intB here. 
                            soapObject.addProperty("intA", input1)
                            soapObject.addProperty("intB", input2)

Don't forget to add the parameters, otherwise the api will throw error. 

Also the input and URL all will be posted as XML and the response will also be received as XML, later
that will be converted to string.

                            val soapPrimitive = envelope.response
                            result = soapPrimitive.toString()

class CallWebService {

    fun callApi(methodName: String, input1: String?, input2: String?): String {
        var result = ""
        val SOAP_ACTION = Utils.SOAP_NAMESPACE + methodName
        val soapObject = SoapObject(Utils.SOAP_NAMESPACE, methodName)


        soapObject.addProperty("intA", input1)
        soapObject.addProperty("intB", input2)

        val envelope = SoapSerializationEnvelope(SoapEnvelope.VER11)
        envelope.setOutputSoapObject(soapObject)
        envelope.dotNet = true
        
        val httpTransportSE = HttpTransportSE(Utils.SOAP_URL)

        try {
            httpTransportSE.call(SOAP_ACTION, envelope)
            val soapPrimitive = envelope.response
            result = soapPrimitive.toString()
        } catch (e: Exception) {
            e.printStackTrace()
        }

        return result
    }
}

Utils.kt

This class is to have all static strings and methods to be used throughout the app.

class Utils {
    companion object {
 
        val SOAP_URL = "http://www.dneonline.com/calculator.asmx?"
        val SOAP_NAMESPACE = "http://tempuri.org/"
        val METHOD_ADD = "Add"

        fun isConnected(context: Context): Boolean {
            val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
            val activeNetwork = cm.activeNetworkInfo
            return activeNetwork != null && activeNetwork.isConnectedOrConnecting
        }
    }
}

Run Application:

That's it. We are done!! Now we can run the application to get output.

 

Comments

  1. thank you very much for the example you saved my life

    ReplyDelete
  2. Thanks for the example. Is it on github or somewhere?

    ReplyDelete
  3. Do you have any idea about this problem?

    SoapFault - faultcode: 'a:ActionNotSupported' faultstring: 'The message with Action '' cannot be processed at the receiver, due to a ContractFilter mismatch at the EndpointDispatcher. This may be because of either a contract mismatch (mismatched Actions between sender and receiver) or a binding/security mismatch between the sender and the receiver. Check that sender and receiver have the same contract and the same binding (including security requirements, e.g. Message, Transport, None).' faultactor: 'null' detail: null

    ReplyDelete
  4. Tengo problemas con el SOAPObject , tendras un ejemplo??

    ReplyDelete

Post a Comment

Popular posts from this blog

RecyclerView with different number of columns using SpanSizeLookup

Map, Location update and AutoComplete Places - Kotlin

Stripe Integration in Android - Kotlin

TabLayout in Android with Kotlin

Room with LiveData, ViewModel - Android Architecture Components - Kotlin

Exploring Databinding Library in Android - Kotlin

Android JetPack - Scheduling Tasks with WorkManager

FCM Integration in Android - Kotlin

Using Camera in Android - Kotlin