android实现app更新

首先是一个简易的activity

<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:background="@android:color/holo_orange_dark" >

    <ProgressBar
        android:id="@+id/pb_bar"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:translationY="-50dp"
        android:layout_marginTop="152dp" />

    <TextView
        android:id="@+id/tv_editin"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="@android:color/white"
        android:layout_centerInParent="true"
        android:text="版本:" />
    <TextView
        android:id="@+id/tv_editin_edit"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="@android:color/white"
        android:layout_centerVertical="true"
        android:layout_toRightOf="@+id/tv_editin"
        android:text="122.1" />

</RelativeLayout>

下载与安装的工具类,在这个类中要注意的是intent.addCategory("android.intent.category.DEFAULI");这个方法。有时用它会出现找不到intent的现象,可酌情使用

package cnjoanthan.updata;

import java.io.File;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Environment;
import android.util.Log;
import android.widget.Toast;

/*
 * 2016年8月19日 星期五
 * jonathan
 * 获取版本号和安装apk
 */
public class MyUtils {
	/*
	 * 获取版本号
	 * return 版本号
	 */
	public static String getVersion(Context context){
		PackageManager manager = context.getPackageManager();//PackageManager可以获取文件的信息
		Log.i("VersionUpdateUtils", "manager:" + manager);
		
		try {
			PackageInfo packageInfo = manager.getPackageInfo(context.getPackageName(), 0);
			Log.i("VersionUpdateUtils", "packageInfo:" + packageInfo);
			return packageInfo.versionName;
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			Log.i("VersionUpdateUtils", "MyUtilsTryAbnormal :" + e.getMessage());
			return "";
		}
	}
	
	/*
	 * 安装新版本
	 */
	 public static void installApk(Activity activity){
		Log.i("VersionUpdateUtils", "install activity:"+activity);
		try {
			String path = Environment.getExternalStorageDirectory().getAbsolutePath()+ File.separator+"mobilesafe"+File.separator+"mobilesafe.apk";
//			String path = "/sdcard/mobilesafe/mobilesafe.apk";
			Intent intent = new Intent();
			
			intent.setAction(Intent.ACTION_VIEW);
			//添加默认分类
//			intent.addCategory("android.intent.category.DEFAULI");
			//设置数据类型
			intent.setDataAndType(Uri.fromFile(new File(path)), "application/vnd.android.package-archive");/* Uri.fromFile(new File(path))*///Uri.parse("file://"+path)
			intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
			
			activity.startActivity(intent);
//			activity.startActivityForResult(intent, 0);
			
		} catch (Exception e) {
			// TODO: handle exception
			Log.i("VersionUpdateUtils", "install Excepyion:"+e.getMessage());
		}
		
	}	
	 
	

}

连接下载与解析,其中下载使用了xutile 解析JSONObject都需要jar包

package cnjoanthan.updata;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;

import org.json.JSONException;
import org.json.JSONObject;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.os.Environment;
import android.os.Handler;
import android.util.Log;
import android.widget.Toast;
import cnjoanthan.updata.DownLoadUtils.MyCallBack;

import com.lidroid.xutils.exception.HttpException;
import com.lidroid.xutils.http.ResponseInfo;

/*
 * 更新更新类
 */
public class VersionUpdateUtils {
	private static final String TAG = "VersionUpdateUtils";

	private static final int MESSAGE_NET_ERROR = 101;
	private static final int MESSAGE_IO_ERROR = 102;
	private static final int MESSAGE_JSON_ERROR = 103;
	private static final int MESSAGE_SHOW_DIALOG = 104;
	private static final int MESSAGE_ENTERHOME = 105;
	/* 本地版本号 */
	private String mVersion;
	private Activity context;
	private VersionEntity versionEntity;
	private ProgressDialog mProgressDialog;

	// private Version
	VersionUpdateUtils(String Version, Activity activity) {
		mVersion = Version;
		this.context = activity;
		Log.i(TAG, "VersionUpdateUtils已重构");
	}

