Android app更新方案

Android app更新方案:兼容6.0,7.0系统 包含强制更新,非强制后台更新,浏览器更新

项目中app更新功能是必不可少的  项目中遇到到的动态权限问题,文件权限问题 

根据需求的不同 有时需要用户强制更新 有时更新对于用户是可选的 可以放在后台更新

最简单直接的方法直接打开浏览器更新 完全不用适配什么6.0 什么7.0 几行代码搞定 代码如下:

/**
 * 打开浏览器
 * @param url
 */
public void browerUpdate(String url) {
    Intent intent = new Intent();
    intent.setAction("android.intent.action.VIEW");
    Uri content_url = Uri.parse(url);
    intent.setData(content_url);
    AppManager.getInstance().getTopActivity().startActivity(intent);
}


好了开始入正题,更新无非就是强制更新和后台更新 
2 强制更新采用的是Android 原生的DownloadManager实现文件的下载
3 后台更新采用的是xutils实现的文件下载  

强制更新 完整代码:

package com.langj.update.appconfig;

import android.app.DownloadManager;
import android.app.ProgressDialog;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Handler;
import android.os.Message;
import android.widget.Toast;


import com.langj.update.R;
import com.langj.update.app.Constant;
import com.langj.update.utils.AppManager;
import com.langj.update.utils.SPUtil;

import org.xutils.x;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/

public class DownloadUtils {


    private DownloadManager downloadManager;
    private Context mContext;
    private long downloadId;

    private ProgressDialog progressDialog;
    private DownloadChangeObserver downloadObserver;
    public static final int HANDLE_DOWNLOAD = 0x001;
    private ScheduledExecutorService scheduledExecutorService;

    public DownloadUtils(Context context) {
        this.mContext = context;
    }


