Так получилось, что в рамках своей работы я связался с проектом по разработке приложения для общения Android и 1С. Быстрый поиск в интернете дал достаточно четкие инструкции и куски кода, которые очень быстро оформились в готовую программу, но запускаться она не хотела. Здесь я расскажу основные тонкости и способы их решения.
Первоисточники кода расписаны здесь и тут. Необходимо только подключить стороннюю библиотеку ksoap2-android, чтобы стали доступны классы SoapObject и HttpTransportSE. Старый проверенный способ скачать jar с официального репозитория и положить его в app/libs почему-то не увенчался успехом, и я стал смотреть, как подключить библиотеку используя современный Gradle. Почти на всех ресурсах было написано, что простое добавление
dependencies {
compile 'com.google.code.ksoap2-android:ksoap2-android:3.6.1'
}
должно «подтягивать» нужные ресурсы. Но этого не произошло, т.к. сам ресурс не находится в стандартных репозиториях. Значит, надо указать, откуда его скачивать. Делается это добавлением в Gradle файл проекта следующих строк:
buildTypes {
repositories {
maven { url 'https://oss.sonatype.org/content/repositories/ksoap2-android-releases' }
}
}
После этих простых действий просто синхронизируем проект, и Gradle закачает все, что нужно.
Вот код, который начинает работать после вышеописанных процедур:
public class DataLoader extends AsyncTask<Void, Void, String> {
private static final String NAMESPACE = "namespace";
private static final String URL = "http://host/wsdlAcceptor?wsdl";
private static final String SOAP_ACTION = "http://host/wsdlAcceptor";
private static final String METHOD_NAME = "testOperation";
@Override
protected void onPreExecute() {
super.onPreExecute();
}
@Override
protected String doInBackground(Void... params) {
try {
SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME);
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER10);
request.addProperty("IsFirstRequest", true);
envelope.setOutputSoapObject(request);
HttpTransportSE androidHttpTransport = new HttpTransportSE(URL);
androidHttpTransport.debug = true;
try {
androidHttpTransport.call(SOAP_ACTION, envelope);
SoapObject resultsRequestSOAP = (SoapObject) envelope.bodyIn;
System.out.println("Response::"+resultsRequestSOAP.toString());
} catch (Exception e) {
e.printStackTrace();
}
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
@Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
}
}
Не секрет, что работа с любой сетевой активностью должна делаться из отдельной асинхронной задачи. doInBackground – это стандартный метод AsyncTask. Если еще не знакомы, то вот здесь про него написано просто и очень понятно.
Сама MainActivity выглядит следующим образом:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DataLoader dl = new DataLoader();
dl.execute();
}
}
На этом приключения не заканчиваются. В моем случае запрос к серверу был закрыт Basic Auth, поэтому потребовалось куда-то вводить логин и пароль. И вот на этот вопрос однозначного ответа в интернете я не нашел. Во многих статьях был упомянут некий класс HttpTransportBasicAuthSE, в конструктор которого и передается логин с паролем. Но его было не найти в ksoap2-android, пришлось искать в интернете. Нашелся здесь. Привожу полный текст:
public class HttpTransportBasicAuthSE extends HttpTransportSE {
private String username;
private String password;
/**
* Constructor with username and password
*
* @param url
* The url address of the webservice endpoint
* @param username
* Username for the Basic Authentication challenge RFC 2617
* @param password
* Password for the Basic Authentication challenge RFC 2617
*/
public HttpTransportBasicAuthSE(String url, String username, String password) {
super(url);
this.username = username;
this.password = password;
}
public ServiceConnection getServiceConnection() throws IOException {
ServiceConnectionSE midpConnection = new ServiceConnectionSE(url);
addBasicAuthentication(midpConnection);
return midpConnection;
}
protected void addBasicAuthentication(ServiceConnection midpConnection) throws IOException {
if (username != null && password != null) {
StringBuffer buf = new StringBuffer(username);
buf.append(':').append(password);
byte[] raw = buf.toString().getBytes();
buf.setLength(0);
buf.append("Basic ");
org.kobjects.base64.Base64.encode(raw, 0, raw.length, buf);
midpConnection.setRequestProperty("Authorization", buf.toString());
}
}
}
Полагаю, комментарии к коду излишни. Уточню только, что для применения HttpTransportBasicAuthSE достаточно просто изменить строку в DataLoader
HttpTransportSE androidHttpTransport = new HttpTransportSE(URL);
на
HttpTransportBasicAuthSE androidHttpTransport = new HttpTransportBasicAuthSE(URL, "basicLogin", "authPassword");
и все начинает работать с авторизацией очень четко!
P.S.: не забывайте добавлять в Manifest разрешение на Internet
<uses-permission android:name="android.permission.INTERNET" />
Автор: Анатолий Осолодкин