	/* 用于更新的UI */
	private Handler handler = new Handler() {
		public void handleMessage(android.os.Message msg) {
			Log.i(TAG, "handleMessage启动");
			switch (msg.what) {
			case MESSAGE_IO_ERROR:
				Toast.makeText(context, "IO异常", Toast.LENGTH_SHORT).show();
				enterHome();
				break;
			case MESSAGE_JSON_ERROR:
				Toast.makeText(context, "JSON异常", Toast.LENGTH_SHORT).show();
				enterHome();
				break;
			case MESSAGE_NET_ERROR:
				Toast.makeText(context, "网络异常", Toast.LENGTH_SHORT).show();
				enterHome();
				break;
			case MESSAGE_SHOW_DIALOG:
				Log.i(TAG, "接收到message:"+MESSAGE_SHOW_DIALOG);
				showUpdateDialog(versionEntity);
				break;
			case MESSAGE_ENTERHOME:
				Toast.makeText(context, "即将跳转", Toast.LENGTH_LONG).show();
				break;

			default:
				break;
			}
		}

		/**
		 * 弹出提示框
		 * 
		 * @param versionEntity
		 */
		private void showUpdateDialog(final VersionEntity versionEntity) {
			// TODO Auto-generated method stub
			Log.i(TAG, "showUpdateDialog启动构建");
			/**
			 * 创建dialog
			 */
			AlertDialog.Builder builder = new AlertDialog.Builder(context);
			builder.setTitle("检测到新版本:" + versionEntity.versioncode);
			builder.setMessage(versionEntity.descripting);
			/** 服务器返回的描述信息 */
			builder.setCancelable(false);
			/** 设置手机不能点击返回键 */
			builder.setPositiveButton("立即升级",
					new DialogInterface.OnClickListener() {

						@Override
						public void onClick(DialogInterface dialog, int which) {
							// TODO Auto-generated method stub
							initProgressDialog();
							downloadNewAPK(versionEntity.apkurl);
						}

						/** 下载APK */
						@SuppressLint("SdCardPath") private void downloadNewAPK(String apkurl) {
							Log.i(TAG, "downloadApkurl:"+apkurl);
							// TODO Auto-generated method stub
							String fileName = Environment.getExternalStorageDirectory().getAbsolutePath()+ File.separator+"mobilesafe"+File.separator+"mobilesafe.apk";//getExternalStorageDirectory
//							String fileName = "/sdcard/mobilesafe/mobilesafe.apk";
							Log.i(TAG, "fileName:"+fileName);
							DownLoadUtils dowLoadUtils = new DownLoadUtils();
							dowLoadUtils.downapk(apkurl,
									fileName,
									new MyCallBack() {

										@Override
										public void onSuccess(
												ResponseInfo<File> arg0) {
											// TODO Auto-generated method stub
											mProgressDialog.dismiss();
											Log.i(TAG, "Dialog关闭");
											MyUtils.installApk(context);
										}

										@Override
										public void onLoadding(long total,
												long current,
												boolean isUploading) {
											// TODO Auto-generated method stub
											mProgressDialog.setMax((int) total);
											mProgressDialog
													.setMessage("正在下载...");
											mProgressDialog
													.setProgress((int) current);
											Log.i(TAG, "onLoadding");
										}

										@Override
										public void onFailure(
												HttpException arg0, String arg1) {
											// TODO Auto-generated method stub
											mProgressDialog.setMessage("下载失败");
											mProgressDialog.dismiss();
											enterHome();
											Log.i(TAG, "onFailure->arg0:"+arg0+" arg1:"+ arg1);
										}
									});

						}

						private void initProgressDialog() {
							// TODO Auto-generated method stub
							Log.i(TAG, "initProgressDialog开始运行");
							mProgressDialog = new ProgressDialog(context);
							mProgressDialog.setMessage("准备下载...");
							mProgressDialog
									.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
							mProgressDialog.show();
						}
					});
			builder.setNegativeButton("暂不升级",
					new DialogInterface.OnClickListener() {

						@Override
						public void onClick(DialogInterface dialog, int which) {
							// TODO Auto-generated method stub
							dialog.dismiss();
							enterHome();
						}
					});
			builder.show();

		};
	};

	/*
	 * 获取服务器版本
	 */
	public void getCloudVersion() {
		try {
			new Thread(postThread).start();
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
			Log.i(TAG, "线程异常:" + e.getMessage());
		}
	}