    public void downloadAPK(String url) {

        downloadObserver = new DownloadChangeObserver();
        showProcess();
        registerContentObserver();
        //创建下载任务
        DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
        //移动网络情况下是否允许漫游
        request.setAllowedOverRoaming(false);
        request.setMimeType("application/vnd.android.package-archive");
        //在通知栏中显示,默认就是显示的
        request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_HIDDEN);
        request.setTitle("新版本" + x.app().getResources().getString(R.string.app_name));
        request.setDescription("正在下载" + x.app().getResources().getString(R.string.app_name));
        request.setVisibleInDownloadsUi(true);
        //设置下载的路径
//        request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, " myApp.apk");
        request.setDestinationInExternalFilesDir(mContext.getApplicationContext(), "phoenix", "phoenix.apk");
        //获取DownloadManager
        downloadManager = (DownloadManager) mContext.getSystemService(Context.DOWNLOAD_SERVICE);
        //将下载请求加入下载队列,加入下载队列后会给该任务返回一个long型的id,通过该id可以取消任务,重启任务、获取下载的文件等等
        downloadId = downloadManager.enqueue(request);
        registerBroadcast();
    }

    /**
     * 正在下载中的进度条
     */
    public void showProcess() {
        progressDialog = new ProgressDialog(AppManager.getInstance().getTopActivity());
        progressDialog.setCancelable(false);
        progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
        progressDialog.setMax(100);
        progressDialog.setMessage("正在下载...");
        progressDialog.show();
    }

    /**
     * 注册广播
     */
    private void registerBroadcast() {
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(DownloadManager.ACTION_DOWNLOAD_COMPLETE);
        intentFilter.addAction(DownloadManager.ACTION_NOTIFICATION_CLICKED);
        mContext.registerReceiver(receiver, intentFilter);
    }

    /**
     * 注册ContentObserver
     */
    private void registerContentObserver() {
        /** observer download change **/
        if (downloadObserver != null) {
            mContext.getContentResolver().registerContentObserver(Uri.parse("content://downloads/my_downloads"), true, downloadObserver);
        }
    }

    private BroadcastReceiver receiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            checkStatus();
        }
    };

    //检查下载状态
    private void checkStatus() {
        DownloadManager.Query query = new DownloadManager.Query();
        //通过下载的id查找
        query.setFilterById(downloadId);
        Cursor c = downloadManager.query(query);
        if (c != null && c.moveToFirst()) {
            int state = c.getInt(c.getColumnIndex(DownloadManager.COLUMN_STATUS));
            switch (state) {
                //下载暂停
                case DownloadManager.STATUS_PAUSED:
                    break;
                case DownloadManager.ERROR_CANNOT_RESUME:
                    //下载延迟
                case DownloadManager.STATUS_PENDING:
                    break;
                //正在下载
                case DownloadManager.STATUS_RUNNING:
                    break;
                //下载完成
                case DownloadManager.STATUS_SUCCESSFUL:
                    //下载完成安装APK
                    close();
                    progressDialog.setProgress(100);
                    unregisterBroadcast();
                    unregisterContentObserver();
                    Uri downloadFileUri = downloadManager.getUriForDownloadedFile(downloadId);
                    SPUtil.put(Constant.SP_DOWNLOAD_PATH, downloadFileUri.getPath());
                    installApk(downloadFileUri);

                    break;
                //下载失败
                case DownloadManager.STATUS_FAILED:
                    Toast.makeText(mContext, "下载失败", Toast.LENGTH_SHORT).show();
                    break;
            }
        }
        c.close();
    }


    /**
     * 安装APK
     *
     * @param apkPath 安装包的路径
     */
    public void installApk(Uri apkPath) {
        Intent intent = new Intent();
        intent.setAction(Intent.ACTION_VIEW);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.setDataAndType(apkPath, "application/vnd.android.package-archive");
        mContext.startActivity(intent);
    }

    public Handler downLoadHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if (HANDLE_DOWNLOAD == msg.what) {
                float i = (msg.arg1 / (float) msg.arg2);
                int k = (int) (i * 100);
                if (k >= 0) {
                    progressDialog.setProgress(k);
                }
            }
        }
    };

    /**
     * 关闭定时器,线程等操作
     */
    private void close() {
        if (scheduledExecutorService != null && !scheduledExecutorService.isShutdown()) {
            scheduledExecutorService.shutdown();
        }

        if (downLoadHandler != null) {
            downLoadHandler.removeCallbacksAndMessages(null);
        }
    }

    /**
     * 注销广播
     */
    private void unregisterBroadcast() {
        if (receiver != null) {
            mContext.unregisterReceiver(receiver);
            receiver = null;
        }
    }

    /**
     * 注销ContentObserver
     */
    private void unregisterContentObserver() {
        if (downloadObserver != null) {
            mContext.getContentResolver().unregisterContentObserver(downloadObserver);
        }
    }

    private Runnable progressRunnable = new Runnable() {
        @Override
        public void run() {
            int[] bytesAndStatus = getBytesAndStatus(downloadId);
            downLoadHandler.sendMessage(downLoadHandler.obtainMessage(HANDLE_DOWNLOAD, bytesAndStatus[0], bytesAndStatus[1], bytesAndStatus[2]));
        }
    };

    private int[] getBytesAndStatus(long downloadId) {
        int[] bytesAndStatus = new int[]{
                -1, -1, 0
        };
        DownloadManager.Query query = new DownloadManager.Query().setFilterById(downloadId);
        Cursor cursor = null;
        try {
            cursor = downloadManager.query(query);
            if (cursor != null && cursor.moveToFirst()) {
                //已经下载文件大小
                bytesAndStatus[0] = cursor.getInt(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR));
                //下载文件的总大小
                bytesAndStatus[1] = cursor.getInt(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_TOTAL_SIZE_BYTES));
                //下载状态
                bytesAndStatus[2] = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS));
            }
        } finally {
            if (cursor != null) {
                cursor.close();
            }
        }
        return bytesAndStatus;
    }

    private class DownloadChangeObserver extends ContentObserver {

        public DownloadChangeObserver() {
            super(downLoadHandler);
            scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
        }

        /**
         * 当所监听的Uri发生改变时,就会回调此方法
         *
         * @param selfChange 此值意义不大, 一般情况下该回调值false
         */
        @Override
        public void onChange(boolean selfChange) {
            scheduledExecutorService.scheduleAtFixedRate(progressRunnable, 0, 2, TimeUnit.SECONDS);
        }
    }


}

后台更新:

package com.langj.update.appconfig;

import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.IBinder;
import android.os.SystemClock;
import android.support.annotation.Nullable;
import android.support.v4.content.FileProvider;


import com.langj.update.R;
import com.langj.update.utils.AppManager;

