AndroidAPP更新升級完整實現Demo(搭建本地伺服器) .
市場上的Android應用都能夠自動提示升級更新,這裡就完整的來實現一下AndroidAPP,實現自動升級的功能。
效果圖:
具體如何實現,其實不難,先看看流程:
本地AndroidApp必須要先有一個版本號用於標識當前版本,再從伺服器獲取伺服器最新版本,進行相比較。
實現流程:
1、Manifest.xml新增聯網許可權,讀寫SD卡許可權,版本號versionCode和版本名versionName,其中versionCode用來比較版本使用的變數,versionName為用於顯示在介面上的版本字串。
[html] view plain copy print?- <?
- <manifestxmlns:android="http://schemas.android.com/apk/res/android"
- package="com.eric.androidupdatedemo"
- android:versionCode="1"
- android:versionName="01.00.01">
- <uses-permissionandroid:name='android.permission.INTERNET'/><!-- 聯網許可權 -->
- <uses-permissionandroid:name
- <uses-permissionandroid:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/><!-- 在SD卡中建立和刪除檔案的許可權 -->
- <uses-sdk
- android:minSdkVersion="14"
- android:targetSdkVersion="14"/>
- <application
- android:allowBackup="true"
- android:icon
- android:label="@string/app_name"
- android:theme="@style/AppTheme">
- <activity
- android:name=".MainActivity"
- android:label="@string/app_name">
- <intent-filter>
- <actionandroid:name="android.intent.action.MAIN"/>
- <categoryandroid:name="android.intent.category.LAUNCHER"/>
- </intent-filter>
- </activity>
- </application>
- </manifest>
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.eric.androidupdatedemo"
android:versionCode="1"
android:versionName="01.00.01" >
<uses-permission android:name='android.permission.INTERNET'/> <!-- 聯網許可權 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <!-- 寫入SD卡許可權 -->
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/> <!-- 在SD卡中建立和刪除檔案的許可權 -->
<uses-sdk
android:minSdkVersion="14"
android:targetSdkVersion="14" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".MainActivity"
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、activity_main.xml佈局檔案,簡單的幾個控制元件。 [html] view plain copy print?
- <RelativeLayoutxmlns: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:paddingBottom="@dimen/activity_vertical_margin"
- android:paddingLeft="@dimen/activity_horizontal_margin"
- android:paddingRight="@dimen/activity_horizontal_margin"
- android:paddingTop="@dimen/activity_vertical_margin"
- tools:context="com.eric.androidupdatedemo.MainActivity">
- <TextView
- android:id="@+id/textview_id"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/hello_world"/>
- <Button
- android:id="@+id/button_id"
- android:layout_width="fill_parent"
- android:layout_height="40dp"
- android:layout_below="@id/textview_id"
- android:textColor="#FFF"
- android:text="檢查更新"
- android:background="@drawable/buttonbg"
- />
- <ProgressBar
- android:id="@+id/progressBar_id"
- style="@android:style/Widget.ProgressBar.Horizontal"
- android:layout_width="match_parent"
- android:layout_height="40dp"
- android:layout_below="@id/button_id"
- android:layout_marginTop="10dp"
- android:visibility="gone"/>
- </RelativeLayout>
<RelativeLayout 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:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.eric.androidupdatedemo.MainActivity" >
<TextView
android:id="@+id/textview_id"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello_world" />
<Button
android:id="@+id/button_id"
android:layout_width="fill_parent"
android:layout_height="40dp"
android:layout_below="@id/textview_id"
android:textColor="#FFF"
android:text="檢查更新"
android:background="@drawable/buttonbg"
/>
<ProgressBar
android:id="@+id/progressBar_id"
style="@android:style/Widget.ProgressBar.Horizontal"
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_below="@id/button_id"
android:layout_marginTop="10dp"
android:visibility="gone"/>
</RelativeLayout>
3、MainActivity.java介面初始化,呼叫更新類的方法,重新整理頁面資料。
[java]
view plain
copy
print?
- package com.eric.androidupdatedemo;
- import java.io.File;
- import android.app.Activity;
- import android.app.AlertDialog;
- import android.app.AlertDialog.Builder;
- import android.content.Context;
- import android.content.Intent;
- import android.net.Uri;
- import android.os.Bundle;
- import android.os.Environment;
- import android.os.Handler;
- import android.os.Message;
- import android.view.View;
- import android.view.View.OnClickListener;
- import android.view.Window;
- import android.widget.Button;
- import android.widget.ProgressBar;
- import android.widget.TextView;
- publicclass MainActivity extends Activity {
- private TextView textView;
- publicstaticint version,serverVersion;
- publicstatic String versionName,serverVersionName,downloadResult;
- private Button btn;
- private ProgressBar proBar;
- publicstatic receiveVersionHandler handler;
- private UpdateManager manager = UpdateManager.getInstance();
- @Override
- protectedvoid onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- textView = (TextView) findViewById(R.id.textview_id);
- btn = (Button) findViewById(R.id.button_id);
- proBar=(ProgressBar)findViewById(R.id.progressBar_id);
- Context c = this;
- version = manager.getVersion(c);
- versionName = manager.getVersionName(c);
- textView.setText("當前版本號:"+version+"\n"+"當前版本名:"+versionName);
- handler = new receiveVersionHandler();
- //檢查更新按鈕點選事件
- btn.setOnClickListener(new OnClickListener() {
- @Override
- publicvoid onClick(View v) {
- manager.compareVersion(MainActivity.this);
- }
- });
- }
- publicclass receiveVersionHandler extends Handler{
- @Override
- publicvoid handleMessage(Message msg) {
- proBar.setProgress(msg.arg1);
- proBar.setVisibility(R.id.button_id);
- textView.setText("下載進度:"+msg.arg1);
- if(msg.arg1 == 100){
- Intent intent = new Intent(Intent.ACTION_VIEW);
- String path = Environment.getExternalStorageDirectory()+"/AndroidUpdateDemo.apk";
- intent.setDataAndType(Uri.fromFile(new File(path)),
- "application/vnd.android.package-archive");
- startActivity(intent);
- }
- proBar.setVisibility(R.id.button_id);
- }
- }
- }
package com.eric.androidupdatedemo;
import java.io.File;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
public class MainActivity extends Activity {
private TextView textView;
public static int version,serverVersion;
public static String versionName,serverVersionName,downloadResult;
private Button btn;
private ProgressBar proBar;
public static receiveVersionHandler handler;
private UpdateManager manager = UpdateManager.getInstance();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.textview_id);
btn = (Button) findViewById(R.id.button_id);
proBar=(ProgressBar)findViewById(R.id.progressBar_id);
Context c = this;
version = manager.getVersion(c);
versionName = manager.getVersionName(c);
textView.setText("當前版本號:"+version+"\n"+"當前版本名:"+versionName);
handler = new receiveVersionHandler();
//檢查更新按鈕點選事件
btn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
manager.compareVersion(MainActivity.this);
}
});
}
public class receiveVersionHandler extends Handler{
@Override
public void handleMessage(Message msg) {
proBar.setProgress(msg.arg1);
proBar.setVisibility(R.id.button_id);
textView.setText("下載進度:"+msg.arg1);
if(msg.arg1 == 100){
Intent intent = new Intent(Intent.ACTION_VIEW);
String path = Environment.getExternalStorageDirectory()+"/AndroidUpdateDemo.apk";
intent.setDataAndType(Uri.fromFile(new File(path)),
"application/vnd.android.package-archive");
startActivity(intent);
}
proBar.setVisibility(R.id.button_id);
}
}
}
4、UpdateManager.java更新工具類,包含獲取本地版本資訊,伺服器版本資訊,下載apk檔案等方法。[java] view plain copy print?
- package com.eric.androidupdatedemo;
- import java.io.BufferedInputStream;
- import java.io.BufferedOutputStream;
- import java.io.File;
- import java.io.FileOutputStream;
- import java.net.HttpURLConnection;
- import java.net.URL;
- import org.json.JSONArray;
- import org.json.JSONException;
- import org.json.JSONObject;
- import android.R.integer;
- import android.app.AlertDialog;
- import android.app.AlertDialog.Builder;
- import android.content.Context;
- import android.content.DialogInterface;
- import android.os.Bundle;
- import android.os.Environment;
- import android.os.Handler;
- import android.os.Looper;
- import android.os.Message;
- /*
- *@author Eric
- *@2015-11-7上午8:03:31
- */
- publicclass UpdateManager {
- privatestatic UpdateManager manager = null;
- private UpdateManager(){}
- publicstatic UpdateManager getInstance(){
- manager = new UpdateManager();
- return manager;
- }
- //獲取版本號
- publicint getVersion(Context context){
- int version = 0;
- try {
- version = context.getPackageManager().getPackageInfo(
- "com.eric.androidupdatedemo", 0).versionCode;
- } catch (Exception e) {
- System.out.println("獲取版本號異常!");
- }
- return version;
- }
- //獲取版本名
- public String getVersionName(Context context){
- String versionName = null;
- try {
- versionName = context.getPackageManager().getPackageInfo(
- "com.eric.androidupdatedemo", 0).versionName;
- } catch (Exception e) {
- System.out.println("獲取版本名異常!");
- }
- return versionName;
- }
- //獲取伺服器版本號
- public String getServerVersion(){
- String serverJson = null;
- byte[] buffer = newbyte[128];
- try {
- URL serverURL = new URL("http://192.168.226.106/ver.aspx");
- HttpURLConnection connect = (HttpURLConnection) serverURL.openConnection();
- BufferedInputStream bis = new BufferedInputStream(connect.getInputStream());
- int n = 0;
- while((n = bis.read(buffer))!= -1){
- serverJson = new String(buffer);
- }
- } catch (Exception e) {
- System.out.println("獲取伺服器版本號異常!"+e);
- }
- return serverJson;
- }
- //比較伺服器版本與本地版本彈出對話方塊
- publicboolean compareVersion(Context context){
- final Context contextTemp = context;
- new Thread(){
- publicvoid run() {
- Looper.prepare();
- String serverJson = manager.getServerVersion();
- //解析Json資料
- try {
- JSONArray array = new JSONArray(serverJson);
- JSONObject object = array.getJSONObject(0);
- String getServerVersion = object.getString("version");
- String getServerVersionName = object.getString("versionName");
- MainActivity.serverVersion = Integer.parseInt(getServerVersion);
- MainActivity.serverVersionName = getServerVersionName;
- if(MainActivity.version < MainActivity.serverVersion){
- //彈出一個對話方塊
- AlertDialog.Builder builder = new Builder(contextTemp);
- builder.setTitle("版本更新" ) ;
- builder.setMessage("當前版本:"+MainActivity.versionName
- +"\n"+"伺服器版本:"+MainActivity.serverVersionName ) ;
- builder.setPositiveButton("立即更新",new DialogInterface.OnClickListener() {
- @Override
- publicvoid onClick(DialogInterface dialog, int arg1) {
- //開啟執行緒下載apk
- new Thread(){
- publicvoid run() {
- Looper.prepare();
- downloadApkFile(contextTemp);
- Looper.loop();
- };
- }.start();
- }
- });
- builder.setNegativeButton("下次再說", null);
- builder.show();
- }else{
- AlertDialog.Builder builder = new Builder(contextTemp);
- builder.setTitle("版本資訊" ) ;
- builder.setMessage("當前已經是最新版本" ) ;
- builder.setPositiveButton("確定",null);
- builder.show();
- }
- } catch (JSONException e) {
- e.printStackTrace();
- System.out.println("獲取伺服器版本執行緒異常!"+e);
- }
- Looper.loop();
- };
- }.start();
- returnfalse;
- }
- //下載apk檔案
- publicvoid downloadApkFile(Context context){
- String savePath = Environment.getExternalStorageDirectory()+"/AndroidUpdateDemo.apk";
- String serverFilePath = "http://192.168.226.106/AndroidUpdateDemo.png";
- try {
- if(Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())){
- URL serverURL = new URL(serverFilePath);
- HttpURLConnection connect = (HttpURLConnection) serverURL.openConnection();
- BufferedInputStream bis = new BufferedInputStream(connect.getInputStream());
- File apkfile = new File(savePath);
- BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(apkfile));
- int fileLength = connect.getContentLength();
- int downLength = 0;
- int progress = 0;
- int n;
- byte[] buffer = newbyte[1024];
- while((n=bis.read(buffer, 0, buffer.length))!=-1){
- bos.write(buffer, 0, n);
- downLength +=n;
- progress = (int) (((float) downLength / fileLength) * 100);
- Message msg = new Message();
- msg.arg1 = progress;
- MainActivity.handler.sendMessage(msg);
- //System.out.println("傳送"+progress);
- }
- bis.close();
- bos.close();
- connect.disconnect();
- }
- } catch (Exception e) {
- System.out.println("下載出錯!"+e);
- }
- /*AlertDialog.Builder builder = new Builder(context);
- builder.setTitle("下載apk" ) ;
- builder.setMessage("正在下載" ) ;
- builder.setPositiveButton("確定",null);
- builder.show();*/
- }
- }
package com.eric.androidupdatedemo;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.R.integer;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
/*
*@author Eric
*@2015-11-7上午8:03:31
*/
public class UpdateManager {
private static UpdateManager manager = null;
private UpdateManager(){}
public static UpdateManager getInstance(){
manager = new UpdateManager();
return manager;
}
//獲取版本號
public int getVersion(Context context){
int version = 0;
try {
version = context.getPackageManager().getPackageInfo(
"com.eric.androidupdatedemo", 0).versionCode;
} catch (Exception e) {
System.out.println("獲取版本號異常!");
}
return version;
}
//獲取版本名
public String getVersionName(Context context){
String versionName = null;
try {
versionName = context.getPackageManager().getPackageInfo(
"com.eric.androidupdatedemo", 0).versionName;
} catch (Exception e) {
System.out.println("獲取版本名異常!");
}
return versionName;
}
//獲取伺服器版本號
public String getServerVersion(){
String serverJson = null;
byte[] buffer = new byte[128];
try {
URL serverURL = new URL("http://192.168.226.106/ver.aspx");
HttpURLConnection connect = (HttpURLConnection) serverURL.openConnection();
BufferedInputStream bis = new BufferedInputStream(connect.getInputStream());
int n = 0;
while((n = bis.read(buffer))!= -1){
serverJson = new String(buffer);
}
} catch (Exception e) {
System.out.println("獲取伺服器版本號異常!"+e);
}
return serverJson;
}
//比較伺服器版本與本地版本彈出對話方塊
public boolean compareVersion(Context context){
final Context contextTemp = context;
new Thread(){
public void run() {
Looper.prepare();
String serverJson = manager.getServerVersion();
//解析Json資料
try {
JSONArray array = new JSONArray(serverJson);
JSONObject object = array.getJSONObject(0);
String getServerVersion = object.getString("version");
String getServerVersionName = object.getString("versionName");
MainActivity.serverVersion = Integer.parseInt(getServerVersion);
MainActivity.serverVersionName = getServerVersionName;
if(MainActivity.version < MainActivity.serverVersion){
//彈出一個對話方塊
AlertDialog.Builder builder = new Builder(contextTemp);
builder.setTitle("版本更新" ) ;
builder.setMessage("當前版本:"+MainActivity.versionName
+"\n"+"伺服器版本:"+MainActivity.serverVersionName ) ;
builder.setPositiveButton("立即更新",new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int arg1) {
//開啟執行緒下載apk
new Thread(){
public void run() {
Looper.prepare();
downloadApkFile(contextTemp);
Looper.loop();
};
}.start();
}
});
builder.setNegativeButton("下次再說", null);
builder.show();
}else{
AlertDialog.Builder builder = new Builder(contextTemp);
builder.setTitle("版本資訊" ) ;
builder.setMessage("當前已經是最新版本" ) ;
builder.setPositiveButton("確定",null);
builder.show();
}
} catch (JSONException e) {
e.printStackTrace();
System.out.println("獲取伺服器版本執行緒異常!"+e);
}
Looper.loop();
};
}.start();
return false;
}
//下載apk檔案
public void downloadApkFile(Context context){
String savePath = Environment.getExternalStorageDirectory()+"/AndroidUpdateDemo.apk";
String serverFilePath = "http://192.168.226.106/AndroidUpdateDemo.png";
try {
if(Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())){
URL serverURL = new URL(serverFilePath);
HttpURLConnection connect = (HttpURLConnection) serverURL.openConnection();
BufferedInputStream bis = new BufferedInputStream(connect.getInputStream());
File apkfile = new File(savePath);
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(apkfile));
int fileLength = connect.getContentLength();
int downLength = 0;
int progress = 0;
int n;
byte[] buffer = new byte[1024];
while((n=bis.read(buffer, 0, buffer.length))!=-1){
bos.write(buffer, 0, n);
downLength +=n;
progress = (int) (((float) downLength / fileLength) * 100);
Message msg = new Message();
msg.arg1 = progress;
MainActivity.handler.sendMessage(msg);
//System.out.println("傳送"+progress);
}
bis.close();
bos.close();
connect.disconnect();
}
} catch (Exception e) {
System.out.println("下載出錯!"+e);
}
/*AlertDialog.Builder builder = new Builder(context);
builder.setTitle("下載apk" ) ;
builder.setMessage("正在下載" ) ;
builder.setPositiveButton("確定",null);
builder.show();*/
}
}
具體實現都在UpdateManager類中,詳細說明一下,其中,
getVersion(Context context)、getVersionName(Context context)本地版本的獲取很簡單一看就懂;
getServerVersion()伺服器版本的獲取:讀取伺服器目錄下的ver.aspx檔案,返回json字串;
compareVersion(Context context)比較版本:啟動執行緒,讀取json字串,並解析伺服器版本賦值到serverVersion中,並且比較本地版本和伺服器版本,如果低於伺服器版本,就啟動新執行緒下載apk檔案;
downloadApkFile(Context context)下載apk檔案:設定檔案儲存路徑,伺服器訪問路徑,通過HTTP協議下載檔案,這裡測試的時候,apk檔案無法下載,故將伺服器的apk修改副檔名為png格式,下載完成後儲存為apk檔案。
搭建本地Web伺服器:
1、開啟功能:控制面板-> 程式-> 程式和功能 -> 開啟或關閉Windows功能,將“Internet資訊服務”下的所有功能都開啟。
2、設定防火牆:控制面板-> 系統安全 -> Windows防火牆 -> 允許程式通過Windows防火牆,勾選“全球資訊網服務(HTTP)”。
3、以上步驟完成後,web伺服器就搭好了,可以win+R,執行cmd,鍵入ipconfig /all ,檢視本機IP地址,開啟瀏覽器輸入地址ip地址測試一下,如果開啟的是IIS7網頁,說明成功了。
然後就是將新版本的apk放到伺服器目錄下,一般是系統盤目錄下C:\inetpub\wwwroot資料夾中。
放置兩個檔案,一個是2.0版本的apk檔案,一個是ver.aspx檔案用於獲取伺服器版本的json字串,裡面的內容為:[{"appname":"AndroidUpdateDemo","apkname":"AndroidUpdateDemo.apk","versionName":"02.00.01","version":"2"}] 。
由於測試時候apk檔案無法直接下載,想了個辦法將apk副檔名改為png,在Android端下載完成後把它在儲存為apk檔案。
上述操作結束後,伺服器端就完全搭好了,可以開始測試升級流程。