Android APP更新下载,实现Notification通知栏进度通知,下载完成后点击安装

 简单做一个APP检测更新的小工具,有点粗糙。不能断点续传,只用为个人觉得没有必要,自己可根据大家的想法添加更多的功能,这里只是为了想我一样的初学者和比较简约的人所提供。

   效果如下:

    

    基本思路先理一理,以我的实际开发为例:首先当然要一个网络去请求我们的服务器,获得仓库中的apk版本信息和下载路径,在和自己当前的版本号进行比较,当自己的版本号小于仓库中的版本号,就提示用户下载,在根据更新等级进行下载强度操作(是否强制下载还是什么的)。在下的时候监听文件下载的Progress 来更新 notification中的进度条和进度信息等待,当下载完成后,可让用户点击(关闭通知就行)进入到安装apk界面,这样就算完成了。

    本次使用了okhttp (okgo)网络框架进行下载文件,这里确定下载的是apk就不多过滤信息了,直接下载安装。

首先想到的是要用一个单例来做下载管理,我们需要传入一个context 。

  Context context;
    private static final AppUpdateService INSTANCE = new AppUpdateService();
 
    private static class LazyHolder {
        public static AppUpdateService getThis(Context context) {
            INSTANCE.context = context;
            return INSTANCE;
        }
    }
 
    public static AppUpdateService getInstance(Context context) {
        return LazyHolder.getThis(context);
    }
初始化Notification 、notificationCompat.Builder和notificationManager 

//初始化通知
    private void initNotification() {
        notificationManager = (NotificationManager) MyApplication.getInstance().getSystemService(Context.NOTIFICATION_SERVICE);
        builder = new NotificationCompat.Builder(MyApplication.getInstance());
        builder.setContentTitle("正在更新...") //设置通知标题
                .setSmallIcon(R.mipmap.ic_launcher_round)
                .setLargeIcon(BitmapFactory.decodeResource(MyApplication.getInstance().getResources(), R.mipmap.ic_launcher_round)) //设置通知的大图标
                .setDefaults(Notification.DEFAULT_LIGHTS) //设置通知的提醒方式: 呼吸灯
                .setPriority(NotificationCompat.PRIORITY_MAX) //设置通知的优先级:最大
                .setAutoCancel(false)//设置通知被点击一次是否自动取消
                .setContentText("下载进度:" + "0%")
                .setProgress(100, 0, false);
        notification = builder.build();//构建通知对象
    }
下载更新通知核心代码,可更新直接的选择是否让用户点击后安装,还是直接安装。

public void download(String url, String filePath) {
 
        MyApplication.getInstance().okGo.<File>post(url).execute(new FileCallback() {
            @Override
            public void onSuccess(Response<File> response) {
                File file = response.body();
                Log.e("update", "onSuccess: 下载完成" + file.getPath() + file.getName());
                builder.setContentTitle("下载完成")
                        .setContentText("点击安装")
                        .setAutoCancel(true);//设置通知被点击一次是否自动取消
                //点击安装代码块
                Intent intent = new Intent(Intent.ACTION_VIEW);
                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                intent.setDataAndType(Uri.parse("file://" + file.toString()), "application/vnd.android.package-archive");
                PendingIntent pi = PendingIntent.getActivity(context, 0, intent, 0);
                notification = builder.setContentIntent(pi).build();
                notificationManager.notify(1, notification);
 
                //自动安装
//              installApk(file);
            }
 
            //下载进度
            @Override
            public void downloadProgress(Progress progress) {
                super.downloadProgress(progress);
                Log.e("update", "downloadProgress: " + progress.fraction);
                builder.setProgress(100, (int) (progress.fraction * 100), false);
                builder.setContentText("下载进度:" + (int) (progress.fraction * 100) + "%");
                notification = builder.build();
                notificationManager.notify(1, notification);
            }
 
            @Override
            public void onStart(Request<File, ? extends Request> request) {
                super.onStart(request);
                initNotification();
            }
 
            @Override
            public void onError(Response<File> response) {
                super.onError(response);
                Toast.makeText(context, "下载错误", Toast.LENGTH_SHORT).show();
            }
 
        });
 
    }
安装apk

    private void installApk(File file) {
        //新下载apk文件存储地址
        File apkFile = file;
        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.setDataAndType(Uri.parse("file://" + apkFile.toString()), "application/vnd.android.package-archive");
        context.startActivity(intent);
        notificationManager.cancel(1);//取消通知
 
    }
