Android 调用 WebService

在 Android 开发中,调用 WebService 是一种常见的网络操作,用于与服务器端的 Web 服务进行交互。WebService 通常基于 SOAP(Simple Object Access Protocol)或 REST 协议,Android 开发中主要使用 HTTP 请求(如通过 HttpURLConnection、OkHttp 或 Retrofit)来调用 WebService。由于 SOAP WebService 在 Android 中需要处理 XML 数据,而 REST WebService 通常使用 JSON,两种方式的实现有所不同。本指南将重点讲解 Android 调用 WebService 的方法,涵盖 SOAP 和 REST,结合 HttpURLConnection 和第三方库(如 OkHttp、Retrofit),提供代码示例、注意事项和实践建议。


一、WebService 概述

  • 定义:WebService 是一种跨平台、跨语言的应用程序通信方式,通过标准协议(如 SOAP 或 REST)提供服务。
  • 类型
  • SOAP WebService:基于 XML,使用 WSDL(Web Service Description Language)定义接口,复杂但规范。
  • REST WebService:基于 HTTP,使用 JSON 或 XML,简洁且流行。
  • Android 调用方式
  • SOAP:通过 HttpURLConnection 或第三方库(如 kSOAP2)发送 XML 请求,解析 XML 响应。
  • REST:通过 HttpURLConnection, OkHttp 或 Retrofit 发送 HTTP 请求,解析 JSON/XML 响应。
  • 适用场景
  • SOAP:企业级应用、银行系统、遗留系统。
  • REST:现代 API、移动端开发。

二、准备工作

  1. 权限声明
    AndroidManifest.xml 中添加网络权限:
   <uses-permission android:name="android.permission.INTERNET" />
   <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
  1. 依赖添加
  • kSOAP2(SOAP 专用库):
    gradle implementation 'com.github.ksoap2-android:ksoap2-android:3.6.4'
  • OkHttp(REST 或通用):
    gradle implementation 'com.squareup.okhttp3:okhttp:4.12.0'
  • Retrofit(REST 推荐):
    gradle implementation 'com.squareup.retrofit2:retrofit:2.11.0' implementation 'com.squareup.retrofit2:converter-gson:2.11.0' // JSON 解析 implementation 'com.squareup.retrofit2:converter-simplexml:2.11.0' // XML 解析(SOAP)
  1. WebService 信息
  • SOAP:需要 WSDL URL、命名空间(namespace)、方法名、SOAP Action。
  • REST:需要 API 端点 URL、HTTP 方法(GET/POST 等)、请求/响应格式(JSON/XML)。
  • 示例 SOAP WSDL:http://example.com/service?wsdl
  • 示例 REST API:https://api.example.com/users
  1. 异步处理
  • Android 不允许在主线程执行网络操作,需使用子线程、AsyncTask(已废弃)或 Kotlin 协程。

三、调用 SOAP WebService

SOAP WebService 使用 XML 格式通信,Android 通常使用 kSOAP2 库简化调用,结合 HttpURLConnection 处理 XML 数据。

1. 使用 kSOAP2 调用 SOAP WebService

