Android自动更新App

 自动更新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




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值