转载文章请注明出处:http://blog.csdn.net/dangxw_/article/details/17957541
ios的软件版本更新必须要通过苹果的服务器,而android 却不需要,开发商可以在软件本身嵌套下载安装新版本的功能,对于此是否是个优点暂且不谈(个人感觉还是ios那样更负责人些,用户体验更好点),只将一下实现步骤。
android区分软件是通过包名,也就是所如果两个软件的包名完全相同,系统就会认为是同一款软件,如果已经安装了,又要安装,系统则认为是在更新版本而不是安装新软件。为了避免软件之间的包名产生冲突,android 提倡用自己公司的域名作为包名,因为域名是唯一的,所以就可以很好地区分软件了。但是如果想要安装成功的话除了包名一致外,还要求签名一致。所以在更新apk时新的版本必须要用原先版本的包名和签名打包。
首先要进行网络通信,检测是否有新版本。通信方式可以是socket也可以是http。
private void isHaveUpdate() { new Thread() { @Override public void run(){ URL url; try { Log.d("!!!!!","want get version"); url = new URL("http://fd.alga7.com/Version.aspx"); HttpURLConnection urlConn = (HttpURLConnection) url.openConnection(); urlConn.setConnectTimeout(5*1000); InputStreamReader in = new InputStreamReader(urlConn.getInputStream()); BufferedReader buffer = new BufferedReader(in); String update = buffer.readLine(); Log.d("!!!!!!",getVersionName()); Log.d("!!!!!!",update); if(!getVersionName().equals(update)) { handle.sendEmptyMessage(0x1111); } Log.d("!!!!!",update); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); Log.d("!!!!!","no get version"); } } }.start(); }这里用的是http通信,getVersionName()是自己所写的一个方法,用来检测本软件版本,原理是读取androidManifest里的versionName
下面是详细代码:
private String getVersionName() throws Exception{ PackageManager packageManager = getPackageManager(); PackageInfo packInfo = packageManager.getPackageInfo(getPackageName(), 0); return packInfo.versionName; }
handle发送0x1111消息之后会发生的事:
protected void showUpdataDialog() { AlertDialog.Builder builer = new Builder(this) ; builer.setTitle("版本升级"); builer.setMessage("已发布新的版本,是否要下载升级包?"); //当点确定按钮时从服务器上下载 新的apk 然后安装 builer.setPositiveButton("下次再说", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { // TODO Auto-generated method stub } }); builer.setNegativeButton("立即更新",new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface arg0, int arg1) { // TODO Auto-generated method stub downLoadApk(); } }); AlertDialog dialog = builer.create(); dialog.show(); }当用户点击”立即更新“之后,会儿显示进度条对话框,也就是执行downloadApk()方法。需要动态显示下载进度。
protected void downLoadApk() { pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); pd.setMessage("正在下载更新"); pd.setCanceledOnTouchOutside(false); pd.show(); isDownLoad = true; new Thread(){ @Override public void run() { if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){ URL url; try { url = new URL(UrlAdress.ADDRESS_UPDATEAPK); Log.d("!!!!!!",UrlAdress.ADDRESS_UPDATEAPK); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setConnectTimeout(5000); //获取到文件的大小 pd.setMax(conn.getContentLength()); InputStream is = conn.getInputStream(); Log.d("!!!!!!",UrlAdress.ADDRESS_UPDATEAPK); File updatefile = new File(Environment.getExternalStorageDirectory()+"/Sexy.apk"); Log.d("!!!!!",updatefile.getPath()); if(updatefile.exists()) { updatefile.delete(); updatefile.createNewFile(); } updatefile.createNewFile(); FileOutputStream fos = new FileOutputStream(updatefile); BufferedInputStream bis = new BufferedInputStream(is); byte[] buffer = new byte[1024]; int len ; total=0; while((len =bis.read(buffer))!=-1&&isDownLoad){ fos.write(buffer, 0, len); total+= len; Log.d("!!!!!",String.valueOf(total)); //获取当前下载量 handle.sendEmptyMessage(0x2222); } fos.close(); bis.close(); is.close(); installApk(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); handle.sendEmptyMessage(0x3333); } }}}.start(); }
如果下载成功,会自动安装更新版本。也就是调用installApk()方法:
protected void installApk() { Intent intent = new Intent(); //执行动作 intent.setAction(Intent.ACTION_VIEW); //执行的数据类型 intent.setDataAndType(Uri.fromFile(new File(Environment.getExternalStorageDirectory()+"/Sexy.apk")), "application/vnd.android.package-archive"); startActivity(intent); }
public boolean onKeyDown(int keyCode, KeyEvent event) { if(keyCode == KeyEvent.KEYCODE_BACK&&isDownLoad) //监控/拦截/屏蔽返回键 { showCancelDialog(); return true; } return super.onKeyDown(keyCode, event); }如果正在下载apk的时候按下了返回键,就会让用户确认退出,即是调用showCancelDialog()方法:
private void showCancelDialog() { AlertDialog.Builder builer = new Builder(this) ; builer.setTitle("确认退出"); builer.setMessage("是否要放弃下载?"); //当点确定按钮时从服务器上下载 新的apk 然后安装 builer.setPositiveButton("退出", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { // TODO Auto-generated method stub isDownLoad = false; pd.cancel(); } }); //当点取消按钮时进行登录 builer.setNegativeButton("继续",new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface arg0, int arg1) { // TODO Auto-generated method stub } }); AlertDialog dialog = builer.create(); dialog.show(); }
另外要给出相应的权限。除此dialog.setCanceledOnTouchOutside(false);可以使对话框在用户点击对话框之外是不消失,但是在用户点击按钮的时候还是会立马消失,在某些登陆对话框想要在用户登陆成功后手动调用对话框消失,所以就要用到欺骗android系统使对话框不消失的方法。
static public void dialogClose(boolean isclose) { try { java.lang.reflect.Field field = dialog.getClass().getSuperclass().getDeclaredField("mShowing"); field.setAccessible(true); //设置mShowing值,欺骗android系统 field.set(dialog, isclose); //需要关闭的时候 将这个参数设置为true 他就会自动关闭了 }catch(Exception e) { e.printStackTrace(); } }