0 komentarzy

Komunikacja z usługami sieciowymi przez protokół SOAP

Sierpień 9, 2011 Bez kategorii Biblioteki zewnętrzne Tutoriale

Protokół SOAP oparty o standard XML służy do komunikacji z usługami sieciowymi poprzez HTTP. Jedną z technologii, która wykorzystuje SOAP jest ASP.NET Web Services. Niestety Android domyślnie nie posiada mechanizmów obsługujących ten protokół, w związku z czym aby skomunikować nasze urządzenie mobilne z usługami sieciowymi Microsoftu należy skorzystać z biblioteki, która dostarczy nam taką możliwość. Jedną z takich bibliotek jest ksoap2-android, której przyjrzymy się w niniejszym artykule.

Przykładowa aplikacja

Do demonstracji podstawowej funkcjonalności biblioteki ksoap2-android wykorzystamy ogólnodostępną usługę sieciową, którą znajdziemy pod adresem http://www.w3schools.com/webservices/tempconvert.asmx. Jest to konwerter stopni Celsiusza na stopnie Fahrenheita.

Przygotowania

Po utworzeniu nowego projektu powinniśmy dodać do niego wymagane biblioteki. Paczkę z ksoap2-android można pobrać stąd. Informacje i link do pliku powinny znajdować się na dole strony. W tym wpisie skorzystamy z wersji 2.5.7.

Dodanie zewnętrznej biblioteki do projektu

Najprostszym sposobem na dodanie biblioteki jest wskazanie jej położenia w Build Path projektu. Aby to zrobić w Eclipse należy:

  1. Kliknąć prawym przyciskiem na nasz projekt -> Properties
  2. Wybrać dział Java Build Path -> zakładka Libraries
  3. Klinąć Add External JARs i wskazać naszą bibliotekę.

Jeżeli wszystko odbędzie się jak należy, informacje o naszej bibliotece znajdziemy w Referenced Libraries.

Oto kod źródłowy naszej aplikacji. Jak widać, pozostało nam tylko zaimplementowanie dwóch zaznaczonych metod, za pomocą których będziemy komunikować się z usługą sieciową.

public class MainActivity extends Activity {
	private EditText etConverter;
	private Button btnFahrenheitToCelsius;
	private Button btnCelsiusToFahrenheit;
	private TextView tvResult;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		etConverter = (EditText) findViewById(R.id.etConverter);
		btnCelsiusToFahrenheit = (Button) findViewById(R.id.btnCelsiusToFahrenheit);
		btnFahrenheitToCelsius = (Button) findViewById(R.id.btnFahrenheitToCelsius);
		tvResult = (TextView) findViewById(R.id.tvResult);
		initButtonsOnClick();
	}

	private void initButtonsOnClick() {
		OnClickListener listener = new OnClickListener() {
			public void onClick(View v) {
				switch (v.getId()) {
				case R.id.btnCelsiusToFahrenheit:
					convertCelsiusToFahrenheit();
					break;
				case R.id.btnFahrenheitToCelsius:
					convertFahrenheitToCelsius();
					break;
				default:
					break;
				}
			}
		};
		btnCelsiusToFahrenheit.setOnClickListener(listener);
		btnFahrenheitToCelsius.setOnClickListener(listener);
	}

	private void convertCelsiusToFahrenheit() {
		String celsius = etConverter.getText().toString();
		String fahrenheit = convertToFahrenheit(celsius);
		setConversionResult(celsius + " Celsius degree", 
							fahrenheit + " Fahrenheit degree");
	}
	
	private String convertToFahrenheit(String celsius) {
		return null;
	}

	private void convertFahrenheitToCelsius() {
		String fahrenheit = etConverter.getText().toString();
		String celsius = convertToCelsius(fahrenheit);
		setConversionResult(fahrenheit + " Fahrenheit degree", 
							celsius + " Celsius degree");
	}
	
	private String convertToCelsius(String fahrenheit) {
		return null;
	}

	private void setConversionResult(String from, String to) {
		tvResult.setText(from +" = " + to);
	}
}

Komunikacja z usługą sieciową

Zaczniemy od ustawienia kilku stałych opartych:

