本来以为在java平台上用axis2生成了客户端代理类然后移植到Android平台上就好了。没想到在移植过程中出现了很多问题。说明JVM和android的DVM差距还是很大的。

JVM执行的是class文件,而DVM执行的是dex文件。

在eclipse里面开发Android程序的时候在编译时会把jar包里面的class一个个编译成DVM可执行的dex文件。当然,有个前提是jar包是放在source folder里面的。这样eclipse才会在编译程序的时候将jar包编译到apk文件中去。要不然虽然本地eclipse不会报错,但是在模拟器中会报错NoClassDefFound。

而且有的jar包是不能被dexdump.exe正确转换成dex文件的。这样就导致这个jar包不能用,后果是整个程序都不能正确运行。

我在将axis2移植到Android平台上去的时候有一些jar包转换不了。然后网上找了很多资料,都没人解决这个问题。希望如果有人解决了能共享一下下。

后来实在不行了,看网上说在Android平台都用ksoap2来调用Web Service。自己觉得解决不了axis2的问题。于是只能改变方向。学习了一下ksoap2。在ksoap2调用WCF服务的时候也出现了很多问题。好在后来慢慢都解决了。现在将我遇到的问题和解决的方案都写下来,供其他也碰到这些问题的人参考。

 

下面列举一下我碰到的问题和解决方案

1.调用是参数的说明

static String NameSpace="http://tempuri.org/"; static String URL="https://10.0.2.2:9001/test"; static String SOAP_ACTION="http://tempuri.org/ITestService/GetUser"; static String MethodName="GetUser"; 

Namespace 是你设置的服务命名空间,一般没有设置就是http://tempuri.org/

URL是你服务暴露的地址,通过这个地址可以获取wsdl。在android里面127.0.0.1代表的是模拟器的地址,而10.0.0.2代表的才是电脑的127.0.0.1。所以如果是自己本机做WCF服务器的话,程序里面应该这么设置。

SOAP_ACTION是你的wsdl里面相对应的方法的地址。

MethodName就是SOAP_ACTION最后面的那个指明ACTION的方法名。

 

2.参数传递 复杂对象

服务里面不可避免的是会传递参数,但是在可能在wcf服务端可能解析不了你传的参数。通过tcptrace截取soap后发现是参数的namespace不对应的原因。下面是一个例子

服务端代码:

User ITestService.GetUser(User u) { User user = new User(); user.UId = "Server:" + u.UId; user.UName = "Server:" + u.UName; return user; } 

User类:

[DataContract] public class User { [DataMember] public string UId; [DataMember] public string UName; } 

 

android客户端代码如下:

SoapObject requet=new SoapObject(NameSpace,MethodName); PropertyInfo perPropertyInfo=new PropertyInfo(); User user=new User(); user.setUId("123"); user.setUName("cch"); perPropertyInfo.setName("u"); perPropertyInfo.setValue(user); perPropertyInfo.setType(User.class); requet.addProperty(perPropertyInfo); SoapSerializationEnvelope envelope=new SoapSerializationEnvelope(SoapEnvelope.VER11); envelope.addMapping(User.NAMESPACE,"User",User.class);//register 这个很重要 envelope.setOutputSoapObject(requet); envelope.dotNet=true; AndroidHttpTransport transport=new AndroidHttpTransport (URL); ClientUtil.SetCertification(); //设置证书 try { transport.call(SOAP_ACTION,envelope); // SoapObject response=(SoapObject)envelope.getResponse(); // //PraseXML_SF(response); ((TextView)findViewById(R.id.txt01)).setText(String.valueOf(response.toString())); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (XmlPullParserException e) { // TODO Auto-generated catch block e.printStackTrace(); } 

android端也有一个User类,这个类是继承的BaseObject,BaseObject实现KvmSerializable接口

先BaseObject:

