W tym artykule pokażę, w jak prosty sposób wywoływać metody webserwisów opartych o SOAP w aplikacji mobilnej na system Android. W tym konkretnym przykładzie posłużymy się API systemu PayPal, jednak pokazane tutaj metody, sprawdzą się z dowolnym webserwisem SOAP.
Czym jest Webserwis?
Zanim przejdziemy do mięsa, warto wspomnieć czym jest webserwis. Określenie to (usługa internetowa) odnosi się do aplikacji udostępnionej w sieci (zwykle w Internecie), z którą mogą łączyć się inne aplikacje i korzystać z jej zasobów.
Usługi internetowe są obecnie bardzo popularne i praktycznie każdy większy dostawca oprogramowania udostępnia API w formie webserwisu. Dzięki temu w łatwy sposób możemy tworzyć aplikacje na telefon wyświetlające informacje z Facebooka, Twittera, pokazujące pogodę itp. Te wszystkie dane są pobierane przez aplikację mobilną z webserwisu.
Czym jest SOAP?
Skoro wiemy już czym jest usługa internetowa, to czas zapoznać się z rodzajami takich usług. Mamy dwa główne standardy tworzenia webserwisów:
- REST (Representational State Transfer)
- SOAP (Simple Object Access Protocol)
Nie wchodząc w szczegóły, SOAP był szeroko stosowany kilka-kilkanaście lat temu. Obecnie królują webserwisy REST i większość firm tworzy usługi internetowe właśnie w tym standardzie. Pomimo, iż obecnie REST jest w modzie, to przez ostatnie kilkanaście lat wiele firm stworzyło web serwisy SOAP, więc nadal, pisząc aplikację mobilną, możemy mieć konieczność korzystania właśnie z nich i o tym jest niniejszy post.
Jeśli interesuje Cię co spowodowało, że SOAP został zastąpiony RESTem, to już spieszę z odpowiedzią, gdyż jest ona mocno związana z treścią tego artykułu.
Problemy SOAP
Problem ze standardem SOAP jest taki, iż jest on w miarę skomplikowany i ciężki w użytkowniu. Oczywiście nie jest to rocket science, jednak budowanie zapytań SOAP (bazujące na XML) oraz parsowanie odpowiedzi wymaga bardziej złożonych narzędzi, takich jak:
- Biblioteka do XML
- Narzędzie generujące kod na podstawie WSDL
Na desktopach te problemy były jeszcze w miarę łatwe do rozwiązania. Większość języków i technologii posiada np biblioteki do parsowania XML, a także istnieją narzędzia do generowania kodu z WSDL.
W przypadku platform mobilnych sytuacja często jest o wiele gorsza. Niektóre języki nie posiadają bibliotek do XML, a te które takowe mają, to cierpią na brak narzędzi do generowania kodu.
Generatory kodu z WSDL
Już parę razy wspomniałem o narzędziach do generowania kodu, więc może czas wyjaśnić czym one są i dlaczego są takie istotne.
Zacznijmy jednak od tego, czym jest WSDL? Jest to plik opisujący strukturę zapytań i odpowiedzi danej usługi internetowej. Dzięki niemu wiemy jak stworzyć zapytanie, aby było poprawnie odebrane przez usługę oraz co dostaniemy w odpowiedzi. Jest to taki pradziadek Swaggera 😉
Teoretycznie mając plik WSDL programista mógłby zapytania tworzyć ręcznie, jednak jest to karkołomne zadanie, o wiele trudniejsze niż wysyłanie zapytań do API RESTowego. W związku z tym, powstały narzędzia, które analizują WSDLa i generują kod w różnych językach programowania, który może być użyty do komunikacji z usługą. W praktyce działa to bardzo dobrze. Np narzędzia takie jak Visual Studio mają taki generator wbudowany. W Javie też jest kilka profesjonalnych narzędzi (np. wsdl2Java), które sprawiają, że korzystanie z SOAP na desktopie jest proste.
W przypadku platform mobilnych, takich narzędzi jednak nie ma (lub są hobbistyczne narzędzia open source, które działają tylko w bardzo prostych przypadkach). Z tym problemem spotkałem się osobiście wiele lat temu, gdy tworzyłem aplikację BodyArchitect na system Android (więcej o niej możesz poczytać tutaj). Też miałem webserwis SOAP, z którym moja aplikacja mobilna miała „rozmawiać”. Okazało się wtedy, iż na platformach mobilnych nie jest to takie proste.
I tak pojawił się pomysł napisania własnego generatora kodu…
easyWSDL
easyWSDL jest aplikacją SaaS, która jest uniwersalnym generatorem kodu dla webserwisów SOAP. Jest rozwijana od roku 2014 i do tej pory skorzystało z niej kilkadziesiąt tysięcy użytkowników.
Obsługuje następujące języki programowania:
- Java (Android)
- Java (Pure)
- Kotlin (Android)
- Objective-C (iOS)
- Swift (iOS)
- Dart (Flutter)
Generator wspiera praktycznie wszystkie możliwe ficzery i konstrukcje, które mogą pojawić się w webserwisach SOAP (poza standardami WS-*, czyli WS-Security itp). Przez te wszystkie lata, za każdym razem gdy jakiś użytkownik znalazł błąd, to był on naprawiany i implementowany dla każdego powyższego języka. A generator jest sprawdzony w boju przez takie firmy jak: Dolby, Honeywell, Orange, Bosh i wiele innych.
Jak korzystać z easyWSDL?
Na początku warto wspomnieć, iż korzystanie z easyWSDL jest płatne. Sam generator posiada wersję darmową, ale ma ona następujące ograniczenia:
- Wygenerowany kod nie implementuje zaawansowanych ficzerów
- Wygenerowany kod implementuje tylko połowę dostępnych metod. Druga połowa jest niezaimplementowana
- Kod wygenerowany wersją bezpłatną nie może być wykorzystany w celach komercyjnych
Podsumowując, wersja bezpłatna służy do tego, aby sprawdzić, czy generator będzie działał z konkretnym webserwisem.
Korzystać z easyWSDL można na dwa sposoby:
- Przez stronę https://easywsdl.com – ten sposób działa dla wszystkich języków
- Za pośrednictwem pluginu do IDE Android Studio lub IntelliJ – z tego sposobu mogą skorzystać tylko programiści używający jednego z tych środowisk
Na potrzeby tego artykułu pokaże jak wykorzystać easyWSDL w projekcie aplikacji mobilnej na system Android (Kotlin) przez stronę internetową. Jeśli piszesz aplikację w innym języku (np Swift na iOS) to nadal wiele z tego co przedstawię w tym artykule będzie aktualne.
Nasza przykładowa aplikacja będzie bardzo prosta. Głownym elementem jest przycisk, który po kliknięciu połączy się z API system PayPal, aby pobrać aktualny stan konta. PayPal posiada dwa różne API:
- REST – jest to standardowe API, które umożliwia pobieranie danych związanych z płatnościami, fakturami, zamówieniami itp. Niestety nie obsługuje wielu funkcji, jak np. możliwość pobrania salda konta itp.
- NVP/SOAP – jest to API, które nas interesuje, gdyż ono między innymi umożliwia pobranie stanu konta PayPal. Wykorzystuje standard SOAP, co sprawia, że na mobilkach ciężko użyć. I tutaj cały na biało wchodzi easyWSDL…
Jak korzystać PayPal NVP/SOAP API?
Zanim będziemy mogli skorzystać z API systemu PayPal, należy założyć konto. Możesz to zrobić tutaj.
W celu ułatwienia developmentu, API PayPala udostępnia tryb piaskownicy, który pozwala nam na bezpieczne eksperymentowanie. Dostęp do trybu piaskownicy oraz wiele innych narzędzi pomocych podczas korzystania z API PayPal znajdziesz na stronie https://developer.paypal.com/home/.
Zanim będziemy mogli skorzystać z API, należy dostać dane autoryzujące. W odróżnieniu od REST API, (których dane do autoryzujące tworzymy na stronie https://developer.paypal.com/), to w przypadku API NVP/SOAP należy:
- Zalogować się na swoje konto PayPal i przejść do ustawień konta
![Ustawienia konta PayPal](/wp-content/uploads/2023/04/PayPal1-1024x146.png)
- Przechodzimy do sekcji Dostęp do API
![Konfiguracja danych autoryzujących PayPal](/wp-content/uploads/2023/04/PayPal2-1024x546.png)
- A następnie klikamy Zarządzaj danymi uwierzytelniającymi API w Integracja interfejsu API NVP/SOAP (wersja klasyczna)
![PayPal - dane autoryzujące API](/wp-content/uploads/2023/04/PayPal3-1024x411.png)
- Tutaj znajdziesz trzy wartości, które sobie zapisz, bo będziesz potrzebował ich w kodzie:
- Nazwa użytkownika API
- Hasło API
- Podpis
![PayPal - dane autoryzujące API](/wp-content/uploads/2023/04/PayPal4-1024x408.png)
W związku z tym, iż ten artykuł nie skupia się na korzystaniu z API PayPal, a na generatorze easyWSDL, to powyższe kroki są tylko skrótowym opisem. Jeśli chciałbyś dokładnie zapoznać się z API PayPala to odpowiednie informacje znajdziesz tutaj https://developer.paypal.com/home/.
Przykładowa aplikacja
Jak wspomniałem, w tym artykule skupimy się na generatorze easyWSDL oraz korzystaniu z webserwisów SOAP, a nie na tworzeniu aplikacji mobilnej na Androida. W związku z tym nasz projekt to głównie kod wygenerowany z szablonu Android Studio:
- Po uruchomieniu środowiska Android Studio wybieramy opcję File->New->New Project…
- Jako typ aplikacji wybieramy Phone and Tablet -> Basic Activity. Wygeneruje nam to aplikację z jedym przyciskiem, pod którym umieścimy kod do połączenia z webserwisem.
- Podajemy nazwę aplikacji oraz wybieramy Kotlin jako język programowania. Zwróć uwagę na pole Package name. Wartość z tego pola będziemy w dalszych krokach podawać w generatorze easyWSDL. Nasza testowa aplikacja ma nazwę pakietu
com.example.paypaltester
. - Klikamy Finish.
W tym momencie mamy działającą aplikację. Teraz czas wygenerować kod, który umożliwi nam połączenie się z usługą internetową PayPala. Na początek musimy zdobyć plik WSDL do naszego API. Po małych poszukiwaniach, znalazłem właściwy URL na tej stronie: https://developer.paypal.com/api/nvp-soap/PayPalSOAPAPIArchitecture/.
Nasz plik WSDL jest tutaj: https://www.paypal.com/wsdl/PayPalSvc.wsdl.
Czas przejść do easyWSDL…
Generowanie kodu w easyWSDL
Rozbijmy tą operację na poszczególne kroki:
- Zakładamy konto w serwisie https://easywsdl.com.
- Klikamy link Generate, co spowoduje przejście do strony generatora.
- W tym miejscu możemy skonfigurować nasz generator. Większość ustawień można zostawić bez zmian. Najważniejsze opcje, które możemy/musimy zmienić:
- WSDL Location – adres pliku WSDL naszego webservisu. W naszym przykładzie wprowadzamy wartość https://www.paypal.com/wsdl/PayPalSvc.wsdl.
- Platform – język programowania, w którym chcemy wygenerować kod. U nas będzie to Kotlin/Android.
- Package name – klasy w języku Kotlin lub Java zwykle są umieszczane w pakiecie. W tym miejscu możemy podać nazwę pakietu dla wygenerowanych klas. W naszym przykładzie będzie to
com.example.paypaltester.wsdl
. Zwróć uwagę, że do nazwy pakietu naszego przykładowego projektu dodałem końcówkę wsdl, co wyjaśniej w dalszej części wpisu.
Są to podstawowe opcje, które ustawiamy za każdym razem, gdy korzystamy z easyWSDL. Są też inne, które możemy zmienić: - Add MTOM transfer – MTOM transfer służy do wydajnego przesyłania dużych plików binarnych z/do webservisu. Jeśli masz taki przypadek to zaznacz tą opcję. Pamietaj jednak, że Twój webserwis musi obsługiwać transfer MTOM.
- Detect dictionaries – zaznaczenie spowoduje, że generator wykryje w pliku WSDL klasy słowników (np Hashmap, Map etc) i zamiast standardowo wygenerowanych klas, użyje wbudowanych w Kotlin (Javę) klas słowników.
- Implement Parcerable – zaznacz, jeśli chcesz aby wygenerowane klasy implementowały interface
Parcerable
- Implement Serializable – jak wyżej, z tym że chodzi o interface
Serializable
- Import documentation from wsdl – w plikach wsdl mogą znajdować się opisy (dokumentacja) typów używanych przez dany webserwis. Zaznacz tą opcję, aby zaimportować je do wygenerowanego kodu w postaci komentarzy.
![easyWSDL Generator - ustawienia](/wp-content/uploads/2023/04/easyWSDL_settings-1024x503.png)
- Gdy ustawiliśmy wszystkie opcje, czas kliknąć przycisk Generate. Po dłuższej chwili powinniśmy zobaczyć informację o zakończeniu generowania, a sam plik zip z kodem zacznie się automatycznie ściągać.
![easyWSDL zakończenie generowania](/wp-content/uploads/2023/03/easyWSDL_finish-1024x495.png)
- Rozpakujmy plik zip i zobaczmy co jest w środku:
- ReadMe.txt – zawiera najważniejsze informacje wraz z instrukcją użycia wygenerowanego kodu
- docs – dokumentacja w formacie HTML wygenerowanego kodu
- libs – zewnętrzne biblioteki, które należy dołączyć do projektu, aby kod się kompilował
- src – najważniejsza część, czyli wygenerowany kod, służący do łączenia się z naszym API
Korzystanie z wygenerowanego kodu
Teraz nadszedł czas, aby wygenerowany kod wykorzystać w naszym testowym projekcie. Przejdzmy zatem do Android Studio. Dobrą praktyką jest wydzielenie wygenerowanego kodu od reszty projektu, w związku z czym stworzyłem folder wsdl, do którego skopiuję całą zawartość katalogu src (dlatego właśnie podczas generowania do nazwy pakietu dodałem wsdl).
![Skopiowane pliki źródłowe z easyWSDL do naszego projektu](/wp-content/uploads/2023/03/AndroidStudio_easyWsdl_files.png)
Następnie należy dołączyć do naszego projektu wszystkie pliki jar znajdujące się w katalogu libs (w zależności od wybranych opcji, może nie być żadnych plików jar). W związku z tym, iż w generatorze wybrałem opcję Add MTOM transfer, to mam dwa pliki:
- apache-mime4j-core-0.8.9.jar
- apache-mime4j-dom-0.8.9.jar
Kopiuję je zatem do katalogu libs w naszym projekcie wraz z odpowiednimi wpisami w pliku build.gradle
android {
//added this section because sometimes there are conflicts during build phase
packagingOptions {
exclude 'META-INF/AL2.0'
exclude 'META-INF/LGPL2.1'
exclude 'META-INF/DEPENDENCIES'
exclude 'META-INF/NOTICE'
exclude 'META-INF/LICENSE'
exclude 'META-INF/LICENSE.txt'
exclude 'META-INF/NOTICE.txt'
}
}
dependencies {
implementation 'androidx.core:core-ktx:1.7.0'
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.8.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.navigation:navigation-fragment-ktx:2.5.3'
implementation 'androidx.navigation:navigation-ui-ktx:2.5.3'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
implementation files('libs/apache-mime4j-core-0.8.9.jar', 'libs/apache-mime4j-dom-0.8.9.jar') //<-easyWSDL dependencies
}
Czasem podczas kompilacji gradle zgłasza następujący błąd:
2 files found with path 'META-INF/DEPENDENCIES'.
Mój sposób, aby rozwiązać ten problem jest dodanie sekcji packagingOptions. Jeśli znasz czytelniku lepszy sposób, to daj znać w komentarzach.
W tym momencie kod powinien się poprawnie skompilować.
Następnym krokiem jest dodanie uprawnienia do łączenia się z Internetem. W tym celu dodajemy linijkę:
<uses-permission android:name="android.permission.INTERNET" />
w pliku AndroidManifest.xml.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/Theme.PayPalTester"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:exported="true"
android:label="@string/app_name"
android:theme="@style/Theme.PayPalTester.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Pozostaje nam dodanie kodu, który korzystając z klas wygenerowanych przez easyWSDL, połączy się z PayPalem i pobierze stan naszego konta.
Struktura wygenerowanego kodu easyWSDL
W zależności od wielkości webserwisu, wygenerowanych klas może być nawet kilkaset, dlatego skąd mamy wiedzieć od czego zacząć?
Wygenerowane klasy możemy podzielić na:
- Dane – są to wszystkie klasy, które służą do przesyłania danych z usługi internetowej. W tej kategorii mieszczą się wygenerowane enumy, kolekcje itp. Znajdziemy je jako parametry metod oraz to co one zwracają.
- Klasy serwisów – jedna lub więcej klas reprezentujących webserwis. Te klasy nas najbardziej interesują, gdyż od nich zaczynamy programowanie
- Klasy pomocnicze – wykorzystywane wewnętrznie przez easyWSDL. Zwykle nas nie interesują.
Z powyższego opisu wynika, że spośród tych wszystkich wygenerowanych klas musimy odnaleźć klasy serwisów. Możemy to zrobić na dwa sposoby:
- Na stronie easyWSDL po wygenerowaniu klas
Na poniższym obrazku pokazałem, gdzie znajduje się informacja o klasach serwisowych. Wystarczy skopiować nazwę takiej klasy i wyszukać ją wsród wygenerowanych plików
![easyWSDL - nazwy klas serwisowych](/wp-content/uploads/2023/04/easyWSDL_finish_services-1024x495.png)
- W pliku ReadMe.txt
W wygenerowanym pliku zip znajduje się plik ReadMe.txt, w którym znajduje się wiele praktycznych informacji, łącznie z instrukcją jak korzystać z kodu. Jeden z punktów zawiera pseudokod w stylu:
val service = PayPalAPISoapBinding()
service.MethodToInvoke(...)
W tym przypadku PayPalAPISoapBinding jest nazwą klasy serwisowej, która nas interesuje.
Wywołanie metody GetBalance za pośrednictwem easyWSDL
Pozostaje nam teraz po prostu użyć klasy serwisowej i wywołać wybraną metodę API. W naszym przypadku chcemy pobrać stan konta PayPal:
val service= PayPalAPISoapBinding("https://api-3t.paypal.com/2.0/")
val request= GetBalanceRequestType()
val credentials= CustomSecurityHeaderType()
credentials.Credentials= UserIdPasswordType()
credentials.Credentials!!.Username="podaj swojego użytkownika API"
credentials.Credentials!!.Password="podaj hasło "
credentials.Credentials!!.Signature="podaj podpis"
request.Version="200"
request.ReturnAllCurrencies="1"
val res=service.GetBalance(request,credentials)
var str=""
for (bal in res!!.GetBalanceResponse_1!!.BalanceHoldings)
{
str=str+bal.currencyID+" = "+bal.value+"\r\n"
}
Po wygenerowaniu klas z PayPala, domyślnie łączą się one z kontami sandboxowymi. Aby nasz kod łączył się z produkcyjnym serwerem, należy ustawić odpowiedni URL (tak jak zrobiłem to powyżej). Listę dostępnych endpointów PayPala znajdziesz tutaj.
Zwróć uwagę, że w powyższym kodzie należy podać dane autoryzujące, które stworzyliśmy wcześniej. Dodatkowo należy podać wersję (nie ma ona dużego znaczenia, 200 działa dobrze 😉 ). Parametr ReturnAllCurrencies informuje PayPal, aby zwrócił saldo dla wszystkich walut w portfelu.
Powyższy kod wywoływany jest po kliknięciu w przycisk. W związku z tym, iż operacje sieciowe nie mogą być wykonywane w wątku głównym aplikacji, wykorzystałem lifecycleScope:
lifecycleScope.launch(Dispatchers.IO) {
//kod pobierający saldo z PayPal
}
Tak wygląda nasza aplikacja z wyświetlonym stanem konta PayPal.
![Testowa aplikacja wyświetlająca stan konta PayPal](/wp-content/uploads/2023/04/PayPalBalanceApp.png)
Podsumowanie
Jak widać w naszym przykładzie, korzystanie z API SOAP na platformach mobilnych może być banalnym zadaniem, gdy skorzystamy z narzędzi do generowania, takich jak https://easywsdl.com. W przypadku chęci samodzielnego zaimplementowania całej komunikacji, byłoby to zadanie bardzo czasochłonne.
Mimo iż nasz przykład bazował na języku Kotlin i platformie Android, to w bardzo podobny (i prosty) sposób, korzystamy z easyWSDL dla pozostałych języków i platform (np. Swift, Flutter, itp).
Jeśli masz dodatkowe pytania lub pomysły na następne artykuły związane z generatorem easyWSDL, daj znać w komentarzach.
Webserwis SOAP w aplikacji Android z wykorzystaniem generatora easyWSDL
Dziękujemy za dodanie artykułu – Trackback z dotnetomaniak.pl