kSOAP2 是 Android 上调用 SOAP WebService 的常用库,支持构造 SOAP 请求和解析响应。

  • 示例 SOAP 请求
    假设调用一个天气服务,WSDL 定义如下:
  • 命名空间:http://WebXml.com.cn/
  • 方法名:getWeatherbyCityName
  • SOAP Action:http://WebXml.com.cn/getWeatherbyCityName
  • WSDL URL:http://www.webxml.com.cn/WebServices/WeatherWebService.asmx?wsdl
  • 代码示例
  import org.ksoap2.SoapEnvelope;
  import org.ksoap2.serialization.SoapObject;
  import org.ksoap2.serialization.SoapSerializationEnvelope;
  import org.ksoap2.transport.HttpTransportSE;

  public class SoapClient {
      private static final String NAMESPACE = "http://WebXml.com.cn/";
      private static final String METHOD_NAME = "getWeatherbyCityName";
      private static final String SOAP_ACTION = "http://WebXml.com.cn/getWeatherbyCityName";
      private static final String URL = "http://www.webxml.com.cn/WebServices/WeatherWebService.asmx";

      public static String callWeatherService(String cityName) {
          try {
              // 1. 创建 SOAP 请求
              SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME);
              request.addProperty("theCityName", cityName);

              // 2. 创建 SOAP 信封
              SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
              envelope.dotNet = true; // 如果是 .NET 服务,设置为 true
              envelope.setOutputSoapObject(request);

              // 3. 发送请求
              HttpTransportSE transport = new HttpTransportSE(URL);
              transport.call(SOAP_ACTION, envelope);

              // 4. 获取响应
              SoapObject response = (SoapObject) envelope.getResponse();
              StringBuilder result = new StringBuilder();
              for (int i = 0; i < response.getPropertyCount(); i++) {
                  result.append(response.getProperty(i).toString()).append("\n");
              }
              return result.toString();
          } catch (Exception e) {
              e.printStackTrace();
              return "Exception: " + e.getMessage();
          }
      }
  }
  • 使用示例(异步调用):
  new Thread(() -> {
      String result = SoapClient.callWeatherService("上海");
      runOnUiThread(() -> {
          Log.d("SOAP", result);
      });
  }).start();
  • 说明
  • NAMESPACESOAP_ACTION 从 WSDL 获取。
  • envelope.dotNet = true 用于 .NET 服务。
  • 响应是 XML 格式,需进一步解析(如使用 XmlPullParser)。

2. 使用 HttpURLConnection 调用 SOAP

如果不使用 kSOAP2,可以手动构造 SOAP XML 请求。

  • 代码示例
  import java.io.BufferedReader;
  import java.io.DataOutputStream;
  import java.io.InputStreamReader;
  import java.net.HttpURLConnection;
  import java.net.URL;

  public class SoapClientManual {
      public static String callWeatherService(String cityName) {
          HttpURLConnection conn = null;
          try {
              // 1. 创建 SOAP 请求 XML
              String soapRequest = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
                      "<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " +
                      "xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" " +
                      "xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">" +
                      "<soap:Body>" +
                      "<getWeatherbyCityName xmlns=\"http://WebXml.com.cn/\">" +
                      "<theCityName>" + cityName + "</theCityName>" +
                      "</getWeatherbyCityName>" +
                      "</soap:Body>" +
                      "</soap:Envelope>";

              // 2. 配置连接
              URL url = new URL("http://www.webxml.com.cn/WebServices/WeatherWebService.asmx");
              conn = (HttpURLConnection) url.openConnection();
              conn.setRequestMethod("POST");
              conn.setDoOutput(true);
              conn.setRequestProperty("Content-Type", "text/xml; charset=utf-8");
              conn.setRequestProperty("SOAPAction", "http://WebXml.com.cn/getWeatherbyCityName");

              // 3. 发送请求
              DataOutputStream dos = new DataOutputStream(conn.getOutputStream());
              dos.writeBytes(soapRequest);
              dos.flush();
              dos.close();

              // 4. 获取响应
              int responseCode = conn.getResponseCode();
              if (responseCode == HttpURLConnection.HTTP_OK) {
                  BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
                  StringBuilder response = new StringBuilder();
                  String line;
                  while ((line = reader.readLine()) != null) {
                      response.append(line);
                  }
                  reader.close();
                  return response.toString();
              } else {
                  return "Error: HTTP " + responseCode;
              }
          } catch (Exception e) {
              e.printStackTrace();
              return "Exception: " + e.getMessage();
          } finally {
              if (conn != null) {
                  conn.disconnect();
              }
          }
      }
  }
  • 使用示例
  new Thread(() -> {
      String result = SoapClientManual.callWeatherService("上海");
      runOnUiThread(() -> {
          Log.d("SOAP", result);
      });
  }).start();
  • 说明
  • 手动构造 SOAP XML,复杂且易出错。
  • 响应是 XML 格式,需用 XmlPullParser 或 SAX 解析(参考上一部分“Android XML 数据解析”)。
  • 推荐使用 kSOAP2 简化 SOAP 调用。

四、调用 REST WebService

REST WebService 通常使用 JSON 或 XML 格式,Android 推荐使用 RetrofitOkHttp 调用。

1. 使用 Retrofit 调用 REST WebService

Retrofit 简化 REST API 调用,适合 JSON 或 XML 响应。

  • 示例 REST API
  • URL:https://api.example.com/users
  • 响应(JSON): [ {"id": 1, "name": "Alice", "age": 25}, {"id": 2, "name": "Bob", "age": 30} ]
  • 定义模型类
  public class User {
      private int id;
      private String name;
      private int age;

      @Override
      public String toString() {
          return "User{id=" + id + ", name='" + name + "', age=" + age + "}";
      }
  }
  • 定义接口
  import retrofit2.Call;
  import retrofit2.http.GET;
  import java.util.List;

  public interface RestService {
      @GET("users")
      Call<List<User>> getUsers();
  }
  • 调用代码
  import retrofit2.Retrofit;
  import retrofit2.converter.gson.GsonConverterFactory;
  import java.util.List;

  public class RestClient {
      public static String callRestService(String baseUrl) {
          Retrofit retrofit = new Retrofit.Builder()
                  .baseUrl(baseUrl)
                  .addConverterFactory(GsonConverterFactory.create())
                  .build();
          RestService service = retrofit.create(RestService.class);

          try {
              Call<List<User>> call = service.getUsers();
              Response<List<User>> response = call.execute();
              if (response.isSuccessful() && response.body() != null) {
                  StringBuilder result = new StringBuilder();
                  for (User user : response.body()) {
                      result.append(user.toString()).append("\n");
                  }
                  return result.toString();
              } else {
                  return "Error: HTTP " + response.code();
              }
          } catch (Exception e) {
              e.printStackTrace();
              return "Exception: " + e.getMessage();
          }
      }
  }
  • 使用示例(Kotlin 协程):
  interface RestService {
      @GET("users")
      suspend fun getUsers(): List<User>
  }

  suspend fun callRestService(baseUrl: String): String = withContext(Dispatchers.IO) {
      val retrofit = Retrofit.Builder()
          .baseUrl(baseUrl)
          .addConverterFactory(GsonConverterFactory.create())
          .build()
      val service = retrofit.create(RestService::class.java)

      try {
          val users = service.getUsers()
          users.joinToString("\n") { it.toString() }
      } catch (e: Exception) {
          "Exception: ${e.message}"
      }
  }

  // 调用
  lifecycleScope.launch {
      val result = callRestService("https://api.example.com/")
      Log.d("REST", result)
  }
  • 说明
  • 使用 Gson 解析 JSON 响应。
  • 结合协程简化异步处理。
  • 支持 XML 响应(需添加 converter-simplexml)。

2. 使用 OkHttp 调用 REST WebService

OkHttp 适合需要更灵活控制的场景。

  • 代码示例
  import okhttp3.OkHttpClient;
  import okhttp3.Request;
  import okhttp3.Response;

  public class OkHttpRestClient {
      public static String callRestService(String url) {
          OkHttpClient client = new OkHttpClient();
          Request request = new Request.Builder()
                  .url(url)
                  .get()
                  .addHeader("Accept", "application/json")
                  .build();

          try (Response response = client.newCall(request).execute()) {
              if (response.isSuccessful() && response.body() != null) {
                  return response.body().string();
              } else {
                  return "Error: HTTP " + response.code();
              }
          } catch (Exception e) {
              e.printStackTrace();
              return "Exception: " + e.getMessage();
          }
      }
  }
  • 使用示例(异步调用):
  OkHttpClient client = new OkHttpClient();
  Request request = new Request.Builder()
          .url("https://api.example.com/users")
          .get()
          .build();
  client.newCall(request).enqueue(new Callback() {
      @Override
      public void onFailure(Call call, IOException e) {
          runOnUiThread(() -> Log.e("REST", "Exception: " + e.getMessage()));
      }

      @Override
      public void onResponse(Call call, Response response) throws IOException {
          if (response.isSuccessful() && response.body() != null) {
              String json = response.body().string();
              runOnUiThread(() -> {
                  Log.d("REST", json);
                  // 解析 JSON(参考“Android JSON 数据解析”)
              });
          }
      }
  });