import org.xutils.x;

import java.io.File;

/**
 */
public class DownLoadService extends Service {
    String download_url;
    private int requestCode = (int) SystemClock.uptimeMillis();

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        download_url = intent.getStringExtra("download_url");
        Intent intent_noti = new Intent();
        intent_noti.setAction(Intent.ACTION_VIEW);
//        intent_noti.setDataAndType(Uri.fromFile(mFile), "application/vnd.android.package-archive");
        PendingIntent rightPendIntent = PendingIntent.getActivity(this,
                requestCode, intent_noti, PendingIntent.FLAG_UPDATE_CURRENT);
        int smallIcon = R.mipmap.ic_launcher;
        String ticker = "正在更新" + x.app().getResources().getString(R.string.app_name);
        NotifyUtil notify7 = new NotifyUtil(this, 7);
        notify7.notify_progress(rightPendIntent, smallIcon, ticker, x.app().getResources().getString(R.string.app_name) + "升级程序", "正在下载中",
                false, false, false, download_url, new NotifyUtil.DownLoadListener() {
                    @Override
                    public void OnSuccess(File file) {
                        DownLoadService.this.stopSelf();
                        install(file);
                    }

                    @Override
                    public void onFailure(Throwable t, int errorNo, String strMsg) {

                    }
                });
        return super.onStartCommand(intent, flags, startId);
    }

    /**
     * 安装APk
     * @param file
     */
    public static void install(File file) {
        Uri apkUri;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            apkUri = FileProvider.getUriForFile(AppManager.getInstance().getTopActivity(), "com.langj.update.fileprovider", file);
        } else {
            apkUri = Uri.fromFile(file);
        }
        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        intent.setDataAndType(apkUri, "application/vnd.android.package-archive");
        AppManager.getInstance().getTopActivity().startActivity(intent);
    }
}

后台更新用到的通知类“

package com.langj.update.appconfig;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Build;
import android.os.SystemClock;
import android.support.v7.app.NotificationCompat;
import android.widget.RemoteViews;
import android.widget.Toast;


import com.langj.update.R;
import com.langj.update.utils.AppManager;
import com.langj.update.utils.FileManager;

import org.xutils.common.Callback;
import org.xutils.common.task.PriorityExecutor;
import org.xutils.http.RequestParams;
import org.xutils.x;

import java.io.File;
import java.util.ArrayList;

@SuppressLint("NewApi")
public class NotifyUtil {

    private static final int FLAG = Notification.FLAG_INSISTENT;
    int requestCode = (int) SystemClock.uptimeMillis();
    private int NOTIFICATION_ID;
    private NotificationManager nm;
    private Notification notification;
    private NotificationCompat.Builder cBuilder;
    private Notification.Builder nBuilder;
    private Context mContext;


    public NotifyUtil(Context context, int ID) {
        this.NOTIFICATION_ID = ID;
        mContext = context;
        // 获取系统服务来初始化对象
        nm = (NotificationManager) mContext
                .getSystemService(Activity.NOTIFICATION_SERVICE);
        cBuilder = new NotificationCompat.Builder(mContext);
    }

    /**
     * 设置在顶部通知栏中的各种信息
     *
     * @param pendingIntent
     * @param smallIcon
     * @param ticker
     */
    private void setCompatBuilder(PendingIntent pendingIntent, int smallIcon, String ticker,
                                  String title, String content, boolean sound, boolean vibrate, boolean lights) {
//        // 如果当前Activity启动在前台,则不开启新的Activity。
//        intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
//        // 当设置下面PendingIntent.FLAG_UPDATE_CURRENT这个参数的时候,常常使得点击通知栏没效果,你需要给notification设置一个独一无二的requestCode
//        // 将Intent封装进PendingIntent中,点击通知的消息后,就会启动对应的程序
//        PendingIntent pIntent = PendingIntent.getActivity(mContext,
//                requestCode, intent, FLAG);

        cBuilder.setContentIntent(pendingIntent);// 该通知要启动的Intent
        cBuilder.setSmallIcon(smallIcon);// 设置顶部状态栏的小图标
        cBuilder.setLargeIcon((BitmapFactory.decodeResource(AppManager.getInstance().getTopActivity().getResources(), R.mipmap.ic_launcher)));// 设置顶部状态栏的小图标
        cBuilder.setTicker(ticker);// 在顶部状态栏中的提示信息
        cBuilder.setContentTitle(title);// 设置通知中心的标题
        cBuilder.setContentText(content);// 设置通知中心中的内容
        cBuilder.setWhen(System.currentTimeMillis());

      /*
         * 将AutoCancel设为true后,当你点击通知栏的notification后,它会自动被取消消失,
       * 不设置的话点击消息后也不清除,但可以滑动删除
       */
        cBuilder.setAutoCancel(true);
        // 将Ongoing设为true 那么notification将不能滑动删除
        // notifyBuilder.setOngoing(true);
        /*
         * 从Android4.1开始,可以通过以下方法,设置notification的优先级,
       * 优先级越高的,通知排的越靠前,优先级低的,不会在手机最顶部的状态栏显示图标
       */
        cBuilder.setPriority(NotificationCompat.PRIORITY_MAX);
        /*
         * Notification.DEFAULT_ALL:铃声、闪光、震动均系统默认。
       * Notification.DEFAULT_SOUND:系统默认铃声。
       * Notification.DEFAULT_VIBRATE:系统默认震动。
       * Notification.DEFAULT_LIGHTS:系统默认闪光。
       * notifyBuilder.setDefaults(Notification.DEFAULT_ALL);
       */
        int defaults = 0;

        if (sound) {
            defaults |= Notification.DEFAULT_SOUND;
        }
        if (vibrate) {
            defaults |= Notification.DEFAULT_VIBRATE;
        }
        if (lights) {
            defaults |= Notification.DEFAULT_LIGHTS;
        }

        cBuilder.setDefaults(defaults);
    }

    /**
     * 设置builder的信息,在用大文本时会用到这个
     *
     * @param pendingIntent
     * @param smallIcon
     * @param ticker
     */
    private void setBuilder(PendingIntent pendingIntent, int smallIcon, String ticker, boolean sound, boolean vibrate, boolean lights) {
        nBuilder = new Notification.Builder(mContext);
        // 如果当前Activity启动在前台,则不开启新的Activity。
//        intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
//        PendingIntent pIntent = PendingIntent.getActivity(mContext,
//                requestCode, intent, FLAG);
        nBuilder.setContentIntent(pendingIntent);

        nBuilder.setSmallIcon(smallIcon);


        nBuilder.setTicker(ticker);
        nBuilder.setWhen(System.currentTimeMillis());
        nBuilder.setPriority(Notification.PRIORITY_MAX);

        int defaults = 0;

        if (sound) {
            defaults |= Notification.DEFAULT_SOUND;
        }
        if (vibrate) {
            defaults |= Notification.DEFAULT_VIBRATE;
        }
        if (lights) {
            defaults |= Notification.DEFAULT_LIGHTS;
        }

        nBuilder.setDefaults(defaults);
    }

