android apk版本自动检测升级,安装
2013-03-04 19:40
507 查看
网上看了好多自动升级安装的例子.可能是我没配置好.做起来各种的不爽 虽然代码都大同小异 还是自己做的比较满意
先说下主要的实现逻辑:在测试服务器上放一个xml,用来说明服务器的版本,和新apk的下载地址,运行本地apk的时间.去检测服务器xml里的服务器的版本信息,本地apk的版本信息可以在AndroidManifest.xml中的versionCode拿到.代码是context.getPackageManager().getPackageInfo("com.example.updateversion",
0).0;如果他的版本号比本地的版本号高的话就下载更新服务器上的apk,完了后安装新的apk,这样就实现了自动更新apk的目的,记得发布新的apk的时候一定要修改AndroidManifest.xml中的versionCode,只能搞不能低,然的话就这次可以更新.下次再比对的时候就没法更新了
本例共有3个类文件.一个activity 一个下载的主工具类 一个解析xml的工具类 还有2个布局文件.主布局文件和一个progressbar
1.主要的业务类:注释都在代理里了
2:解析工具类,能做到自动升级的地步,xml解析就不用再注释了吧:
3:activity的代码主ui:
4:下面是主页面的xml和progress的xml
页面:
progress:
以上就是整个程序的代码了 发布新版本只需要修改AndroidManifest.xml文件中的versionCode的值,一定要比升级之前的版本高,那个versionName在本例中没有什么实际意义,主要是versioncode,如果想在ui上看的清楚一点的话 可以经string.xml中的version_msg 标明版本号.这样在ui上就能看到当前的版本了
以后能让自己清楚点再次使用这个例子 把服务器的xml格式也贴上来,新的apk和xml放一个文件夹就行
切记:如果测试的话,不管新的还是旧的apk 都得打包成apk文件.并且用同一个签名.如果是想在debug情况下使用 可以用(win7)C:\Users\rongsheng\.android目录下的debug.keystore这个签名(两个apk签名要一样),系统自带的签名的密码都是android
源码下载
先说下主要的实现逻辑:在测试服务器上放一个xml,用来说明服务器的版本,和新apk的下载地址,运行本地apk的时间.去检测服务器xml里的服务器的版本信息,本地apk的版本信息可以在AndroidManifest.xml中的versionCode拿到.代码是context.getPackageManager().getPackageInfo("com.example.updateversion",
0).0;如果他的版本号比本地的版本号高的话就下载更新服务器上的apk,完了后安装新的apk,这样就实现了自动更新apk的目的,记得发布新的apk的时候一定要修改AndroidManifest.xml中的versionCode,只能搞不能低,然的话就这次可以更新.下次再比对的时候就没法更新了
本例共有3个类文件.一个activity 一个下载的主工具类 一个解析xml的工具类 还有2个布局文件.主布局文件和一个progressbar
1.主要的业务类:注释都在代理里了
package com.example.updateversion; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.util.HashMap; import android.app.AlertDialog; import android.app.AlertDialog.Builder; import android.app.Dialog; import android.content.Context; import android.content.DialogInterface; import android.content.DialogInterface.OnClickListener; import android.content.Intent; import android.content.pm.PackageManager.NameNotFoundException; import android.net.Uri; import android.os.Environment; import android.os.Handler; import android.os.Message; import android.view.LayoutInflater; import android.view.View; import android.widget.ProgressBar; import android.widget.Toast; /** * 检测安装更新文件的助手类 * * @author Administrator * */ public class UpdateVersionService { private static final int DOWN = 1;// 用于区分正在下载 private static final int DOWN_FINISH = 0;// 用于区分下载完成 private HashMap<String, String> hashMap;// 存储跟心版本的xml信息 private String fileSavePath;// 下载新apk的厨房地点 private String updateVersionXMLPath;// 检测更新的xml文件 private int progress;// 获取新apk的下载数据量,更新下载滚动条 private boolean cancelUpdate = false;// 是否取消下载 private Context context; private ProgressBar progressBar; private Dialog downLoadDialog; private Handler handler = new Handler() {// 跟心ui @Override public void handleMessage(Message msg) { super.handleMessage(msg); switch ((Integer) msg.obj) { case DOWN: progressBar.setProgress(progress); break; case DOWN_FINISH: Toast.makeText(context, "文件下载完成,正在安装更新", Toast.LENGTH_SHORT).show(); installAPK(); break; default: break; } } }; /** * 构造方法 * * @param updateVersionXMLPath * 比较版本的xml文件地址(服务器上的) * @param context * 上下文 */ public UpdateVersionService(String updateVersionXMLPath, Context context) { super(); this.updateVersionXMLPath = updateVersionXMLPath; this.context = context; } /** * 检测是否可更新 * * @return */ public void checkUpdate() { if (isUpdate()) { showUpdateVersionDialog();// 显示提示对话框 } else { Toast.makeText(context, "已经是新版本", Toast.LENGTH_SHORT).show(); } } /** * 更新提示框 */ private void showUpdateVersionDialog() { // 构造对话框 AlertDialog.Builder builder = new Builder(context); builder.setTitle("软件更新"); builder.setMessage("检测到新版本,是否下载更新"); // 更新 builder.setPositiveButton("更新", new OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); // 显示下载对话框 showDownloadDialog(); } }); // 稍后更新 builder.setNegativeButton("稍后更新", new OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); } }); Dialog noticeDialog = builder.create(); noticeDialog.show(); } /** * 下载的提示框 */ protected void showDownloadDialog() { { // 构造软件下载对话框 AlertDialog.Builder builder = new Builder(context); builder.setTitle("正在更新"); // 给下载对话框增加进度条 final LayoutInflater inflater = LayoutInflater.from(context); View v = inflater.inflate(R.layout.downloaddialog, null); progressBar = (ProgressBar) v.findViewById(R.id.updateProgress); builder.setView(v); // 取消更新 builder.setNegativeButton("取消", new OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); // 设置取消状态 cancelUpdate = true; } }); downLoadDialog = builder.create(); downLoadDialog.show(); // 现在文件 downloadApk(); } } /** * 下载apk,不能占用主线程.所以另开的线程 */ private void downloadApk() { new downloadApkThread().start(); } /** * 判断是否可更新 * * @return */ private boolean isUpdate() { int versionCode = getVersionCode(context); try { // 把version.xml放到网络上,然后获取文件信息 URL url = new URL(updateVersionXMLPath); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setReadTimeout(5 * 1000); conn.setRequestMethod("GET");// 必须要大写 InputStream inputStream = conn.getInputStream(); // 解析XML文件。 ParseXmlService service = new ParseXmlService(); hashMap = service.parseXml(inputStream); } catch (Exception e) { e.printStackTrace(); } if (null != hashMap) { int serverCode = Integer.valueOf(hashMap.get("versionCode")); // 版本判断 if (serverCode > versionCode) { Toast.makeText(context, "新版本是: " + serverCode, Toast.LENGTH_SHORT).show(); return true; } } return false; } /** * 获取当前版本和服务器版本.如果服务器版本高于本地安装的版本.就更新 * * @param context2 * @return */ private int getVersionCode(Context context2) { int versionCode = 0; try { // 获取软件版本号,对应AndroidManifest.xml下android:versionCode versionCode = context.getPackageManager().getPackageInfo("com.example.updateversion", 0).versionCode; Toast.makeText(context, "当前版本是: " + versionCode, Toast.LENGTH_SHORT).show(); } catch (NameNotFoundException e) { e.printStackTrace(); } return versionCode; } /** * 安装apk文件 */ private void installAPK() { File apkfile = new File(fileSavePath, hashMap.get("fileName") + ".apk"); if (!apkfile.exists()) { return; } // 通过Intent安装APK文件 Intent i = new Intent(Intent.ACTION_VIEW); System.out.println("filepath=" + apkfile.toString() + " " + apkfile.getPath()); i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); i.setDataAndType(Uri.parse("file://" + apkfile.toString()), "application/vnd.android.package-archive"); context.startActivity(i); android.os.Process.killProcess(android.os.Process.myPid());// 如果不加上这句的话在apk安装完成之后点击单开会崩溃 } /** * 卸载应用程序(没有用到) */ public void uninstallAPK() { Uri packageURI = Uri.parse("package:com.example.updateversion"); Intent uninstallIntent = new Intent(Intent.ACTION_DELETE, packageURI); context.startActivity(uninstallIntent); } /** * 下载apk的方法 * * @author rongsheng * */ public class downloadApkThread extends Thread { @Override public void run() { // TODO Auto-generated method stub super.run(); try { // 判断SD卡是否存在,并且是否具有读写权限 if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { // 获得存储卡的路径 String sdpath = Environment.getExternalStorageDirectory() + "/"; fileSavePath = sdpath + "download"; URL url = new URL(hashMap.get("loadUrl")); // 创建连接 HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setReadTimeout(5 * 1000);// 设置超时时间 conn.setRequestMethod("GET"); conn.setRequestProperty("Charser", "GBK,utf-8;q=0.7,*;q=0.3"); // 获取文件大小 int length = conn.getContentLength(); // 创建输入流 InputStream is = conn.getInputStream(); File file = new File(fileSavePath); // 判断文件目录是否存在 if (!file.exists()) { file.mkdir(); } File apkFile = new File(fileSavePath, hashMap.get("fileName") + ".apk"); FileOutputStream fos = new FileOutputStream(apkFile); int count = 0; // 缓存 byte buf[] = new byte[1024]; // 写入到文件中 do { int numread = is.read(buf); count += numread; // 计算进度条位置 progress = (int) (((float) count / length) * 100); // 更新进度 Message message = new Message(); message.obj = DOWN; handler.sendMessage(message); if (numread <= 0) { // 下载完成 // 取消下载对话框显示 downLoadDialog.dismiss(); Message message2 = new Message(); message2.obj = DOWN_FINISH; handler.sendMessage(message2); break; } // 写入文件 fos.write(buf, 0, numread); } while (!cancelUpdate);// 点击取消就停止下载. fos.close(); is.close(); } } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } } }
2:解析工具类,能做到自动升级的地步,xml解析就不用再注释了吧:
package com.example.updateversion; import java.io.IOException; import java.io.InputStream; import java.util.HashMap; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import android.util.Xml; public class ParseXmlService { public HashMap<String, String> parseXml(InputStream inputStream) { HashMap<String, String> hashMap = null; boolean flag = true; try { XmlPullParser pullParser = Xml.newPullParser(); pullParser.setInput(inputStream, "UTF-8"); int event = pullParser.getEventType(); while (event != XmlPullParser.END_DOCUMENT) { switch (event) { case XmlPullParser.START_DOCUMENT: hashMap = new HashMap<String, String>(); break; case XmlPullParser.START_TAG: flag = true; String name = pullParser.getName(); if ("VERSIONCODE".equalsIgnoreCase(name) && flag == true) { hashMap.put("versionCode", pullParser.nextText().trim()); } else if ("FILENAME".equalsIgnoreCase(name) && flag == true) { hashMap.put("fileName", pullParser.nextText().trim()); } else if ("LOADURL".equalsIgnoreCase(name) && flag == true) { hashMap.put("loadUrl", pullParser.nextText().trim()); } break; case XmlPullParser.END_TAG: flag = false; break; } event = pullParser.next(); } } catch (XmlPullParserException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } // hashMap = new HashMap<String, String>(); // hashMap.put("versionCode", "2"); // hashMap.put("fileName", "updateversion"); // hashMap.put("loadUrl", // "http://192.168.1.30:8080/server/updateversion/updateversion.apk"); return hashMap; } }
3:activity的代码主ui:
package com.example.updateversion; import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.view.View; public class MainActivity extends Activity { private UpdateVersionService updateVersionService; private static final String UPDATEVERSIONXMLPATH = "http://192.168.1.30:8080/server/updateversion/version.xml"; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // TODO Auto-generated method stub new Handler().postDelayed(new Runnable() { @Override public void run() { // TODO Auto-generated method stub updateVersionService = new UpdateVersionService(UPDATEVERSIONXMLPATH, MainActivity.this);// 创建更新业务对象 updateVersionService.checkUpdate();// 调用检查更新的方法,如果可以更新.就更新.不能更新就提示已经是最新的版本了 } }, 2000);// 2秒之后执行 } /** * 更新按钮的监听事件 * * @param view */ public void updateVersion(View view) { updateVersionService = new UpdateVersionService(UPDATEVERSIONXMLPATH, this); updateVersionService.checkUpdate(); } }
4:下面是主页面的xml和progress的xml
页面:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center_vertical|center_horizontal" android:orientation="vertical" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/version_msg" android:textSize="30sp" tools:context=".MainActivity" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="30dp" android:onClick="updateVersion" android:text="@string/update" /> </LinearLayout>
progress:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <ProgressBar android:id="@+id/updateProgress" style="@android:attr/progressBarStyleHorizontal" android:layout_width="fill_parent" android:layout_height="wrap_content" /> </LinearLayout>
以上就是整个程序的代码了 发布新版本只需要修改AndroidManifest.xml文件中的versionCode的值,一定要比升级之前的版本高,那个versionName在本例中没有什么实际意义,主要是versioncode,如果想在ui上看的清楚一点的话 可以经string.xml中的version_msg 标明版本号.这样在ui上就能看到当前的版本了
以后能让自己清楚点再次使用这个例子 把服务器的xml格式也贴上来,新的apk和xml放一个文件夹就行
<?xml version="1.0" encoding="UTF-8"?> <VERSION> <VERSIONCODE>2</VERSIONCODE> <FILENAME>updateversion</FILENAME> <LOADURL>http://192.168.1.30:8080/server/updateversion/updateversion.apk </LOADURL> </VERSION>
切记:如果测试的话,不管新的还是旧的apk 都得打包成apk文件.并且用同一个签名.如果是想在debug情况下使用 可以用(win7)C:\Users\rongsheng\.android目录下的debug.keystore这个签名(两个apk签名要一样),系统自带的签名的密码都是android
源码下载
相关文章推荐
- Android自动检测版本及自动升级 .
- Android自动检测版本及自动升级
- Android自动检测版本及自动升级
- android 获得安装apk包的版本信息 和 版本升级 代码
- Android编程实现自动检测版本及自动升级的方法
- android 自动检测版本升级
- Android版本检测,更新,安装及运行APK
- Android 自动检测更新apk版本
- android 自动检测版本升级
- android 自动检测版本升级
- Android自动检测版本及自动升级
- Android自动检测版本及自动升级
- 获得Android系统所有已安装的应用并联网自动检测升级更新
- 获得Android系统所有已安装的应用并联网自动检测升级更新
- android的APP自动更新程序,检测版本,然后下载安装,但app安装后不提示“完成,打开”?
- android 自动检测版本升级
- binbinyang---Android自动检测版本及自动升级
- Android 一步一步实现版本自动更新(第二步 下载和安装apk)
- android 自动检测版本升级
- Android 版本更新下载自动安装APK,并解决Android6.0安装失败的问题