热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

通过NotificationManager一键更新下载apk安装包

如何使用?直接new一个对象,把apk的下载链接传入即可.如果想取消,调用interrupt()方法即可.本源码不需要再引用其他代码和资源文件.一.关于下载完的apk存储路径1.优先存储于

如何使用?
直接new一个对象,把apk的下载链接传入即可.如果想取消,调用interrupt()方法即可.本源码不需要再引用其他代码和资源文件.

一.关于下载完的apk存储路径
1.优先存储于外部存储的应用缓存中,即通过context.getExternalCacheDir()获得,前提是要有android.permission.WRITE_EXTERNAL_STORAGE权限
2.其次再存储在应用内部缓存中,即通过context.getCacheDir()获得

二.下载步骤
1.判断下载链接是否有效
2.启动线程下载
3.调用系统Notification通知下载进度
4.下载完成,执行apk与当前应用校验
5.校验成功后,安装apk.

废话不多说,直接上源码

import android.annotation.TargetApi;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.WeakReference;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

import static android.os.Environment.MEDIA_MOUNTED;

public class CWJApkDownload extends Thread {

private static final int DOWN_UPDATE = 1;
private static final int DOWN_OVER = 2;
private static final int DOWN_CANCEL = 3;
private static final String TAG = "CWJ_APK_DOWNLOAD";
private static int progress;

private Down_handler handler;

private static int length;
private static int count;

private Context context;
private static File apkFile;
private String apkUrl;
private String saveFileName;

public CWJApkDownload(Context context) {
this.cOntext= context;
handler = new Down_handler(context);
}

public CWJApkDownload(Context context, String apkUrl) {
this.cOntext= context;
this.apkUrl=apkUrl;

if(TextUtils.isEmpty(apkUrl)){
Toast.makeText(context, "下载链接不能为空", Toast.LENGTH_LONG).show();
return ;
}
if(apkUrl.indexOf("/")>0){
saveFileName=apkUrl.substring(apkUrl.lastIndexOf("/")+1,apkUrl.length());
}else{
saveFileName="NewVsersion.apk";
}

Notification.Builder builder=notificationInit();
NotificationManager notificatiOnManager= (NotificationManager) context.getSystemService(context.NOTIFICATION_SERVICE);
handler = new Down_handler(context, builder, notificationManager);
}

private class Down_handler extends Handler {
WeakReference mContextReference;
Notification.Builder builder;
NotificationManager notificationManager;

Down_handler(Context context) {
mCOntextReference= new WeakReference<>(context);
}

Down_handler(Context context, Notification.Builder builder, NotificationManager notificationManager) {
mCOntextReference= new WeakReference<>(context);
this.builder = builder;
this.notificatiOnManager= notificationManager;
}

@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
@Override
public void handleMessage(Message msg) {
Context cOntext= mContextReference.get();
switch (msg.what) {
case DOWN_UPDATE:
builder.setProgress(length, count, false)
.setContentText("下载进度:" + progress + "%");
notificationManager.notify(1115, builder.build());
break;
case DOWN_OVER:
builder.setTicker("下载完成");
notificationManager.notify(1115, builder.build());
notificationManager.cancel(1115);
length = 0;
count = 0;

if (checkApk()) {
Log.i(TAG, "APK路径:" + apkFile);
if (!apkFile.exists()) {
return;
}
Intent i = new Intent(Intent.ACTION_VIEW);
i.setDataAndType(Uri.parse("file://" + apkFile.toString()),
"application/vnd.android.package-archive");
context.startActivity(i);
}
break;
case DOWN_CANCEL:
builder.setTicker("下载取消");
notificationManager.notify(1115, builder.build());
notificationManager.cancel(1115);
break;
default:
break;
}
}

}

public void run() {
URL url = null;
HttpURLConnection cOnn= null;
InputStream is = null;
try {
url = new URL(apkUrl);
} catch (MalformedURLException e) {
e.printStackTrace();
}
Log.i(TAG, String.format("ApkDownloadUrl:%s", apkUrl));
try {
cOnn= (HttpURLConnection) url.openConnection();
conn.connect();
length = conn.getContentLength();
is = conn.getInputStream();
} catch (FileNotFoundException e0) {
// e0.printStackTrace();
try {
conn.disconnect();
cOnn= (HttpURLConnection) url.openConnection();
conn.setInstanceFollowRedirects(false);
conn.connect();
String location = new String(conn.getHeaderField("Location").getBytes("ISO-8859-1"), "UTF-8").replace(" ", "");
url = new URL(location);
cOnn= (HttpURLConnection) url.openConnection();
conn.connect();
length = conn.getContentLength();
is = conn.getInputStream();
} catch (IOException e1) {
e1.printStackTrace();
}
} catch (IOException e2) {
e2.printStackTrace();
}


try {
File file = getCacheDirectory();
if (!file.exists()) {
file.mkdir();
}

apkFile = new File(file, saveFileName);
FileOutputStream fos = new FileOutputStream(apkFile);
long tempFileLength = file.length();
byte buf[] = new byte[1024];
int times = 0; //这很重要
int numread;
do {
numread = is.read(buf);
count += numread;
progress = (int) (((float) count / length) * 100);
if ((times == 512) || (tempFileLength == length)) {
handler.sendEmptyMessage(DOWN_UPDATE);
times = 0;
}
times++;
if (numread <= 0) {
handler.sendEmptyMessage(DOWN_OVER);
break;
}
fos.write(buf, 0, numread);
} while (true);
fos.flush();
fos.close();
is.close();
conn.disconnect();

} catch (IOException e3) {
e3.printStackTrace();
}
}

@Override
public void interrupt() {
handler.sendEmptyMessage(DOWN_CANCEL);
super.interrupt();
}

//检查当前app与下载的apk包名是否一致
private boolean checkApk() {
String apkName = getAPKPackageName(apkFile.toString());
String appName = context.getPackageName();
if (apkName.equals(appName)) {
Log.i(TAG, "apk检验:包名相同,安装apk");
return true;
} else {
Log.i(TAG, String.format("apk检验:包名不同。该app包名:%s,apk包名:%s", appName, apkName));
Toast.makeText(context, "apk检验:包名不同,不进行安装", Toast.LENGTH_LONG).show();
return false;
}
}
//获取apk的包名
private String getAPKPackageName(String apkPath) {
PackageManager pm = context.getPackageManager();
PackageInfo info = pm.getPackageArchiveInfo(apkPath, PackageManager.GET_ACTIVITIES);
if (info != null) {
ApplicationInfo appInfo = info.applicationInfo;
return appInfo.packageName;
}
return null;
}
//获取app应用名称
private String getAppName() {
String appName = "";
try {
PackageInfo pi = context.getPackageManager()
.getPackageInfo(context.getPackageName(), 0);
appName = pi.applicationInfo.loadLabel(context.getPackageManager()).toString();
if (appName == null || appName.length() <= 0) {
return "";
}
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
return appName;
}
//Notification初始化
private Notification.Builder notificationInit() {
Intent intent = new Intent(context, context.getClass());
PendingIntent pIntent = PendingIntent.getActivity(context, 0, intent, 0);

Notification.Builder builder = new Notification.Builder(context);
builder.setSmallIcon(android.R.drawable.stat_sys_download)
.setTicker("开始下载")
.setContentTitle(getAppName())
.setContentText("正在更新")
.setContentIntent(pIntent)
.setWhen(System.currentTimeMillis());
return builder;
}
//获取apk存储路径
public File getCacheDirectory() {
File appCacheDir = null;
if (MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) && hasExternalStoragePermission()) {
appCacheDir = context.getExternalCacheDir();
}
if (appCacheDir == null) {
appCacheDir = context.getCacheDir();
}
if (appCacheDir == null) {
Log.w(TAG, "Can't define system cache directory! The app should be re-installed.");
}
return appCacheDir;
}
//判断是否有读写条件
private boolean hasExternalStoragePermission() {
int perm = context.checkCallingOrSelfPermission("android.permission.WRITE_EXTERNAL_STORAGE");
return perm == PackageManager.PERMISSION_GRANTED;
}
}

