-----------------------------------uni-app--------------------------------------
// 版本更新
export function checkAppVersion(_t, isShowWarn = false) {
// #ifdef APP-PLUS
// 若是正在更新不执行
if(_t.isShowModal || _t.isUpdate) return;
const os_type = plus.os.name.toLowerCase();
const app_version = plus.runtime.version;
plus.runtime.getProperty(plus.runtime.appid, function(info) {
uni.setStorageSync('VERSION', info.version);
const res_version = info.version;
const requestData = {
osType: os_type,
appVersion: app_version,
resVersion: res_version
}
_t.$api.getAppVersion(requestData).then(res => {
Log.d("版本信息:" + JSON.stringify(res));
if (res.statusCode != 200 || !res.data.success) return;
const data = res.data.result;
if (data.isUpdate === 0) return;
const app_version_db = data.appVersion;
const res_version_db = data.resVersion;
const app_url = data.appUrl;
const res_url = data.resUrl;
const app_version_desc = data.content;
//大版本更新(涉及安卓壳子或壳子改动)
if (app_version_db !== app_version && (parseInt(app_version.replace(/\./g, "")) <
parseInt(app_version_db.replace(/\./g, "")))) {
// 定义安卓apk存放路径
const filename = "_downloads/park.apk";
// 处理安装提示在本应用上方弹出导致下载弹窗重复弹出问题
nativeJs("bridge", "getFileApkVersion", {
path: plus.io.convertLocalFileSystemURL(filename)
}, originAppVersion => {
Log.d("原来存在的apk包版本:" + originAppVersion)
if(parseInt(originAppVersion.replace(/\./g, "")) === parseInt(app_version_db.replace(/\./g, ""))) {
// 如果原来存在的apk包版本比app版本高直接提示安装
if(parseInt(originAppVersion.replace(/\./g, "")) > parseInt(app_version.replace(/\./g, ""))) {
// 决定是否弹出安装,解决部分机型在应用界面弹出安装提示而重复提示问题
nativeJs("bridge", "getFileCreatedTime", {
path: plus.io.convertLocalFileSystemURL(filename)
}, createdTime => {
if(createdTime) {
Log.d("现在时间" + new Date().getTime())
Log.d("文件创建时间" + parseInt(createdTime))
Log.d("现在时间与文件创建时间差" + (new Date().getTime() - parseInt(createdTime)))
// 超过1分钟提示安装
if(new Date().getTime() - parseInt(createdTime) > 60 * 1 * 1000) {
_t.isShowModal = true;
uni.showModal({ //提醒用户更新
title: "版本更新",
content: "是否立即更新",
showCancel: false,
complete: () => {
_t.isShowModal = false;
},
success: res => {
if(res.confirm) {
plus.runtime.install(plus.io.convertLocalFileSystemURL(filename), //安装APP
{
force: true
},
function() {
Log.d('安装旧包准备成功');
},
function() {
Log.d('安装旧包准备失败');
});
}
}
})
}
}
})
}else {
// 删除原来安装包缩小体积
nativeJs("bridge", "deleteFile", {
path: plus.io.convertLocalFileSystemURL(filename)
});
}
return;
}
_t.isShowModal = true;
uni.showModal({ //提醒用户更新
title: "版本更新",
content: app_version_desc,
showCancel: false,
complete: () => {
_t.isShowModal = false;
},
success: res => {
if(res.confirm) {
// plus.downloader.clear();
Log.d("全量更新地址:" + app_url)
// 清除下载任务
if(_t.dtask) _t.dtask.abort();
// 下载前清除以前下载的缓存,避免apk包累积应用变大
nativeJs("bridge", "deleteFile", {
path: plus.io.convertLocalFileSystemURL(filename)
});
_t.dtask = plus.downloader.createDownload(app_url, {
method: "GET",
filename //利用保存路径,实现下载文件的重命名
},
function(d, status){
Log.d("createDownloaded下载完成" + JSON.stringify(d))
if(status !== 200) {
_t.isUpdate = false;
// 清除下载任务
_t.dtask.abort();
}
});
_t.dtask.addEventListener("statechanged", function(task, status) {
switch(task.state) {
case 1: // 开始
break;
case 2: //已连接到服务器
break;
case 3: // 已接收到数据
const current = parseInt(100 * task.downloadedSize / task.totalSize);
nativeJs("notification", "setProgress", {
current
});
break;
case 4: // 下载完成
nativeJs("notification", "compProgressNotification", {
title: '下载完成'
});
plus.runtime.install(plus.io.convertLocalFileSystemURL(task.filename), //安装APP
{
force: true
},
function() {
Log.d('安装准备成功');
_t.isUpdate = false;
},
function() {
Log.d('安装准备失败');
_t.isUpdate = false;
});
break;
}
});
nativeJs("notification", "init");
_t.isUpdate = true;
_t.dtask.start();
}
}
})
});
} else {
//小版本更新(uniapp中的改动)
if (res_version_db !== res_version && (parseInt(res_version.replace(/\./g, "")) <
parseInt(res_version_db.replace(/\./g, "")))) {
uni.showLoading({
title: '更新中...',
mask: true
});
Log.d("热更新地址:" + res_url)
_t.isUpdate = true;
uni.downloadFile({
url: res_url,
success: (downloadResult) => {
Log.d("补丁信息:" + JSON.stringify(downloadResult))
if (downloadResult.statusCode === 200) {
plus.runtime.install(downloadResult.tempFilePath, {
force: true
}, function() {
Log.d('install success...');
uni.hideLoading();
_t.isUpdate = false;
plus.runtime.restart();
// 删除安装包
nativeJs("bridge", "deleteFile", {
path: plus.io.convertLocalFileSystemURL(downloadResult.tempFilePath)
});
}, function(e) {
uni.hideLoading();
_t.isUpdate = false;
Log.d('install fail...' + JSON.stringify(e));
// 删除安装包
nativeJs("bridge", "deleteFile", {
path: plus.io.convertLocalFileSystemURL(downloadResult.tempFilePath)
});
});
} else {
uni.hideLoading();
_t.isUpdate = false;
}
},
fail() {
uni.hideLoading();
_t.isUpdate = false;
}
});
}
if (isShowWarn && res_version_db === res_version && app_version_db ===
app_version) {
uni.showToast({
title: '已是最新版本',
icon: 'none',
duration: 1000,
mask: false
});
}
if (isShowWarn && (parseInt(res_version.replace(/\./g, "")) > parseInt(
res_version_db.replace(/\./g, "")) || parseInt(app_version.replace(
/\./g, "")) > parseInt(app_version_db.replace(/\./g, "")))) {
uni.showToast({
title: '暂无新版本',
icon: 'none',
duration: 1000,
mask: false
});
}
}
})
});
// #endif
}
// 通过uniapp自带一套执行
export function nativeJs(targetClass, method, params = {}, successCallback, errorCallback) {
// #ifdef APP-PLUS
return plus.bridge.exec(targetClass, method, [plus.bridge.callbackId(typeof successCallback ===
'function' ? successCallback : null, typeof errorCallback === 'function' ? errorCallback :
null), JSON.stringify(params)]);
// #endif
}
-----------------------------------android--------------------------------------
package com.park;
import android.content.Intent;
import android.util.Log;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.park.util.AppUtil;
import org.json.JSONArray;
import java.io.File;
import io.dcloud.common.DHInterface.IWebview;
import io.dcloud.common.DHInterface.StandardFeature;
import io.dcloud.common.util.JSUtil;
public class BridgeForUniApp extends StandardFeature {
/**
* h5调此跳转
* @param pWebView
* @param arr
*/
public void goTargetActivity(IWebview pWebView, JSONArray arr){
Intent intent = new Intent(pWebView.getContext(), RawActivity.class);
intent.putExtra("CallBackID", arr.optString(0));
JSONObject params = JSON.parseObject(arr.optString(1));
intent.putExtra("access_token", params.getString("token"));
Log.d("params", params.toJSONString());
pWebView.getContext().startActivity(intent);
}
/**
* 删除文件
* @param pWebView
* @param arr
* @return
*/
public Boolean deleteFile(IWebview pWebView, JSONArray arr){
JSONObject params = JSON.parseObject(arr.optString(1));
File file = new File(params.getString("path"));
if(file.exists()) file.delete();
Log.d("h5","删除文件成功" + params.getString("path"));
return true;
}
/**
* 获取apk版本号
* @param pWebView
* @param arr
* @return
*/
public void getFileApkVersion(IWebview pWebView, JSONArray arr){
JSONObject params = JSON.parseObject(arr.optString(1));
JSUtil.execCallback(pWebView, arr.optString(0), AppUtil.getFileApkVersion(pWebView.getActivity(), params.getString("path")), JSUtil.OK,false);
}
/**
* 根据文件路径获取文件创建时间
* @param pWebView
* @param arr
* @return
*/
public void getFileCreatedTime(IWebview pWebView, JSONArray arr){
JSONObject params = JSON.parseObject(arr.optString(1));
File file = new File(params.getString("path"));
if(!file.exists()) return;
JSUtil.execCallback(pWebView, arr.optString(0), file.lastModified(), JSUtil.OK,false);
}
}
package com.park;
import org.json.JSONArray;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.android.park.R;
import com.park.util.NotificationUtils;
import io.dcloud.common.DHInterface.IWebview;
import io.dcloud.common.DHInterface.StandardFeature;
/**
* app下载进度
* @author 蓝之静云
*/
public class DownloadProgress extends StandardFeature {
static final int ids = 1000;
// 通知工具栏
NotificationUtils notificationUtils;
public void init(IWebview pWebView, JSONArray array){
if(null != notificationUtils) notificationUtils.clearNotification();
notificationUtils = new NotificationUtils(pWebView.getActivity());
}
/**
* 初始设置
*
* @param pWebView
* @param array
*/
public void setNotification(IWebview pWebView, JSONArray array) {
JSONObject params = JSON.parseObject(array.optString(1));
String title = params.getString("title");
String content = params.getString("content");
notificationUtils.sendNotification(ids, title, content, R.mipmap.ic_launcher);
}
/**
* 进度显示
*
* @param pWebView
* @param array
*/
public void setProgress(IWebview pWebView, final JSONArray array) {
JSONObject params = JSON.parseObject(array.optString(1));
notificationUtils.setNotification(Integer.parseInt(params.getString("current")));
}
/**
* 下载完成后
*
* @param pWebView
* @param array
*/
public void compProgressNotification(IWebview pWebView, JSONArray array) {
JSONObject params = JSON.parseObject(array.optString(1));
String title = params.getString("title");
notificationUtils = new NotificationUtils(pWebView.getActivity());
notificationUtils.sendNotification(ids, title, "请去安装体验吧", R.mipmap.ic_launcher);
}
}
package com.park.util;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.util.Log;
import java.io.File;
/**
* Created by lenovo on 2019/10/17.
*/
public class AppUtil {
/**
* 获取apk文件的包信息
* @param context
* @param apkPath
* @return
*/
public static String getFileApkVersion(Context context, String apkPath) {
File apkFile = new File(apkPath);
if(!apkFile.exists()) return "";
PackageManager pm = context.getPackageManager();
PackageInfo info = pm.getPackageArchiveInfo(apkPath, PackageManager.GET_ACTIVITIES);
if (info != null) {
ApplicationInfo appInfo = info.applicationInfo;
String packageName = appInfo.packageName; //得到安装包名称
String version = info.versionName;//获取安装包的版本号
int versionCode = info.versionCode;
try {
return version;
} catch (OutOfMemoryError e) {
Log.d("yue-tag", "GetApkInfo: " + e);
}
}
return "";
}
}
package com.park.util;
import android.annotation.TargetApi;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
import android.graphics.Color;
import android.net.Uri;
import android.os.Build;
import android.widget.RemoteViews;
import androidx.annotation.RequiresApi;
import androidx.core.app.NotificationCompat;
import com.android.park.R;
import static android.app.Notification.VISIBILITY_SECRET;
import static androidx.core.app.NotificationCompat.PRIORITY_DEFAULT;
/**
*
* @author WTY
* desc : 通知栏工具类
* revise:
*
*/
public class NotificationUtils extends ContextWrapper {
public static final String CHANNEL_ID = "default";
private static final String CHANNEL_NAME = "Default_Channel";
private NotificationManager mManager;
private int[] flags;
public NotificationUtils(Context base) {
super(base);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
//android 8.0以上需要特殊处理,也就是targetSDKVersion为26以上
createNotificationChannel();
}
}
@TargetApi(Build.VERSION_CODES.O)
private void createNotificationChannel() {
//第一个参数:channel_id
//第二个参数:channel_name
//第三个参数:设置通知重要性级别
//注意:该级别必须要在 NotificationChannel 的构造函数中指定,总共要五个级别;
//范围是从 NotificationManager.IMPORTANCE_NONE(0) ~ NotificationManager.IMPORTANCE_HIGH(4)
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, CHANNEL_NAME,
NotificationManager.IMPORTANCE_LOW);
channel.canBypassDnd();//是否绕过请勿打扰模式
channel.enableLights(true);//是否在桌面icon右上角展示小红点
channel.setLockscreenVisibility(VISIBILITY_SECRET);//锁屏显示通知
channel.setLightColor(Color.RED);//闪关灯的灯光颜色
channel.canShowBadge();//桌面launcher的消息角标
channel.enableVibration(true);//是否允许震动
channel.getAudioAttributes();//获取系统通知响铃声音的配置
channel.getGroup();//获取通知取到组
channel.setBypassDnd(true);//设置可绕过 请勿打扰模式
channel.setSound(null, null);
channel.setVibrationPattern(new long[]{100, 100, 200});//设置震动模式
channel.shouldShowLights();//是否会有灯光
channel.setShowBadge(true); //是否在久按桌面图标时显示此渠道的通知
getManager().createNotificationChannel(channel);
}
/**
* 获取创建一个NotificationManager的对象
* @return NotificationManager对象
*/
public NotificationManager getManager() {
if (mManager == null) {
mManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
}
return mManager;
}
/**
* 清空所有的通知
*/
public void clearNotification(){
getManager().cancelAll();
}
/**
* 获取Notification
* @param title title
* @param content content
*/
public Notification getNotification(String title, String content , int icon){
Notification build;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
//android 8.0以上需要特殊处理,也就是targetSDKVersion为26以上
//通知用到NotificationCompat()这个V4库中的方法。但是在实际使用时发现书上的代码已经过时并且Android8.0已经不支持这种写法
Notification.Builder builder = getChannelNotification(title, content, icon);
build = builder.build();
} else {
NotificationCompat.Builder builder = getNotificationCompat(title, content, icon);
build = builder.build();
}
if (flags!=null && flags.length>0){
for (int a=0 ; a<flags.length ; a++){
build.flags |= flags[a];
}
}
return build;
}
/**
* 建议使用这个发送通知
* 调用该方法可以发送通知
* @param notifyId notifyId
* @param title title
* @param content content
*/
public void sendNotification(int notifyId, String title, String content , int icon) {
Notification build;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
//android 8.0以上需要特殊处理,也就是targetSDKVersion为26以上
//通知用到NotificationCompat()这个V4库中的方法。但是在实际使用时发现书上的代码已经过时并且Android8.0已经不支持这种写法
Notification.Builder builder = getChannelNotification(title, content, icon);
build = builder.build();
} else {
NotificationCompat.Builder builder = getNotificationCompat(title, content, icon);
build = builder.build();
}
if (flags!=null && flags.length>0){
for (int a=0 ; a<flags.length ; a++){
build.flags |= flags[a];
}
}
getManager().notify(notifyId, build);
}
/**
* 调用该方法可以发送通知
* @param notifyId notifyId
* @param title title
* @param content content
*/
public void sendNotificationCompat(int notifyId, String title, String content , int icon) {
NotificationCompat.Builder builder = getNotificationCompat(title, content, icon);
Notification build = builder.build();
if (flags!=null && flags.length>0){
for (int a=0 ; a<flags.length ; a++){
build.flags |= flags[a];
}
}
getManager().notify(notifyId, build);
}
private NotificationCompat.Builder getNotificationCompat(String title, String content, int icon) {
NotificationCompat.Builder builder;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
builder = new NotificationCompat.Builder(getApplicationContext(), CHANNEL_ID);
} else {
//注意用下面这个方法,在8.0以上无法出现通知栏。8.0之前是正常的。这里需要增强判断逻辑
builder = new NotificationCompat.Builder(getApplicationContext());
builder.setPriority(PRIORITY_DEFAULT);
}
builder.setContentTitle(title);
builder.setContentText(content);
builder.setSmallIcon(icon);
builder.setPriority(priority);
builder.setOnlyAlertOnce(onlyAlertOnce);
builder.setOngoing(ongoing);
if (remoteViews!=null){
builder.setContent(remoteViews);
}
if (intent!=null){
builder.setContentIntent(intent);
}
if (ticker!=null && ticker.length()>0){
builder.setTicker(ticker);
}
if (when!=0){
builder.setWhen(when);
}
if (sound!=null){
builder.setSound(sound);
}
if (defaults!=0){
builder.setDefaults(defaults);
}
//点击自动删除通知
builder.setAutoCancel(true);
return builder;
}
@RequiresApi(api = Build.VERSION_CODES.O)
private Notification.Builder getChannelNotification(String title, String content, int icon){
Notification.Builder builder = new Notification.Builder(getApplicationContext(), CHANNEL_ID);
Notification.Builder notificationBuilder = builder
//设置标题
.setContentTitle(title)
//消息内容
.setContentText(content)
//设置通知的图标
.setSmallIcon(icon)
//让通知左右滑的时候是否可以取消通知
.setOngoing(ongoing)
//设置优先级
.setPriority(priority)
//是否提示一次.true - 如果Notification已经存在状态栏即使在调用notify函数也不会更新
.setOnlyAlertOnce(onlyAlertOnce)
.setAutoCancel(true);
if (remoteViews!=null){
//设置自定义view通知栏
notificationBuilder.setContent(remoteViews);
}
if (intent!=null){
notificationBuilder.setContentIntent(intent);
}
if (ticker!=null && ticker.length()>0){
//设置状态栏的标题
notificationBuilder.setTicker(ticker);
}
if (when!=0){
//设置通知时间,默认为系统发出通知的时间,通常不用设置
notificationBuilder.setWhen(when);
}
if (sound!=null){
//设置sound
notificationBuilder.setSound(sound);
}
if (defaults!=0){
//设置默认的提示音
notificationBuilder.setDefaults(defaults);
}
if (pattern!=null){
//自定义震动效果
notificationBuilder.setVibrate(pattern);
}
return notificationBuilder;
}
private boolean ongoing = false;
private RemoteViews remoteViews = null;
private PendingIntent intent = null;
private String ticker = "";
private int priority = Notification.PRIORITY_DEFAULT;
private boolean onlyAlertOnce = false;
private long when = 0;
private Uri sound = null;
private int defaults = 0;
private long[] pattern = null;
/**
* 让通知左右滑的时候是否可以取消通知
* @param ongoing 是否可以取消通知
* @return
*/
public NotificationUtils setOngoing(boolean ongoing){
this.ongoing = ongoing;
return this;
}
/**
* 设置自定义view通知栏布局
* @param remoteViews view
* @return
*/
public NotificationUtils setContent(RemoteViews remoteViews){
this.remoteViews = remoteViews;
return this;
}
/**
* 设置内容点击
* @param intent intent
* @return
*/
public NotificationUtils setContentIntent(PendingIntent intent){
this.intent = intent;
return this;
}
/**
* 设置状态栏的标题
* @param ticker 状态栏的标题
* @return
*/
public NotificationUtils setTicker(String ticker){
this.ticker = ticker;
return this;
}
/**
* 设置优先级
* 注意:
* Android 8.0以及上,在 NotificationChannel 的构造函数中指定,总共要五个级别;
* Android 7.1(API 25)及以下的设备,还得调用NotificationCompat 的 setPriority方法来设置
*
* @param priority 优先级,默认是Notification.PRIORITY_DEFAULT
* @return
*/
public NotificationUtils setPriority(int priority){
this.priority = priority;
return this;
}
/**
* 是否提示一次.true - 如果Notification已经存在状态栏即使在调用notify函数也不会更新
* @param onlyAlertOnce 是否只提示一次,默认是false
* @return
*/
public NotificationUtils setOnlyAlertOnce(boolean onlyAlertOnce){
this.onlyAlertOnce = onlyAlertOnce;
return this;
}
/**
* 设置通知时间,默认为系统发出通知的时间,通常不用设置
* @param when when
* @return
*/
public NotificationUtils setWhen(long when){
this.when = when;
return this;
}
/**
* 设置sound
* @param sound sound
* @return
*/
public NotificationUtils setSound(Uri sound){
this.sound = sound;
return this;
}
/**
* 设置默认的提示音
* @param defaults defaults
* @return
*/
public NotificationUtils setDefaults(int defaults){
this.defaults = defaults;
return this;
}
/**
* 自定义震动效果
* @param pattern pattern
* @return
*/
public NotificationUtils setVibrate(long[] pattern){
this.pattern = pattern;
return this;
}
/**
* 设置flag标签
* @param flags flags
* @return
*/
public NotificationUtils setFlags(int... flags){
this.flags = flags;
return this;
}
public void setNotification(int progress) {
if (this==null){
return;
}
Intent intent = new Intent();
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
RemoteViews remoteViews = new RemoteViews(this.getPackageName(), R.layout.remote_notification_view);
remoteViews.setTextViewText(R.id.tvTitle, "正在下载:");
remoteViews.setProgressBar(R.id.pb, 100, progress, false);
NotificationManager manager = this.getManager();
Notification notification = this.setContentIntent(pendingIntent)
.setContent(remoteViews)
.setFlags(Notification.FLAG_AUTO_CANCEL)
.setOnlyAlertOnce(true)
.getNotification("新消息", "应用开始更新", R.mipmap.ic_launcher);
//下载成功或者失败
if (progress == 100 || progress == -1) {
this.clearNotification();
} else {
manager.notify(1, notification);
}
}
}