Android-啓動界面檢查更新以及安裝

在安卓開發過程中,很多時候再軟件啓動時需要檢查進行更版本更新,在本文中,採取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運行如下:


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章