Android ako SMS Gateway
V ďalšom "voľnom pokračovaní" mini-série článkov na tému ďalšieho využitia starých mobilných telefónov s Androidom, sa tento krát pokúsime urobiť z telefónu SMS bránu.
Už je to pár týždňov od vydania článku Bezpečnostná kamera z Android telefónu > link <, kde sme si jeden staručký telefón prerobili na improvizovanú bezpečnostnú kameru a nastal čas na nejaký ďalší projekt.Pod pojmom SMS Gateway (SMS brána) si môžeme predstaviť službu, cez ktorú je možné posielať SMS správy (napríklad SMS notifikácie) pre aplikácie / skripty, ktoré túto možnosť samé o sebe nemajú. Pravdepodobne ste sa už stretli s tým, že nejaký WEB od Vás vyžadoval overenie cez SMS, prípadne ste dostali SMS notifikáciu o transakcii na účte od Vašej banky. Tieto a podobné riešenia používajú nejakú formu SMS brány.V tomto článku sa samozrejme nebudem venovať tomu, ako si nejakú SMS bránu predplatiť, ale opäť siahneme do šuplíka so starými telefónmi a z jedného si SMS bránu spravíme. Toľko na úvod, pusťme sa do toho.
CALLBACK_TYPE_ERROR - Chybové hlásenie, ktoré by malo byť zvýraznené (bude červenou farbou)
CALLBACK_TYPE_RESULT - Hlásenie o výsledku odoslania SMS správy, ktoré dostaneme od triedy SmsManager a podľa výsledku zobrazíme ako informáciu alebo chybu.Ďalší súbor na vytvorenie je Functions.java, ktorý bude obsahovať metódy sendSMS a sendInfoToApp, ktoré budú v aplikácii zabezpečovať samotné odoslanie SMS správy a posielanie správ do vizuálnej časti aplikácie.
Vytvoríme preto súbor SMSGatewayService.java
A ako posledný krok nám ostalo už len doplnenie kódu MainActivity.java
Ostatné texty v seriály
Popis riešenia
Vytvoríme Android aplikáciu, ktorá bude slúžiť ako server počúvajúci na určenom porte a dáta od pripojených klientov bude odosielať ako SMS správy. Takémuto telefónu môžeme nastaviť statickú IP adresu, následne sa na neho vieme pripojiť z čohokoľvek čo umožňuje takúto komunikáciu a je na lokálnej sieti (v prípade potreby je vždy možné "otvoriť port" na routry a umožniť prístup aj mimo lokálnej siete, no treba zvážiť aj riziká s tým spojené). V našom prípade budeme používať nástroj telnet, ktorý je prítomný skoro na každom PC, prípadne je ľahko doinštalovateľný (napríklad > link <). Klient odošle riadok textu s inštrukciami v tvare sms adresát text, čiže napríklad sms +421900123456 Vas overovaci kod je: 123456" a server odpovie kódom 0 v prípade, ak bola jeho požiadavka úspešne zaznamenaná. V opačnom prípade odpovie číslom chyby. Telefón musí mať samozrejme funkčnú SIM kartu.Technické riešenie
Otvoríme si Android Studio a vytvoríme novú aplikáciu s jednoduchou Activity. Môžeme ju nazvať SMS Gateway a ako package použiť sk.codeblog.smsgateway. Na úvod si do súboru AndroidManifest.xml zapíšeme požadované oprávenia:Zdrojový kód:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" ...>... <uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.SEND_SMS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <application ...>...
Pokračujeme s layoutom hlavnej Activity, kde si na stred umiestníme TextView, v ktorom budeme zobrazovať aktuálne informácie k činnosti aplikácie:<uses-permission android:name="android.permission.SEND_SMS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <application ...>...
Zdrojový kód:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" > <TextView
android:id="@+id/tv_status"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:text="Waiting..." /></RelativeLayout>
Vytvoríme súbor Constants.java, v ktorom zadefinujeme konštanty, ktoré budeme neskôr v kóde využívať. Ako ich mená napovedajú, budeme ich používať pri predávaní informácií medzi servisom na pozadí a vizuálnou častou aplikácie.<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" > <TextView
android:id="@+id/tv_status"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:text="Waiting..." /></RelativeLayout>
Zdrojový kód:
package sk.codeblog.smsgateway;public class Constants {
public static final String CALLBACK = "SK.CODEBLOG.SMSGATEWAY.ACTIVITY_CALLBACK";
public static final String CALLBACK_TYPE = "SK.CODEBLOG.SMSGATEWAY.ACTIVITY_CALLBACK.TYPE";
public static final String CALLBACK_MSG = "SK.CODEBLOG.SMSGATEWAY.ACTIVITY_CALLBACK.MSG"; public static final int CALLBACK_TYPE_INFO = 0;
public static final int CALLBACK_TYPE_ERROR = 1;
public static final int CALLBACK_TYPE_RESULT = 2;
}
Prvé tri konštanty využijeme ako kľúče / názvy pre hodnoty v dátach Intentu, cez ktorý bude komunikácia prebiehať a zvyšné tri sú príznakmi, ktoré budú reprezentovať informáciu o type (CALLBACK_TYPE) udalosti o ktorej chceme aplikáciu informovať. CALLBACK_TYPE_INFO - Všeobecná informácia na zobrazenie, bez nejakého špeciálneho významupublic static final String CALLBACK = "SK.CODEBLOG.SMSGATEWAY.ACTIVITY_CALLBACK";
public static final String CALLBACK_TYPE = "SK.CODEBLOG.SMSGATEWAY.ACTIVITY_CALLBACK.TYPE";
public static final String CALLBACK_MSG = "SK.CODEBLOG.SMSGATEWAY.ACTIVITY_CALLBACK.MSG"; public static final int CALLBACK_TYPE_INFO = 0;
public static final int CALLBACK_TYPE_ERROR = 1;
public static final int CALLBACK_TYPE_RESULT = 2;
}
CALLBACK_TYPE_ERROR - Chybové hlásenie, ktoré by malo byť zvýraznené (bude červenou farbou)
CALLBACK_TYPE_RESULT - Hlásenie o výsledku odoslania SMS správy, ktoré dostaneme od triedy SmsManager a podľa výsledku zobrazíme ako informáciu alebo chybu.Ďalší súbor na vytvorenie je Functions.java, ktorý bude obsahovať metódy sendSMS a sendInfoToApp, ktoré budú v aplikácii zabezpečovať samotné odoslanie SMS správy a posielanie správ do vizuálnej časti aplikácie.
Zdrojový kód:
package sk.codeblog.smsgateway;import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.telephony.SmsManager;public class Functions {
public static void sendSMS(Context context, String address, String body, String clientIP)
{ Intent i = new Intent(Constants.CALLBACK);
i.putExtra(Constants.CALLBACK_TYPE, Constants.CALLBACK_TYPE_RESULT);
i.putExtra(Constants.CALLBACK_MSG, "SMS from " + clientIP); PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, android.app.PendingIntent.FLAG_ONE_SHOT); SmsManager smsManager = SmsManager.getDefault();
smsManager.sendTextMessage(address, null, body, pi, null);
} public static void sendInfoToApp(Context context, int callbackType, String message)
{
try { Intent i = new Intent(Constants.CALLBACK);
i.putExtra(Constants.CALLBACK_TYPE, callbackType);
i.putExtra(Constants.CALLBACK_MSG, message); PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, android.app.PendingIntent.FLAG_ONE_SHOT);
pi.send(); } catch (PendingIntent.CanceledException e) {
e.printStackTrace();
}
}
}
Metóda sendSMS používa už spomenutú triedu SmsManager, kde pomocou metódy sendTextMessage odosiela samotnú SMS správu. Jedným z jej parametrov je aj PendingIntent, ktorý bude odoslaný po vykonaný pokusu o odoslanie správy. Intent bude smerovaný na rovnaké miesto ako v metóde sendInfoToApp, avšak bude obsahovať inú informáciu o svojom type CALLBACK_TYPE.Nasleduje CommandThread.java, ktorý bude obsahovať rovnomennú triedu, vychádzajúcu z triedy Thread a bude slúžiť na spracovanie jednotlivých požiadaviek od klientov.import android.content.Context;
import android.content.Intent;
import android.telephony.SmsManager;public class Functions {
public static void sendSMS(Context context, String address, String body, String clientIP)
{ Intent i = new Intent(Constants.CALLBACK);
i.putExtra(Constants.CALLBACK_TYPE, Constants.CALLBACK_TYPE_RESULT);
i.putExtra(Constants.CALLBACK_MSG, "SMS from " + clientIP); PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, android.app.PendingIntent.FLAG_ONE_SHOT); SmsManager smsManager = SmsManager.getDefault();
smsManager.sendTextMessage(address, null, body, pi, null);
} public static void sendInfoToApp(Context context, int callbackType, String message)
{
try { Intent i = new Intent(Constants.CALLBACK);
i.putExtra(Constants.CALLBACK_TYPE, callbackType);
i.putExtra(Constants.CALLBACK_MSG, message); PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, android.app.PendingIntent.FLAG_ONE_SHOT);
pi.send(); } catch (PendingIntent.CanceledException e) {
e.printStackTrace();
}
}
}
Zdrojový kód:
package sk.codeblog.smsgateway;import android.content.Context;import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;public class CommandThread extends Thread{ Context context;
Socket socket;
BufferedReader input = null;
BufferedWriter output = null; public CommandThread(Context context, Socket socket)
{
this.context = context;
this.socket = socket;
} @Override
public void run() {
super.run(); try { openStreams(); String command = readFromSocket(); if (command.startsWith("sms")) {
String[] params = command.split(" ", 3);
if (params.length == 3) {
String phoneNum = params[1];
String message = params[2]; if (!phoneNum.equals("") && !message.equals(""))
{
String clientIP = this.socket.getRemoteSocketAddress().toString();
Functions.sendInfoToApp(this.context , Constants.CALLBACK_TYPE_INFO, "SMS request from " + clientIP);
Functions.sendSMS(this.context, phoneNum, message, clientIP);
writeToSocket("0: Request accepted");
}
else
{
writeToSocket("3: Invalid parameter count");
}
}
else
{
writeToSocket("2: Invalid parameter count");
}
}
else
{
writeToSocket("1: Invalid command");
} } catch (Exception e) {
e.printStackTrace();
} finally {
closeSocket();
} } private void openStreams() throws IOException {
input = new BufferedReader(new InputStreamReader(this.socket.getInputStream()));
output = new BufferedWriter(new OutputStreamWriter(this.socket.getOutputStream()));
} private void closeSocket() {
try {
if (input != null)
input.close();
} catch (Exception e) {
e.printStackTrace();
} try {
if (output != null)
output.close();
} catch (Exception e) {
e.printStackTrace();
} try {
this.socket.close();
} catch (Exception ex) {
ex.printStackTrace();
}
} private String readFromSocket() throws IOException {
return input.readLine();
} private void writeToSocket(String Message) throws IOException {
output.write(Message + "\n");
output.flush();
}
}
V preťaženej metóde run si otvoríme streamy pre načítanie požadavky od klienta a samozrejme aj na našu odpoveď. Následne si cez metódu readFromSocket načítame text požiadavky. Text požiadavky skontrolujeme, či obsahuje podporovaný príkaz (v našom prípade je to len jeden príkaz a to sms) a následne skontrolujeme počet zadaných parametrov. Ak nie sú všetky podmienky splnené, použijeme metódu writeToSocket na odoslanie chybového kódu klientovi. V prípade, ak je všetko menované splnené, pošleme informáciu o požiadavke do aplikácie (Functions.sendInfoToApp(), zadáme požiadavku o odoslanie SMS (Functions.sendInfoToApp) a nakoniec oznámime úspešné vytvorenie požiadavky klientovi (writeToSocket).Nasleduje ServiceThread.java, v ktorom si zadefinujeme pracovné vlákno servisu, ktoré bude prijímať pripojenia od klientov a posúvať ich ďalej do už definovaného vlákna CommandThread:import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;public class CommandThread extends Thread{ Context context;
Socket socket;
BufferedReader input = null;
BufferedWriter output = null; public CommandThread(Context context, Socket socket)
{
this.context = context;
this.socket = socket;
} @Override
public void run() {
super.run(); try { openStreams(); String command = readFromSocket(); if (command.startsWith("sms")) {
String[] params = command.split(" ", 3);
if (params.length == 3) {
String phoneNum = params[1];
String message = params[2]; if (!phoneNum.equals("") && !message.equals(""))
{
String clientIP = this.socket.getRemoteSocketAddress().toString();
Functions.sendInfoToApp(this.context , Constants.CALLBACK_TYPE_INFO, "SMS request from " + clientIP);
Functions.sendSMS(this.context, phoneNum, message, clientIP);
writeToSocket("0: Request accepted");
}
else
{
writeToSocket("3: Invalid parameter count");
}
}
else
{
writeToSocket("2: Invalid parameter count");
}
}
else
{
writeToSocket("1: Invalid command");
} } catch (Exception e) {
e.printStackTrace();
} finally {
closeSocket();
} } private void openStreams() throws IOException {
input = new BufferedReader(new InputStreamReader(this.socket.getInputStream()));
output = new BufferedWriter(new OutputStreamWriter(this.socket.getOutputStream()));
} private void closeSocket() {
try {
if (input != null)
input.close();
} catch (Exception e) {
e.printStackTrace();
} try {
if (output != null)
output.close();
} catch (Exception e) {
e.printStackTrace();
} try {
this.socket.close();
} catch (Exception ex) {
ex.printStackTrace();
}
} private String readFromSocket() throws IOException {
return input.readLine();
} private void writeToSocket(String Message) throws IOException {
output.write(Message + "\n");
output.flush();
}
}
Zdrojový kód:
package sk.codeblog.smsgateway;import android.content.Context;import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;class ServiceThread extends Thread { private Context context;
private ServerSocket serverSocket = null; public ServiceThread(Context context)
{
this.context = context;
} @Override
public void run() { try {
serverSocket = new ServerSocket(1234);
Functions.sendInfoToApp(this.context , Constants.CALLBACK_TYPE_INFO,"Listening..."); while (!this.isInterrupted()) {
Socket socket = serverSocket.accept();
processSocket(socket);
}
}
catch (SocketException socExcp)
{
String errMsg = socExcp.getMessage();
if (errMsg.equals("Socket closed")) { Functions.sendInfoToApp(this.context , Constants.CALLBACK_TYPE_ERROR, "Service error: " + errMsg); socExcp.printStackTrace();
} }
catch (IOException e) { this.cancel(); e.printStackTrace();
}
} public void cancel()
{
if (this.serverSocket != null)
{
try {
this.interrupt(); this.serverSocket.close();
this.serverSocket = null; Functions.sendInfoToApp(this.context , Constants.CALLBACK_TYPE_INFO, "Service interrupted");
}
catch (Exception ex) { ex.printStackTrace();}
}
} private void processSocket(Socket socket)
{
CommandThread th = new CommandThread( this.context, socket);
th.start();
}
}
Vlákno inicializuje ServerSocket na porte 1234, pošle informáciu do MainActivity a v cykle čaká na pripojenie od klientov cez metódu accept. Pripojení klienti sú následne metódou processSocket poslaný na spracovanie v novom vlákne typu CommandThread. A nakoniec je tu metóda cancel slúžiacia na ukončenie vlákna servisu.Výkonný kód servisu máme vytvorený, potrebujeme ešte samotný servis, pre ktorý bol vytvorený. import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;class ServiceThread extends Thread { private Context context;
private ServerSocket serverSocket = null; public ServiceThread(Context context)
{
this.context = context;
} @Override
public void run() { try {
serverSocket = new ServerSocket(1234);
Functions.sendInfoToApp(this.context , Constants.CALLBACK_TYPE_INFO,"Listening..."); while (!this.isInterrupted()) {
Socket socket = serverSocket.accept();
processSocket(socket);
}
}
catch (SocketException socExcp)
{
String errMsg = socExcp.getMessage();
if (errMsg.equals("Socket closed")) { Functions.sendInfoToApp(this.context , Constants.CALLBACK_TYPE_ERROR, "Service error: " + errMsg); socExcp.printStackTrace();
} }
catch (IOException e) { this.cancel(); e.printStackTrace();
}
} public void cancel()
{
if (this.serverSocket != null)
{
try {
this.interrupt(); this.serverSocket.close();
this.serverSocket = null; Functions.sendInfoToApp(this.context , Constants.CALLBACK_TYPE_INFO, "Service interrupted");
}
catch (Exception ex) { ex.printStackTrace();}
}
} private void processSocket(Socket socket)
{
CommandThread th = new CommandThread( this.context, socket);
th.start();
}
}
Vytvoríme preto súbor SMSGatewayService.java
Zdrojový kód:
package sk.codeblog.smsgateway;import android.app.Service;
import android.content.Intent;
import android.os.IBinder;import androidx.annotation.Nullable;public class SMSGatewayService extends Service {
ServiceThread serviceThread; @Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
} @Override
public void onCreate() {
super.onCreate();
} @Override
public int onStartCommand(Intent intent, int flags, int startId) { serviceThread = new ServiceThread(this);
serviceThread.start(); return super.onStartCommand(intent, flags, startId);
} @Override
public void onDestroy() {
super.onDestroy(); if (serviceThread != null)
serviceThread.cancel();
}
}
Servis samozrejme zaregistrujeme aj do AndroidManifest.xml pred MainActivityimport android.content.Intent;
import android.os.IBinder;import androidx.annotation.Nullable;public class SMSGatewayService extends Service {
ServiceThread serviceThread; @Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
} @Override
public void onCreate() {
super.onCreate();
} @Override
public int onStartCommand(Intent intent, int flags, int startId) { serviceThread = new ServiceThread(this);
serviceThread.start(); return super.onStartCommand(intent, flags, startId);
} @Override
public void onDestroy() {
super.onDestroy(); if (serviceThread != null)
serviceThread.cancel();
}
}
Zdrojový kód:
...
<service android:name=".SMSGatewayService" />
...
<service android:name=".SMSGatewayService" />
...
A ako posledný krok nám ostalo už len doplnenie kódu MainActivity.java
Zdrojový kód:
package sk.codeblog.smsgateway;import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Color;
import android.os.Bundle;import androidx.appcompat.app.AppCompatActivity;
import android.widget.TextView;public class MainActivity extends AppCompatActivity { private TextView tv_status = null; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
try { Intent service = new Intent(this.getApplicationContext(), SMSGatewayService.class);
startService(service); setContentView(R.layout.activity_main); tv_status = (TextView) findViewById(R.id.tv_status); } catch (Exception ex) {
ex.printStackTrace();
}
} @Override
protected void onResume() {
super.onResume(); IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Constants.CALLBACK);
registerReceiver(callbackReceiver, intentFilter);
} @Override
protected void onPause() {
super.onPause(); unregisterReceiver(callbackReceiver);
} private BroadcastReceiver callbackReceiver =
new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) { int callbackType = intent.getIntExtra(Constants.CALLBACK_TYPE, 0);
String message = intent.getStringExtra(Constants.CALLBACK_MSG);
int textColor = Color.BLACK; switch (callbackType) {
case Constants.CALLBACK_TYPE_ERROR: {
textColor = Color.RED;
}
break;
case Constants.CALLBACK_TYPE_RESULT: {
int resultCode = getResultCode();
if (resultCode == Activity.RESULT_OK) {
message += "... OK";
} else {
textColor = Color.RED;
message += "... Failed";
}
}
break;
} tv_status.setTextColor(textColor);
tv_status.setText(message);
}
};
}
V metóde onCreate cez startService naštartujeme servis, načítame layout samotnej Activity a referenciu na tv_status, na ktorom budeme zobrazovať aktuálnu činnosť servisu. Zároven si zadefinujeme BroadcastReceiver, cez ktorý budeme prijímať "hlásenia" o činnosti servisu a následne ich zobrazovať. Pretažená metóda onReceive BroadcastReceiveru vyhodnotí typ prijatého záznamu a prípadne upraví farbu a text hlásenia, ktoré následne zobrazí cez tv_status.Aplikáciu môžeme skompilovať a vyskúšať na vašom telefóne. Pred tým si ale musíme pozriet, akú IP adresu má pridelenú. Dá sa to zistiť v nastaveniach sietí, v časti WIFI a v podponuke rozšírené nastavenia. import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Color;
import android.os.Bundle;import androidx.appcompat.app.AppCompatActivity;
import android.widget.TextView;public class MainActivity extends AppCompatActivity { private TextView tv_status = null; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
try { Intent service = new Intent(this.getApplicationContext(), SMSGatewayService.class);
startService(service); setContentView(R.layout.activity_main); tv_status = (TextView) findViewById(R.id.tv_status); } catch (Exception ex) {
ex.printStackTrace();
}
} @Override
protected void onResume() {
super.onResume(); IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Constants.CALLBACK);
registerReceiver(callbackReceiver, intentFilter);
} @Override
protected void onPause() {
super.onPause(); unregisterReceiver(callbackReceiver);
} private BroadcastReceiver callbackReceiver =
new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) { int callbackType = intent.getIntExtra(Constants.CALLBACK_TYPE, 0);
String message = intent.getStringExtra(Constants.CALLBACK_MSG);
int textColor = Color.BLACK; switch (callbackType) {
case Constants.CALLBACK_TYPE_ERROR: {
textColor = Color.RED;
}
break;
case Constants.CALLBACK_TYPE_RESULT: {
int resultCode = getResultCode();
if (resultCode == Activity.RESULT_OK) {
message += "... OK";
} else {
textColor = Color.RED;
message += "... Failed";
}
}
break;
} tv_status.setTextColor(textColor);
tv_status.setText(message);
}
};
}
Test SMS brány cez telnet
Otvoríme si príkazový riadok / terminál a zavoláme telnet s príslušnými parametramiZdrojový kód:
telnet xxx.xxx.xxx.xxx 1234
Po úspešnom pripojení zadáme príkaz na odoslanie sms správyZdrojový kód:
sms +4219xxyyyzzz text spravy
Následne by sme mali dostať odpoveď z našej SMS brány. Celá komunikácia by mohla vyzerať nasledovneZdrojový kód:
codeblog@codeblog-server:~$ telnet 192.168.1.78 1234
Trying 192.168.1.78...
Connected to 192.168.1.78.
Escape character is '^]'.
sms +421900123456 Test SMS brany
0: Request accepted
Connection closed by foreign host.
Trying 192.168.1.78...
Connected to 192.168.1.78.
Escape character is '^]'.
sms +421900123456 Test SMS brany
0: Request accepted
Connection closed by foreign host.
Záverom
Ak sme postupovali správne, mali by sme mať funkčný prototyp SMS brány, ktorý je následne možné rozšíriť, napríklad plnohodnotným ovládaním servisu, prípadne podrobnejším zaznamenávaním aktivít servisu aj mimo MainActivity, nejakou formou autentifikácie a pod. No, to je už nad rámec toho článku.V prípade, ak ste našli nejakú chybu alebo máte návrh na zlepšenie neváhajte zanechať komentár pod článkom.Zdrojové kódy projektu sú k dispozícii na > link <.Použité zdroje
Sending and Receiving Data with Sockets in android - tutorialspoint.com > link <Android ako SMS Gateway | 0 |
Android ako SMS Gateway II - Klientské aplikácie | 0 |
Žiadne príspevky v diskusii.
Na prispievanie do diskusie musíte byť prihlásený.