好啦,我们继续我们昨天的那个项目,昨天我们只完成了一个程序启动时的欢迎界面,但是提到了,启动那个界面时会进行版本的检查,所以今天我们就做那个版本的检查那一块。
既然要做版本检查,那肯定要有服务器啦,所以我们就用到tomcat啦,因为这个项目是Android, 所以我就不写那个服务器端的程序啦,我只用tomcat来进行一个简单的从服务器读取数据,然后更新程序。不会专门写一个服务器端来进行业务的处理。
好,废话不多说,可能有些人还没接触过Web方面的,所以我把tomcat的搭建也简单的说一下,大神可以直接跳到下面去。
首先,我们去tomcat官网上下载一个tomcat 下载地址
在这里选择是32位的还是64位的
下载下来后,安装也很简单,直接解压出来就行啦(前提是你的java环境要正确)
解压好之后,我们就可以去到它的bin目录下面,双击那个startup.bat文件啦
然后我们就会看到一个黑呼呼的界面
然后,我们去浏览器输入 http://localhost:8080/ 然后出现下面的界面,那就说明你的tomcat配置成功了
那么,我们的服务器配置好之后,我们就要用它来为我们的app做一些东西啦
首先,我们在tomcat的webapps目录下载新建一个文件夹叫Security(这个是个人喜欢的,因为我们app叫Security)
update.xml里面的内容
<?xml version="1.0" encoding="utf-8"?> <update> <version>1.0</version> <description>这里写一些这个版本的特点</description> <apkurl>http://192.168.1.5:8080/Security/new.apk</apkurl> <!--这里的ip地址一定要写你服务器所在的电脑的ip地址,我们会在Security这个目录下面放置一下new.apk的,用来更新的--> </update>
好啦,现在测试一下,在浏览器里面输入http://localhost:8080/Security/update.xml 如果能够看到我们刚刚写的update.xml里面的内容,那么,你的服务器就配置成功啦!
先恭喜你,你又会弄服务器啦!!!!!
ps:因为这个要涉及服务器这些知识,所以我们这个app运行的手机上的ip一定要和你运行tomcat那台电脑上的ip是处于同一个局域网的,当时如果有外部ip那就不同,所以最好就是电脑和手机接同一个wifi这个一般会在同一个局域网啦,当然,用模拟器就一定是在同一个局域网啦
好啦,配置好了服务器后,我们就可以继续我们的项目啦,因为要和服务器交互,那么,我们肯定要把交互的地址存起来的啦,所以我们在我们的项目的values目录下新建一个config.xml文件
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="serverUrl">http://192.168.1.5:8080/Security/update.xml</string> </resources>
好啦,现在,我们的任务是从服务器上读取到update.xml里面的内容,然后再解析它,拿到apk的下载地址,和最新的版本与当时的版本比较嘛,看一下要不要下载,所以我们就要有一个model来存放这些更新的信息了嘛
所以我们就新建一个类com.xiaobin.security.domain.UpdateInfo
package com.xiaobin.security.domain; public class UpdateInfo { private String version; private String description; private String url; public String getVersion() { return version; } public void setVersion(String version) { this.version = version; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } }
然后呢,我们要从服务器上读取到一个update.xml嘛,所以我们也要新建一个类,用来与服务器交互啦
所以新建一个类com.xiaobin.security.engine.UpdateInfoService
package com.xiaobin.security.engine; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; import android.content.Context; import com.xiaobin.security.domain.UpdateInfo; public class UpdateInfoService { private Context context; public UpdateInfoService(Context context) { this.context = context; } public UpdateInfo getUpdateInfo(int urlId) throws Exception { String path = context.getResources().getString(urlId);//拿到config.xml里面存放的地址 URL url = new URL(path); HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();//开启一个http链接 httpURLConnection.setConnectTimeout(5000);//设置链接的超时时间,现在为5秒 httpURLConnection.setRequestMethod("GET");//设置请求的方式 InputStream is = httpURLConnection.getInputStream();//拿到一个输入流。里面包涵了update.xml的信息 return UpdateInfoParser.getUpdateInfo(is);//解析xml } }
刚刚上面那个类里面有一个解析xml的操作,所以我们现在把解析xml的这个类也写一下
所以新建一个类com.xiaobin.security.engine.UpdateInfoParser
package com.xiaobin.security.engine; import java.io.InputStream; import org.xmlpull.v1.XmlPullParser; import android.util.Xml; import com.xiaobin.security.domain.UpdateInfo; public class UpdateInfoParser { public static UpdateInfo getUpdateInfo(InputStream is) throws Exception { UpdateInfo info = new UpdateInfo(); XmlPullParser xmlPullParser = Xml.newPullParser(); xmlPullParser.setInput(is, "utf-8"); int type = xmlPullParser.getEventType(); while(type != XmlPullParser.END_DOCUMENT) { switch(type) { case XmlPullParser.START_TAG : if(xmlPullParser.getName().equals("version")) { info.setVersion(xmlPullParser.nextText()); } else if(xmlPullParser.getName().equals("description")) { info.setDescription(xmlPullParser.nextText()); } else if(xmlPullParser.getName().equals("apkurl")) { info.setUrl(xmlPullParser.nextText()); } break; default : break; } type = xmlPullParser.next(); } return info; } }
好啦,现在我们回去给我们昨天写的那个SplashActivity加上一些逻辑啦
package com.xiaobin.security.ui; import android.app.Activity; import android.app.AlertDialog; import android.content.DialogInterface; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.os.Bundle; import android.view.Window; import android.view.WindowManager; import android.view.animation.AlphaAnimation; import android.widget.LinearLayout; import android.widget.TextView; import android.widget.Toast; import com.xiaobin.security.R; import com.xiaobin.security.domain.UpdateInfo; import com.xiaobin.security.engine.UpdateInfoService; public class SplashActivity extends Activity { private TextView tv_version; private LinearLayout ll; private UpdateInfo info; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.splash); getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); tv_version = (TextView) findViewById(R.id.tv_splash_version); String version = getVersion(); tv_version.setText("版本号 " + version); ll = (LinearLayout) findViewById(R.id.ll_splash_main); AlphaAnimation alphaAnimation = new AlphaAnimation(0.0f, 1.0f); alphaAnimation.setDuration(2000); ll.startAnimation(alphaAnimation); if(isNeedUpdate(version)) { showUpdateDialog(); } } private void showUpdateDialog() { AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setIcon(android.R.drawable.ic_dialog_info); builder.setTitle("升级提醒"); builder.setMessage(info.getDescription()); builder.setCancelable(false); builder.setPositiveButton("确定", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { // TODO Auto-generated method stub } }); builder.setNegativeButton("取消", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { // TODO Auto-generated method stub } }); builder.create().show(); } private boolean isNeedUpdate(String version) { UpdateInfoService updateInfoService = new UpdateInfoService(this); try { info = updateInfoService.getUpdateInfo(R.string.serverUrl); String v = info.getVersion(); if(v.equals(version)) { System.out.println("不用更新"); return false; } else { System.out.println("要更新"); return true; } } catch (Exception e) { e.printStackTrace(); Toast.makeText(this, "获取更新信息异常,请稍后再试", Toast.LENGTH_SHORT).show(); } return false; } private String getVersion() { try { PackageManager packageManager = getPackageManager(); PackageInfo packageInfo = packageManager.getPackageInfo(getPackageName(), 0); return packageInfo.versionName; } catch (NameNotFoundException e) { e.printStackTrace(); return "版本号未知"; } } }
因为我们访问了Internet。所以要在AndroidManifest里面加上权限
<uses-permission android:name="android.permission.INTERNET"/>
好啦,现在可以进行测试一下啦,只要修改update.xml里面的那个version,那样就会提示下载的啦,今天的代码有点多,而且有点乱,所以如果有什么不明白的,或出了什么问题的,都可以留言交流,
最后提示一个,记得要把服务器打开再测试,不然就没效果啦
update:
很多朋友都在这里说不能与服务器交互,其实是这样的,这个一个bug来的,这个bug就是在Android4以上,我们已经不能在主线程里面进行网络操作的啦,如果进行网络操作,就会报错
所以我们就要做一下改动,我们在onCreate方法里面开启一个线程,用来检测更新信息的
new Thread() { public void run() { try { UpdateInfoService updateInfoService = new UpdateInfoService(SplashActivity.this); info = updateInfoService.getUpdateInfo(R.string.serverUrl); } catch (Exception e) { e.printStackTrace(); } }; }.start();
private boolean isNeedUpdate(String version) { if(info == null) { Toast.makeText(this, "获取更新信息异常,请稍后再试", Toast.LENGTH_SHORT).show(); loadMainUI(); return false; } String v = info.getVersion(); if(v.equals(version)) { Log.i(TAG, "当前版本:" + version); Log.i(TAG, "最新版本:" + v); loadMainUI(); return false; } else { Log.i(TAG, "需要更新"); return true; } }
以上这些更新的信息,大家和下一篇文章一起看,就会很清楚的啦,这样子,安装apk也应该可以成功的啦!
今天源码下载