package CCH.Model; import org.ksoap2.serialization.KvmSerializable; import org.ksoap2.serialization.SoapObject; public abstract class BaseObject implements KvmSerializable { public static final String NAMESPACE = "http://schemas.datacontract.org/2004/07/TestService"; //public static final String NAMESPACE = "http://schemas.datacontract.org/2004/07/HL7.Base.Struct"; public BaseObject() { super(); } } 

然后是User类

package CCH.Model; import java.util.Hashtable; import org.ksoap2.serialization.PropertyInfo; public class User extends BaseObject { private String UId; private String UName; public Object getProperty(int index) { // TODO Auto-generated method stub switch (index) { case 0: return UId; case 1: return UName; default: return null; } } public int getPropertyCount() { // TODO Auto-generated method stub return 2; } public void getPropertyInfo(int index, Hashtable ht, PropertyInfo info) { // TODO Auto-generated method stub info.namespace=super.NAMESPACE;//这个很重要 switch (index) { case 0: info.type=PropertyInfo.STRING_CLASS; info.name="UId"; break; case 1: info.type=PropertyInfo.STRING_CLASS; info.name="UName"; break; default: break; } } public void setProperty(int index, Object value) { // TODO Auto-generated method stub switch (index) { case 0: UId=value.toString(); break; case 1: UName=value.toString(); break; default: break; } } public String getUId() { return UId; } public void setUId(String uId) { UId = uId; } public String getUName() { return UName; } public void setUName(String uName) { UName = uName; } }  

因为要序列化啊什么什么的,解释起来比较烦。这边也不解释了。大家有兴趣可以去查一下。只说明一下是通过info.namespace+info.name来反序列化的。

 

3.如果有证书加密,会一直说timeout。

解决方法是在android客户端调用下面这个方法。这个方法要在httptransport.call()之前调用

 

ClientUtil.SetCertification(); //设置证书

类是这么写的:

public class ClientUtil { //设置证书被信任 public static void SetCertification() { try { HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier(){ @Override public boolean verify(String hostname, SSLSession session) { // TODO Auto-generated method stub return true; }}); SSLContext context = SSLContext.getInstance("TLS"); context.init(null, new X509TrustManager[]{new X509TrustManager(){ public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {} public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {} public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; }}}, new SecureRandom()); HttpsURLConnection.setDefaultSSLSocketFactory( context.getSocketFactory()); } catch (Exception e) { e.printStackTrace(); } } }  

这个信任一切证书。应为自制的证书是不被信任的,所以shakehand的时候一直timeout。

4.wcf设置的自定义帐号密码认证(userNameAuthentication  )

加入这个之后要在soap发送前在head里面加入用户信息。

加入的方法是:

/* * authenticator 加入密码账号验证 * */ ServiceConnection connection=super.getServiceConnection(); String Login=Base64.encode("cch:cch1".getBytes()); connection.setRequestProperty("Authorization","Basic "+Login);  

这个需要重写httptransport的getServiceConnection()方法。

因为在调用httptransport.call()的时候Connection才被初始化,所以在程序外getServiceConnection().setRequestProperty()会报错说nullpoint。

 

希望对大家有所帮助。

 

贴一下解析代码:

int resultCount=response.getPropertyCount(); ArrayList list=new ArrayList(); for (int i = 0; i < resultCount; i++) { SoapObject item = (SoapObject)response.getProperty(i); String sdzbh = item.getProperty("Sdzbh").toString(); String sfm = item.getProperty("Sfm").toString(); Dy_sdzbh modelDySdzbh=new Dy_sdzbh(); modelDySdzbh.setSfdzbm(sdzbh); modelDySdzbh.setSfm(sfm); list.add(modelDySdzbh); } for (int i = 0; i < resultCount; i++) { java.lang.System.out.println(list.get(i).getSfm()); } 

更多相关文章

  1. Android(安卓)targetSdkVersion了解一下
  2. 详解Android中AsyncTask的使用
  3. android实现分享给好友功能
  4. Android中native进程内存泄露的调试技巧
  5. Android——面试笔试集锦
  6. Android下使用dlopen函数动态调用.so链接库
  7. Android使用JNI生成.so文件并调用(使用传统生成.h的方法)
  8. Android实现分享(Share)功能
  9. Android基础 : Android(安卓)Service

随机推荐

  1. Android进程间通信IPC机制Binder
  2. android 操作sdcard中的多媒体文件(一)——
  3. Android(安卓)Studio 3.6 正式版终于发布
  4. Android高性能编程
  5. android开机动画制作与播放原理简介
  6. Android的系统架构
  7. Android系列教程之Android项目的目录结构
  8. android Widget添加过程和android添加wid
  9. Android核心分析(17) ------电话系统之rilD
  10. android蓝牙遥控车