IntentService+Notifcation实现应用app后台下载完成后并安装(已适配8.0)

本文主要是介绍IntentService+Notifcation实现应用app后台下载完成后并安装(已适配8.0),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

转载自IntentService+Notifcation实现应用app后台下载完成后并安装(已适配8.0)

现在已兼容8.0的通知栏显示,确保你的targetSdkVersion 是26或以上

以下为8.0的显示图片:

这里写图片描述

这里写图片描述

app的更新模块放在后台服务可以大大提高app的体验,采用IntentService这种google为我们封装好的用于执行服务中有网络操作的类并搭配Notification来实现一下(下载工具用的是自带的URLConnection,因为Retrofit+rxjava并没有提供进度的回调,网上也有很多改进的方案,可以自定义让retrofit+rxjava实现进度的回调,在此,没有采用)

效果图如下:(看了一下淘宝的更新,所以就成这样的界面了,)
这里写图片描述
代码:自定义的IntentService类

/*** 更新包下载安装服务*/
public class UpdateService extends IntentService {private static final int NOTIFY_DOWNLOAD= 0;private static final int NOTIFY_FINISH = 1;private static final String PENDING_INSTALL_ACTION = "gaoxin.com.inforindustry.click.toinstall";private Context mContext;private String apkUrl;public UpdateService() {super("UpdateService");}private NotificationUtils notificationUtils;private File  downapkfile;private Handler mHandler = new Handler(new Handler.Callback() {@Overridepublic boolean handleMessage(Message msg) {switch (msg.what){case 0://正在下载中RemoteViews contentView = notificationUtils.getNotification().contentView;contentView.setTextViewText(R.id.notify_tv, "更新包下载中...");contentView.setProgressBar(R.id.notify_progress_pb, 100, msg.arg1, false);contentView.setTextViewText(R.id.notify_progress_tv,msg.arg1+"%");// 更新UInotificationUtils.getManager().notify(NOTIFY_DOWNLOAD,notificationUtils.getNotification());break;case 1:notificationUtils.cancelNotification(NOTIFY_DOWNLOAD);createNotification(NOTIFY_FINISH);break;}return true;}});@Overrideprotected void onHandleIntent(Intent intent) {if (intent != null) {apkUrl = intent.getStringExtra("apkurl");handleActionFoo(apkUrl);}}private void handleActionFoo(String param1) {if(NetworkUtils.isConnected()){createNotification(NOTIFY_DOWNLOAD);try {DownApk(param1);} catch (Exception e) {e.printStackTrace();}}}//发送消息进行更新进度条public void sendMessage(int what,int mprogress) {Message msg0 = mHandler.obtainMessage();msg0.what = what;msg0.arg1 = mprogress;mHandler.sendMessage(msg0);}private void DownApk(String param1) {int oldProcess = 0;if (SDCardUtils.isSDCardEnable()){downapkfile = new File(Environment.getExternalStorageDirectory().getAbsolutePath()+"/industry.apk");try {URL url = new URL(param1.trim());HttpURLConnection connection  = (HttpURLConnection) url.openConnection();if (connection.getResponseCode() == 200){InputStream inputStream = connection.getInputStream();FileOutputStream fos = new FileOutputStream(downapkfile);//总长度int totalLength = connection.getContentLength();//已下载的长度int currentLength  = 0;byte[] bytes = new byte[512];connection.connect();int flag = 0;while (flag < 100){if (inputStream != null){int read = inputStream.read(bytes);if (read <= 0){sendMessage(1,0);break;}else {fos.write(bytes,0,read);currentLength += read;int mprogress = (int) ((currentLength*100)/totalLength);if(oldProcess <= mprogress-5 ){// 避免notifymanager ANR,每下载百分之5才进行通知一次oldProcess =mprogress;sendMessage(0, mprogress);}}}}fos.close();inputStream.close();}connection.disconnect();} catch (MalformedURLException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}}private void createNotification(int notifyId) {switch (notifyId){case NOTIFY_DOWNLOAD:RemoteViews remoteViews = new RemoteViews(AppUtils.getAppPackageName(),R.layout.notify_custom_view_layout);remoteViews.setTextViewText(R.id.notify_tv,"正在下载...");remoteViews.setProgressBar(R.id.notify_progress_pb,100,0,false);remoteViews.setTextViewText(R.id.notify_progress_tv,"0%");notificationUtils.sendNotification(notifyId,"","",remoteViews,null);break;case NOTIFY_FINISH:Intent intent = new Intent(getApplicationContext(),NotificationBroadCast.class);intent.setAction(PENDING_INSTALL_ACTION);intent.putExtra("notifyId",NOTIFY_FINISH);PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext,0,intent,PendingIntent.FLAG_ONE_SHOT);notificationUtils.sendNotification(notifyId,"点击安装","更新包已下载完成",null,pendingIntent);break;default:break;}}@Overridepublic void onCreate() {super.onCreate();mContext = this;//初始化通知窗口管理notificationUtils = new NotificationUtils(getApplicationContext());}
}
  • 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
  • 140
  • 141
  • 142
  • 143
  • 144

NotificationUtils,用来进行适配8.0系统

public class NotificationUtils extends ContextWrapper {private NotificationManager mManager;public static final String ANDROID_CHANNEL_ID = "com.gaoxin.industry.ANDROID";public static final String ANDROID_CHANNEL_NAME = "ANDROID CHANNEL";private Notification notification;public NotificationUtils(Context base) {super(base);if (Build.VERSION.SDK_INT >= 26){createChannels();}}@RequiresApi(api = Build.VERSION_CODES.O)public void createChannels() {// create android channelNotificationChannel androidChannel = new NotificationChannel(ANDROID_CHANNEL_ID,ANDROID_CHANNEL_NAME, NotificationManager.IMPORTANCE_DEFAULT);// Sets whether notifications posted to this channel should display notification lightsandroidChannel.enableLights(true);// Sets whether notification posted to this channel should vibrate.androidChannel.enableVibration(true);// Sets the notification light color for notifications posted to this channelandroidChannel.setLightColor(Color.GREEN);// Sets whether notifications posted to this channel appear on the lockscreen or notandroidChannel.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);getManager().createNotificationChannel(androidChannel);}public NotificationManager getManager() {if (mManager == null) {mManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);}return mManager;}@RequiresApi(api = Build.VERSION_CODES.O)public Notification.Builder getAndroidChannelNotification(String title,String content) {return new Notification.Builder(getApplicationContext(), ANDROID_CHANNEL_ID).setContentTitle(title).setContentText(content).setSmallIcon(android.R.drawable.stat_notify_more);}public NotificationCompat.Builder getNotification_25(String title, String content){return new NotificationCompat.Builder(getApplicationContext()).setContentTitle(title).setContentText(content).setSmallIcon(android.R.drawable.stat_notify_more);}public void sendNotification(int id,String title, String content, RemoteViews remoteViews, PendingIntent intent){if (Build.VERSION.SDK_INT>=26){notification = getAndroidChannelNotification(title, content).setCustomContentView(remoteViews).setContentIntent(intent).build();getManager().notify(id,notification);}else{notification = getNotification_25(title, content).setCustomContentView(remoteViews).setContentIntent(intent).build();getManager().notify(id,notification);}}public void cancelNotification(int id){getManager().cancel(id);}public Notification getNotification(){if (notification != null){return notification;}return null;}
}
  • 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

需要注意的点: Notification必须设置smallIcon这个属性,否则会报错,
如果是下载完成后不希望自动安装,而是点击后进行安装,可以使用PendingIntent这个类来进行触发,否则点击后是没有什么效果的,必须传递意图Intent

Android 8.0在安装应用的时候需要权限

8.0系统设置中不再提供是否允许安装未知来源的应用这个选项,所以在进行安装的时候,一定注意这个权限,否则会报错
其他注意事项:清单文件中必须包含provider

<provider
            android:name="android.support.v4.content.FileProvider"android:authorities="包名.fileprovider"android:exported="false"android:grantUriPermissions="true"><meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"android:resource="@xml/file_paths" /></provider>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

res文件夹下建立xml文件夹
在xml中新建file_paths.xml文件,如下:

<?xml version="1.0" encoding="utf-8"?>
<paths><external-path
        name="external_storage_root"path="." />
</paths>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

安装

 public static void installApp(final File file, final String authority) {if (!isFileExists(file)) return;Utils.getApp().startActivity(IntentUtils.getInstallAppIntent(file, authority, true));}
public static Intent getInstallAppIntent(final File file,final String authority,final boolean isNewTask) {if (file == null) return null;Intent intent = new Intent(Intent.ACTION_VIEW);Uri data;String type = "application/vnd.android.package-archive";if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {data = Uri.fromFile(file);} else {intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);data = FileProvider.getUriForFile(Utils.getApp(), authority, file);}intent.setDataAndType(data, type);return getIntent(intent, isNewTask);}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

布局也贴一下,根据自己的需求

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="wrap_content"android:background="@color/white_alpha_6"><ImageView
        android:layout_width="wrap_content"android:layout_height="wrap_content"android:id="@+id/notify_download_iv"android:src="@mipmap/ic_launcher_round"android:layout_marginTop="12dp"android:layout_centerVertical="true"android:layout_marginRight="8dp"/><TextView
        android:layout_width="wrap_content"android:layout_height="wrap_content"android:id="@+id/notify_tv"android:textColor="@color/black"android:layout_marginTop="8dp"android:layout_toRightOf="@+id/notify_download_iv"android:text="正在下载..."/><ProgressBar
        android:layout_width="match_parent"android:layout_height="wrap_content"android:id="@+id/notify_progress_pb"style="?android:attr/progressBarStyleHorizontal"android:layout_below="@+id/notify_tv"android:layout_toRightOf="@+id/notify_download_iv"/><TextView
            android:layout_width="wrap_content"android:layout_height="wrap_content"android:textSize="12sp"android:textColor="@color/black"android:id="@+id/notify_progress_instruction_tv"android:layout_below="@+id/notify_progress_pb"android:text="客户端已经下载了"android:layout_toRightOf="@+id/notify_download_iv"/><TextView
            android:layout_width="wrap_content"android:layout_height="wrap_content"android:textSize="12sp"android:id="@+id/notify_progress_tv"android:textColor="@color/black"android:layout_toRightOf="@+id/notify_progress_instruction_tv"android:layout_below="@+id/notify_progress_pb"android:text="50%"/></RelativeLayout>
  • 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

启动服务:

 /*** 传入url*/Intent intent = new Intent(MainActivity.this,UpdateService.class);intent.putExtra("apkurl", updataVersionUrl);startService(intent);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

下载完成后,点击事件的处理,采用了BroadCastReceiver方式

public class NotificationBroadCast extends BroadcastReceiver {private File downFile = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/industry.apk");private static final String INSTALL_ACTION = "包名.click.toinstall";@Overridepublic void onReceive(Context context, Intent intent) {String action = intent.getAction();if (action.equals(INSTALL_ACTION)){int notifyId = intent.getIntExtra("notifyId", 0);NotificationManager manager = (NotificationManager) context.getSystemService(NOTIFICATION_SERVICE);manager.cancel(notifyId);if (FileUtils.isFileExists(downFile) && downFile.length() > 0) {AppUtils.installApp(downFile, "gaoxin.com.inforindustry.fileprovider");}}}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

最后不要忘记在清单文件中注册一下,

这篇关于IntentService+Notifcation实现应用app后台下载完成后并安装(已适配8.0)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/516342

相关文章

Zookeeper安装和配置说明

一、Zookeeper的搭建方式 Zookeeper安装方式有三种,单机模式和集群模式以及伪集群模式。 ■ 单机模式:Zookeeper只运行在一台服务器上,适合测试环境; ■ 伪集群模式:就是在一台物理机上运行多个Zookeeper 实例; ■ 集群模式:Zookeeper运行于一个集群上,适合生产环境,这个计算机集群被称为一个“集合体”(ensemble) Zookeeper通过复制来实现

CentOS7安装配置mysql5.7 tar免安装版

一、CentOS7.4系统自带mariadb # 查看系统自带的Mariadb[root@localhost~]# rpm -qa|grep mariadbmariadb-libs-5.5.44-2.el7.centos.x86_64# 卸载系统自带的Mariadb[root@localhost ~]# rpm -e --nodeps mariadb-libs-5.5.44-2.el7

Centos7安装Mongodb4

1、下载源码包 curl -O https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel70-4.2.1.tgz 2、解压 放到 /usr/local/ 目录下 tar -zxvf mongodb-linux-x86_64-rhel70-4.2.1.tgzmv mongodb-linux-x86_64-rhel70-4.2.1/

中文分词jieba库的使用与实景应用(一)

知识星球:https://articles.zsxq.com/id_fxvgc803qmr2.html 目录 一.定义: 精确模式(默认模式): 全模式: 搜索引擎模式: paddle 模式(基于深度学习的分词模式): 二 自定义词典 三.文本解析   调整词出现的频率 四. 关键词提取 A. 基于TF-IDF算法的关键词提取 B. 基于TextRank算法的关键词提取

水位雨量在线监测系统概述及应用介绍

在当今社会,随着科技的飞速发展,各种智能监测系统已成为保障公共安全、促进资源管理和环境保护的重要工具。其中,水位雨量在线监测系统作为自然灾害预警、水资源管理及水利工程运行的关键技术,其重要性不言而喻。 一、水位雨量在线监测系统的基本原理 水位雨量在线监测系统主要由数据采集单元、数据传输网络、数据处理中心及用户终端四大部分构成,形成了一个完整的闭环系统。 数据采集单元:这是系统的“眼睛”,

hdu1043(八数码问题,广搜 + hash(实现状态压缩) )

利用康拓展开将一个排列映射成一个自然数,然后就变成了普通的广搜题。 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#inclu

csu 1446 Problem J Modified LCS (扩展欧几里得算法的简单应用)

这是一道扩展欧几里得算法的简单应用题,这题是在湖南多校训练赛中队友ac的一道题,在比赛之后请教了队友,然后自己把它a掉 这也是自己独自做扩展欧几里得算法的题目 题意:把题意转变下就变成了:求d1*x - d2*y = f2 - f1的解,很明显用exgcd来解 下面介绍一下exgcd的一些知识点:求ax + by = c的解 一、首先求ax + by = gcd(a,b)的解 这个

hdu1394(线段树点更新的应用)

题意:求一个序列经过一定的操作得到的序列的最小逆序数 这题会用到逆序数的一个性质,在0到n-1这些数字组成的乱序排列,将第一个数字A移到最后一位,得到的逆序数为res-a+(n-a-1) 知道上面的知识点后,可以用暴力来解 代码如下: #include<iostream>#include<algorithm>#include<cstring>#include<stack>#in

Centos7安装JDK1.8保姆版

工欲善其事,必先利其器。这句话同样适用于学习Java编程。在开始Java的学习旅程之前,我们必须首先配置好适合的开发环境。 通过事先准备好这些工具和配置,我们可以避免在学习过程中遇到因环境问题导致的代码异常或错误。一个稳定、高效的开发环境能够让我们更加专注于代码的学习和编写,提升学习效率,减少不必要的困扰和挫折感。因此,在学习Java之初,投入一些时间和精力来配置好开发环境是非常值得的。这将为我

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象