    /**
     * 普通的通知
     * 

* 1. 侧滑即消失,下拉通知菜单则在通知菜单显示 * * @param pendingIntent * @param smallIcon * @param ticker * @param title * @param content */ public void notify_normal_singline(PendingIntent pendingIntent, int smallIcon, String ticker, String title, String content, boolean sound, boolean vibrate, boolean lights) { setCompatBuilder(pendingIntent, smallIcon, ticker, title, content, sound, vibrate, lights); sent(); } /** * 进行多项设置的通知(在小米上似乎不能设置大图标,系统默认大图标为应用图标) * * @param pendingIntent * @param smallIcon * @param ticker * @param title * @param content */ public void notify_mailbox(PendingIntent pendingIntent, int smallIcon, int largeIcon, ArrayList messageList, String ticker, String title, String content, boolean sound, boolean vibrate, boolean lights) { setCompatBuilder(pendingIntent, smallIcon, ticker, title, content, sound, vibrate, lights); // 将Ongoing设为true 那么notification将不能滑动删除 //cBuilder.setOngoing(true); Bitmap bitmap = BitmapFactory.decodeResource(mContext.getResources(), largeIcon); cBuilder.setLargeIcon(bitmap); cBuilder.setDefaults(Notification.DEFAULT_ALL);// 设置使用默认的声音 //cBuilder.setVibrate(new long[]{0, 100, 200, 300});// 设置自定义的振动 cBuilder.setAutoCancel(true); // builder.setSound(Uri.parse("file:///sdcard/click.mp3")); // 设置通知样式为收件箱样式,在通知中心中两指往外拉动,就能出线更多内容,但是很少见 //cBuilder.setNumber(messageList.size()); NotificationCompat.InboxStyle inboxStyle = new NotificationCompat.InboxStyle(); for (String msg : messageList) { inboxStyle.addLine(msg); } inboxStyle.setSummaryText("[" + messageList.size() + "条]" + title); cBuilder.setStyle(inboxStyle); sent(); } /** * 自定义视图的通知 * * @param remoteViews * @param pendingIntent * @param smallIcon * @param ticker */ public void notify_customview(RemoteViews remoteViews, PendingIntent pendingIntent, int smallIcon, String ticker, boolean sound, boolean vibrate, boolean lights) { setCompatBuilder(pendingIntent, smallIcon, ticker, null, null, sound, vibrate, lights); notification = cBuilder.build(); notification.contentView = remoteViews; // 发送该通知 nm.notify(NOTIFICATION_ID, notification); } /** * 可以容纳多行提示文本的通知信息 (因为在高版本的系统中才支持,所以要进行判断) * * @param pendingIntent * @param smallIcon * @param ticker * @param title * @param content */ public void notify_normail_moreline(PendingIntent pendingIntent, int smallIcon, String ticker, String title, String content, boolean sound, boolean vibrate, boolean lights) { final int sdk = Build.VERSION.SDK_INT; if (sdk < Build.VERSION_CODES.JELLY_BEAN) { notify_normal_singline(pendingIntent, smallIcon, ticker, title, content, sound, vibrate, lights); Toast.makeText(mContext, "您的手机低于Android 4.1.2,不支持多行通知显示!!", Toast.LENGTH_SHORT).show(); } else { setBuilder(pendingIntent, smallIcon, ticker, true, true, false); nBuilder.setContentTitle(title); nBuilder.setContentText(content); nBuilder.setPriority(Notification.PRIORITY_HIGH); notification = new Notification.BigTextStyle(nBuilder).bigText(content).build(); // 发送该通知 nm.notify(NOTIFICATION_ID, notification); } } /** * 有进度条的通知,可以设置为模糊进度或者精确进度 * * @param pendingIntent * @param smallIcon * @param ticker * @param title * @param content */ public void notify_progress(PendingIntent pendingIntent, int smallIcon, String ticker, String title, String content, boolean sound, boolean vibrate, boolean lights, String download_url, final DownLoadListener listener) { setCompatBuilder(pendingIntent, smallIcon, ticker, title, content, sound, vibrate, lights); /* * 因为进度条要实时更新通知栏也就说要不断的发送新的提示,所以这里不建议开启通知声音。 * 这里是作为范例,给大家讲解下原理。所以发送通知后会听到多次的通知声音。 */ String path = FileManager.getCompressFilePath() + x.app().getResources().getString(R.string.app_name) + ".apk"; RequestParams params = new RequestParams(download_url); params.setSaveFilePath(path); params.setAutoResume(true); params.setExecutor(new PriorityExecutor(2, true)); params.setCancelFast(false); x.http().get(params, new Callback.ProgressCallback() { @Override public void onWaiting() { } @Override public void onStarted() { } @Override public void onLoading(long total, long current, boolean isDownloading) { double a = total; double b = current; double currentPro = (b / a) * 100; cBuilder.setProgress(100, (int) currentPro, false); sent(); } @Override public void onSuccess(File result) { cBuilder.setContentText("下载完成").setProgress(0, 0, false); sent(); listener.OnSuccess(result); } @Override public void onError(Throwable ex, boolean isOnCallback) { ex.printStackTrace(); } @Override public void onCancelled(CancelledException cex) { } @Override public void onFinished() { } }); } /** * 容纳大图片的通知 * * @param pendingIntent * @param smallIcon * @param ticker * @param title * @param bigPic */ public void notify_bigPic(PendingIntent pendingIntent, int smallIcon, String ticker, String title, String content, int bigPic, boolean sound, boolean vibrate, boolean lights) { setCompatBuilder(pendingIntent, smallIcon, ticker, title, null, sound, vibrate, lights); NotificationCompat.BigPictureStyle picStyle = new NotificationCompat.BigPictureStyle(); final BitmapFactory.Options options = new BitmapFactory.Options(); options.inScaled = true; options.inSampleSize = 2; Bitmap bitmap = BitmapFactory.decodeResource(mContext.getResources(), bigPic, options); picStyle.bigPicture(bitmap); picStyle.bigLargeIcon(bitmap); cBuilder.setContentText(content); cBuilder.setStyle(picStyle); sent(); } /** * 里面有两个按钮的通知 * * @param smallIcon * @param leftbtnicon * @param lefttext * @param leftPendIntent * @param rightbtnicon * @param righttext * @param rightPendIntent * @param ticker * @param title * @param content */ public void notify_button(int smallIcon, int leftbtnicon, String lefttext, PendingIntent leftPendIntent, int rightbtnicon, String righttext, PendingIntent rightPendIntent, String ticker, String title, String content, boolean sound, boolean vibrate, boolean lights) { requestCode = (int) SystemClock.uptimeMillis(); setCompatBuilder(rightPendIntent, smallIcon, ticker, title, content, sound, vibrate, lights); cBuilder.addAction(leftbtnicon, lefttext, leftPendIntent); cBuilder.addAction(rightbtnicon, righttext, rightPendIntent); sent(); } public void notify_HeadUp(PendingIntent pendingIntent, int smallIcon, int largeIcon, String ticker, String title, String content, int leftbtnicon, String lefttext, PendingIntent leftPendingIntent, int rightbtnicon, String righttext, PendingIntent rightPendingIntent, boolean sound, boolean vibrate, boolean lights) { setCompatBuilder(pendingIntent, smallIcon, ticker, title, content, sound, vibrate, lights); cBuilder.setLargeIcon(BitmapFactory.decodeResource(mContext.getResources(), largeIcon)); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { cBuilder.addAction(leftbtnicon, lefttext, leftPendingIntent); cBuilder.addAction(rightbtnicon, righttext, rightPendingIntent); } else { Toast.makeText(mContext, "版本低于Andriod5.0,无法体验HeadUp样式通知", Toast.LENGTH_SHORT).show(); } sent(); } /** * 发送通知 */ private void sent() { notification = cBuilder.build(); // 发送该通知 nm.notify(NOTIFICATION_ID, notification); } /** * 根据id清除通知 */ public void clear() { // 取消通知 nm.cancelAll(); } DownLoadListener listener; public void setOnDownLoadListener(DownLoadListener l) { listener = l; } public interface DownLoadListener { void OnSuccess(File file); void onFailure(Throwable t, int errorNo, String strMsg); } }

更新管理类:

package com.langj.update.appconfig;

import android.Manifest;
import android.app.Dialog;
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.Build;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;


import com.google.gson.Gson;
import com.langj.update.R;
import com.langj.update.app.Constant;
import com.langj.update.net.ApiListener;
import com.langj.update.net.ApiTool;
import com.langj.update.utils.AppManager;
import com.langj.update.utils.JSONUtils;
import com.langj.update.utils.SPUtil;
import com.tbruyelle.rxpermissions.RxPermissions;

import org.xutils.common.Callback;
import org.xutils.common.util.LogUtil;
import org.xutils.http.RequestParams;
import org.xutils.x;

import java.io.File;
import java.sql.Timestamp;
import java.util.Map;

import rx.functions.Action1;


public class UpdateManager {

    /**
     * FoceUpdate        强制更新
     * BrowSerUpdate     浏览器更新
     * BackGroundUpdate  后台更新
     */
    public static final String FoceUpdate = "foceupdate";
    public static final String BrowSerUpdate = "browserupdate";
    public static final String BackGroundUpdate = "backgroundupdate";

    private static UpdateManager manager = new UpdateManager();
    private checkVersionListen checkVersionListen;

    /**
     * 检查更新
     *
     * @param url          效验url
     * @param hasHint      如果是最新版本是否显示提示
     * @param isFoceUpdate 是否强制更新
     */
    public static final void checkUpdate(String url, boolean hasHint, String isFoceUpdate) {
        manager.check(url, hasHint, isFoceUpdate);
    }

    public void setCheckVersionListen(checkVersionListen checkVersionListen) {
        this.checkVersionListen = checkVersionListen;
    }

    public interface checkVersionListen {
        void checkVerssion(String str);
    }

    public void check(String url, final boolean hasHint, final String updateType) {
        removeOldApk();
        RequestParams params = new RequestParams(url);
        params.addBodyParameter("command", "config.app.update.check");
        params.addBodyParameter("pubsJson", getPubJson());
        ApiTool apiTool = new ApiTool();
        apiTool.postApi(params, new ApiListener() {
            @Override
            public void onCancelled(Callback.CancelledException cex) {
                if (checkVersionListen != null) {
                    checkVersionListen.checkVerssion("0");
                }
            }

            @Override
            public void onComplete(RequestParams params, String result, String type) {
                Map, String> map = JSONUtils.parseKeyAndValueToMap(result);
                if (map.get("hasNewVersion").equals("1")) {
                    if (checkVersionListen != null) {
                        checkVersionListen.checkVerssion("1");
                    }
                    switch (updateType) {
                        case UpdateManager.FoceUpdate:
                            startDownload(map.get("downloadUrl"));
                            break;
                        case UpdateManager.BackGroundUpdate:
//                            showBuilder(result, "");
                            break;
                        case UpdateManager.BrowSerUpdate:
                            browerUpdate(map.get("downloadUrl"));
                            break;
                    }
                } else {
                    if (checkVersionListen != null) {
                        checkVersionListen.checkVerssion("0");
                    }
                    if (hasHint) Toast.makeText(x.app(), "已是最新版本", Toast.LENGTH_SHORT).show();
                }
            }

            @Override
            public void onError(Map, String> var1, RequestParams var2) {
                LogUtil.e(var1.get("message"));
                if (checkVersionListen != null) {
                    checkVersionListen.checkVerssion("0");
                }
            }

            @Override
            public void onExceptionType(Throwable var1, RequestParams params, String type) {
                if (checkVersionListen != null) {
                    checkVersionListen.checkVerssion("0");
                }
            }
        }, "");
    }

    /**
     * 更新
     * @param url
     * @param updateType
     */

    public void update(final String url, String updateType) {
        switch (updateType) {
            case UpdateManager.FoceUpdate:
                startDownload(url);
                break;
            case UpdateManager.BackGroundUpdate:
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                    RxPermissions.getInstance(AppManager.getInstance().getTopActivity())
                            // 申请权限
                            .request(Manifest.permission.WRITE_EXTERNAL_STORAGE)
                            .subscribe(new Action1() {
                                @Override
                                public void call(Boolean granted) {
                                    if (granted) {
                                        showBuilder("", url);
                                    } else {
                                    }
                                }
                            });
                } else {
                    showBuilder("", url);
                }
                break;
            case UpdateManager.BrowSerUpdate:
                browerUpdate(url);
                break;
        }
    }

    /**
     * 打开浏览器
     * @param url
     */
    public void browerUpdate(String url) {
        Intent intent = new Intent();
        intent.setAction("android.intent.action.VIEW");
        Uri content_url = Uri.parse(url);
        intent.setData(content_url);
        AppManager.getInstance().getTopActivity().startActivity(intent);
    }

    public void showBuilder(String result, final String url) {
        final Map, String> map = JSONUtils.parseKeyAndValueToMap(result);
        View view = View.inflate(AppManager.getInstance().getTopActivity(), R.layout.dlg_update, null);
        TextView tv_content = (TextView) view.findViewById(R.id.update_description);
        TextView tv_no = (TextView) view.findViewById(R.id.buildeexti_tv_no);
        TextView tv_ok = (TextView) view.findViewById(R.id.builderexit_tv_ok);
        final Dialog dialog = new Dialog(AppManager.getInstance().getTopActivity(), R.style.dialog);
//        tv_content.setText(map.get("new_features"));
        if (map != null && !TextUtils.isEmpty(map.get("newVersionDescribe"))) {
            tv_content.setText(map.get("newVersionDescribe"));
        }
        tv_no.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                dialog.cancel();
            }
        });
        tv_ok.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                dialog.cancel();
                Intent intent = new Intent(AppManager.getInstance().getTopActivity(), DownLoadService.class);
                if (map != null && !TextUtils.isEmpty(map.get("downloadUrl"))) {
                    intent.putExtra("download_url", map.get("downloadUrl"));
                } else {
                    intent.putExtra("download_url", url);
                }
                AppManager.getInstance().getTopActivity().startService(intent);

            }
        });
        dialog.setContentView(view);
        dialog.setCancelable(false);
        dialog.show();
    }

    public void startDownload(final String url) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            RxPermissions.getInstance(AppManager.getInstance().getTopActivity())
                    // 申请权限
                    .request(Manifest.permission.WRITE_EXTERNAL_STORAGE)
                    .subscribe(new Action1() {
                        @Override
                        public void call(Boolean granted) {
                            if (granted) {
                                downloadFile(url);
                            } else {
                            }
                        }
                    });
        } else {
            downloadFile(url);
        }
    }

    /**
     * 更新之前先移除残留app文件
     */
    private void removeOldApk() {
        File fileName = new File(SPUtil.getString(Constant.SP_DOWNLOAD_PATH, ""));
        if (fileName != null && fileName.exists() && fileName.isFile()) {
            fileName.delete();
        }
    }

    // 下载文件
    private synchronized void downloadFile(String url) {
        DownloadUtils downloadUtils = new DownloadUtils(AppManager.getInstance().getTopActivity());
        downloadUtils.downloadAPK(url);
    }

    // 获取版本号
    private String getVersionCode() {
        try {
            PackageInfo packageInfo = x.app().getPackageManager().getPackageInfo(x.app().getPackageName(), 0);
            return packageInfo.versionName;
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
            return "";
        }
    }

    public String getPubJson() {
        PubsJson pubsJson = new PubsJson();
        pubsJson.setImei(getIMSI());
        pubsJson.setOs("Android");
        pubsJson.setOsVersion(Build.DISPLAY);
        pubsJson.setAppVersion(getVersionCode());
        pubsJson.setTimestamp(getTimesTamp());
        Gson gson = new Gson();
        String s1 = gson.toJson(pubsJson);
        return s1;
    }

    /**
     * 获取手机IMSI号
     */
    public String getIMSI() {
        TelephonyManager mTelephonyMgr = (TelephonyManager) x.app().getSystemService(Context.TELEPHONY_SERVICE);
        String imsi = mTelephonyMgr.getSubscriberId();
        return imsi;
    }

    public String getTimesTamp() {
        Timestamp now = new Timestamp(System.currentTimeMillis());//获取系统当前时间
        return now.toString();
    }
}