获取本地版本号

  public  int getVersionCode() {
        PackageManager packageManager = context.getPackageManager();
        int versionCode = 0;
        try {
            PackageInfo packageInfo = packageManager.getPackageInfo(context.getPackageName(), 0);
            versionCode = packageInfo.versionCode;
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        return versionCode;
    }
获取更新信息,自己根据自己的网络框架修改。

 public void getUpdate() {
 
        MyApplication.getInstance().okGo.<String>post("*****").execute(new StringCallback() {
            @Override
            public void onSuccess(Response<String> response) {
                ApkSer apkSer = new ApkSer();
                    apkSer = new Gson().fromJson(response.body(), ApkSer.class);
                CustomDialog("有新版本需要更新", 3, apkSer.getUpdatePath());
            }
        });
 
    }
提示框信息提示用户。

 public void CustomDialog(final String cominit, int updatelv, final String url) {
        CustomDialog.Builder dialog = new CustomDialog.Builder(context);
        dialog.setTitle("版本更新")
                .setMessage(cominit);
        dialog.setCancelable(false);
        //更新等级 0:普通 1:重点bug修复更新  2:新功能更新 3:配置更新 4:特殊更新,强制用户更新
        if (updatelv == 0 || updatelv == 2) {
            dialog.setCancelBtn("下次提醒", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int i) {
                    dialog.dismiss();
                }
            });
        } else {
            dialog.setCanceledOnTouchOutside(false);
        }
        dialog.setCancelBtn("重点更新", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int i) {
                Toast.makeText(context,"已添加到下载任务",Toast.LENGTH_SHORT).show();
                dialog.dismiss();
                download(url, "path");
            }
        });
        dialog.create().show();
    }
版本信息对象字段

public class ApkSer {
        public String type;            //更新内容类型,apk安装包  res资源
        public String apkName;
        public String packageName;        //apk包名
        public Long versionCode;     //库版本号
        public String versionName;     //库版本名称
        public int important;          //更新等级 0:普通 1:重点bug修复更新  2:新功能更新 3:配置更新 4:特殊更新,强制用户更新
        public String commit;          //更新内容
        public String updatePath;      //更新下载地址
        public String updateTime;        //更新时间
}
完整代码如下,欢迎大家点评。

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.support.v4.app.NotificationCompat;
import android.util.Log;
import android.widget.Toast;
 
import com.google.gson.Gson;
import com.hx.view.widget.CustomDialog;
import com.lzy.okgo.callback.FileCallback;
import com.lzy.okgo.callback.StringCallback;
import com.lzy.okgo.model.Progress;
import com.lzy.okgo.model.Response;
import com.lzy.okgo.request.base.Request;
import com.pay.library.config.AppConfig;
import com.yhx.loan.R;
import com.yhx.loan.base.MyApplication;
 
import java.io.File;
 
public class AppUpdateService {
 
    private NotificationManager notificationManager;
    private Notification notification; //下载通知进度提示
    private NotificationCompat.Builder builder;
    private boolean flag = false; //进度框消失标示 之后发送通知
    public static boolean isUpdate = false; //是否正在更新
 
    Context context;
    private static final AppUpdateService INSTANCE = new AppUpdateService();
 
    private static class LazyHolder {
        public static AppUpdateService getThis(Context context) {
            INSTANCE.context = context;
            return INSTANCE;
        }
    }
 
    public static AppUpdateService getInstance(Context context) {
        return LazyHolder.getThis(context);
    }
 
    private AppUpdateService() {
 
    }
 
    public void getUpdate() {
 
        MyApplication.getInstance().okGo.<String>post(AppConfig.updateAPP_url)
               .upJson("{'package':'包名'}")
                .execute(new StringCallback() {
            @Override
            public void onSuccess(Response<String> response) {
                ApkSer apkSer = new ApkSer();
                    apkSer = new Gson().fromJson(response.body(), ApkSer.class);
                CustomDialog("有新版本需要更新", 3, apkSer.getUpdatePath());
            }
        });
 
    }
 