	private Thread postThread = new Thread() {
		public void run() {
			Log.i(TAG, "postThread线程启动");
			String target = "要提交的服务器的URL";
			URL url;
			try {
				url = new URL(target);
				HttpURLConnection urlConn = (HttpURLConnection) url
						.openConnection();
				urlConn.setRequestMethod("POST");
				urlConn.setDoInput(true);
				urlConn.setDoOutput(true);
				urlConn.setUseCaches(true);// 禁止缓存
				urlConn.setInstanceFollowRedirects(true);
				urlConn.setRequestProperty("Content-Type",
						"application/x-www-form-urlencoded");
				DataOutputStream out = new DataOutputStream(
						urlConn.getOutputStream());
				String param = "字段="
						+ URLEncoder.encode("字段值",
								"UTF-8") + "&" + "第二个字段="
						+ URLEncoder.encode("字段值", "UTF-8");
				out.writeBytes(param);
				out.flush();
				out.close();

				if (urlConn.getResponseCode() == HttpURLConnection.HTTP_OK) {
					InputStreamReader in = new InputStreamReader(
							urlConn.getInputStream(), "UTF-8");
					BufferedReader buffer = new BufferedReader(in);
					String inputLine = null;
					while ((inputLine = buffer.readLine()) != null) {
						Log.i(TAG, "inputLine:" + inputLine);
						try {
							JSONObject jsonObject = new JSONObject(inputLine);
							Log.i(TAG,
									"result_code:"
											+ jsonObject
													.getString("result_code"));
							if ((jsonObject.getString("result_code"))
									.equalsIgnoreCase("2")) {/* 服务器是否返回成功 */
								JSONObject request = jsonObject
										.getJSONObject("data");
								versionEntity = new VersionEntity();
								String code = request.getString("code");
								Log.i(TAG, "code:"+code);
								versionEntity.versioncode = code;
								String des = request.getString("des");
								Log.i(TAG, "des:"+des);
								versionEntity.descripting = des;
								String apkurl = request.getString("apkurl");
								Log.i(TAG, "apkurl:"+apkurl);
								versionEntity.apkurl = apkurl;
								if (!mVersion
										.equalsIgnoreCase(versionEntity.versioncode)) {
									/* 版本号不一致的时候 */
									handler.sendEmptyMessage(MESSAGE_SHOW_DIALOG);
									Log.i(TAG, "进入版本不一致模式");
								} else {
									enterHome();
								}
							}
						} catch (JSONException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					}
				}

			} catch (MalformedURLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

		};
	};

	/* end */
	private void enterHome() {
		handler.sendEmptyMessageDelayed(MESSAGE_ENTERHOME, 2000);
	}
}


下载的工具类

package cnjoanthan.updata;

import java.io.File;

import com.lidroid.xutils.HttpUtils;
import com.lidroid.xutils.exception.HttpException;
import com.lidroid.xutils.http.ResponseInfo;
import com.lidroid.xutils.http.callback.RequestCallBack;

/*
 * 下载工具类
 * jonathan 2016年8月19日 星期五
 */
public class DownLoadUtils {
	public void downapk(String url,String targerFile, final MyCallBack myCallBack){
		//创建HttpUtils对象
		HttpUtils httpUtils = new HttpUtils();
		//调用HttpUtils 下载的方法下载指定文件
		httpUtils.download(url, targerFile,new RequestCallBack<File>(){

			@Override
			public void onFailure(HttpException arg0, String arg1) {
				// TODO Auto-generated method stub
				myCallBack.onFailure(arg0, arg1);
			}

			@Override
			public void onSuccess(ResponseInfo<File> arg0) {
				// TODO Auto-generated method stub
				myCallBack.onSuccess(arg0);
			}
			
			@Override
			public void onLoading(long total, long current, boolean isUploading) {
				// TODO Auto-generated method stub
				super.onLoading(total, current, isUploading);
				myCallBack.onLoadding(total, current, isUploading);
			}
			
		});
	}
	
	interface MyCallBack{
		/* 下载成功时调用*/
		void onSuccess(ResponseInfo<File> arg0);
		/*下载失败时调用*/
		void onFailure(HttpException arg0,String arg1);
		/*下载中调用*/
		void onLoadding(long total, long current, boolean isUploading);
	}
}



信息实体

package cnjoanthan.updata;

import android.widget.TextView;

public class VersionEntity {
	/* 服务器版本号*/
	public String versioncode;
	/*版本描述*/
	public String descripting;
	/*apk 下载地址*/
	public String apkurl;
}


主函数

package cnjoanthan.updata;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.Window;
import android.widget.TextView;

public class MainActivity extends Activity {
	private String mVersion;//本地版本号
	private TextView mVersionTv;//应用版本号

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.i("VersionUpdateUtils", "正常");
        mVersion = MyUtils.getVersion(getApplicationContext());
        initView();
        
        
    }

	private void initView() {
		// TODO Auto-generated method stub
		mVersionTv = (TextView) findViewById(R.id.tv_editin_edit);
		mVersionTv.setText(mVersion);
		Log.i("VersionUpdateUtils", "mVersion:"+mVersion);
		
		final VersionUpdateUtils updateUtils = new VersionUpdateUtils(mVersion,MainActivity.this);
		Log.i("VersionUpdateUtils", "子线程启动");
		new Thread(){
			@Override
			public void run() {
				// TODO Auto-generated method stub
//				super.run();
				Log.i("VersionUpdateUtils", "匿名子线程运行");
				updateUtils.getCloudVersion();
			}
			
		}.start();
		
		
	}
}


manifest


<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="cnjoanthan.updata"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="19"
        android:targetSdkVersion="19" />
    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    
    <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>

其中的存储目录是写了一个固定的可更改
框架内部支持中/英文(其他语言只需要在对应的string.xml中取相同的名字即可)内部对话框背景图片、按钮支持自定义了查看版本中的Log只需要过滤AppUpdate开头的Tag重点: 如果没有设置downloadPath则默认为getExternalCacheDir()目录,同时不会申请[存储]权限!目录编译问题效果图功能介绍DownloadManagerUpdateConfiguration使用步骤Demo下载体验版本更新记录结语编译问题因为适配了Android O的通知栏,所以依赖的v7包版本比较高appcompat-v7:26.1.0使用的gradle版本为gradle-4.1-all,所以建议使用Android Studio 3.0及以上的版本打开此项目效果图     功能介绍 支持断点下载 支持后台下载 支持自定义下载过程 支持 设备 >= Android M 动态权限的申请 支持通知栏进度条展示(或者自定义显示进度) 支持Android N 支持Android O 支持中/英文双语 支持自定内置对话框的样式 使用HttpURLConnection下载,未集成其他第三方框架更加详细的文档参阅此处《AppUpdate API文档》DownloadManager:配置文档初始化使用DownloadManager.getInstance(this)属性描述默认值是否必须设置context上下文nulltrueapkUrlapk的下载地址nulltrueapkNameapk下载好的名字nulltruedownloadPathapk下载的位置getExternalCacheDir()falseshowNewerToast是否提示用户 "当前已是最新版本"falsefalsesmallIcon通知栏的图标(资源id)-1trueconfiguration这个库的额外配置nullfalseapkVersionCode更新apk的versionCode (如果设置了那么库中将会进行版本判断下面的属性也就需要设置了)1falseapkVersionName更新apk的versionNamenullfalseapkDescription更新描述nullfalseapkSize新版本的安装包大小(单位M)nullfalseauthorities兼容Android N uri授权应用包名falseUpdateConfiguration:配置文档属性描述默认值notifyId通知栏消息id1011notificationChannel适配Android O的渠道通知详情查阅源码httpManager设置自己的下载过程nullbreakpointDownload是否需要支持断点下载trueenableLog是否需要日志输出trueonDownloadListener下载过程的回调nulljumpInstallPage下载完成是否自动弹出安装页面trueshowNotification是否显示通知栏进度(后台下载提示)trueforcedUpgrade是否强制升级falseonButtonClickListener按钮点击事件回调nulldialogImage对话框背景图片资源(图片规范参考demo)-1dialogButtonColor对话框按钮的颜色-1dialogButtonTextColor对话框按钮的文字颜色-1所有版本:点击查看使用步骤第一步: app/build.gradle进行依赖implementation 'com.azhon:appupdate:1.7.3'第二步:创建DownloadManager,更多用法请查看这里示例代码DownloadManager manager = DownloadManager.getInstance(this); manager.setApkName("appupdate.apk")         .setApkUrl("https://raw.githubusercontent.com/azhon/AppUpdate/master/apk/appupdate.apk")         .setSmallIcon(R.mipmap.ic_launcher)         //可设置,可不设置         .setConfiguration(configuration)         .download();第三步:兼容Android N 及以上版本,在你应用的Manifest.xml添加如下代码<--! android:authorities="${applicationId}"  这个值必须与DownloadManager中的authorities一致(不设置则为应用包名)--> <provider     android:name="android.support.v4.content.FileProvider"     android:authorities="${applicationId}"     android:exported="false"     android:grantUriPermissions="true">     <meta-data         android:name="android.support.FILE_PROVIDER_PATHS"         android:resource="@xml/file_paths_public" /> </provider>第四步:资源文件res/xml/file_paths_public.xml内容<?xml version="1.0" encoding="utf-8"?> <paths>     <external-path         name="app_update_external"         path="/" />     <external-cache-path         name="app_update_cache"         path="/" /> </paths>兼容Android O及以上版本,需要设置NotificationChannel(通知渠道);库中已经写好可以前往查阅NotificationUtil.java温馨提示:升级对话框中的内容是可以上下滑动的哦!如果需要实现自己一套下载过程,只需要继承BaseHttpDownloadManager 并使用listener更新进度public class MyDownload extends BaseHttpDownloadManager {}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值