public class MainActivity extends Activity {
	private static final String SERVICE_URL = "http://www.w3schools.com/webservices/tempconvert.asmx";
	private static final String SERVICE_NAMESPACE = "http://tempuri.org/";
	private static final String METHOD_CEL_TO_FAHR = "CelsiusToFahrenheit";
	private static final String METHOD_FAHR_TO_CEL = "FahrenheitToCelsius";
	private static final String SOAP_ACTION_CEL_TO_FAHR = "http://tempuri.org/CelsiusToFahrenheit";
	private static final String SOAP_ACTION_FAHR_TO_CEL = "http://tempuri.org/FahrenheitToCelsius";
	...

Każde z tych pól będzie potrzebne podczas komunikacji z usługą sieciową. Na szczęście w wypadku aplikacji pisanej w ASP.NET wszystkie te dane można znaleźć wchodząc na stronę usługi sieciowej bezpośrednio z przeglądarki.

Dla jasności, oto opis każdego pola:

  • SERVICE_URL – adres URL naszej usługi,
  • SERVICE_NAMESPACE – przestrzeń nazw, którą możemy znaleźć bezpośrednio pod listą metod usługi. Informacja wygląda tak: This web service is using http://tempuri.org/ as its default namespace.
  • METHOD_… – nazwy metod, z których będziemy korzystać. Wszystkie dostępne wylistowane zostały na stronie usługi.
  • SOAP_ACTION_… – odpowiedniki wykorzystywanych metod. Można je znaleźć wchodząc na stronę każdej z metod.

Jeżeli mamy już wszystkie wymagane dane, pozostało nam zaimplementowanie metod łączących się ze wskazaną usługą.

	private String callWebService(String soapAction, String method, String attribute, String val) {
		SoapObject request = prepareRequest(method, attribute, val);
		SoapSerializationEnvelope envelope = prepareSoapEnvelope(request);
		return sendRequest(soapAction, envelope);
	}

Jak widać, całość sprowadza się do 3 kroków:

  • Przygotowanie odpowiedniego zapytania – podajemy tu metodę którą chcemy wywołać wraz z jej argumentami.
  • Opakowanie zapytania w kopertę SOAP – ustawiamy kilka właściwości koperty – m.in. wersja protokołu, wykorzystywana technologia itp.
  • Wysłanie zapytania – tu wskazujemy akcję i kopertę, którą chcemy do niej wysłać. W odpowiedzi otrzymujemy wynik z wywołanej akcji/metody.

W praktyce całość wygląda w ten sposób:

	private SoapObject prepareRequest(String method, String attribute, String val) {
		SoapObject request = new SoapObject(SERVICE_NAMESPACE, method);
		request.addProperty(attribute, val);
		return request;
	}

	private SoapSerializationEnvelope prepareSoapEnvelope(SoapObject request) {
		SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
		envelope.setOutputSoapObject(request);
		envelope.dotNet = true;
		return envelope;
	}

	private String sendRequest(String soapAction, SoapSerializationEnvelope envelope) {
		HttpTransportSE httpTransportSE = new HttpTransportSE(SERVICE_URL);
		try {
			httpTransportSE.call(soapAction, envelope);
			SoapPrimitive result = (SoapPrimitive) envelope.getResponse();
			return result.toString();
		} catch (Exception e) {
			Toast.makeText(getApplicationContext(), e.toString(),
					Toast.LENGTH_LONG).show();
			return "";
		}
	}

Teraz wystarczy tylko wywołać metodę callWebService(…) w odpowiednim miejscu i odpowiednimi danymi:

package pl.froger.soapcommunication;

import org.ksoap2.SoapEnvelope;
import org.ksoap2.serialization.SoapObject;
import org.ksoap2.serialization.SoapPrimitive;
import org.ksoap2.serialization.SoapSerializationEnvelope;
import org.ksoap2.transport.HttpTransportSE;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity {
	private static final String SERVICE_URL = "http://www.w3schools.com/webservices/tempconvert.asmx";
	private static final String SERVICE_NAMESPACE = "http://tempuri.org/";
	private static final String METHOD_CEL_TO_FAHR = "CelsiusToFahrenheit";
	private static final String METHOD_FAHR_TO_CEL = "FahrenheitToCelsius";
	private static final String SOAP_ACTION_CEL_TO_FAHR = "http://tempuri.org/CelsiusToFahrenheit";
	private static final String SOAP_ACTION_FAHR_TO_CEL = "http://tempuri.org/FahrenheitToCelsius";
	
	private EditText etConverter;
	private Button btnFahrenheitToCelsius;
	private Button btnCelsiusToFahrenheit;
	private TextView tvResult;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		etConverter = (EditText) findViewById(R.id.etConverter);
		btnCelsiusToFahrenheit = (Button) findViewById(R.id.btnCelsiusToFahrenheit);
		btnFahrenheitToCelsius = (Button) findViewById(R.id.btnFahrenheitToCelsius);
		tvResult = (TextView) findViewById(R.id.tvResult);
		initButtonsOnClick();
	}

	private void initButtonsOnClick() {
		OnClickListener listener = new OnClickListener() {
			public void onClick(View v) {
				switch (v.getId()) {
				case R.id.btnCelsiusToFahrenheit:
					convertCelsiusToFahrenheit();
					break;
				case R.id.btnFahrenheitToCelsius:
					convertFahrenheitToCelsius();
					break;
				default:
					break;
				}
			}
		};
		btnCelsiusToFahrenheit.setOnClickListener(listener);
		btnFahrenheitToCelsius.setOnClickListener(listener);
	}

	private void convertCelsiusToFahrenheit() {
		String celsius = etConverter.getText().toString();
		String fahrenheit = convertToFahrenheit(celsius);
		setConversionResult(celsius + " Celsius degree", 
							fahrenheit + " Fahrenheit degree");
	}
	
	private String convertToFahrenheit(String celsius) {
		return callWebService(SOAP_ACTION_CEL_TO_FAHR, 
				METHOD_CEL_TO_FAHR, 
				"Celsius", 
				celsius);
	}

	private void convertFahrenheitToCelsius() {
		String fahrenheit = etConverter.getText().toString();
		String celsius = convertToCelsius(fahrenheit);
		setConversionResult(fahrenheit + " Fahrenheit degree", 
							celsius + " Celsius degree");
	}
	
	private String convertToCelsius(String fahrenheit) {
		return callWebService(SOAP_ACTION_FAHR_TO_CEL, 
				METHOD_FAHR_TO_CEL, 
				"Fahrenheit", 
				fahrenheit);
	}

	private void setConversionResult(String from, String to) {
		tvResult.setText(from +" = " + to);
	}
	
	private String callWebService(String soapAction, String method, String attribute, String val) {
		SoapObject request = prepareRequest(method, attribute, val);
		SoapSerializationEnvelope envelope = prepareSoapEnvelope(request);
		return sendRequest(soapAction, envelope);
	}

	private SoapObject prepareRequest(String method, String attribute, String val) {
		SoapObject request = new SoapObject(SERVICE_NAMESPACE, method);
		request.addProperty(attribute, val);
		return request;
	}

	private SoapSerializationEnvelope prepareSoapEnvelope(SoapObject request) {
		SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
		envelope.setOutputSoapObject(request);
		envelope.dotNet = true;
		return envelope;
	}

	private String sendRequest(String soapAction, SoapSerializationEnvelope envelope) {
		HttpTransportSE httpTransportSE = new HttpTransportSE(SERVICE_URL);
		try {
			httpTransportSE.call(soapAction, envelope);
			SoapPrimitive result = (SoapPrimitive) envelope.getResponse();
			return result.toString();
		} catch (Exception e) {
			Toast.makeText(getApplicationContext(), e.toString(),
					Toast.LENGTH_LONG).show();
			return "";
		}
	}
}

Powyżej zaprezentowany został kompletny kod źródłowy Aktywności komunikującej się z usługą sieciową.

Oczywiście należy również pamiętać o dodaniu pozwolenia na połączenie z siecią w pliku AndroidManifest.xml

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

Zrzut ekranu

Kompletny kod źródłowy

Cały projekt, wraz z wymaganymi bibliotekami dostępny jest na naszym Githubie – AndroidSoapCommunication.

Komentarze (0) Subskrybuj

Prześlij komentarz

Zaloguj się lub skorzystaj z profilu:

[rpxlogin redirect="http://www.android4devs.pl" prompt="" style="large"]

Możesz również zostawić komentarz bez rejestracji, korzystając z poniższego formularza:

Musisz być zalogowany aby móc pisać komentarze.