自动更新App,很多App都有这个功能,现在记录一下过程。
首先导入grandle
compile "com.squareup.retrofit:retrofit:2.0.0-beta2"
compile "com.squareup.retrofit:converter-gson:2.0.0-beta2"
compile "com.squareup.retrofit:adapter-rxjava:2.0.0-beta2"
这里我用了retrofit进行检查网络状态。创建几个关键类。
package com.abings.updateapp.upapp;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.os.Message;
import android.util.Xml;
import com.abings.updateapp.AppUtils;
import com.abings.updateapp.NetworkUtil;
import com.abings.updateapp.R;
import org.xmlpull.v1.XmlPullParser;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
/**
* 检查版本
*
* @author zwj
* @Date 2016-05-24
*/
public class CheckVersionThread extends Thread {
/**
* 读取服务器的版本号
*/
public final String kVersion = "version";
/**
* 下载连接
*/
public final String kUrl = "url";
/**
* 描述
*/
public final String kDesc = "desc";
private Context bContext;
private Handler mHandler;
/**
* 升级
*/
public final static int NEEDUPDATE = 1;
/**
* 已经最新
*/
public final static int Newest = 2;
private String bFilePath;//文件目录
private String updateUrl;//升级地址
private boolean isManual = false;
private ProgressDialog mProgressDialog = null;
@SuppressWarnings("unused")
private CheckVersionThread() {
}
/**
* @param bContext
* @param bFilePath
* @param updateUrl
*/
public CheckVersionThread(Context bContext, String bFilePath, String updateUrl) {
this.bContext = bContext;
this.bFilePath = bFilePath;
this.updateUrl = updateUrl;
mHandler = new MHandler();
}
/**
* @param bContext
* @param bFilePath
* @param updateUrl
* @param isManual 是否手动申请查看最新版
*/
public CheckVersionThread(Context bContext, String bFilePath, String updateUrl, boolean isManual) {
this(bContext, bFilePath, updateUrl);
this.isManual = isManual;
if (isManual) {
mProgressDialog = showProgressDialog(mProgressDialog, "提示", "正在获取最新版本信息", bContext);
}
}
@Override
public void run() {
super.run();
try {
String nowVersion = AppUtils.getVersionName(bContext);
// 不需要在这里做自动升级判断
if (!NetworkUtil.isNetworkConnected(bContext)) {
// 不自动升级,无网络
//sendHandler(BaseHandler.netNo);
return;
}
Map<String, String> updateInfo = getUpdateInfo(updateUrl);
if (updateInfo != null && updateInfo.isEmpty()) {
/* 获取服务器上的最新版本信息失败 */
} else {
if (nowVersion.equals(updateInfo.get(kVersion))) {
// 不用显示更新的对话框
/* 没有升级信息,进入主界面 */
sendHandler(Newest, "已经是最新版本");
} else {
// 显示更新的对话框
sendHandler(NEEDUPDATE, updateInfo);
}
}
} catch (Exception e) {
e.printStackTrace();
// 获取服务器上的最新版本信息失败
// sendHandler(BaseHandler.netUnkownErr);
} finally {
dismissProgressDialog(mProgressDialog);
}
}
/**
* 获取服务上的最新的版本信息
*
* @param path 路径
* @return
* @throws Exception
*/
private Map<String, String> getUpdateInfo(String path) throws Exception {
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(5000);
conn.setRequestMethod("GET");
if (conn.getResponseCode() == 200) {
InputStream is = conn.getInputStream();
return parserUpdateInfo(is);
}
return new HashMap<String, String>();
}
/**
* 解析服务的流信息为UpdateInfo对象
*
* @param is
* @return
* @throws Exception
*/
private Map<String, String> parserUpdateInfo(InputStream is) throws Exception {
Map<String, String> map = null;
XmlPullParser parser = Xml.newPullParser();
parser.setInput(is, "UTF-8");
int eventType = parser.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT) {
switch (eventType) {
case XmlPullParser.START_TAG:
if ("updateinfo".equals(parser.getName())) {
map = new HashMap<String, String>();
} else if (kVersion.equals(parser.getName())) {
String version = parser.nextText();
map.put(kVersion, version);
} else if (kUrl.equals(parser.getName())) {
String url = parser.nextText();
map.put(kUrl, url);
} else if (kDesc.equals(parser.getName())) {
String description = parser.nextText();
map.put(kDesc, description);
}
break;
default:
break;
}
eventType = parser.next();
}
return (map != null && !map.isEmpty()) ? map : new HashMap<String, String>();
}
private void sendHandler(int iWhat, Object obj) {
Message msg = Message.obtain();
msg.what = iWhat;
msg.obj = obj;
this.mHandler.sendMessage(msg);
}
private void sendHandler(int iWhat) {
Message msg = Message.obtain();
msg.what = iWhat;
this.mHandler.sendMessage(msg);
}
private class MHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case Newest:
if (isManual) {
// DialogUtils.ShowMsgDialog(mContext, msg.obj.toString());
}
break;
case NEEDUPDATE:
final Map<String, String> map = (Map<String, String>) msg.obj;
setNotification(map.get(kDesc), map.get(kUrl));
break;
default:
super.handleMessage(msg);
break;
}
}
}
private void setNotification(String desc, String url) {
setNotificationUpdate(bContext, desc, url);
}
/**
* 升级的提醒
*
* @param mContext
*/
public static void setNotificationUpdate(Context mContext, String desc, String url) {
int NOTIFICATION_FLAG = 1;
NotificationManager manager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
Intent intent = new Intent(mContext, UpAppDialogActivity.class);
intent.putExtra("desc", desc);
intent.putExtra("url", url);
PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, intent, 0);
Notification notify = new Notification.Builder(mContext)
.setSmallIcon(R.drawable.logo)
.setTicker("新版本来了,请尽快升级哦!")
.setContentTitle("升级提醒")
.setContentText("新版本来了,请尽快升级哦!")
.setContentIntent(pendingIntent).setNumber(1).getNotification();
notify.defaults = Notification.DEFAULT_ALL;
notify.flags |= Notification.FLAG_AUTO_CANCEL;
notify.flags |= Notification.FLAG_SHOW_LIGHTS;
manager.notify(NOTIFICATION_FLAG, notify);
}
/**
* @param mProgressDialog
* @param title
* @param msg
* @param context
* @return
* @author zwj
*/
private ProgressDialog showProgressDialog(ProgressDialog mProgressDialog, String title, String msg, Context context) {
if (mProgressDialog != null) {
if (mProgressDialog.isShowing()) {
mProgressDialog.dismiss();
}
mProgressDialog = null;
}
mProgressDialog = new ProgressDialog(context,
ProgressDialog.THEME_HOLO_LIGHT);
mProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
mProgressDialog.setTitle(title);
mProgressDialog.setCanceledOnTouchOutside(false);
mProgressDialog.setCancelable(false);
mProgressDialog.setMessage(msg);
mProgressDialog.show();
return mProgressDialog;
}
/**
* 取消等待条
*
* @param mProgressDialog
* @date 2014-6-19上午10:18:24
*/
private void dismissProgressDialog(ProgressDialog mProgressDialog) {
if (null != mProgressDialog && mProgressDialog.isShowing()) {
mProgressDialog.dismiss();
}
}
}
CheckVersionThread 是用来检测版本是否更新的类。
在创建一个类来获取当前app的版本。
<pre name="code" class="java">package com.abings.updateapp;
import android.content.Context;
import android.provider.Settings;
public class AppUtils {
public AppUtils() {
}
public static int getVersionCode(Context context) {
int i;
try {
i = context.getPackageManager().getPackageInfo(context.getPackageName(), 0).versionCode;
} catch (Throwable throwable) {
throw new RuntimeException(throwable);
}
return i;
}
public static String getVersionName(Context context) {
String s;
try {
s = context.getPackageManager().getPackageInfo(context.getPackageName(), 0).versionName;
} catch (Throwable throwable) {
throw new RuntimeException(throwable);
}
return s;
}
public static String getDeviceId(Context context) {
return Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);
}
public static String getSystemVersion() {
return android.os.Build.VERSION.RELEASE;// android系统版本号
}
}
创建一个网络检测的类。
package com.abings.updateapp;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import retrofit.HttpException;
public class NetworkUtil {
/**
* Returns true if the Throwable is an instance of RetrofitError with an
* http status code equals to the given one.
*/
public static boolean isHttpStatusCode(Throwable throwable, int statusCode) {
return throwable instanceof HttpException
&& ((HttpException) throwable).code() == statusCode;
}
public static boolean isNetworkConnected(Context context) {
ConnectivityManager cm =
(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
return activeNetwork != null && activeNetwork.isConnectedOrConnecting();
}
}
最后是现实的Activity.
package com.abings.updateapp.upapp;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import com.abings.updateapp.R;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.Response;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.TimeUnit;
/**
* Created by HaomingXu on 2016/6/29.
*/
public class UpAppDialogActivity extends AppCompatActivity {
private TextView tvDesc;
private String apkpath;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_upapp_dialog);
initId();
String desc = getIntent().getStringExtra("desc");
tvDesc.setText(desc);
}
private void initId() {
tvDesc = (TextView) findViewById(R.id.upappdialog_tv_desc);
}
public void play(View v){
switch (v.getId()){
case R.id.upappdialog_btn_ok:
if(Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())){
String url = getIntent().getStringExtra("url");
String fileName = url.substring(url.lastIndexOf("/") + 1);
apkpath = fileName;
download(url,Const.apkDownPath,fileName);
finish();
}else{
Toast.makeText(this, "SDCard不存在", Toast.LENGTH_SHORT).show();
}
break;
case R.id.upappdialog_btn_cancel:
finish();
break;
}
}
public void showLoadingProgress(boolean show) {
if (show) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setIcon(R.drawable.logo);
builder.setTitle("提示");
builder.setMessage("正在下载中...");
builder.create().show();
}
}
public void installApp(String path) {
Log.i("TAG00",path);
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
File file = new File(path);
intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
startActivity(intent);
}
Handler handler = new Handler() {
public void handleMessage(Message msg){
switch (msg.what){
case 0:
showLoadingProgress(false);
break;
}
}
};
public void download(final String loadurl, final String path, final String fileName){
showLoadingProgress(true);
Log.i("TAG00",loadurl);
OkHttpClient mOkHttpClient = new OkHttpClient();
mOkHttpClient.setReadTimeout(3000, TimeUnit.MILLISECONDS);
mOkHttpClient.setWriteTimeout(3000, TimeUnit.MILLISECONDS);
mOkHttpClient.setConnectTimeout(3000, TimeUnit.MILLISECONDS);
Request request = new Request.Builder().url(loadurl).tag(this).build();
mOkHttpClient.newCall(request).enqueue(new com.squareup.okhttp.Callback() {
@Override
public void onFailure(Request request, IOException e) {
}
@Override
public void onResponse(Response response) throws IOException {
if (response.isSuccessful()) {
InputStream is = response.body().byteStream();
byte[] buf = new byte[2048];
int len = 0;
FileOutputStream fos = null;
try {
is = response.body().byteStream();
final long total = response.body().contentLength();
long sum = 0;
File dir = new File(path);
if (!dir.exists()) {
dir.mkdirs();
}
File file = new File(dir, fileName);
fos = new FileOutputStream(file);
while ((len = is.read(buf)) != -1) {
sum += len;
fos.write(buf, 0, len);
final long finalSum = sum;
}
fos.flush();
} finally {
if (is != null) is.close();
if (fos != null) fos.close();
handler.sendEmptyMessage(0);
installApp(Const.apkDownPath + apkpath);
}
} else {
Log.i("TAG00", "文件下载链接失败。。。");
}
}
});
}
}
所有关键的类都已经创建,在MainActivity进入时,调用CheckThread检测版本是否更新,若是更新,那么发出一个Notification提示用户,点击之后跳转UpAppDialogActivity,让用户进行选择,是否是更新。点击更新,开启异步网络加载,使用Okhttp,使用文件流下载,下载完成之后提示安装。
时间比较短,所以写的比较潦草,我直接上代码,相信各位都能看懂。
https://github.com/SingleShu/UpdateApp