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运行如下:


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