版本更新

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

原创  2017年02月28日 17:37:15

每个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);

            }
        });


    }


}
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139

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);

    }

}
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131

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();

    }
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

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

//比对版本号,更新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();
                }

            }
        }
    }
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
    //下载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);

    }
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

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

 <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" />
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

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

<?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>
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53

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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值