Android實現在線更新的過程案例
阿新 • • 發佈:2018-05-28
客戶端 cati 重新 2.0 對話框 environ lis exc root
一、更新軟件的準備
在線更新軟件的話需要我們有簽名的應用,我們需要把簽過名之後的軟件放入到服務器中,我的如下:
其中apk是有簽名的更新版本!
updateinfo.html代碼如下:
{"version":"2.0","description":"有全新版本,請下載!","apkurl":"hhtp://172.23.252.89:8080/MobileSafe2.0.apk"}
- 1
二、具體客戶端軟件的實現
項目結構如下:
主要的業務邏輯在這裏SplashActivity.java
package com.xuliugen.mobilesafe;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import net.tsz.afinal.FinalHttp;
import net.tsz.afinal.http.AjaxCallBack;
import org.json.JSONException;
import org.json.JSONObject;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.DialogInterface.OnCancelListener;
import android.content.DialogInterface.OnClickListener;
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;
import android.view.View;
import android.view.animation.AlphaAnimation;
import android.widget.TextView;
import android.widget.Toast;
/**
* splash界面的作用
* 1、用來展現產品的Logo;
* 2、應用程序初始化的操作;
* 3、檢查應用程序的版本;
* 4、檢查當前應用程序是否合法註冊;
*
*
* 更新安裝的話要使用簽名
* @author xuliugen
*
*/
public class SplashActivity extends Activity {
protected static final int SHOW_UPDATE_DIALOG = 0;
protected static final int ENTER_HOME = 1;
protected static final int URL_ERROR = 2;
protected static final int NETWORK_ERROR = 3;
protected static final int JSON_ERROR = 40;
private TextView tv_splash_version;
private TextView tv_update_info;//升級進度
private String description;// 版本信息的描述
private String apkurl;// 版本更新的地址
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash);
tv_splash_version = (TextView) this.findViewById(R.id.tv_splash_version);
tv_update_info = (TextView) findViewById(R.id.tv_update_info);
tv_splash_version.setText("版本號:" + getVersionName());
// 檢查更新
checkUpdate();
// 設置動畫
AlphaAnimation alphaAnimation = new AlphaAnimation(0.2f, 1.0f);
alphaAnimation.setDuration(3000);// 設置動畫的時長
//執行動畫
findViewById(R.id.rl_root_splash).startAnimation(alphaAnimation);
}
/**
* 由於更新界面是在主線程中操作
*
* 所以可以使用handler,當子線程中運行結束的時候們可以通知主線程進行相關的操作
*/
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
//得到handler發送的message消息進行處理
switch (msg.what) {
case SHOW_UPDATE_DIALOG:// 顯示升級的對話框
showUpdateDialog();
break;
case ENTER_HOME:// 進入主頁面
enterHome();
break;
case URL_ERROR:// URL錯誤
enterHome();
Toast.makeText(getApplicationContext(), "URL錯誤", 0).show();
break;
case NETWORK_ERROR:// 網絡異常
enterHome();
Toast.makeText(SplashActivity.this, "網絡異常", 0).show();
break;
case JSON_ERROR:// JSON解析出錯
enterHome();
Toast.makeText(SplashActivity.this, "JSON解析出錯", 0).show();
break;
default:
break;
}
}
};
/**
* 檢查是否有新版本
*
* 需要請求網絡,一般在子線程中使用
*/
private void checkUpdate() {
new Thread() {
public void run() {
// URL:http://172.23.252.89:8080/updateinfo.json
Message message = Message.obtain();// 得到一個存在的信息,用於存放更新的信息
long startTime = System.currentTimeMillis();
try {
URL url = new URL(getString(R.string.serverurl));
//URL url = new URL("http://172.23.252.89:8080/updateinfo.json");
// 聯網操作
HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
httpURLConnection.setRequestMethod("GET");//設置請求方式
httpURLConnection.setConnectTimeout(4000);//設置超時時間
int code = httpURLConnection.getResponseCode();// 獲得響應碼
if (code == 200) {// 成功
InputStream inputStream = httpURLConnection.getInputStream();
//把流轉換為一個String類型
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len = 0;
while((len = inputStream.read(buffer))!=-1){
baos.write(buffer, 0, len);
}
inputStream.close();
String result = baos.toString();//得到string類型的數據
baos.close();
//因為得到的數據是一個json的string所以要json解析
JSONObject jsonObj = new JSONObject(result);
//得到服務器的版本信息
String version = (String) jsonObj.get("version");
description = (String) jsonObj.get("description");
apkurl = (String) jsonObj.get("apkurl");
//校驗是否有新版本
if (getVersionName().equals(version)) {// 版本一致,進入主界面
message.what = ENTER_HOME;
} else {// 有新版本,彈出一個升級對話框
message.what = SHOW_UPDATE_DIALOG;
}
}
} catch (MalformedURLException e) {
message.what = URL_ERROR;
e.printStackTrace();
} catch (IOException e) {
message.what = NETWORK_ERROR;
e.printStackTrace();
} catch (JSONException e) {
message.what = JSON_ERROR;
e.printStackTrace();
} finally {
long endTime = System.currentTimeMillis();
long dTime = endTime-startTime;//花費的時間
//在界面中停留3秒
if(dTime < 3000){
try {
Thread.sleep(3000-dTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
handler.sendMessage(message);// 將消息發送出去
}
}
}.start();
}
/**
* 得到應用層序的版本名稱
*
* @return
*/
private String getVersionName() {
// 用於管理安裝的apk和未安裝的apk
PackageManager packageManager = getPackageManager();
try {
// 得到apk的功能清單文件:為了防止出錯直接使用getPackageName()方法獲得包名
// packageManager.getPackageInfo("com.xuliugen.mobilesafe", 0);
PackageInfo packageInfo = packageManager.getPackageInfo(getPackageName(), 0);
//返回版本名稱
return packageInfo.versionName;
} catch (NameNotFoundException e) {
e.printStackTrace();
return "";
}
}
/**
* 彈出升級對話框
*/
protected void showUpdateDialog() {
AlertDialog.Builder builder = new Builder(this);
builder.setTitle("提示升級");
// builder.setCancelable(false);//強制升級:就是不讓用戶取消
builder.setMessage(description);//為dialog設置信息
builder.setOnCancelListener(new OnCancelListener() { //
@Override
public void onCancel(DialogInterface dialog) {
// 進入主頁面
enterHome();
dialog.dismiss(); // 取消顯示對話框
}
});
builder.setNegativeButton("下次再說", new OnClickListener() {// 取消
@Override
public void onClick(DialogInterface dialog, int which) {
// 進入主頁面
enterHome();
dialog.dismiss(); // 取消顯示對話框
}
});
builder.setPositiveButton("立刻升級", new OnClickListener() {//確認
@Override
public void onClick(DialogInterface dialog, int which) {
// 下載APK,並且替換安裝
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {//得到sd卡的狀態
// sdcard存在
// 使用afnal下載apk文件
FinalHttp finalhttp = new FinalHttp();
// 得到sdcard路徑
String SDCARD_PATH = Environment
.getExternalStorageDirectory()
.getAbsolutePath()
+ "/mobilesafe2.0.apk";
finalhttp.download(apkurl, SDCARD_PATH,
new AjaxCallBack<File>() {
@Override
public void onFailure(Throwable t, int errorNo,
String strMsg) {
t.printStackTrace();
Toast.makeText(getApplicationContext(),