Biblioteka Java SMS API

Java od wielu lat utrzymuje się w ścisłej czołówce najpowszechniejszych języków programowania na świecie. SMSAPI wychodzi temu trendowi naprzeciw dzięki udostępnieniu gotowej biblioteki Java do obsługi komunikacji SMS. Jeśli więc Twoje programy są napisane właśnie w tym języku, to czytaj dalej!

Jak wszystkie biblioteki SMSAPI, ta również jest w całości udostępniona na GitHubie. Tam też możesz obejrzeć kod źródłowy. To oczywiście najpewniejsze źródło informacji o jej działaniu i możliwościach. Natomiast w tym poradniku przybliżam bibliotekę Java znacznie przystępniej, tak aby stworzenie własnej aplikacji było prostsze niż wstawienie kawy w firmowym automacie. Zaczynajmy!

Instalacja biblioteki do obsługi SMS w Javie

Na początek, dołącz pliki biblioteki Java do Twojego projektu. Możez to zautomatyzować korzystając z narzędzia Maven. W pliku konfiguracyjnym POM wystarczy dodać po jednym elemencie do list repozytoriów i zależności.

<repositories>
	<repository>
		<releases>
			<enabled>true</enabled>
			<updatePolicy>always</updatePolicy>
			<checksumPolicy>fail</checksumPolicy>
		</releases>
		<id>smsapi</id>
		<name>smsapi</name>
		<url>https://labs.smsapi.com/maven/</url>
		<layout>default</layout>
	</repository>
</repositories>

<dependencies>
	<dependency>
		<groupId>pl.smsapi</groupId>
		<artifactId>smsapi-lib</artifactId>
		<version>2.5</version>
	</dependency>
</dependencies>

Na serwerze SMSAPI znajdziesz wersje biblioteki od 1.1 aż do 2.5. Zawierają one archiwa JAR z kodem źródłowym, skompilowanym kodem bajtowym, szczegółową dokumentacją wygenerowaną przez Javadoc oraz pliki POM.

Jeśli do zarządzania rozwojem aplikacji wybrałeś narzędzie Gradle, to skorzystanie z biblioteki SMSAPI w Javie jest równie łatwe. Do pliku build.gradle dodaj odwołania do wtyczek do Javy oraz jej bibliotek:

plugins {
	id 'java'
	id 'java-library'
}

Do repozytoriów dołącz bibliotekę SMSAPI:

repositories {
	mavenCentral()
	maven {
		url 'https://labs.smsapi.com/maven/'
	}
}

Ostatnia rzecz to dodanie biblioteki w odpowiedniej wersji do zależności Twojego projektu:

dependencies {
	api 'pl.smsapi:smsapi-lib:2.5'
}

Początek aplikacji obsługującej wysyłki SMS w Javie: konfiguracja

Przed rozpoczęciem właściwego programowania potrzeba zrobić jeszcze jedną podstawową rzecz: załóż konto SMSAPI!

Umożliwi to nam rozpoczęcie współpracy. Panel Klienta to graficzny interfejs, za pomocą którego możesz ręcznie obsługiwać całą Twoją kampanię SMS. Znajdziesz tam opcje: ustawień konta, wysyłki SMS i MMS, zarządzania bazą odbiorców oraz polami nadawcy i inne. O szczegółach przeczytaj w artykułach z serii SMSAPI Zrób to sam.

Komunikacja z serwerem SMSAPI odbywa się poprzez metody HTTP: POST, GET, PUT oraz DELETE. W kodzie biblioteki obsługuje je pakiet Proxy dzięki interfejsowi Client. To niejako zaplecze biblioteki, nie musisz go dokładnie poznawać.

Do nawiązania bezpiecznego połączenia potrzeba albo pary login-hasło, albo 40-znakowego tokenu. To pierwsze rozwiązanie nie jest jednak zalecane ze względów bezpieczeństwa. Drugie wymaga wygenerowania tokenu OAuth2. Wtedy utworzenie klienta wygląda w przybliżeniu tak: 

import pl.smsapi.OAuthClient;
import pl.smsapi.proxy.Proxy;
import pl.smsapi.proxy.ProxyNative;

class Main{
	public static void main(String[] args){
		String token = "0000000000000000000000000000000000000000";
		var client = new OAuthClient(token);
		var proxy = new ProxyNative("https://api.smsapi.pl/");
	}
}