    public void CustomDialog(final String cominit, int updatelv, final String url) {
        CustomDialog.Builder dialog = new CustomDialog.Builder(context);
        dialog.setTitle("版本更新")
                .setMessage(cominit);
        dialog.setCancelable(false);
        //更新等级 0:普通 1:重点bug修复更新  2:新功能更新 3:配置更新 4:特殊更新,强制用户更新
        if (updatelv == 0 || updatelv == 2) {
            dialog.setCancelBtn("下次提醒", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int i) {
                    dialog.dismiss();
                }
            });
        } else {
            dialog.setCanceledOnTouchOutside(false);
        }
        dialog.setCancelBtn("重点更新", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int i) {
                Toast.makeText(context,"已添加到下载任务",Toast.LENGTH_SHORT).show();
                dialog.dismiss();
                download(url, "path");
            }
        });
        dialog.create().show();
    }
 
 
    //初始化通知
    private void initNotification() {
        notificationManager = (NotificationManager) MyApplication.getInstance().getSystemService(Context.NOTIFICATION_SERVICE);
        builder = new NotificationCompat.Builder(MyApplication.getInstance());
        builder.setContentTitle("正在更新...") //设置通知标题
                .setSmallIcon(R.mipmap.ic_launcher_round)
                .setLargeIcon(BitmapFactory.decodeResource(MyApplication.getInstance().getResources(), R.mipmap.ic_launcher_round)) //设置通知的大图标
                .setDefaults(Notification.DEFAULT_LIGHTS) //设置通知的提醒方式: 呼吸灯
                .setPriority(NotificationCompat.PRIORITY_MAX) //设置通知的优先级:最大
                .setAutoCancel(false)//设置通知被点击一次是否自动取消
                .setContentText("下载进度:" + "0%")
                .setProgress(100, 0, false);
        notification = builder.build();//构建通知对象
    }
 
    public void download(String url, String filePath) {
 
        MyApplication.getInstance().okGo.<File>post(url).execute(new FileCallback() {
            @Override
            public void onSuccess(Response<File> response) {
                File file = response.body();
                Log.e("update", "onSuccess: 下载完成" + file.getPath() + file.getName());
                builder.setContentTitle("下载完成")
                        .setContentText("点击安装")
                        .setAutoCancel(true);//设置通知被点击一次是否自动取消
 
                Intent intent = new Intent(Intent.ACTION_VIEW);
                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                intent.setDataAndType(Uri.parse("file://" + file.toString()), "application/vnd.android.package-archive");
                PendingIntent pi = PendingIntent.getActivity(context, 0, intent, 0);
                notification = builder.setContentIntent(pi).build();
                notificationManager.notify(1, notification);
 
                //自动安装
//              installApk(file);
            }
 
            //下载进度
            @Override
            public void downloadProgress(Progress progress) {
                super.downloadProgress(progress);
                Log.e("update", "downloadProgress: " + progress.fraction);
                builder.setProgress(100, (int) (progress.fraction * 100), false);
                builder.setContentText("下载进度:" + (int) (progress.fraction * 100) + "%");
                notification = builder.build();
                notificationManager.notify(1, notification);
            }
 
            @Override
            public void onStart(Request<File, ? extends Request> request) {
                super.onStart(request);
                initNotification();
            }
 
            @Override
            public void onError(Response<File> response) {
                super.onError(response);
                Toast.makeText(context, "下载错误", Toast.LENGTH_SHORT).show();
            }
 
        });
 
    }
 
    /**
     * 安装apk
     */
    private void installApk(File file) {
        //新下载apk文件存储地址
        File apkFile = file;
        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.setDataAndType(Uri.parse("file://" + apkFile.toString()), "application/vnd.android.package-archive");
        context.startActivity(intent);
        notificationManager.cancel(1);//取消通知
 
    }
 
    /**
     * 获取本地版本号
     *
     * @return
     */
    public  int getVersionCode() {
        PackageManager packageManager = context.getPackageManager();
        int versionCode = 0;
        try {
            PackageInfo packageInfo = packageManager.getPackageInfo(context.getPackageName(), 0);
            versionCode = packageInfo.versionCode;
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        return versionCode;
    }
 
}
 
最后发现API>=24 用这种方法肯定不行的。对于 file:///storage/emulated/0/xxx, android N文件访问crash android.os.FileUriExposedException异常。这里要网上就用很多方法里就不在一一重复介绍,请看以下几个博主的介绍吧

https://blog.csdn.net/honjane/article/details/54411820
https://blog.csdn.net/ruancoder/article/details/67639621
https://blog.csdn.net/xiaoyu940601/article/details/54406725

最后发现对于file:///storage/emulated/0/xxx/...的文件来说。我们的filepaths.xml中的path要有xxx路径,这样才能找到文件不报错。也不是太懂。反正最后是解决报错的问题了。
 

猜你喜欢

转载自blog.csdn.net/qq_26280383/article/details/115064168