五、注意事项

  1. 异步处理
  • 网络操作必须在子线程执行,避免 NetworkOnMainThreadException
  • 使用 Thread、OkHttp 回调、Retrofit 异步调用或 Kotlin 协程。
  1. SOAP 特定
  • 获取 WSDL 中的命名空间、方法名和 SOAP Action。
  • 使用 kSOAP2 简化 SOAP 请求,减少手动构造 XML 的复杂性。
  • 解析 XML 响应(参考“Android XML 数据解析”)。
  1. REST 特定
  • 确认 API 的请求方法(GET/POST)、参数和响应格式(JSON/XML)。
  • 使用 Retrofit + Gson/Moshi 解析 JSON。
  1. 错误处理
  • 处理 HTTP 状态码(4xx、5xx)。
  • 处理 IOExceptionSoapFault(SOAP)或 JSONException(REST)。
  • 示例:
    java if (responseCode != HttpURLConnection.HTTP_OK) { InputStream errorStream = conn.getErrorStream(); String error = new BufferedReader(new InputStreamReader(errorStream)).lines().collect(Collectors.joining("\n")); Log.e("Error", error); }
  1. 资源释放
  • 关闭 InputStreamOutputStreamHttpURLConnection
  • OkHttp 和 Retrofit 自动管理连接。
  1. 安全性
  • 使用 HTTPS 确保数据安全。
  • 验证服务器证书,避免信任所有证书。
  • 添加认证头(如 Authorization: Bearer token)。
  1. 性能优化
  • 使用 Gzip 压缩(Accept-Encoding: gzip)。
  • 缓存响应数据(参考 Cache-Control 头)。
  • 优化 XML/JSON 解析(参考“Android XML/JSON 数据解析”)。

六、学习建议与实践

  1. 学习路径
  • 了解 SOAP 和 REST WebService 的区别及协议(SOAP 使用 XML,REST 使用 JSON/XML)。
  • 掌握 kSOAP2 调用 SOAP WebService。
  • 学习 Retrofit 调用 REST WebService。
  • 结合 OkHttp 处理复杂请求(如自定义头、进度监听)。
  • 解析 XML/JSON 响应(参考“Android XML/JSON 数据解析”)。
  1. 实践项目
  • SOAP 项目:调用公开 SOAP 服务(如 http://www.webxml.com.cn/ 的天气服务),显示结果。
  • REST 项目:调用公开 REST API(如 GitHub API),解析用户数据并显示。
  • 综合项目:实现登录功能,调用 REST 或 SOAP 认证接口。
  1. 调试工具
  • Postman:测试 SOAP/REST API,验证请求/响应。
  • SoapUI:专门测试 SOAP WebService,查看 WSDL 和响应。
  • Charles/Fiddler:抓包分析 HTTP 请求。
  • Android Studio Network Profiler:查看请求详情。
  1. 推荐资源
  • kSOAP2 文档:https://github.com/simpligility/ksoap2-android
  • Retrofit 文档:https://square.github.io/retrofit/
  • OkHttp 文档:https://square.github.io/okhttp/
  • 公开 API:http://www.webxml.com.cn/(SOAP)、https://api.github.com/(REST)

七、总结

  • SOAP WebService
  • 使用 kSOAP2 简化调用,构造 XML 请求,解析 XML 响应。
  • 替代方案:HttpURLConnection 手动构造 SOAP 请求(复杂)。
  • REST WebService
  • 使用 Retrofit 简化 API 调用,结合 Gson/Moshi 解析 JSON。
  • 替代方案:OkHttp 提供灵活控制。
  • 注意事项:异步处理、错误处理、资源释放、HTTPS 安全。
  • 推荐:SOAP 使用 kSOAP2,REST 使用 Retrofit + OkHttp。
  • 实践:调用公开 WebService,解析响应,显示数据。

如果需要更详细的代码示例(如复杂 SOAP 请求、REST 认证、XML 解析)或特定场景的讲解,请告诉我!

类似文章

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注