Jak widać, do połączenia z serwerem potrzebny jest jeszcze obiekt proxy. Łączy się on z jedną z dwóch domen, w zależności od tego, z której usługi korzystasz: https://api.smsapi.pl/ lub https://api.smsapi.com/. Możesz jednak pominąć jawne utworzenie proxy. Wtedy zostanie on utworzony domyślnie, łącząc się z usługą api.smsapi.pl.

Podstawowa wysyłka SMS w Javie

Czas przejść do konkretów! Działanie omawianej biblioteki opiera się na fabrykach oraz akcjach. Pierwsze odpowiadają poszczególnym funkcjonalnościom, drugie pozwalają ustawiać ich parametry.

Każdą czynność należy rozpocząć od utworzenia fabryki, a zakończyć wywołaniem funkcji execute() z klasy bazowej. Oczywiście raz utworzoną fabrykę możesz później wykorzystywać do woli. Poszerzając poprzedni listing o proste wysłanie SMS-a (proxy jest tworzony domyślnie):

import pl.smsapi.OAuthClient;
import pl.smsapi.api.SmsFactory;
import pl.smsapi.api.action.sms.SMSSend;

class Main{
public static void main(String[] args){
	var client = new OAuthClient("0000000000000000000000000000000000000000");

	var smsFactory = new SmsFactory(client);
	var actionSmsSend = smsFactory.actionSend("+48111222333", "Hello world!");
	actionSmsSend.execute();
}
}

Przydatna może okazać się możliwość łańcuchowego łączenia metod z klas akcji. Poniższy fragment zadziała identycznie:

var smsFactory = new SmsFactory(client);
smsFactory.actionSend()
	.setTo("+48111222333")
	.setText("Hello world!")
	.execute();

Biblioteka Java: masowa wysyłka SMS

Prowadzenie masowych wysyłek SMS nie obyłoby się bez możliwości wysyłania wiadomości do wielu odbiorców naraz. Fabryka SmsFactory umożliwia to bardzo prosto, dzięki przeciążeniu metod actionSend i setTo:

SendStatusResponse response = smsFactory.actionSend(
		new String[]{"+48111222333", "+48444555666"},
		"Hello receivers!")
		.execute();

SendStatusResponse response = smsFactory.actionSend()
		.setTo(new String[]{"+48111222333", "+48444555666"})
		.setText("Hello again receivers!")
		.execute();

To jednak nie wszystko. W Panelu klienta zauważysz, że odbiorców da się łączyć w grupy. Wysłanie identycznych powiadomień SMS do wszystkich członków danej grupy jest bardzo proste:

SendStatusResponse response = smsFactory.actionSend()
		.setGroup("Group_name")
		.setText("Hello group!")
		.execute();

W powyższych listingach zachowano obiekt, zwracany przez metodę execute(). W tym przypadku jest to klasa SendStatusResponse. Posiada ona metody:

  • getParts() – zwraca liczbę części, na którą podzielony został SMS.
  • getCount() – zwraca liczbę zleconych wysyłek wiadomości.
  • getList() – zwraca listę (ArrayList) obiektów klasy MessageResponse. Z kolei jej metody zwracają informacje o poszczególnych wysłanych SMS-ach. Są to:
    • getId() – unikalny identyfikator w systemie.
    • getPoints() – koszt wiadomości, wyrażony w punktach pobranych z Twojego konta.
    • getNumber() – numer odbiorcy.
    • getStatus() – jeden ze statusów doręczenia.

Ważny aspekt: planowanie wysyłki SMS

Jest jeszcze kilka praktycznych funkcjonalności omawianej biblioteki, o których warto wspomnieć. Pierwszą jest planowanie wysyłki SMS na przyszłość. Odpowiednia data i godzina dostarczenia powiadomienia do Twoich klientów ma kluczowy wpływ na ich reakcję. Jaki? Sprawdź poniższy artykuł.

W swoim kodzie możesz łatwo ustawić zadany czas za pomocą metod setDateSent z akcji SMSSend. Przyjmują one albo obiekt Calendar, albo liczbę sekund od początku epoki. Ten przykład ustawi wysyłkę na 1 stycznia 2022, o 12:00:

import java.util.GregorianCalendar;

var sendDate = new GregorianCalendar(2022, 0, 1, 12, 0);
SendStatusResponse response = smsFactory.actionSend()
	.setTo("+48111222333")
	.setText("Hello in the future!")
	.setDateSent(sendDate)
	.execute();

Poniższy przykład zaś wyśle SMS-a za godzinę:

import java.util.Date;

var sendDate = new Date().getTime()/1000 + 3600;
SendStatusResponse response = smsFactory.actionSend()
	.setTo("+48111222333")
	.setText("Hello in the future!")
	.setDateSent(sendDate)
	.execute();

