首页 > 代码库 > 基于 Android 和 WCF 技术的软件开发

基于 Android 和 WCF 技术的软件开发

最近,同学的同学找我做了一款简单的安卓手机软件,第一次,一个人,做一个完整的项目。所以,在这里总结一下完整的开发流程和步骤,方便后来人入门学习。


其实,我是一个新手,没有系统的学过android也没有系统的学过WCF,这些都是自己一点一点尝试出来的。


先说一下我的基础:

  • 安卓在三年前接触过,当时乱看一气。主要看的网站就是这个(http://www.fenby.com);
  • 今年三月份,深入学习了数据库相关知识,对于数据的增删改查,三范式,E-R有了深刻了解;
  • 今天五月份,负责一个软件开发的服务器端的接口编写,也就是用WCF技术实现接口。

如今,自己做了一个项目。下面开始正式的项目介绍。

本系统设计三部分内容:
  • 数据库的设计;
  • 服务器端接口开发;
  • Android客户端功能实现和接口调用。

数据库的结构设计


说实话,数据库的设计完全就是另外一门技术,能够“设计表的结构,灵活使用增删改查等语句”,就够了。

设计的时候,要符合三范式,注意表和属性的命名规范即可。

在这里推荐大家使用一个PowerDesigner软件,这个软件上手快,可视化的方式设计E-R图,自动生成各种数据库系统sql脚本,还能快速生成用户字典等文本文件。在这里就不多说了,读者可以自己了解。这个软件只是提高效率仅此而已。


值得强调一下



前期使用阿里云服务器ECS,这一个服务器就够了,这个服务器及可以配置IIS发布站点也可以安装数据库,用这一个就够了。
技术分享


后期,数据明显数据量剧增,就需要使用阿里云数据库RDS,使用MySQL数据库会比SQL Server 每个月的使用费用便宜一点,毕竟MySQL开源嘛,所以,推荐使用MySQL数据库。所以,最开始做项目的时候,就推荐使用MySQL数据库。
技术分享



关于云服务器ECS

我还想说点:(反正我是第一次用的时候,好多迷惑)


  1. 上面说了,一开始部署的时候不用租用“阿里云数据库RDS”;
  2. 购买完以后,会给你服务器IP,自己设置账号密码以后,就可以在自己电脑上进行远程操作啦;
  3. 在服务器中发布站点和在自己电脑发布站点的步骤一样,没有什么特殊的。
远程操作:
  1. 开始菜单那输入 mstsc;
  2. 输入账号密码即可。
技术分享



服务器端


服务器概述

这一部分主要由两部分组成:

  • 接口的编写(VS 2013 的.NET平台WCF技术)
  • 接口的部署(IIS)

接口的编写

本人第一次接触WCF技术的时候,是由一位在职场工作多年的技术经理告诉我的,也就是他带领我完成了今年五月份的项目。


要做好WCF部分工作,要注意一下几个方面:

  • 什么是WCF技术?
  • 怎么创建一个WCF工程?
  • 怎么调试和运行一个WCF工程?
  • WCF怎么和数据库建立链接?
  • 怎么配置数据库服务器的连接地址(也就是IP)?
  • 返回值用什么样的规范?如何编写返回值?


什么是WCF技术

这个大家自己百度就好了,我就不抄袭别人的东西了。(  传送门:WCF技术 - 百度百科  )。其实,我没管那么多,能用就行。



怎么创建一个WCF工程

这个,也来一个传送门吧!(  传送门:新建WCF项目  )



如何调试和运行一个WCF工程

在上面的博客连接中已经有说明,这里在强调一下。F5快速调试。(就是这么厉害)



 WCF怎么和数据库建立连接

其实,WCF和SQL Server 还是很好连接的,毕竟都是微软自家东西(  传送门:WCF的数据库连接和访问  )


配置数据库服务器的连接地址(也就是IP)

不过,按照上面的方式,就把数据库的连接字符串写在程序内部了,如果服务器IP地址改变,或者更换服务器的时候,就需要重新打开原项目工程进行IP地址的修改(最终的编译结果会生成一个dll文件),这是一件我们不愿意做而且很麻烦的事情,所以,要注意,把连接字符串写在web.config文件中。这样就可以灵活的修改IP地址。(传送门:连接字符串的修改操作)



返回值用什么样的规范?如何编写返回值?

对于WCF而言,返回值都是用JSON串的形式返回的,所以,对于一般的查询结果我们可以自己拼接出来返回一个状态值。


例如:如果验证这个用户是否合法,就可以返回

  • {"State" :1}表示合法;
  • {“State” :0}表示不合法;
  • {“State” :2}表示服务器异常。


当然,你还可以选择自己增加更多的内容。例如:

  • {“UserID” :10001 , "Token" : "8fc043eb-0722-4c11-a0f4-8b9194066a35"}  //返回用户ID和令牌(GUID)。


只要把你想要返回的东西以JSON格式返回就可以了,剩下的就是Android客户端的调用。如何调用,我们会后续讲解。


对于WCF返回JSON格式,有一个现成的dll文件,直接引用即可。(  传送门:用NuGet安装NewtonSoft.json  )


IIS环境配置和接口发布

其实,对于这样的项目工程而言,接口的发布之前还需要Android端和接口在线调试。也就是说,一个人开打VS2013,另一个人打开ADT,面对面直接调试,这样VS端的可以打断点,当Android端的调用接口的时候,VS会自动停在断点处,这样调试和查看参数更加方便。(这个没有找到对应的传送门,后面讲解)


本节三部分组成:

  • IIS环境配置
  • 在线调试
  • 接口发布


IIS环境的配置

在调试和接口发布之前,一定要配置好IIS环境。


关于IIS环境的配置,推荐两个博客结合安装(  传送门:IIS部署和WCF发布  IIS部署  )


这两个博客把WCF发布的内容也讲述了,其实,现在还没有到发布的时候,此时需要的是IIS配置好以后,进行在线调试,等一切都调试通过以后,就可以发布了。



在线调试

这个没有找到合适博客,在这里,本人说明一下。


打开IIS配置文件

技术分享

按照上面的步骤,打开IIS配置文件。


找到对应的绑定

在VS调试的时候,你就可以知道自己的调试端口号是什么,然后就“ctrl + F”找到对应的端口即可,赋值当前行,把localhost改为本机IP地址,保存,关闭。

技术分享


打开防火墙

如图,按照序号操作,为了简化文章长度,我把最后的显示结果截成此图,实际上,三个窗体的显示顺序整好与现在的层级显示关系相反。

技术分享

剩下的就不说了,百度上有打开防火墙端口的教程。(  传送门:打开防火墙端口  )


添加服务

技术分享

技术分享

只需要把localhost修改为本机IP即可。


通过以上步骤,Android客户端就可以访问这个连接了。也就是,同一个局域网的用户,都可以访问这个网站了。


剩下的工作就是在线调试。


接口发布

这个接口发布和上面的调试有什么区别呢?


这个问题问的好。

  • 上面的调试是在VS打开的情况下才可以访问,而且端口号是VS自己确定的;
  • 此时的发布完全由自己控制,就是自己发布一个网站的过程,端口号(如果和上面的端口号不一样,要打开防火墙端口号)可以任意设置,而且不打开VS也可以访问网站。


在上文中已经发过博客链接,在这里,再发一次(传送门:WCF发布   重点看第三部分


还有一点值得说明,在自己发布接口的根目录下,新建一个文件夹,用于存放签名且加固好的APK,以此来提供用户下载。


但是,在网页中,下载APK需要一些站点的设置,请看传送门(  如何配置IIS使其支持APK文件的下载  )


Android客户端的开发



此部分分为两部分设计:

  • 基本的界面设计和控件使用触发事件的响应
  • 服务器接口调用


界面的设计

不同软件类型的开发,使用的界面控件和布局效果肯定大不一样,所以,在这里,只说明本人在制作软件过程中使用到的相关技术和知识。



数据的存储问题

例如,当用户登陆过apk以后,肯定不希望下一次登录的时候还输入账号密码等信息,所以,此时需要把用户输入的数据进行本地存储,安卓平台有五种数据存储方式,我使用的是“用SharedPreferences存储数据”。这个相对简单,而且只是三两个数据,这个足够了。(  传送门:Android平台进行数据存储的五大方式  )


// 保存登录数据:账号,密码,ID,令牌 到 data 文件中
SharedPreferences sp2 = (LoginActivity.this).getSharedPreferences("data",MODE_PRIVATE);
SharedPreferences.Editor editor = sp2.edit();// 获取编辑对象

//editor.clear();
editor.putString("USERID", uid);
editor.putString("PASSWORD", psw_md5.getMD5(psw));
editor.putInt("ID", id);
editor.putString("TOKEN", token);

editor.commit();// 提交保存修改

// 用户退出,清空data中的数据
SharedPreferences sp = ExitActivity().getSharedPreferences("data", MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();// 获取编辑对象
editor.clear();

editor.commit();// 提交保存修改



自定义ListView控件

这个技术在安卓开发中利用的最多了,纵观网上各种做法,推荐这篇博客(  传送门:Android 自定义ListView)



ListView的滚动事件

如何监听ListView的滚动事件?如果内容滑动到最底部,如何加载新数据?


在网上发现了这篇文章,感觉不错,大家可以看看。(  传送门:ListView加载数据  )


其实,ListView加载数据的事件就是这个,在loadData()的地方写好自己的数据加载代码即可。

listview.setOnScrollListener(new OnScrollListener() {
         //AbsListView view 这个view对象就是listview
         @Override
      public void onScrollStateChanged(AbsListView view, int scrollState) {
        if (scrollState == OnScrollListener.SCROLL_STATE_IDLE) {
          if (view.getLastVisiblePosition() == view.getCount() - 1) {
            loadData();
          }
        }
      }
      @Override
      public void onScroll(AbsListView view, int firstVisibleItem,
          int visibleItemCount, int totalItemCount) {
           lastItem = firstVisibleItem + visibleItemCount - 1 ;
      }
});

就简单的列举几个吧!做项目的时候,每个人都会遇到各种不一样的问题,自己百度解决就好了。


接口调用

这才是,重点!!!



调用接口,编写客户端函数

对于WCF这样的服务器接口,一般来说,推荐使用KSOP。这个还是跟简单的,在服务器中,包含很多接口,那么在自己的客户端上,你就对应设计每个接口即可。


为了有所了解,请先看文章(传送门:Android平台调用WebService详解   Android调用WCF   Android调用C#的WebService),这三篇文章写的很好,很详细。


不过,我还是贴一段代码,来显示一下我认为的规范开发。

package com.DLMU.freeride.WCFService;

import java.io.IOException;

import org.ksoap2.SoapEnvelope;
import org.ksoap2.serialization.SoapObject;
import org.ksoap2.serialization.SoapSerializationEnvelope;
import org.ksoap2.transport.HttpTransportSE;
import org.xmlpull.v1.XmlPullParserException;

import android.util.Log;

public class Services {

	private static String NameSpace = "http://tempuri.org/";
	private static String URL = "http://你的IP:端口号/Service1.svc";

	private static String MethodName_login = "login";

	public String Login(String phonenum, String password) {

		String methodName = MethodName_login;

		// 指定WebService的命名空间和调用的方法名
		SoapObject soapObject = new SoapObject(NameSpace, methodName);

		// 设置需调用WebService接口需要传入的参数token
		soapObject.addProperty("phonenum", phonenum);
		soapObject.addProperty("password", password);

		// 生成调用WebService方法的SOAP请求信息,并指定SOAP的版本
		SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(
				SoapEnvelope.VER11);

		envelope.bodyOut = soapObject;

		// 设置是否调用的是dotNet开发的WebService
		envelope.dotNet = true;

		// 等价于envelope.bodyOut = rpc;
		envelope.setOutputSoapObject(soapObject);

		HttpTransportSE trans = new HttpTransportSE(URL);
		trans.debug = true; // 使用调试功能

		try {
			// 调用WebService
			String SOAP_ACTION = "http://tempuri.org/IService1/" + methodName;
			Log.d("WCF", SOAP_ACTION);
			trans.call(SOAP_ACTION, envelope);
		} catch (IOException e) {
			System.out.println("IOException");
			e.printStackTrace();
		} catch (XmlPullParserException e) {
			System.out.println("XmlPullParserException");
			e.printStackTrace();
		}

		// 获取返回的数据
		SoapObject result = (SoapObject) envelope.bodyIn;

		// 获取返回的结果
		String json = null;

		if (result == null) {
			json = "接口调用失败";
		} else {
			json = result.getProperty(0).toString();
		}
		Log.d("WCF", json);
		return json;
	}

}

注意这里,一个参数的大小写要和服务器接口的大小写保持一致,而且先后顺序也不能改变。

// 设置需调用WebService接口需要传入的参数token
soapObject.addProperty("phonenum", phonenum);
soapObject.addProperty("password", password);


3.2.2  接口的实际调用

如果你认为,编写完对象中的方法就能直接调用,那你就错了。使用接口函数的时候还要注意一点。见代码

try {

	Thread thread = new Thread(new Runnable() {
		
		@Override
		public void run() {
			Services s = new Services();
			String result = s.Login(uid, psw);

			if (result.length() >= 12) {
				//在我的接口中,定义{"State":0},表示账号密码错误,长度为11
				//合法用户应该返回:{“UserID” :10001 , "Token" : "8fc043eb-0722-4c11-a0f4-8b9194066a35"},长度大于11
				//所以用12来做比较

				// 身份合理,正确跳转
				Intent intent = new Intent(
						LoginActivity.this,
						MainActivity.class);
				startActivity(intent);
				finish();
				
			} else {
			
				Looper.prepare();
				Toast.makeText(LoginActivity.this,
						"账号或密码错误", Toast.LENGTH_SHORT)
						.show();
				Looper.loop();
				
			}
		}
	});
	thread.start();
	
} catch (Exception e) {
	e.printStackTrace();
}

注意,接口调用要写在线程中,而且要try{}catch{}。


到此,接口的工作就完成了,因为接口返回的数据格式是JSON串,所以,需要在客户端进行JSON串解析。

//{
// [{"ID":1,"TEL":"123456"}],
// [{"ID":2,"TEL":"123457"}],
// [{"ID":3,"TEL":"123458"}],
// [{"ID":4,"TEL":"123454"}]
//}

JSONTokener jsonTokener = new JSONTokener(data);
JSONArray array = (JSONArray) jsonTokener.nextValue();
				
for (int i = 0; i < array.length(); i++) {
				
	// 提取数据
	JSONObject item = array.getJSONObject(i);
	int id = item.getInt("ID");
	String tel = item.getString("TEL");
					
}

根据上面的例子,我对于一个JSON串,如果遇到{[],[],[]},我们需要先使用JSONArray;如果遇到{},我们使用JSONObject来获取数据。


至此,教程结束。



一个上午的时间,都在编写这教程。

其实,做一个安卓手机联网软件不是很难。大家都可以试试。

其实就由两部分组成:客户端 + 服务器。

搞好客户端,写好服务器,做好客户端的接口调用,部署好服务器的站点,足矣。


基于 Android 和 WCF 技术的软件开发