安卓---app自动更新
主要参考:http://blog.csdn.net/jdsjlzx/article/details/46356013/
效果如下:
大致思路:【原文】
【自己】借鉴了一下思路,不过我把.apk和.txt文件发布到了iis,具体的发布方法可以看我的另一篇博客:http://www.cnblogs.com/rainday1/p/5272394.html
如下图所示:需要添加一下对apk的支持,发布完成后,双击mime,然后在右上角添加.apk(因为我已经添加,所以弹窗显示的是编辑)application/vnd.android.package-archive
测试发布成功没,可以在浏览器输入自己的ip+端口号+.apk名(例如):http://115.159.158.208:8888/autoUpdate.apk
准备工作完成
下面开始安卓app的编写,直接上代码:
1.新建一个UpdateInfo类,用来与update.txt的内容对应,这个很简单:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package com.example.autoupdate; /** * 更新类,用来与服务器的update.txt对应 */ 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; } }
2.GetServerUrl,这个类是用来存放后台地址信息的
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package com.example.autoupdate; /** * * @author rain * 获取服务器IP地址 */ public class GetServerUrl { static String url="http://115.159.158.208:8888";//没错,我这里用的是本地的JAVAEE工程,各位根据实际情况修改。 public static String getUrl(){ return url; } }
3.UpdateInfoService去获取更新的信息,即我们的update.txt文件:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package com.example.autoupdate; import java.io.BufferedReader; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; import android.content.Context; /** * * @author rain * 获取更新的信息,即我们写的update.txt文件 * 这里获取文件的方法是先创建一个HttpURLConnection,再获取输入流. * 细心的朋友可能注意到其中有个类,叫GetServerUrl,这个类是用来存放后台地址信息的 */ public class UpdateInfoService { public UpdateInfoService(Context context) { } /** * 获取详细的版本信息 * @return 版本号,版本描述,下载链接 * @throws Exception */ public UpdateInfo getUpDateInfo() throws Exception { String path = GetServerUrl.getUrl() + "/update.txt"; StringBuffer sb = new StringBuffer(); String line = null; BufferedReader reader = null; try { // 创建一个url对象 URL url = new URL(path); // 通过url对象,创建一个HttpURLConnection对象(连接) HttpURLConnection urlConnection = (HttpURLConnection) url .openConnection(); // 通过HttpURLConnection对象,得到InputStream reader = new BufferedReader(new InputStreamReader( urlConnection.getInputStream(),"GB2312"));//加编码格式,不然中文会乱码 // 使用io流读取文件 while ((line = reader.readLine()) != null) { sb.append(line); } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } finally { try { if (reader != null) { reader.close(); } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } String info = sb.toString(); UpdateInfo updateInfo = new UpdateInfo(); updateInfo.setVersion(info.split("&")[1]); updateInfo.setDescription(info.split("&")[2]); updateInfo.setUrl(info.split("&")[3]); return updateInfo; } }
4.main函数调用
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package com.example.autoupdate; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.DefaultHttpClient; import android.support.v7.app.ActionBarActivity; import android.util.Log; import android.widget.Toast; import android.annotation.SuppressLint; import android.app.AlertDialog; import android.app.ProgressDialog; import android.content.DialogInterface; import android.content.Intent; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.net.Uri; import android.os.Bundle; import android.os.Environment; import android.os.Handler; import android.os.Message; public class MainActivity extends ActionBarActivity { // 更新版本要用到的一些信息 private UpdateInfo info; private ProgressDialog pBar; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Toast.makeText(MainActivity.this, "正在检查版本更新...", Toast.LENGTH_SHORT) .show(); // 自动检查有没有新版本 如果有新版本就提示更新 new Thread() { public void run() { try { UpdateInfoService updateInfoService = new UpdateInfoService( MainActivity.this); info = updateInfoService.getUpDateInfo(); handler1.sendEmptyMessage(0); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } }; }.start(); } @SuppressLint("HandlerLeak") private Handler handler1 = new Handler() { public void handleMessage(Message msg) { // 如果有更新就提示 if (isNeedUpdate()) { showUpdateDialog(); } } }; /** * 判断是否需要更新 * * @return */ protected boolean isNeedUpdate() { String v = info.getVersion();// 最新版本的版本号 Log.i("update", v); Toast.makeText(MainActivity.this, v, Toast.LENGTH_SHORT).show(); if (v.equals(getVersion())) { return false; } else { return true; } } /** * 获取当前版本号 * * @return 版本号 */ private Object getVersion() { try { PackageManager packageManager = getPackageManager(); PackageInfo packageInfo = packageManager.getPackageInfo( getPackageName(), 0); return packageInfo.versionName; } catch (NameNotFoundException e) { e.printStackTrace(); return "版本号未知"; } } /** * 显示更新对话框 */ protected void showUpdateDialog() { AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setIcon(R.drawable.update); builder.setTitle("请升级APP至版本" + info.getVersion()); 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 if (Environment.getExternalStorageState().equals( Environment.MEDIA_MOUNTED)) { downFile(info.getUrl()); } else { Toast.makeText(MainActivity.this, "SD卡不可用,请插入SD卡", Toast.LENGTH_SHORT).show(); } } }); builder.setNegativeButton("取消", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { // TODO Auto-generated method stub } }); builder.create().show(); } /** * 下载apk文件,并更新进度条 * @param url */ protected void downFile(final String url) { // TODO Auto-generated method stub pBar = new ProgressDialog(MainActivity.this);// 进度条,在下载的时候实时更新进度,提高用户友好度 pBar.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); pBar.setTitle("正在下载"); pBar.setMessage("请稍候..."); pBar.setProgress(0); pBar.show(); new Thread() { public void run() { HttpClient client = new DefaultHttpClient(); HttpGet get = new HttpGet(url); HttpResponse response; try { response = client.execute(get); HttpEntity entity = response.getEntity(); int length = (int) entity.getContentLength();// //获取文件大小 pBar.setMax(length);// 设置进度条的总长度 InputStream is = entity.getContent(); FileOutputStream fileOutputStream = null; if (is != null) { File file = new File( Environment.getExternalStorageDirectory(), "autoUpdate.apk");//这里的名字一定要与下面的安装名相同 fileOutputStream = new FileOutputStream(file); byte[] buf = new byte[512*1024];// 这个是缓冲区,即一次读取10个比特,我弄的小了点,因为在本地,所以数值太大一 // 下就下载完了,看不出progressbar的效果。 int ch = -1; int process = 0; while ((ch = is.read(buf)) != -1) { fileOutputStream.write(buf, 0, ch); process += ch; pBar.setProgress(process);//这里就是关键的实时更新进度了! } } fileOutputStream.flush(); if (fileOutputStream != null) { fileOutputStream.close(); } down(); } catch (ClientProtocolException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalStateException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }.start(); } /** * 隐藏进度条,安装apk */ protected void down() { handler1.post(new Runnable() { @Override public void run() { // TODO Auto-generated method stub pBar.cancel(); update(); } }); } /** * 安装文件,一般固定写法 */ protected void update() { // TODO Auto-generated method stub Intent intent = new Intent(Intent.ACTION_VIEW); intent.setDataAndType(Uri.fromFile(new File(Environment .getExternalStorageDirectory(), "autoUpdate.apk")), "application/vnd.android.package-archive"); startActivity(intent); } }
5.权限androidmanifest,模拟器调试不给权限不报错,但是没法下载,真机会直接报错
<uses-permission android:name="android.permission.RESTART_PACKAGES" >
</uses-permission>
<uses-permission android:name="android.permission.VIBRATE" >
</uses-permission>
<uses-permission android:name="android.permission.GET_TASKS" >
</uses-permission>
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" >
</uses-permission>
<uses-permission android:name="android.permission.INTERNET" >
</uses-permission>
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RESTART_PACKAGES" />
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" >
</uses-permission>
<uses-permission android:name="android.permission.GET_TASKS" >
</uses-permission>
<uses-permission android:name="android.permission.VIBRATE" >
</uses-permission>
<uses-permission android:name="android.permission.INTERNET" >
</uses-permission>