W ten sposób da się ustawić datę maksymalnie na 3 miesiące naprzód. Jeżeli w międzyczasie zmienisz plany, usuń SMS z harmonogramu za pomocą akcji SMSDelete. Potrzebny jest do tego wspomniany wyżej unikalny identyfikator zaplanowanego SMS-a. Wygląda to na przykład tak:

String smsIdToDelete = response.getList().get(0).getId()
smsFactory.actionDelete(smsIdToDelete).execute();

Z obiektu klasy SendStatusResponse bierzemy listę wysłanych SMS-ów, z niej – zerowy element, a z niego ID. Metodą z fabryki actionDelete tworzymy akcję, od razu podając do niej parametr i wykonujemy ją.

Jak zrobić dobre wrażenie przy pomocy kampanii SMS?

Najważniejsza jest oczywiście treść, ale ta najpewniej będzie identyczna dla mnóstwa odbiorców. Biblioteka udostępnia pewne dwa proste sposoby.

Pierwszy to pole nadawcy SMS (inaczej branding SMS). Jest to krótki tekst, wyświetlany na ekranie zamiast numeru telefonu. Nazwa ta powinna jakoś identyfikować Twoją firmę, markę lub produkt, aby od razu było wiadomo, kto pisze.

To prosta, ale zarazem przydatna w marketingu SMS metoda zwrócenia uwagi odbiorcy. Do ręcznego zarządzania polami nadawcy służy odpowiednia sekcja Panelu klienta. W kodzie możesz skorzystać z już istniejącego pola za pomocą metody akcji SMSSend:

smsFactory.actionSend()
	.setTo("+48111222333")
	.setText("Hello world!")
	.setSender("sender_name")
	.execute();

Drugi ze wspomnianych sposobów to parametryzacja wiadomości. Specjalne ciągi znaków w tekście SMS umożliwiają personalizację masowo wysyłanych wiadomości.

Dzięki temu nie będą one identyczne, ale skierowane bardziej indywidualnie do odbiorców. Możesz skorzystać z czterech pól dowolnych oraz wartości pól z bazy kontaktów. Szczegółowo opisuje je Dokumentacja. Zobaczmy na przykładzie:

smsFactory.actionSend()
	.setTo(new String[]{"+48111222333", "+48444555666"})
	.setText("Hello [%imie%], your number is [%1%]!")
	.setParam(0, new String[]{"11", "22"})
	.execute();

Teksty wszystkich (dwóch) SMS-ów zostaną zmodyfikowane dwukrotnie. Pola [%imie%] będą zamienione na odpowiednie wartości z bazy kontaktów.

Metoda setParam zapewni podmianę pola [%1%]. Pierwszy jej argument to indeks parametru, drugi to tablica stringów, wstawianych do kolejnych wiadomości zamiast ciągów specjalnych. Dostępne są cztery takie dowolne parametry: [%1%], [%2%], [%3%], [%4%], którym odpowiadają indeksy 0, 1, 2, 3.

Obsługa pól nadawcy SMS w bibliotece Java SMSAPI

Jak wspomniałem wyżej, warto skorzystać z funkcjonalności pól nadawcy SMS. Ich programową obsługę zapewnia fabryka SenderFactory oraz klasy akcji: SenderList, SenderAdd, SenderDefault, SenderDelete.

Poniższy przykład pokazuje, jak przywołać listę istniejących pól nadawców SMS, dodać nowego, ustawić go jako domyślnego i usunąć. Zakładam, że wcześniej utworzono obiekt klienta (potrzebny dla fabryki).

var senderNameFactory = new SenderFactory(client);
SendersResponse response = senderNameFactory.actionList().execute();
for (SenderResponse elem: response.getList()){
	System.out.println(
		"Sender name: "+elem.getName()
		+"Sender status: "+elem.getStatus()
		+"is default?: "+elem.isDefault()
	);
}
senderNameFactory.actionAdd("NewSenderName").execute();
senderNameFactory.actionSetDefault("NewSenderName").execute();
senderNameFactory.actionDelete("NewSenderName").execute();

Pole nadawcy wiadomości musi spełniać pewne wymogi. Najważniejsze, to pamiętać, że ze względów bezpieczeństwa każde nowe pole musi być zatwierdzone przez naszego pracownika w godzinach pracy SMSAPI.

Obsługa błędów w bibliotece Java SMS API

