This commit is contained in:
2025-11-18 15:12:24 +08:00
parent c173c425ce
commit a7d2035e70
1361 changed files with 367452 additions and 0 deletions
@@ -0,0 +1,424 @@
package cn.shangyu.gdxzExpert.service;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Build;
import android.os.SystemClock;
import android.widget.RemoteViews;
import android.widget.Toast;
import net.tsz.afinal.FinalHttp;
import net.tsz.afinal.http.AjaxCallBack;
import net.tsz.afinal.http.HttpHandler;
import java.io.File;
import java.util.ArrayList;
import androidx.core.app.NotificationCompat;
//提醒的util的封装
@SuppressLint("NewApi")
public class NotifyUtil {
private static final int FLAG = Notification.FLAG_INSISTENT;
int requestCode = (int) SystemClock.uptimeMillis();
private int NOTIFICATION_ID;
private NotificationManager nm;
private Notification notification;
private NotificationCompat.Builder cBuilder;
private Notification.Builder nBuilder;
private Context mContext;
public NotifyUtil(Context context, int ID) {
this.NOTIFICATION_ID = ID;
mContext = context;
// 获取系统服务来初始化对象
nm = (NotificationManager) mContext
.getSystemService(Activity.NOTIFICATION_SERVICE);
cBuilder = new NotificationCompat.Builder(mContext);
}
/**
* 设置在顶部通知栏中的各种信息
*
* @param pendingIntent
* @param smallIcon
* @param ticker
*/
private void setCompatBuilder(PendingIntent pendingIntent, int smallIcon,
String ticker, String title, String content, boolean sound,
boolean vibrate, boolean lights) {
// // 如果当前Activity启动在前台,则不开启新的Activity。
// intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
// //
// 当设置下面PendingIntent.FLAG_UPDATE_CURRENT这个参数的时候,常常使得点击通知栏没效果,你需要给notification设置一个独一无二的requestCode
// // 将Intent封装进PendingIntent中,点击通知的消息后,就会启动对应的程序
// PendingIntent pIntent = PendingIntent.getActivity(mContext,
// requestCode, intent, FLAG);
cBuilder.setContentIntent(pendingIntent);// 该通知要启动的Intent
cBuilder.setSmallIcon(smallIcon);// 设置顶部状态栏的小图标
cBuilder.setTicker(ticker);// 在顶部状态栏中的提示信息
cBuilder.setContentTitle(title);// 设置通知中心的标题
cBuilder.setContentText(content);// 设置通知中心中的内容
cBuilder.setWhen(System.currentTimeMillis());
/*
* 将AutoCancel设为true后,当你点击通知栏的notification后,它会自动被取消消失,
* 不设置的话点击消息后也不清除,但可以滑动删除
*/
cBuilder.setAutoCancel(true);
// 将Ongoing设为true 那么notification将不能滑动删除
// notifyBuilder.setOngoing(true);
/*
* 从Android4.1开始,可以通过以下方法,设置notification的优先级,
* 优先级越高的,通知排的越靠前,优先级低的,不会在手机最顶部的状态栏显示图标
*/
cBuilder.setPriority(NotificationCompat.PRIORITY_MAX);
/*
* Notification.DEFAULT_ALL:铃声、闪光、震动均系统默认。
* Notification.DEFAULT_SOUND:系统默认铃声。
* Notification.DEFAULT_VIBRATE:系统默认震动。
* Notification.DEFAULT_LIGHTS:系统默认闪光。
* notifyBuilder.setDefaults(Notification.DEFAULT_ALL);
*/
int defaults = 0;
if (sound) {
defaults |= Notification.DEFAULT_SOUND;
}
if (vibrate) {
defaults |= Notification.DEFAULT_VIBRATE;
}
if (lights) {
defaults |= Notification.DEFAULT_LIGHTS;
}
cBuilder.setDefaults(defaults);
}
/**
* 设置builder的信息,在用大文本时会用到这个
*
* @param pendingIntent
* @param smallIcon
* @param ticker
*/
private void setBuilder(PendingIntent pendingIntent, int smallIcon,
String ticker, boolean sound, boolean vibrate, boolean lights) {
nBuilder = new Notification.Builder(mContext);
// 如果当前Activity启动在前台,则不开启新的Activity。
// intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
// PendingIntent pIntent = PendingIntent.getActivity(mContext,
// requestCode, intent, FLAG);
nBuilder.setContentIntent(pendingIntent);
nBuilder.setSmallIcon(smallIcon);
nBuilder.setTicker(ticker);
nBuilder.setWhen(System.currentTimeMillis());
nBuilder.setPriority(Notification.PRIORITY_MAX);
int defaults = 0;
if (sound) {
defaults |= Notification.DEFAULT_SOUND;
}
if (vibrate) {
defaults |= Notification.DEFAULT_VIBRATE;
}
if (lights) {
defaults |= Notification.DEFAULT_LIGHTS;
}
nBuilder.setDefaults(defaults);
}
/**
* 普通的通知
* <p/>
* 1. 侧滑即消失,下拉通知菜单则在通知菜单显示
*
* @param pendingIntent
* @param smallIcon
* @param ticker
* @param title
* @param content
*/
public void notify_normal_singline(PendingIntent pendingIntent,
int smallIcon, String ticker, String title, String content,
boolean sound, boolean vibrate, boolean lights) {
setCompatBuilder(pendingIntent, smallIcon, ticker, title, content,
sound, vibrate, lights);
sent();
}
/**
* 进行多项设置的通知(在小米上似乎不能设置大图标,系统默认大图标为应用图标)
*
* @param pendingIntent
* @param smallIcon
* @param ticker
* @param title
* @param content
*/
public void notify_mailbox(PendingIntent pendingIntent, int smallIcon,
int largeIcon, ArrayList<String> messageList, String ticker,
String title, String content, boolean sound, boolean vibrate,
boolean lights) {
setCompatBuilder(pendingIntent, smallIcon, ticker, title, content,
sound, vibrate, lights);
// 将Ongoing设为true 那么notification将不能滑动删除
// cBuilder.setOngoing(true);
/**
* // 删除时 Intent deleteIntent = new Intent(mContext,
* DeleteService.class); int deleteCode = (int)
* SystemClock.uptimeMillis(); // 删除时开启一个服务 PendingIntent
* deletePendingIntent = PendingIntent.getService(mContext, deleteCode,
* deleteIntent, PendingIntent.FLAG_UPDATE_CURRENT);
* cBuilder.setDeleteIntent(deletePendingIntent);
**/
Bitmap bitmap = BitmapFactory.decodeResource(mContext.getResources(),
largeIcon);
cBuilder.setLargeIcon(bitmap);
cBuilder.setDefaults(Notification.DEFAULT_ALL);// 设置使用默认的声音
// cBuilder.setVibrate(new long[]{0, 100, 200, 300});// 设置自定义的振动
cBuilder.setAutoCancel(true);
// builder.setSound(Uri.parse("file:///sdcard/click.mp3"));
// 设置通知样式为收件箱样式,在通知中心中两指往外拉动,就能出线更多内容,但是很少见
// cBuilder.setNumber(messageList.size());
NotificationCompat.InboxStyle inboxStyle = new NotificationCompat.InboxStyle();
for (String msg : messageList) {
inboxStyle.addLine(msg);
}
inboxStyle.setSummaryText("[" + messageList.size() + "条]" + title);
cBuilder.setStyle(inboxStyle);
sent();
}
/**
* 自定义视图的通知
*
* @param remoteViews
* @param pendingIntent
* @param smallIcon
* @param ticker
*/
public void notify_customview(RemoteViews remoteViews,
PendingIntent pendingIntent, int smallIcon, String ticker,
boolean sound, boolean vibrate, boolean lights) {
setCompatBuilder(pendingIntent, smallIcon, ticker, null, null, sound,
vibrate, lights);
notification = cBuilder.build();
notification.contentView = remoteViews;
// 发送该通知
nm.notify(NOTIFICATION_ID, notification);
}
/**
* 可以容纳多行提示文本的通知信息 (因为在高版本的系统中才支持,所以要进行判断)
*
* @param pendingIntent
* @param smallIcon
* @param ticker
* @param title
* @param content
*/
public void notify_normail_moreline(PendingIntent pendingIntent,
int smallIcon, String ticker, String title, String content,
boolean sound, boolean vibrate, boolean lights) {
final int sdk = Build.VERSION.SDK_INT;
if (sdk < Build.VERSION_CODES.JELLY_BEAN) {
notify_normal_singline(pendingIntent, smallIcon, ticker, title,
content, sound, vibrate, lights);
Toast.makeText(mContext, "您的手机低于Android 4.1.2,不支持多行通知显示!!",
Toast.LENGTH_SHORT).show();
} else {
setBuilder(pendingIntent, smallIcon, ticker, true, true, false);
nBuilder.setContentTitle(title);
nBuilder.setContentText(content);
nBuilder.setPriority(Notification.PRIORITY_HIGH);
notification = new Notification.BigTextStyle(nBuilder).bigText(
content).build();
// 发送该通知
nm.notify(NOTIFICATION_ID, notification);
}
}
/**
* 有进度条的通知,可以设置为模糊进度或者精确进度
*
* @param pendingIntent
* @param smallIcon
* @param ticker
* @param title
* @param content
*/
public void notify_progress(PendingIntent pendingIntent, int smallIcon,
String ticker, String title, String content, boolean sound,
boolean vibrate, boolean lights, String download_url,
String savePath, final DownLoadListener listener) {
setCompatBuilder(pendingIntent, smallIcon, ticker, title, content,
sound, vibrate, lights);
/*
* 因为进度条要实时更新通知栏也就说要不断的发送新的提示,所以这里不建议开启通知声音。
* 这里是作为范例,给大家讲解下原理。所以发送通知后会听到多次的通知声音。
*/
FinalHttp fh = new FinalHttp();
HttpHandler<File> httpHandler = fh.download(download_url, savePath,
new AjaxCallBack<File>() {
@Override
public void onLoading(long count, long current) {
super.onLoading(count, current);
double a = count;
double b = current;
double currentPro = (double) ((b / a) * 100);
cBuilder.setProgress(100, (int) currentPro, false);
sent();
}
@Override
public void onSuccess(File file) {
super.onSuccess(file);
cBuilder.setContentText("下载完成")
.setProgress(0, 0, false);
sent();
listener.OnSuccess(file);
}
@Override
public void onFailure(Throwable t, int errorNo,
String strMsg) {
super.onFailure(t, errorNo, strMsg);
listener.onFailure(t, errorNo, strMsg);
}
});
}
/**
* 容纳大图片的通知
*
* @param pendingIntent
* @param smallIcon
* @param ticker
* @param title
* @param bigPic
*/
public void notify_bigPic(PendingIntent pendingIntent, int smallIcon,
String ticker, String title, String content, int bigPic,
boolean sound, boolean vibrate, boolean lights) {
setCompatBuilder(pendingIntent, smallIcon, ticker, title, null, sound,
vibrate, lights);
NotificationCompat.BigPictureStyle picStyle = new NotificationCompat.BigPictureStyle();
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inScaled = true;
options.inSampleSize = 2;
Bitmap bitmap = BitmapFactory.decodeResource(mContext.getResources(),
bigPic, options);
picStyle.bigPicture(bitmap);
picStyle.bigLargeIcon(bitmap);
cBuilder.setContentText(content);
cBuilder.setStyle(picStyle);
sent();
}
/**
* 里面有两个按钮的通知
*
* @param smallIcon
* @param leftbtnicon
* @param lefttext
* @param leftPendIntent
* @param rightbtnicon
* @param righttext
* @param rightPendIntent
* @param ticker
* @param title
* @param content
*/
public void notify_button(int smallIcon, int leftbtnicon, String lefttext,
PendingIntent leftPendIntent, int rightbtnicon, String righttext,
PendingIntent rightPendIntent, String ticker, String title,
String content, boolean sound, boolean vibrate, boolean lights) {
requestCode = (int) SystemClock.uptimeMillis();
setCompatBuilder(rightPendIntent, smallIcon, ticker, title, content,
sound, vibrate, lights);
cBuilder.addAction(leftbtnicon, lefttext, leftPendIntent);
cBuilder.addAction(rightbtnicon, righttext, rightPendIntent);
sent();
}
public void notify_HeadUp(PendingIntent pendingIntent, int smallIcon,
int largeIcon, String ticker, String title, String content,
int leftbtnicon, String lefttext, PendingIntent leftPendingIntent,
int rightbtnicon, String righttext,
PendingIntent rightPendingIntent, boolean sound, boolean vibrate,
boolean lights) {
setCompatBuilder(pendingIntent, smallIcon, ticker, title, content,
sound, vibrate, lights);
cBuilder.setLargeIcon(BitmapFactory.decodeResource(
mContext.getResources(), largeIcon));
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
// cBuilder.addAction(leftbtnicon, lefttext, leftPendingIntent);
// cBuilder.addAction(rightbtnicon, righttext, rightPendingIntent);
// } else {
// Toast.makeText(mContext, "版本低于Andriod5.0,无法体验HeadUp样式通知",
// Toast.LENGTH_SHORT).show();
// }
sent();
}
/**
* 发送通知
*/
private void sent() {
notification = cBuilder.build();
// 发送该通知
nm.notify(NOTIFICATION_ID, notification);
}
/**
* 根据id清除通知
*/
public void clear() {
// 取消通知
nm.cancelAll();
}
DownLoadListener listener;
public void setOnDownLoadListener(DownLoadListener l) {
listener = l;
}
public interface DownLoadListener {
void OnSuccess(File file);
void onFailure(Throwable t, int errorNo, String strMsg);
}
}
@@ -0,0 +1,271 @@
package cn.shangyu.gdxzExpert.service;
import android.annotation.SuppressLint;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.net.Uri;
import android.os.Environment;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import androidx.core.content.FileProvider;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import cn.shangyu.gdxzExpert.activity.SettingVersionActivity;
import cn.shangyu.gdxzExpert.utils.NotificationUtils;
import cn.shangyu.gdxzExpert.utils.UIUtils;
public class UpdateService extends Service {
// 标题
private int titleId = 0;
private final static int DOWNLOAD_COMPLETE = 0;
private final static int DOWNLOAD_FAIL = 1;
// 下載的连接
private String url;
// 版本号
// private String appVersion;
// 文件存储
private File updateDir = null;
private File updateFile = null;
private File updateFile2 = null;
// 通知栏
private NotificationManager updateNotificationManager = null;
// private Notification updateNotification = null;
// 通知栏跳转Intent
private Intent updateIntent = null;
private PendingIntent updatePendingIntent = null;
private String firstUrl = null;
private Intent Intentsss = null;
private Notification.Builder builder;
private Notification notification;
private NotificationUtils notificationUtils;
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
@Override
public void onCreate() {
super.onCreate();
}
@SuppressLint("WrongConstant")
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent == null) {
return START_NOT_STICKY;
}
Intentsss = intent;
// 获取名称
titleId = intent.getIntExtra("titleId", 0);
url = intent.getStringExtra("url");
String newVersion = intent.getStringExtra("newVersion");
String oldVersion = intent.getStringExtra("oldVersion");
firstUrl = url;
// appVersion = intent.getStringExtra("appVersion");
// 创建文件
if (Environment.MEDIA_MOUNTED.equals(Environment
.getExternalStorageState())) {
updateDir = new File(UIUtils.getContext().getExternalFilesDir(""),
"/app/download/");
updateFile = new File(updateDir.getPath(), (titleId + newVersion)
+ ".apk");
updateFile2 = new File(updateDir.getPath(), (titleId + oldVersion)
+ ".apk");
if (updateFile2.exists()) {
updateFile2.delete();
}
}
this.updateNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
updateIntent = new Intent(this, SettingVersionActivity.class);
updatePendingIntent = PendingIntent.getActivity(this, 0, updateIntent, 0);
updateIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK| Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);//关键的一步,设置启动模式
notificationUtils = new NotificationUtils(this,0,updatePendingIntent);
notificationUtils.sendUpVersonNotification("开始下载", "当前下载进度:0%");
// 开启一个新的线程下载,如果使用Service同步下载,会导致ANR问题,Service本身也会阻塞
new Thread(new updateRunnable()).start();// 这个是下载的重点,是下载的过程
return super.onStartCommand(intent, flags, startId);
}
private Handler updateHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case DOWNLOAD_COMPLETE:
// notification.flags |= notification.FLAG_AUTO_CANCEL;
// 点击安装PendingIntent
// Uri uri = Uri.fromFile(updateFile);
// Intent installIntent = new Intent(Intent.ACTION_VIEW);
// installIntent.setDataAndType(uri,
// "application/vnd.android.package-archive");
// updatePendingIntent = PendingIntent.getActivity(
// UpdateService.this, 0, installIntent, 0);
// installAPK(updateFile);//下载完成直接安装
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// Intent intent = new Intent();
// intent.setAction("android.intent.action.VIEW");
// intent.addCategory("android.intent.category.DEFAULT");
// intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK );
// intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK| Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);//关键的一步,设置启动模式
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.setDataAndType(FileProvider.getUriForFile(UpdateService.this, "cn.shangyu.gdxzExpert.fileprovider", updateFile),"application/vnd.android.package-archive");
getApplicationContext().startActivity(intent);
// startActivity(intent);
updatePendingIntent = PendingIntent.getActivity(UpdateService.this, 0, intent, 0);
NotificationUtils notificationUtils1 = new NotificationUtils(UpdateService.this,0,updatePendingIntent);
notificationUtils1.sendUpVersonNotification("肝胆相照专家版", "下载完成,点击安装");
stopService(Intentsss);
break;
case DOWNLOAD_FAIL:
notificationUtils.sendUpVersonNotification("肝胆相照专家版", "下载出错,请重新检查更新");
// builder.setContentInfo("");
// builder.setContentText("下载完成");
// builder.setContentTitle("肝胆相照");
// builder.setSmallIcon(R.drawable.ic_launcher);
// builder.setTicker("肝胆相照");
// builder.setAutoCancel(true);
// builder.setWhen(System.currentTimeMillis());
//// builder.setContentIntent(updatePendingIntent);
// Notification notification1 = builder.build();
// updateNotificationManager.notify(0, notification1);
// 下载失败
// updateNotification.setLatestEventInfo(UpdateService.this,
// "肝胆相照", "下载完成,点击安装。", updatePendingIntent);
// updateNotificationManager.notify(0, updateNotification);
stopService(Intentsss);
break;
default:
stopService(Intentsss);
}
}
};
private void installAPK(File t) {
Intent intent = new Intent();
intent.setAction("android.intent.action.VIEW");
intent.addCategory("android.intent.category.DEFAULT");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK );
intent.setDataAndType(Uri.fromFile(t),"application/vnd.android.package-archive");
startActivity(intent);
}
class updateRunnable implements Runnable {
Message message = updateHandler.obtainMessage();
public void run() {
message.what = DOWNLOAD_COMPLETE;
try {
// 增加权限<uses-permission
// android:name="android.permission.WRITE_EXTERNAL_STORAGE">;
if (!updateDir.exists()) {
updateDir.mkdirs();
}
if (!updateFile.exists()) {
updateFile.createNewFile();
}
// 下载肝胆相照app
long downloadSize = downloadUpdateFile(url, updateFile);
if (downloadSize > 0) {
// 下载成功
updateHandler.sendMessage(message);
}
} catch (Exception ex) {
ex.printStackTrace();
message.what = DOWNLOAD_FAIL;
// 下载失败
updateHandler.sendMessage(message);
}
}
}
public long downloadUpdateFile(String downloadUrl, File saveFile)
throws Exception {
// 下载代码
int downloadCount = 0;
int currentSize = 0;
long totalSize = 0;
int updateTotalSize = 0;
HttpURLConnection httpConnection = null;
InputStream is = null;
FileOutputStream fos = null;
try {
URL url = new URL(downloadUrl);
httpConnection = (HttpURLConnection) url.openConnection();
httpConnection
.setRequestProperty("User-Agent", "PacificHttpClient");
if (currentSize > 0) {
httpConnection.setRequestProperty("RANGE", "bytes="
+ currentSize + "-");
}
httpConnection.setConnectTimeout(10000);
httpConnection.setReadTimeout(20000);
updateTotalSize = httpConnection.getContentLength();
if (httpConnection.getResponseCode() == 404) {
throw new Exception("fail!");
}
is = httpConnection.getInputStream();
fos = new FileOutputStream(saveFile, false);
byte buffer[] = new byte[4096];
int readsize = 0;
while ((readsize = is.read(buffer)) > 0) {
fos.write(buffer, 0, readsize);
totalSize += readsize;
// 为了防止频繁的通知导致应用吃紧,百分比增加10才通知一次
if ((downloadCount == 0) || (int) (totalSize * 100 / updateTotalSize) - 10 > downloadCount) {
downloadCount += 10;
/* builder.setContentInfo("");
// builder.setContentText("当前下载进度:" + (int) totalSize * 100 / updateTotalSize + "%");
builder.setContentText("当前下载进度:" + downloadCount+ "%");
builder.setContentTitle("肝胆相照");
builder.setSmallIcon(R.drawable.ic_launcher);
builder.setTicker("肝胆相照");
builder.setAutoCancel(true);
builder.setWhen(System.currentTimeMillis());
// builder.setContentIntent(updatePendingIntent);
Notification notification1 = builder.build();
updateNotificationManager.notify(0, notification1);*/
notificationUtils.sendUpVersonNotification("正在下载", "当前下载进度:"+downloadCount+"%");
}
}
} finally {
if (httpConnection != null) {
httpConnection.disconnect();
}
if (is != null) {
is.close();
}
if (fos != null) {
fos.close();
}
}
return totalSize;
}
@Override
public void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
}
}