推荐阅读
  • 本文介绍了Android 7的学习笔记总结,包括最新的移动架构视频、大厂安卓面试真题和项目实战源码讲义。同时还分享了开源的完整内容,并提醒读者在使用FileProvider适配时要注意不同模块的AndroidManfiest.xml中配置的xml文件名必须不同,否则会出现问题。 ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • eclipse学习(第三章:ssh中的Hibernate)——11.Hibernate的缓存(2级缓存,get和load)
    本文介绍了eclipse学习中的第三章内容,主要讲解了ssh中的Hibernate的缓存,包括2级缓存和get方法、load方法的区别。文章还涉及了项目实践和相关知识点的讲解。 ... [详细]
  • 关键词:Golang, Cookie, 跟踪位置, net/http/cookiejar, package main, golang.org/x/net/publicsuffix, io/ioutil, log, net/http, net/http/cookiejar ... [详细]
  • 个人学习使用:谨慎参考1Client类importcom.thoughtworks.gauge.Step;importcom.thoughtworks.gauge.T ... [详细]
  • Java中包装类的设计原因以及操作方法
    本文主要介绍了Java中设计包装类的原因以及操作方法。在Java中,除了对象类型,还有八大基本类型,为了将基本类型转换成对象,Java引入了包装类。文章通过介绍包装类的定义和实现,解答了为什么需要包装类的问题,并提供了简单易用的操作方法。通过本文的学习,读者可以更好地理解和应用Java中的包装类。 ... [详细]
  • Java自带的观察者模式及实现方法详解
    本文介绍了Java自带的观察者模式,包括Observer和Observable对象的定义和使用方法。通过添加观察者和设置内部标志位,当被观察者中的事件发生变化时,通知观察者对象并执行相应的操作。实现观察者模式非常简单,只需继承Observable类和实现Observer接口即可。详情请参考Java官方api文档。 ... [详细]
  • Spring学习(4):Spring管理对象之间的关联关系
    本文是关于Spring学习的第四篇文章,讲述了Spring框架中管理对象之间的关联关系。文章介绍了MessageService类和MessagePrinter类的实现,并解释了它们之间的关联关系。通过学习本文,读者可以了解Spring框架中对象之间的关联关系的概念和实现方式。 ... [详细]
  • 面向对象之3:封装的总结及实现方法
    本文总结了面向对象中封装的概念和好处,以及在Java中如何实现封装。封装是将过程和数据用一个外壳隐藏起来,只能通过提供的接口进行访问。适当的封装可以提高程序的理解性和维护性,增强程序的安全性。在Java中,封装可以通过将属性私有化并使用权限修饰符来实现,同时可以通过方法来访问属性并加入限制条件。 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
  • 本文介绍了如何在给定的有序字符序列中插入新字符,并保持序列的有序性。通过示例代码演示了插入过程,以及插入后的字符序列。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • 在重复造轮子的情况下用ProxyServlet反向代理来减少工作量
    像不少公司内部不同团队都会自己研发自己工具产品,当各个产品逐渐成熟,到达了一定的发展瓶颈,同时每个产品都有着自己的入口,用户 ... [详细]
author-avatar
admin
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有