Podczas automatycznej obsługi SMS-ów mogą wystąpić błędy, i to w wielu miejscach. Przykładowo: w łączeniu się z serwerem, konstruowaniu zapytań, stosowaniu różnorodnych parametrów oraz przetwarzaniu odpowiedzi z serwera. Kiedy coś pójdzie nie tak, serwer zamiast oczekiwanej odpowiedzi wyśle kod i wiadomość błędu.

Szczegółową listę kodów znajdziesz w Dokumentacji. Przed błędami warto się zabezpieczyć, dlatego omawiana biblioteka definiuje kilka klas wyjątków.

  • ClientException – te wyjątki dotyczą metod HTTP. Używane kody błędów to np. 101 (niepoprawny token OAuth2) i 103 (brak punktów do wysłania SMS).
  • HostException – oznaczają błędy po stronie serwera SMSAPI. Kody m.in. to 8 (błąd w odwołaniu) i 201 lub 999 (wewnętrzne błędy systemu).
  • ActionException – te wyjątki wynikają z niepoprawnego użycia którejś z akcji. Kod błędu 11 to za długi tekst wiadomości lub jego brak. 13 to błędny numer odbiorcy lub jednoczesne użycie grupy i pojedynczego numeru. 14 oznacza, że pole nadawcy jest nieprawidłowe; 40 – nie istnieje podana grupa.
  • ProxyException – występują przy błędzie połączenia z serwerem, nie mają kodu z SMSAPI. Są rzucane, gdy wystąpi wyjątek z klasy java.io.IOException.

Konkretne kody błędów zwraca metoda getCode(). W jednym przypadku rzucany jest jeszcze wyjątek indeksu poza tablicą (ArrayIndexOutOfBoundsException): gdy usiłowano odwołać się do parametru wiadomości o indeksie innym, niż 0, 1, 2, 3.

Biblioteka SMSAPI w Javie – inne funkcjonalności

Istnieją jeszcze inne, nieopisane wyżej fabryki, które oferują dalsze możliwości dla Twojej aplikacji w Javie. Jedną z nich jest ContactsFactory – jak łatwo się domyślić, służy do obsługi bazy kontaktów. Umożliwia listowanie, usuwanie, edycję poszczególnych odbiorców oraz ich grup. Utworzenie nowego wpisu może wyglądać w przybliżeniu tak – zakładając, że istnieje już obiekt klienta HTTP:

ContactsFactory contactsFactory = new ContactsFactory(client);
contactsFactory.actionContactAdd()
	.setFirstName("Test First Name")
	.setLastName("Test Last Name")
	.setPhoneNumber(numberTest)
	.setEmail("test@example.com")
	.execute();

Wysyłka MMS z Java

Inna fabryka o nazwie MMSFactory służy do obsługi wiadomości multimedialnych. Kluczowa jest jej metoda actionSend, która działa analogicznie, jak dla opisanej powyżej wysyłki SMS-ów.

Jej wykonanie (metodą execute()) zwraca obiekt SendStatusResponse, a za pomocą metod “set” ustawisz parametry wiadomości, takie jak odbiorca i data wysłania. Zamiast zwykłego tekstu musisz dostarczyć wiadomość w formacie SMIL oraz jej temat. Poniższy fragment zakłada, że istnieje już taka poprawna treść:

mmsFactory = new MMSFactory(client);
mmsFactory.actionSend()
	.setTo("+48111222333")
	.setSubject("test_subject")
	.setSmil(smil_content)
	.execute();

Na koniec wskażę Ci kilka miejsc, gdzie możesz szukać odpowiedzi na wszelkie powstałe pytania techniczne. Pierwsze to często już wspominana dokumentacja API. Brak jest tam nawiązań do kodu Javy, ale mnóstwo jest szczegółowych wyjaśnień. Pomogą one zrozumieć przeznaczenie poszczególnych parametrów, kodów błędów i sposobów działania różnych funkcjonalności.

Jeśli wygodnie korzysta Ci się z dokumentacji Javadoc, ściągnij jej najnowszą wersję (2.5) z serwera SMSAPI. Dzięki licznym komentarzom i przejrzystej strukturze znacznie ułatwi ona odnalezienie się wśród dostępnych klas, metod i pakietów.

Dobrym źródłem informacji są też testy jednostkowe, napisane przy użyciu JUnit. Znajdziesz je na GitHubie. Na etapie tworzenia biblioteki służyły zapewnieniu jakości, a dla Ciebie dostarczą przykładów zastosowań poszczególnych interfejsów i metod. Jeśli to dalej nie rozwieje wszystkich wątpliwości, sięgnij do najpełniejszego źródła wiedzy, czyli samego kodu biblioteki. Powodzenia!

Kilka słów o autorze