项目用到的第三方:

compile 'org.xutils:xutils:3.3.36'   //文件下载
compile 'com.zhy:autolayout:1.4.3'   //适配
compile 'com.tbruyelle.rxpermissions:rxpermissions:0.7.0@aar'  //权限申请
compile 'io.reactivex:rxjava:1.1.6'
compile 'com.google.code.gson:gson:2.8.2'

最后在Activity中调用更新:

package com.langj.update;

import android.os.Bundle;
import android.view.View;

import com.langj.update.appconfig.UpdateManager;
import com.langj.update.utils.AppManager;
import com.zhy.autolayout.AutoLayoutActivity;

import org.xutils.view.annotation.Event;
import org.xutils.x;

public class MainActivity extends AutoLayoutActivity {

    private UpdateManager manager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        AppManager.getInstance().addActivity(this);
        x.view().inject(this);
        manager = new UpdateManager();
    }


    @Event(value = {R.id.btn_01, R.id.btn_02, R.id.btn_03})
    private void onTestBaidulClick(View view) {

        switch (view.getId()) {
            case R.id.btn_01:
                //浏览器更新
                manager.update("http://dakaapp.troila.com/download/daka.apk?v=3.0", UpdateManager.BrowSerUpdate);
                break;
            case R.id.btn_02:
                //后台更新更新
                manager.update("http://dakaapp.troila.com/download/daka.apk?v=3.0", UpdateManager.BackGroundUpdate);
                break;
            case R.id.btn_03:
                //强制更新
                manager.update("http://dakaapp.troila.com/download/daka.apk?v=3.0", UpdateManager.FoceUpdate);
                break;
        }
    }
}

核心代码到此结束,完整源码请后续看我GitHub地址

 
  
 
  
 
  
 
 

你可能感兴趣的:(Android app更新方案)