在安卓開發過程中,很多時候再軟件啓動時需要檢查進行更版本更新,在本文中,採取tomcat7.0作爲服務器,進行相關版本的獲取。
功能描述:軟件啓動時進行版本檢查,檢查到新版本時提示更新。
1、首先我們編寫界面文件如下(activity_start):
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/rl_root"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/bg2"
tools:context=".StartActivity" >
<ProgressBar
android:id="@+id/progressBar1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:layout_marginLeft="114dp" />
<TextView
android:id="@+id/tv_version_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_marginBottom="60dp"
android:layout_marginLeft="87dp"
android:shadowColor="#ffff00"
android:shadowDx="1"
android:shadowDy="1"
android:shadowRadius="2"
android:text="版本號:1.0"
android:textColor="#FFFFFF"
android:textSize="24sp" />
</RelativeLayout>
2、接下來需要編寫對應的java文件,如下:
package com.sw.xmk;
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 org.json.JSONException;
import org.json.JSONObject;
import com.lidroid.xutils.HttpUtils;
import com.lidroid.xutils.exception.HttpException;
import com.lidroid.xutils.http.ResponseInfo;
import com.lidroid.xutils.http.callback.RequestCallBack;
import com.sw.xmk.utils.StreamUtil;
import com.sw.xmk.utils.ToastUtil;
import com.sw.xmk.R;
import com.sw.xmk.R.layout;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
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.text.style.UpdateAppearance;
import android.util.Log;
import android.view.Menu;
import android.view.Window;
import android.view.animation.AlphaAnimation;
import android.widget.RelativeLayout;
import android.widget.TextView;
/**
* @author Swxctx
*
*/
public class StartActivity extends Activity {
private TextView textView;
private TextView tv_version_name;
private int mLocalVersionCode;//本地的版本號
private String mVersionDes;
private String mDownloadUrl;
protected static final String tag="SplashActivity";
protected static final int UPDATE_VERSION = 100;
protected static final int ENTER_HOME = 101;
protected static final int URL_ERROR = 102;
protected static final int IO_ERROR = 103;
protected static final int JSON_ERROR = 104;
//handler爲類的成員變量,對handler重新命名爲mHandler
private Handler mHandler = new Handler(){
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case UPDATE_VERSION:
//彈出對話框,提示用戶更新
showUpdateDialog();
break;
case ENTER_HOME:
//當接收到ENTER_HOME後,由splash界面進入應用程序主界面,activity跳轉過程,封裝到enterHome方法中
enterHome();//選中此方法,ctrl+1,選中第2個(在splash中創建)創建Activity的成員方法,去寫此方法。
break;
case URL_ERROR:
//Toast.makeText(context, text, duration).show();
ToastUtil.show(StartActivity.this, "url異常");
enterHome();
break;
case IO_ERROR:
//Toast.makeText(context, text, duration).show();
ToastUtil.show(StartActivity.this, "讀取異常");
enterHome();
break;
case JSON_ERROR:
ToastUtil.show(StartActivity.this, "json解析異常");
enterHome();
break;
}
}
};
private RelativeLayout rl_root;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_start);
//初始化UI
initUI();
//初始化數據
initData();
//初始化動畫,(ctrl+1)創建此方法
initAnimation();
}
/**
* 添加淡入動畫效果
*/
private void initAnimation() {
//Animation(2),它是抽象類,其有很多子類,選中它(ctrl+t)查看其子類,
//調用第2個構造方法,從一個透明度到另外一個透明度fromAlpha=0, toAlpha=1,由完全透明到完全不透明
AlphaAnimation alphaAnimation= new AlphaAnimation(0,1);
//選中AlphaAnimation(ctrl+1)生成對應的對象alphaAnimation
//設定時長
alphaAnimation.setDuration(3000);
rl_root.startAnimation(alphaAnimation);
}
//顯示對話框操作
protected void showUpdateDialog() {
// TODO Auto-generated method stub
Builder builder = new AlertDialog.Builder(this);
//設置左上角圖標
builder.setIcon(R.drawable.ic_launcher);
builder.setTitle("版本更新");
//設置描述內容
builder.setMessage(mVersionDes);
builder.setPositiveButton("立即更新", new DialogInterface.OnClickListener(){
@Override
public void onClick(DialogInterface dialog, int which) {
// 下載apk,apk的鏈接地址,downloadUrl
downloadApk(); //將其作爲類的成員方法,在splashActivity中創建
}
});
//消極按鈕
builder.setNegativeButton("稍後再說 ", new DialogInterface.OnClickListener(){
@Override
public void onClick(DialogInterface dialog, int which) {
// 取消對話框,進入主界面
enterHome();
}
});
//點擊取消事件監聽
builder.setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
// 即使用戶點擊取消,也要進入應用程序主界面
enterHome();
dialog.dismiss();
}
});
builder.show();
}
protected void downloadApk() {
//apk下載鏈接地址,放置apk的所在路徑
//1,判斷sd卡是否可用,是否掛載在上面
if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
//2,獲取sd路徑,拿到絕對路徑。
String path = Environment.getExternalStorageDirectory().getAbsolutePath()
+File.separator+"SplashActivity.apk";
//3,發送請求,獲取apk,並且放置到指定路徑.
HttpUtils httpUtils = new HttpUtils();
//4,發送請求,傳遞參數(下載地址,下載應用放置位置),target參數是path路徑
httpUtils.download(mDownloadUrl, path,new RequestCallBack<File>() {
@Override
public void onSuccess(ResponseInfo<File> responseInfo) {
// TODO Auto-generated method stub
// 下載成功(下載過後的放置在sd卡中的apk)
Log.i(tag, "下載成功");
File file = responseInfo.result;
//提示用戶安裝,作爲類的成員方法
installApk(file);
}
// 下載失敗
@Override
public void onFailure(HttpException arg0, String arg1) {
// TODO Auto-generated method stub
Log.i(tag, "下載失敗");
}
//剛剛開始下載的方法(Alt+/)
@Override
public void onStart() {
Log.i(tag, "剛剛開始下載");
super.onStart();
}
//下載過程中的方法,進度條的改變(Alt+/),total總數,current當前的,isUploading是否正在下載
@Override
public void onLoading(long total, long current, boolean isUploading) {
Log.i(tag, "下載中.......");
Log.i(tag, "total = "+total);
Log.i(tag, "current = "+current);
super.onLoading(total, current, isUploading);
}
});
}
}
protected void installApk(File file) {
Intent intent =new Intent("android.intent.action.VIEW");
intent.addCategory("android.intent.category.DEFAULT");
intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
//startActivity(intent);
startActivityForResult(intent,0);
}
//開啓一個activity後,返回結果調用的方法
@Override
//一旦後面一個界面結束回到前一個界面,就會去調用前一個界面的onActivityResult方法,只寫onActivityResult回車,所有內容都包含了。
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
enterHome(); //只需要跳轉到HomeActivity方法
super.onActivityResult(requestCode, resultCode, data);
}
/**
* 進入應用程序主界面
*/
protected void enterHome() {
// TODO Auto-generated method stub
Intent intent = new Intent(this,LoginActivity.class);
startActivity(intent);
//在開啓一個新的界面後,將導航界面關閉(導航界面只可見一次)
finish();
}
private void initData() {
//1,應用版本名稱
String versionName = getVersionName();
//String versionName(13)=getVersionName();
tv_version_name.setText("版本名稱"+getVersionName());
//將 int versionCode(ctrl+1)轉換爲類的成員變量mVersionCode
//2,獲取本地版本號,將mVersionCode(alt+shift+R)變爲mLocalVersionCode
mLocalVersionCode = getVersionCode();
//獲取服務器版本號
//3,獲取服務器版本號(客戶端請求,服務器端響應(json,xml))
//http://www.oxxx.com/update74.jon?key=value 返回200請求成功,流的方式將數據讀取下來
/*json中內容包含:
* 更新版本的版本名稱
* 新版本的描述信息
* 服務器版本號
* 新版本apk的下載地址
*/
checkVersion();
}
private void checkVersion() {
new Thread(){
public void run() {
Message msg = Message.obtain();//返回一個msg對象
long startTime = System.currentTimeMillis();
try {
//1,封裝url地址
URL url = new URL("http://10.0.2.2:8080/update.json");
//2,開啓一個鏈接
HttpURLConnection connection = (HttpURLConnection) url.openConnection();//返回HttpURLConnection的對象
//3,設置常見請求參數(請求頭)
//請求超時,指鏈接超時,根本就沒連接上
connection.setConnectTimeout(2000);
//讀取超時
connection.setReadTimeout(2000);
//默認就是get請求方式
connection.setRequestMethod("POST");
//4,獲取請求成功響應碼
if(connection.getResponseCode()==200){
//5,以流的形式,將數據獲取下來
InputStream is = connection.getInputStream();
//6,將流轉換成字符串(攻擊類封裝)
String json = StreamUtil.streamToString(is);
Log.i(tag, json);//用log來打印日誌
//7,json解析
JSONObject jsonObject = new JSONObject(json);
mDownloadUrl = jsonObject.getString("downloadUrl");
String versionCode = jsonObject.getString("versionCode");
mVersionDes = jsonObject.getString("versionDes");
String versionName = jsonObject.getString("versionName");
Log.i(tag,mDownloadUrl);
Log.i(tag,versionCode);
Log.i(tag,mVersionDes);
Log.i(tag,versionName);
//8,比對版本號(本地版本號<服務器版本號,提示用戶更新)
if(mLocalVersionCode<Integer.parseInt(versionCode)){
//提示用戶更新,彈出對話框(UI)可視化範疇,在此要彈出對話框,要用消息機制,去頂部創建Handler對象
msg.what=UPDATE_VERSION;//將其維護到SplashA當中設置常量爲100
}else{
//進入應用程序主界面
msg.what = ENTER_HOME;//ENTER_HOME應用程序主界面狀態碼,被改爲101
}
}
} catch (MalformedURLException e) {
e.printStackTrace();
msg.what = URL_ERROR;
}catch (IOException e) {
e.printStackTrace();
msg.what = IO_ERROR;
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
msg.what = JSON_ERROR;
}finally{
//指定睡眠時間,請求網絡的時長超過4秒則不做處理
//請求網絡時間的時長小於4秒,強制讓其睡眠滿4秒鐘,去計算一下代碼運行時間
long endTime = System.currentTimeMillis();
if(endTime-startTime<4000){
try {
Thread.sleep(4000-(endTime-startTime));
} catch (Exception e) {
e.printStackTrace();
}
}
mHandler.sendMessage(msg);
}
};
}.start();
}
/**
* 返回版本號
* @return
* 非0則代表獲取成功
*/
private int getVersionCode() {
// 1,包管理者對象packageManaer
PackageManager pm = getPackageManager();
//2,從包的管理者對象中,獲取指定包名的基本信息(版本名稱,版本號),用getPackageInfo,傳0代表獲取基本信息
try {
PackageInfo packageInfo = pm.getPackageInfo(getPackageName(), 0);
return packageInfo.versionCode;//private String getVersionName()
} catch (Exception e) {
e.printStackTrace();
}
return 0;
}
/**
* 獲取版本名稱;清單文件中
* @return 應用版本名稱 返回null代表異常
*
*/
private String getVersionName() {
// 1,包管理者對象packageManaer
PackageManager pm = getPackageManager();
//2,從包的管理者對象中,獲取指定包名的基本信息(版本名稱,版本號),用getPackageInfo,傳0代表獲取基本信息
try {
PackageInfo packageInfo = pm.getPackageInfo(getPackageName(), 0);
/**3,獲取版本名稱爲清單文件SplashActivity1.Manifest裏的 android:versionCode="1"
*android:versionName="1.0",此方法有了返回值,將此方法返回值類型void改爲String
*/
return packageInfo.versionName;//private String getVersionName()
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
/*初始化UI*/
private void initUI() {
tv_version_name = (TextView) findViewById(R.id.tv_version_name);
rl_root = (RelativeLayout) findViewById(R.id.rl_root);
}
}
注:AndroidManifest.xml編寫:
<activity
android:name="com.sw.xmk.StartActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
完成了代碼的編寫後,需要在tomcat/webapps/ROOT目錄下放入我們的apk文件,我們取名爲:xc.apk
同時需要在此目錄下放置一個Json文件,內容如下:
{
"downloadUrl": "http://10.0.2.2:8080/xc.apk",
"versionCode": "2",
"versionDes": "Welcome to use 2.0,please download",
"versionName": "2.0"
}
如上,則完成了所有的操作,接下來我們進行測試,注意需要啓動tomcat服務器,接下來啓動app運行如下: