app版本更新和下载,通知栏实时进度(使用服务和广播)

来源:互联网 发布:男人至死都是少年 知乎 编辑:程序博客网 时间:2024/04/30 00:25

每个app都需要有版本更新的功能,下面简单介绍一下最近在项目中使用的app更新功能。
1、首先需要使用服务和广播实现后台更新,使用到了xUtils,其他的网络请求框架代码类似。
服务代码如下,注释写的很详细

import android.app.Service;import android.content.Intent;import android.os.IBinder;import android.support.annotation.Nullable;import android.text.TextUtils;import android.util.Log;import org.xutils.common.Callback;import org.xutils.ex.HttpException;import org.xutils.http.RequestParams;import org.xutils.x;import java.io.File;import java.text.NumberFormat;/** * 下载的services,配合xutils的httputils使用,完成notification的下载功能 */public class UpdateService extends Service {    //是否已经开始下载    private boolean isBegin = false;    Intent intent;    private NumberFormat numberFormat;    public static Callback.Cancelable downLoadHandler;    @Nullable    @Override    public IBinder onBind(Intent intent) {        return null;    }    @Override    public void onCreate() {        super.onCreate();        intent = new Intent();        numberFormat = NumberFormat.getInstance();        numberFormat.setMaximumFractionDigits(2);    }    @Override    public int onStartCommand(Intent intent, int flags, int startId) {        String downUrl = intent.getStringExtra("downUrl");        String filePath = intent.getStringExtra("filePath");        //如果下载地址为空,则什么都不干        if (TextUtils.isEmpty(downUrl)) {            stopSelf();//            throw  new IllegalArgumentException("the download url is empty!!!!");            return START_NOT_STICKY;        }        if (isBegin) {            //此时已经开始了            return START_NOT_STICKY;        } else {            isBegin = true;        }        downLoad(downUrl,filePath);        return super.onStartCommand(intent, flags, startId);    }    int progress = -1;    private void downLoad(final String downUrl,String filePath) {        RequestParams requestParams = new RequestParams(downUrl);        requestParams.setSaveFilePath(filePath);        downLoadHandler = x.http().get(requestParams, new Callback.ProgressCallback<File>() {            @Override            public void onSuccess(File result) {                intent.setAction("com.ycb.www.complete");                intent.putExtra("filepath", result.getAbsolutePath());                Log.i("tag", "onSuccess");                Log.i("tag", result.getAbsolutePath());                sendBroadcast(intent);                stopSelf();            }            @Override            public void onError(Throwable ex, boolean isOnCallback) {                intent.setAction("com.ycb.www.failed");                intent.putExtra("downUrl", downUrl);                Log.i("tag", "onFailure!!!"+ex.getMessage());//                sendBroadcast(intent);                if (ex instanceof HttpException) {                    HttpException httpEx = (HttpException) ex;                    Log.i("tag","onError:"+httpEx.getCode()+httpEx.getMessage());                }            }            @Override            public void onCancelled(CancelledException cex) {                Log.i("tag", "onCancelled");                stopSelf();            }            @Override            public void onFinished() {                Log.i("tag", "onFinished");//                 stopSelf();            }            @Override            public void onWaiting() {                Log.i("tag", "onWaiting");            }            @Override            public void onStarted() {                Log.i("tag","Started");                intent.putExtra("rate",0);                intent.setAction("com.ycb.www.updating");                sendBroadcast(intent);            }            @Override            public void onLoading(long total, long current, boolean isDownloading) {                Double rate= (double)current / (double)total;                String format = numberFormat.format(rate);                int   r= (int) (Double.valueOf(format)*100);                Log.i("tag", ""+r);                intent.putExtra("rate", r);                intent.setAction("com.ycb.www.updating");                sendBroadcast(intent);            }        });    }}

2、然后添加一个广播,用于实时处理下载进度,并在通知栏实时显示

import android.annotation.TargetApi;import android.app.Notification;import android.app.NotificationManager;import android.app.PendingIntent;import android.content.BroadcastReceiver;import android.content.Context;import android.content.Intent;import android.net.Uri;import android.os.Build;import android.widget.RemoteViews;import java.io.File;/** * notification更新的广播接收者,根据action不同,做出的结果不同, * 其中intent因为是同一个intent的,所以并没有new 新的 */public class UpdateReceiver extends BroadcastReceiver {    private NotificationManager manager;    private RemoteViews views;    private Notification notification;    @Override    public void onReceive(Context context, Intent intent) {        if (notification == null) {            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN)                initNotification(context);            else {                initNotificationForLowVersion(context);            }        }        String action = intent.getAction();        switch (action) {            case "com.ycb.www.cancel":                manager.cancel(0);                UpdateService.downLoadHandler.cancel();                break;            case "com.ycb.www.failed":                intent.setAction("com.ycb.www.restart");                PendingIntent failedpendingIntent = PendingIntent.getBroadcast(context, 200, intent, PendingIntent.FLAG_CANCEL_CURRENT);                views.setOnClickPendingIntent(R.id.ll_content, failedpendingIntent);                views.setTextViewText(R.id.tv_info, "下载失败,点击重试");                manager.notify(0, notification);                break;            case "com.ycb.www.restart":                manager.cancel(0);                intent.setClass(context, UpdateService.class);                context.startService(intent);                break;            case "com.ycb.www.install":                manager.cancel(0);                Intent startInstall = new Intent();                startInstall.setAction(Intent.ACTION_VIEW);                String filepath = intent.getStringExtra("filepath");                startInstall.setDataAndType(Uri.fromFile(new File(filepath)), "application/vnd.android.package-archive");                startInstall.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);                context.startActivity(startInstall);                break;            case "com.ycb.www.complete":                intent.setAction("com.ycb.www.install");                PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 200, intent, PendingIntent.FLAG_CANCEL_CURRENT);                views.setOnClickPendingIntent(R.id.ll_content, pendingIntent);                views.setTextViewText(R.id.tv_info, "下载完成,点击安装");                views.setProgressBar(R.id.progressBar, 100, 100, false);                manager.notify(0, notification);                break;            case "com.ycb.www.updating":                int rate = intent.getIntExtra("rate", 0);                views.setTextViewText(R.id.tv_info, "正在下载...." + rate + "%");                views.setProgressBar(R.id.progressBar, 100, rate, false);                manager.notify(0, notification);        }    }    private void initNotificationForLowVersion(Context context) {        //设置notifiction布局        views = new RemoteViews(context.getPackageName(), R.layout.notification_update);        notification = new Notification();        notification.when = System.currentTimeMillis();        notification.tickerText = "xxxx新版正在下载";        //设置view        notification.contentView = views;        //设置小图标        notification.icon = R.mipmap.icon;        //设置布局文件中的textView的内容        views.setTextViewText(R.id.tv_info, "下载中....0%");        //设置布局文件中的ProgressBar进度        views.setProgressBar(R.id.progressBar, 100, 0, false);        //退出的intent        Intent intent = new Intent("com.ycb.www.cancel");        //退出的延迟意图        PendingIntent mPendingIntent = PendingIntent.getBroadcast(context.getApplicationContext(), 200, intent, PendingIntent.FLAG_UPDATE_CURRENT);        //点击之后退出        views.setOnClickPendingIntent(R.id.ib_close, mPendingIntent);    }    /**     * 初始化notification     *     * @param context     */    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)    private void initNotification(Context context) {        manager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);        views = new RemoteViews(context.getPackageName(), R.layout.notification_update);        Notification.Builder builder = new Notification.Builder(context.getApplicationContext());        notification = builder.setAutoCancel(false).setSmallIcon(R.mipmap.icon).setContentText("下载中").setContentTitle("下载").                setWhen(System.currentTimeMillis()).setTicker("xxxxx新版正在下载")                .setContent(views).build();        views.setTextViewText(R.id.tv_info, "下载中....0%");        views.setProgressBar(R.id.progressBar, 100, 0, false);        Intent intent = new Intent("com.ycb.www.cancel");        PendingIntent mPendingIntent = PendingIntent.getBroadcast(context.getApplicationContext(), 200, intent, PendingIntent.FLAG_UPDATE_CURRENT);        views.setOnClickPendingIntent(R.id.ib_close, mPendingIntent);    }}

3、在MainActivity或者LoginActivity页面检测app版本是否有更新,若有更新,开启服务,注册广播,开始下载更新操作
在onCreate方法中添加如下代码:

//检查版本更新    private void checkAppVersion() {        try {            PackageManager manager = this.getPackageManager();            PackageInfo info = manager.getPackageInfo(this.getPackageName(), 0);            versionCode = info.versionName;            System.out.println("versionCode:" + versionCode);        } catch (PackageManager.NameNotFoundException e) {            e.printStackTrace();        }        new Thread(new Runnable() {            @Override            public void run() {                OkHttpUtils.get()                        .url(Constant.DB_URL + Constant.PORT + Constant.XHB_DIR + Constant.GET_APP_VERSION_DATA)                        .addParams("type", "0")                        .build()                        .execute(new StringCallback() {                            @Override                            public void onError(Call call, Exception e) {                                Toast.makeText(LoginActivity.this, "网络异常", Toast.LENGTH_SHORT).show();                            }                            @Override                            public void onResponse(String response) {                                System.out.println("downApp:" + response);                                //版本号对比,若不同下载app                                downLoadApp(response);                            }                        });            }        }).start();    }

倘若有更新时,开启服务执行下载操作,执行下面方法:

//比对版本号,更新app    private void downLoadApp(String response) {        final AppVersionResponse appVersionResponse = new Gson().fromJson(response, AppVersionResponse.class);        AppVersionResponse.DataBean dataBean = appVersionResponse.getData();        if (appVersionResponse.isIsSuccess() && dataBean != null) {            if (!versionCode.equals(appVersionResponse.getData().getCode())) {                //强制更新                if(dataBean.getIsForced() == 1){                    btn_land.setEnabled(false);                    //弹出窗口是否强制更新版本                    AlertDialog alertDialog = new AlertDialog.Builder(this).setIcon(android.R.drawable.ic_dialog_info).setTitle("版本升级")                            .setMessage(dataBean.getContent())                            .setCancelable(false)                            .setPositiveButton("确定", new DialogInterface.OnClickListener() {                                @Override                                public void onClick(DialogInterface dialogInterface, int i) {                                    //下载操作                                    downLoad(appVersionResponse.getData().getCode());                                }                            }).create();                    alertDialog.show();                }else if(dataBean.getIsForced() == 0){                    //非强制更新//                    btn_land.setEnabled(false);                    //弹出窗口是否强制更新版本                    AlertDialog alertDialog = new AlertDialog.Builder(this).setIcon(android.R.drawable.ic_dialog_info).setTitle("版本升级提示")                            .setMessage(dataBean.getContent())                            .setCancelable(false)                            .setNegativeButton("取消", new DialogInterface.OnClickListener() {                                @Override                                public void onClick(DialogInterface dialogInterface, int i) {                                    dialogInterface.dismiss();                                }                            })                            .setPositiveButton("确定", new DialogInterface.OnClickListener() {                                @Override                                public void onClick(DialogInterface dialogInterface, int i) {                                    //下载操作                                    downLoad(appVersionResponse.getData().getCode());                                }                            }).create();                    alertDialog.show();                }            }        }    }
    //下载app    private void downLoad(final String version) {        updateReceiver = new UpdateReceiver();        IntentFilter filter = new IntentFilter();        filter.addAction("com.ycb.www.cancel");        filter.addAction("com.ycb.www.failed");        filter.addAction("com.ycb.www.restart");        filter.addAction("com.ycb.www.install");        filter.addAction("com.ycb.www.complete");        filter.addAction("com.ycb.www.updating");        registerReceiver(updateReceiver,filter);        Intent intent = new Intent(this, UpdateService.class);        String url = Constant.DB_URL + Constant.PORT + Constant.XHB_DIR + Constant.DOWNLOAD_APP_URL;        intent.putExtra("downUrl", url);        intent.putExtra("filePath",Environment.getExternalStorageDirectory().getPath()+"/Downloads/xiahubao_"+version+".apk");        startService(intent);    }

另外需要在配置文件中添加下面的服务和广播注册

 <receiver android:name=".appUpdateUtils.UpdateReceiver">            <intent-filter>                <action android:name="com.ycb.www.complete" />                <action android:name="com.ycb.www.install" />                <action android:name="com.ycb.www.cancel" />                <action android:name="com.ycb.www.updating" />                <action android:name="com.ycb.www.failed" />                <action android:name="com.ycb.www.restart" />            </intent-filter>        </receiver> <service android:name=".appUpdateUtils.UpdateService" />

最后,在通知栏显示的自定义进度条代码如下,紧供参考

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:id="@+id/ll_content"    android:layout_width="match_parent"    android:layout_height="wrap_content"    android:gravity="center_vertical"    android:orientation="horizontal">    <ImageView        android:id="@+id/img_menu"        android:layout_width="40dp"        android:layout_height="40dp"        android:src="@mipmap/icon" />    <LinearLayout        android:layout_width="0dip"        android:layout_height="wrap_content"        android:layout_weight="1"        android:gravity="center"        android:layout_marginLeft="10dp"        android:layout_marginTop="6dp"        android:orientation="vertical">        <ProgressBar            android:id="@+id/progressBar"            style="?android:attr/progressBarStyleHorizontal"            android:layout_width="match_parent"            android:layout_height="wrap_content"            android:progressDrawable="@drawable/seek_bar_progress_bg" />        <TextView            android:id="@+id/tv_info"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_marginTop="6dp"            android:textColor="@color/textBlackColor"            />    </LinearLayout>    <ImageButton        android:id="@+id/ib_close"        android:layout_width="15dp"        android:layout_height="15dp"        android:layout_marginLeft="10dp"        android:layout_marginRight="3dp"        android:background="@null"        android:src="@android:drawable/ic_menu_close_clear_cancel" /></LinearLayout>

progressDrawable的配置如下,显示的更美观

<?xml version="1.0" encoding="utf-8"?><layer-list    xmlns:android="http://schemas.android.com/apk/res/android">    <item android:id="@android:id/background">        <shape>            <solid android:color="#c6c6c6" />            <corners android:radius="3dp"/>        </shape>    </item>    <item android:id="@android:id/secondaryProgress">        <clip>            <shape>                <solid android:color="#c6c6c6" />                <corners android:radius="3dp"/>            </shape>        </clip>    </item>    <item android:id="@android:id/progress">        <clip>            <shape>                <solid android:color="#06a7fa" />                <corners android:radius="3dp"/>            </shape>        </clip>    </item></layer-list>
0 0