傳送門 ☞ 輪子的專欄 ☞ 轉載請註明 ☞ http://blog.csdn.net/leverage_1229
html
今天咱們學習如何實現Android應用的自動更新版本功能,這是在各類語言編寫的應用中都會常常遇到的情景。當咱們的應用檢測到網絡上有新版本發佈時,系統會提示是否下載新版本應用,當新版本應用下載完畢後,系統會自動安裝下載的新版本應用(或跳轉到相關安裝頁面詢問)。咱們將下載的應用存放在sdcard中,因爲整個流程涉及對sdcard的讀寫操做,因此要賦給咱們應用讀寫外存的權限。下面給出該場景的案例:java
1.1程序清單文件中須要配置以下權限:android
訪問網絡網絡
<uses-permission android:name="android.permission.INTERNET"/>讀取sdcard
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>寫入sdcard
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
1.2建立一個HttpURLConnection鏈接,從網絡下載新版本應用到本地app
1.3建立一個ProgressBar下載進度條,實時顯示下載應用的進度ide
1.4應用下載完畢後,構建Intent跳轉至其安裝頁面,該Intent的配置以下:佈局
Action:Intent.ACTION_VIEW學習
DataAndType:Uri.parse("file://" + appFile.toString()),"application/vnd.android.package-archive"
ui
2.1AndroidManifest.xmlthis
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="cn.lynn.autoupdate" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="15" /> <uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <application android:icon="@drawable/ic_launcher" android:label="@string/app_name" > <activity android:name=".AutoUpdateMainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>2.2strings.xml
<resources> <string name="app_name">Android實現應用自動更新</string> </resources>2.3main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout>2.4下載進度條佈局文件:progressBar.xml
<?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="wrap_content"> <ProgressBar android:id="@+id/progressBar" style="?android:attr/progressBarStyleHorizontal" android:layout_width="match_parent" android:layout_height="wrap_content" /> </LinearLayout>2.5AutoUpdateMainActivity.java
package cn.lynn.autoupdate; import android.app.Activity; import android.os.Bundle; public class AutoUpdateMainActivity extends Activity { private UpdateAppManager updateManager; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); updateManager = new UpdateAppManager(this); updateManager.checkUpdateInfo(); } }2.6UpdateAppManager.java
package cn.lynn.autoupdate; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; import android.app.AlertDialog; import android.app.Dialog; import android.content.Context; import android.content.DialogInterface; import android.content.DialogInterface.OnClickListener; import android.content.Intent; 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; public class UpdateAppManager { // 文件分隔符 private static final String FILE_SEPARATOR = "/"; // 外存sdcard存放路徑 private static final String FILE_PATH = Environment.getExternalStorageDirectory() + FILE_SEPARATOR +"autoupdate" + FILE_SEPARATOR; // 下載應用存放全路徑 private static final String FILE_NAME = FILE_PATH + "autoupdate.apk"; // 更新應用版本標記 private static final int UPDARE_TOKEN = 0x29; // 準備安裝新版本應用標記 private static final int INSTALL_TOKEN = 0x31; private Context context; private String message = "檢測到本程序有新版本發佈,建議您更新!"; // 以華爲每天聊hotalk.apk爲例 private String spec = "http://222.42.1.209:81/1Q2W3E4R5T6Y7U8I9O0P1Z2X3C4V5B/mt.hotalk.com:8080/release/hotalk1.9.17.0088.apk"; // 下載應用的對話框 private Dialog dialog; // 下載應用的進度條 private ProgressBar progressBar; // 進度條的當前刻度值 private int curProgress; // 用戶是否取消下載 private boolean isCancel; public UpdateAppManager(Context context) { this.context = context; } private final Handler handler = new Handler(){ @Override public void handleMessage(Message msg) { switch (msg.what) { case UPDARE_TOKEN: progressBar.setProgress(curProgress); break; case INSTALL_TOKEN: installApp(); break; } } }; /** * 檢測應用更新信息 */ public void checkUpdateInfo() { showNoticeDialog(); } /** * 顯示提示更新對話框 */ private void showNoticeDialog() { new AlertDialog.Builder(context) .setTitle("軟件版本更新") .setMessage(message) .setPositiveButton("下載", new OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); showDownloadDialog(); } }).setNegativeButton("之後再說", new OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); } }).create().show(); } /** * 顯示下載進度對話框 */ private void showDownloadDialog() { View view = LayoutInflater.from(context).inflate(R.layout.progressbar, null); progressBar = (ProgressBar) view.findViewById(R.id.progressBar); AlertDialog.Builder builder = new AlertDialog.Builder(context); builder.setTitle("軟件版本更新"); builder.setView(view); builder.setNegativeButton("取消", new OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); isCancel = true; } }); dialog = builder.create(); dialog.show(); downloadApp(); } /** * 下載新版本應用 */ private void downloadApp() { new Thread(new Runnable() { @Override public void run() { URL url = null; InputStream in = null; FileOutputStream out = null; HttpURLConnection conn = null; try { url = new URL(spec); conn = (HttpURLConnection) url.openConnection(); conn.connect(); long fileLength = conn.getContentLength(); in = conn.getInputStream(); File filePath = new File(FILE_PATH); if(!filePath.exists()) { filePath.mkdir(); } out = new FileOutputStream(new File(FILE_NAME)); byte[] buffer = new byte[1024]; int len = 0; long readedLength = 0l; while((len = in.read(buffer)) != -1) { // 用戶點擊「取消」按鈕,下載中斷 if(isCancel) { break; } out.write(buffer, 0, len); readedLength += len; curProgress = (int) (((float) readedLength / fileLength) * 100); handler.sendEmptyMessage(UPDARE_TOKEN); if(readedLength >= fileLength) { dialog.dismiss(); // 下載完畢,通知安裝 handler.sendEmptyMessage(INSTALL_TOKEN); break; } } out.flush(); } catch (Exception e) { e.printStackTrace(); } finally { if(out != null) { try { out.close(); } catch (IOException e) { e.printStackTrace(); } } if(in != null) { try { in.close(); } catch (IOException e) { e.printStackTrace(); } } if(conn != null) { conn.disconnect(); } } } }).start(); } /** * 安裝新版本應用 */ private void installApp() { File appFile = new File(FILE_NAME); if(!appFile.exists()) { return; } // 跳轉到新版本應用安裝頁面 Intent intent = new Intent(Intent.ACTION_VIEW); intent.setDataAndType(Uri.parse("file://" + appFile.toString()), "application/vnd.android.package-archive"); context.startActivity(intent); } }