fix:孔夫子搜索会话过期自动重登录-搜索接口检测/KONGZ_SESSION_EXPIRED后使用已保存账号重登录再重试

This commit is contained in:
ShenQiLun 2026-06-25 14:29:51 +08:00
parent ac0217b724
commit a1cb8512de
60 changed files with 3501 additions and 43 deletions

26
_auto_push.ps1 Normal file
View File

@ -0,0 +1,26 @@
# 大商道扫书入库 - 快速提交脚本
# 运行后自动 add -> commit -> push
$repoDir = Split-Path -Parent $MyInvocation.MyCommand.Path
$message = $args[0]
if (-not $message) {
$message = "自动提交 " + (Get-Date -Format "yyyy-MM-dd HH:mm:ss")
}
Write-Host "=== 提交变更到服务器 ===" -ForegroundColor Cyan
Set-Location $repoDir
git add -A
$status = git status --porcelain
if (-not $status) {
Write-Host "没有需要提交的变更" -ForegroundColor Yellow
exit 0
}
Write-Host "变更文件:" -ForegroundColor Yellow
git status --short
git commit -m $message
git push
Write-Host "=== 提交完成 ===" -ForegroundColor Green

View File

@ -1,8 +1,8 @@
{
"name" : "scanBook",
"appid" : "",
"name" : "书海寻源-上书",
"appid" : "__UNI__40357CF",
"description" : "",
"versionName" : "1.0.0",
"versionName" : "1.1.0.3",
"versionCode" : "100",
"transformPx" : false,
/* 5+App */
@ -17,7 +17,10 @@
"delay" : 0
},
/* */
"modules" : {},
"modules" : {
"Camera" : {},
"Barcode" : {}
},
/* */
"distribute" : {
/* android */
@ -41,9 +44,43 @@
]
},
/* ios */
"ios" : {},
"ios" : {
"dSYMs" : false
},
/* SDK */
"sdkConfigs" : {}
"sdkConfigs" : {},
"icons" : {
"android" : {
"hdpi" : "unpackage/res/icons/72x72.png",
"xhdpi" : "unpackage/res/icons/96x96.png",
"xxhdpi" : "unpackage/res/icons/144x144.png",
"xxxhdpi" : "unpackage/res/icons/192x192.png"
},
"ios" : {
"appstore" : "unpackage/res/icons/1024x1024.png",
"ipad" : {
"app" : "unpackage/res/icons/76x76.png",
"app@2x" : "unpackage/res/icons/152x152.png",
"notification" : "unpackage/res/icons/20x20.png",
"notification@2x" : "unpackage/res/icons/40x40.png",
"proapp@2x" : "unpackage/res/icons/167x167.png",
"settings" : "unpackage/res/icons/29x29.png",
"settings@2x" : "unpackage/res/icons/58x58.png",
"spotlight" : "unpackage/res/icons/40x40.png",
"spotlight@2x" : "unpackage/res/icons/80x80.png"
},
"iphone" : {
"app@2x" : "unpackage/res/icons/120x120.png",
"app@3x" : "unpackage/res/icons/180x180.png",
"notification@2x" : "unpackage/res/icons/40x40.png",
"notification@3x" : "unpackage/res/icons/60x60.png",
"settings@2x" : "unpackage/res/icons/58x58.png",
"settings@3x" : "unpackage/res/icons/87x87.png",
"spotlight@2x" : "unpackage/res/icons/80x80.png",
"spotlight@3x" : "unpackage/res/icons/120x120.png"
}
}
}
}
},
/* */

View File

@ -3,4 +3,4 @@
"blueimp-md5": "^2.19.0",
"js-sha256": "^0.11.1"
}
}
}

View File

@ -59,6 +59,22 @@
"style": {
"navigationBarTitleText": "连拍"
}
},
{
"path": "uni_modules/uni-upgrade-center-app/pages/upgrade-popup",
"style": {
"disableScroll": true,
"app-plus": {
"backgroundColorTop": "transparent",
"background": "transparent",
"titleNView": false,
"scrollIndicator": false,
"popGesture": "none",
"animationType": "fade-in",
"animationDuration": 200
}
}
}
],
"globalStyle": {

View File

@ -131,7 +131,7 @@
<script>
// manifest.json versionName
var APP_VERSION = '1.0.4'
var APP_VERSION = '1.1.0.3'
export default {
data() {

View File

@ -1347,6 +1347,7 @@ export default {
uni.showToast({ title: '请先登录孔网账号', icon: 'none' })
return
}
var that = this
let keyword = ''
if (this.compareType === 'isbn') {
if (!this.isbn) {
@ -1381,21 +1382,17 @@ export default {
})
}
// 2. -
const phpsessid = this.kongfzToken || uni.getStorageSync('kongfz_phpsessid') || ''
// 7=() 5=
// 2. -
const sortType = this.sortBy === 'book' ? '5' : '7'
// + +
Promise.all([
searchProducts(keyword, { phpsessid, sortType, quality: this.conditionValue }),
searchFacet(keyword, { phpsessid, dataType: 0 }),
searchFacet(keyword, { phpsessid, dataType: 1 })
]).then(([productsData, onSaleFacet, soldFacet]) => {
this.isLoading = false
this.kongfzSearchWithRetry(keyword, { sortType: sortType, quality: this.conditionValue }).then(function(result) {
var productsData = result[0]
var onSaleFacet = result[1]
var soldFacet = result[2]
that.isLoading = false
if (productsData && productsData.total > 0) {
// 12
const list = (productsData.list || []).slice(0, 12)
this.productList = list.map(item => {
that.productList = list.map(item => {
const cleanPrice = parseFloat((item.priceText || '0').replace(/[^\d.]/g, ''))
let shippingFee = 0
//
@ -1431,22 +1428,22 @@ export default {
}
})
//
this.$nextTick(() => {
if (this.calculatedPrice > 0) {
this.price = String(this.calculatedPrice)
that.$nextTick(() => {
if (that.calculatedPrice > 0) {
that.price = String(that.calculatedPrice)
}
})
}
// 使facettotalFound
this.marketData = {
that.marketData = {
onSale: onSaleFacet ? onSaleFacet.totalFound : (productsData ? productsData.total : 0),
old: onSaleFacet ? onSaleFacet.oldCount : 0,
new: onSaleFacet ? onSaleFacet.newCount : 0,
sold: soldFacet ? (soldFacet.oldCount + soldFacet.newCount) : 0
}
}).catch(() => {
this.isLoading = false
this.marketData = { onSale: 0, old: 0, new: 0, sold: 0 }
}).catch(function() {
that.isLoading = false
that.marketData = { onSale: 0, old: 0, new: 0, sold: 0 }
})
},
@ -2923,6 +2920,56 @@ export default {
this.searchNoIsbnKongfz()
},
// +
kongfzSearchWithRetry(keyword, searchOpts) {
var that = this
var maxRetry = 1 // 1
return new Promise(function(resolve, reject) {
var doSearch = function(phpsessid, retryCount) {
var opts = Object.assign({}, searchOpts, { phpsessid: phpsessid })
Promise.all([
searchProducts(keyword, opts),
searchFacet(keyword, opts),
searchFacet(keyword, Object.assign({}, opts, { dataType: 1 }))
]).then(function(results) {
resolve(results)
}).catch(function(err) {
if (err && err.message === 'KONGZ_SESSION_EXPIRED' && retryCount < maxRetry) {
console.warn('孔夫子-会话过期,尝试自动重新登录...')
// 使
var accountList = that.savedAccountList || []
if (accountList.length > 0) {
var acc = accountList[0]
console.log('孔夫子-自动登录:', acc.username)
uni.showToast({ title: '孔网会话过期,自动登录中...', icon: 'none', duration: 2000 })
kongfzLogin(acc.username, acc.password).then(function(loginRes) {
if (loginRes.success) {
that.kongfzToken = loginRes.token
that.isLoggedIn = true
uni.setStorageSync('kongfz_phpsessid', loginRes.token)
console.log('孔夫子-自动登录成功,重试搜索')
doSearch(loginRes.token, retryCount + 1)
} else {
console.warn('孔夫子-自动登录失败:', loginRes.message)
resolve([{ total: 0, list: [] }, { newCount: 0, oldCount: 0, totalFound: 0 }, { newCount: 0, oldCount: 0, totalFound: 0 }])
}
}).catch(function() {
resolve([{ total: 0, list: [] }, { newCount: 0, oldCount: 0, totalFound: 0 }, { newCount: 0, oldCount: 0, totalFound: 0 }])
})
} else {
console.warn('孔夫子-无已保存账号,无法自动登录')
resolve([{ total: 0, list: [] }, { newCount: 0, oldCount: 0, totalFound: 0 }, { newCount: 0, oldCount: 0, totalFound: 0 }])
}
} else {
resolve([{ total: 0, list: [] }, { newCount: 0, oldCount: 0, totalFound: 0 }, { newCount: 0, oldCount: 0, totalFound: 0 }])
}
})
}
var phpsessid = that.kongfzToken || uni.getStorageSync('kongfz_phpsessid') || ''
doSearch(phpsessid, 0)
})
},
// ISBN - searchNoIsbn
searchNoIsbnKongfz() {
if (!this.isLoggedIn) {
@ -2933,22 +2980,21 @@ export default {
uni.showToast({ title: '请输入书名', icon: 'none' })
return
}
var that = this
this.noIsbnLoading = true
this.noIsbnProductList = []
const phpsessid = this.kongfzToken || uni.getStorageSync('kongfz_phpsessid') || ''
const keyword = this.noIsbnBookName
Promise.all([
searchProducts(keyword, { phpsessid, sortType: '7', quality: this.noIsbnConditionValue }),
searchFacet(keyword, { phpsessid, dataType: 0 }),
searchFacet(keyword, { phpsessid, dataType: 1 })
]).then(([productsData, onSaleFacet, soldFacet]) => {
this.noIsbnLoading = false
this.kongfzSearchWithRetry(keyword, { sortType: '7', quality: this.noIsbnConditionValue }).then(function(result) {
var productsData = result[0]
var onSaleFacet = result[1]
var soldFacet = result[2]
that.noIsbnLoading = false
//
const authorSet = new Set()
const publisherSet = new Set()
if (productsData && productsData.total > 0) {
const list = (productsData.list || []).slice(0, 12)
this.noIsbnProductList = list.map(item => {
that.noIsbnProductList = list.map(item => {
const cleanPrice = parseFloat((item.priceText || '0').replace(/[^\d.]/g, ''))
let shippingFee = 0
if (item.postage) {
@ -2983,25 +3029,25 @@ export default {
})
}
//
this.noIsbnMarketData = {
that.noIsbnMarketData = {
onSale: onSaleFacet ? onSaleFacet.totalFound : (productsData ? productsData.total : 0),
old: onSaleFacet ? onSaleFacet.oldCount : 0,
new: onSaleFacet ? onSaleFacet.newCount : 0,
sold: soldFacet ? (soldFacet.oldCount + soldFacet.newCount) : 0
}
//
this.noIsbnAuthorOptions = Array.from(authorSet).filter(Boolean).slice(0, 10)
this.noIsbnPublisherOptions = Array.from(publisherSet).filter(Boolean).slice(0, 10)
that.noIsbnAuthorOptions = Array.from(authorSet).filter(Boolean).slice(0, 10)
that.noIsbnPublisherOptions = Array.from(publisherSet).filter(Boolean).slice(0, 10)
//
this.$nextTick(() => {
if (this.calculatedNoIsbnPrice > 0) {
this.noIsbnPrice = String(this.calculatedNoIsbnPrice)
that.$nextTick(() => {
if (that.calculatedNoIsbnPrice > 0) {
that.noIsbnPrice = String(that.calculatedNoIsbnPrice)
}
})
}).catch(err => {
}).catch(function(err) {
console.error('无ISBN搜索失败:', err)
this.noIsbnLoading = false
this.noIsbnMarketData = { onSale: 0, old: 0, new: 0, sold: 0 }
that.noIsbnLoading = false
that.noIsbnMarketData = { onSale: 0, old: 0, new: 0, sold: 0 }
uni.showToast({ title: '查询失败', icon: 'none' })
})
},

BIN
static/login.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 9.0 KiB

BIN
static/tb.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 814 KiB

BIN
static/tb_144x144.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

BIN
static/tb_192x192.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

BIN
static/tb_72x72.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

BIN
static/tb_96x96.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -0,0 +1,12 @@
// 本文件用于使用JQL语法操作项目关联的uniCloud空间的数据库方便开发调试和远程数据库管理
// 编写clientDB的js API也支持常规js语法比如var可以对云数据库进行增删改查操作。不支持uniCloud-db组件写法
// 可以全部运行也可以选中部分代码运行。点击工具栏上的运行按钮或者按下【F5】键运行代码
// 如果文档中存在多条JQL语句只有最后一条语句生效
// 如果混写了普通js最后一条语句需是数据库操作语句
// 此处代码运行不受DB Schema的权限控制移植代码到实际业务中注意在schema中配好permission
// 不支持clientDB的action
// 数据库查询有最大返回条数限制详见https://uniapp.dcloud.net.cn/uniCloud/cf-database.html#limit
// 详细JQL语法请参考https://uniapp.dcloud.net.cn/uniCloud/jql.html
// 下面示例查询uni-id-users表的所有数据
db.collection('uni-id-users').get();

View File

@ -0,0 +1,6 @@
## 0.0.32022-11-11
- 修复 config 方法获取根节点为数组格式配置时错误的转化为了对象的Bug
## 0.0.22021-04-16
- 修改插件package信息
## 0.0.12021-03-15
- 初始化项目

View File

@ -0,0 +1,81 @@
{
"id": "uni-config-center",
"displayName": "uni-config-center",
"version": "0.0.3",
"description": "uniCloud 配置中心",
"keywords": [
"配置",
"配置中心"
],
"repository": "",
"engines": {
"HBuilderX": "^3.1.0"
},
"dcloudext": {
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": "",
"type": "unicloud-template-function"
},
"directories": {
"example": "../../../scripts/dist"
},
"uni_modules": {
"dependencies": [],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
},
"client": {
"App": {
"app-vue": "u",
"app-nvue": "u"
},
"H5-mobile": {
"Safari": "u",
"Android Browser": "u",
"微信浏览器(Android)": "u",
"QQ浏览器(Android)": "u"
},
"H5-pc": {
"Chrome": "u",
"IE": "u",
"Edge": "u",
"Firefox": "u",
"Safari": "u"
},
"小程序": {
"微信": "u",
"阿里": "u",
"百度": "u",
"字节跳动": "u",
"QQ": "u"
},
"快应用": {
"华为": "u",
"联盟": "u"
},
"Vue": {
"vue2": "y",
"vue3": "u"
}
}
}
}
}

View File

@ -0,0 +1,93 @@
# 为什么使用uni-config-center
实际开发中很多插件需要配置文件才可以正常运行,如果每个插件都单独进行配置的话就会产生下面这样的目录结构
```bash
cloudfunctions
└─────common 公共模块
├─plugin-a // 插件A对应的目录
│ ├─index.js
│ ├─config.json // plugin-a对应的配置文件
│ └─other-file.cert // plugin-a依赖的其他文件
└─plugin-b // plugin-b对应的目录
├─index.js
└─config.json // plugin-b对应的配置文件
```
假设插件作者要发布一个项目模板,里面使用了很多需要配置的插件,无论是作者发布还是用户使用都是一个大麻烦。
uni-config-center就是用了统一管理这些配置文件的使用uni-config-center后的目录结构如下
```bash
cloudfunctions
└─────common 公共模块
├─plugin-a // 插件A对应的目录
│ └─index.js
├─plugin-b // plugin-b对应的目录
│ └─index.js
└─uni-config-center
├─index.js // config-center入口文件
├─plugin-a
│ ├─config.json // plugin-a对应的配置文件
│ └─other-file.cert // plugin-a依赖的其他文件
└─plugin-b
└─config.json // plugin-b对应的配置文件
```
使用uni-config-center后的优势
- 配置文件统一管理,分离插件主体和配置信息,更新插件更方便
- 支持对config.json设置schema插件使用者在HBuilderX内编写config.json文件时会有更好的提示后续HBuilderX会提供支持
# 用法
在要使用uni-config-center的公共模块或云函数内引入uni-config-center依赖请参考[使用公共模块](https://uniapp.dcloud.net.cn/uniCloud/cf-common)
```js
const createConfig = require('uni-config-center')
const uniIdConfig = createConfig({
pluginId: 'uni-id', // 插件id
defaultConfig: { // 默认配置
tokenExpiresIn: 7200,
tokenExpiresThreshold: 600,
},
customMerge: function(defaultConfig, userConfig) { // 自定义默认配置和用户配置的合并规则,不设置的情况侠会对默认配置和用户配置进行深度合并
// defaudltConfig 默认配置
// userConfig 用户配置
return Object.assign(defaultConfig, userConfig)
}
})
// 以如下配置为例
// {
// "tokenExpiresIn": 7200,
// "passwordErrorLimit": 6,
// "bindTokenToDevice": false,
// "passwordErrorRetryTime": 3600,
// "app-plus": {
// "tokenExpiresIn": 2592000
// },
// "service": {
// "sms": {
// "codeExpiresIn": 300
// }
// }
// }
// 获取配置
uniIdConfig.config() // 获取全部配置注意uni-config-center内不存在对应插件目录时会返回空对象
uniIdConfig.config('tokenExpiresIn') // 指定键值获取配置返回7200
uniIdConfig.config('service.sms.codeExpiresIn') // 指定键值获取配置返回300
uniIdConfig.config('tokenExpiresThreshold', 600) // 指定键值获取配置如果不存在则取传入的默认值返回600
// 获取文件绝对路径
uniIdConfig.resolve('custom-token.js') // 获取uni-config-center/uni-id/custom-token.js文件的路径
// 引用文件require
uniIDConfig.requireFile('custom-token.js') // 使用require方式引用uni-config-center/uni-id/custom-token.js文件。文件不存在时返回undefined文件内有其他错误导致require失败时会抛出错误。
// 判断是否包含某文件
uniIDConfig.hasFile('custom-token.js') // 配置目录是否包含某文件true: 文件存在false: 文件不存在
```

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,13 @@
{
"name": "uni-config-center",
"version": "0.0.3",
"description": "配置中心",
"main": "index.js",
"keywords": [],
"author": "DCloud",
"license": "Apache-2.0",
"origin-plugin-dev-name": "uni-config-center",
"origin-plugin-version": "0.0.3",
"plugin-dev-name": "uni-config-center",
"plugin-version": "0.0.3"
}

View File

@ -0,0 +1,38 @@
## 1.0.192025-12-16
- 增加配置参数缺失时的错误提示,指明配置文件路径
## 1.0.182024-07-08
- checkToken时如果传入的token为空则返回uni-id-check-token-failed错误码以便uniIdRouter能正常跳转
## 1.0.172024-04-26
- 兼容uni-app-x对客户端uniPlatform的调整uni-app-x内uniPlatform区分app-android、app-ios
## 1.0.162023-04-25
- 新增maxTokenLength配置用于限制数据库用户记录token数组的最大长度
## 1.0.152023-04-06
- 修复部分语言国际化出错的Bug
## 1.0.142023-03-07
- 修复 admin用户包含其他角色时未包含在token的Bug
## 1.0.132022-07-21
- 修复 创建token时未传角色权限信息生成的token不正确的bug
## 1.0.122022-07-15
- 提升与旧版本uni-id的兼容性补充读取配置文件时回退平台app-plus、h5但是仍推荐使用新平台名进行配置app、web
## 1.0.112022-07-14
- 修复 部分情况下报`read property 'reduce' of undefined`的错误
## 1.0.102022-07-11
- 将token存储在用户表的token字段内与旧版本uni-id保持一致
## 1.0.92022-07-01
- checkToken兼容token内未缓存角色权限的情况此时将查库获取角色权限
## 1.0.82022-07-01
- 修复clientDB默认依赖时部分情况下获取不到uni-id配置的Bug
## 1.0.72022-06-30
- 修复config文件不合法时未抛出具体错误的Bug
## 1.0.62022-06-28
- 移除插件内的数据表schema
## 1.0.52022-06-27
- 修复使用多应用配置时报`Cannot read property 'appId' of undefined`的Bug
## 1.0.42022-06-27
- 修复使用自定义token内容功能报错的Bug [详情](https://ask.dcloud.net.cn/question/147945)
## 1.0.22022-06-23
- 对齐旧版本uni-id默认配置
## 1.0.12022-06-22
- 补充对uni-config-center的依赖
## 1.0.02022-06-21
- 提供uni-id token创建、校验、刷新接口简化旧版uni-id公共模块

View File

@ -0,0 +1,101 @@
{
"id": "uni-id-common",
"displayName": "uni-id-common",
"version": "1.0.19",
"description": "包含uni-id token生成、校验、刷新功能的云函数公共模块",
"keywords": [
"uni-id-common",
"uniCloud",
"token",
"权限"
],
"repository": "https://gitcode.net/dcloud/uni-id-common",
"engines": {
"uni-app": "^3.1.0",
"uni-app-x": "^3.1.0"
},
"dcloudext": {
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": "",
"type": "unicloud-template-function",
"darkmode": "-",
"i18n": "-",
"widescreen": "-"
},
"uni_modules": {
"dependencies": [
"uni-config-center"
],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "√",
"aliyun": "√",
"alipay": "√"
},
"client": {
"uni-app": {
"vue": {
"vue2": "-",
"vue3": "-"
},
"web": {
"safari": "-",
"chrome": "-"
},
"app": {
"vue": "-",
"nvue": "-",
"android": "-",
"ios": "-",
"harmony": "-"
},
"mp": {
"weixin": "-",
"alipay": "-",
"toutiao": "-",
"baidu": "-",
"kuaishou": "-",
"jd": "-",
"harmony": "-",
"qq": "-",
"lark": "-"
},
"quickapp": {
"huawei": "-",
"union": "-"
}
},
"uni-app-x": {
"web": {
"safari": "-",
"chrome": "-"
},
"app": {
"android": "-",
"ios": "-",
"harmony": "-"
},
"mp": {
"weixin": "-"
}
}
}
}
}
}

View File

@ -0,0 +1,3 @@
# uni-id-common
文档请参考:[uni-id-common](https://uniapp.dcloud.net.cn/uniCloud/uni-id-common.html)

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,20 @@
{
"name": "uni-id-common",
"version": "1.0.19",
"description": "uni-id token生成、校验、刷新",
"main": "index.js",
"homepage": "https:\/\/uniapp.dcloud.io\/uniCloud\/uni-id-common.html",
"repository": {
"type": "git",
"url": "git+https:\/\/gitee.com\/dcloud\/uni-id-common.git"
},
"author": "DCloud",
"license": "Apache-2.0",
"dependencies": {
"uni-config-center": "file:..\/..\/..\/..\/..\/uni-config-center\/uniCloud\/cloudfunctions\/common\/uni-config-center"
},
"origin-plugin-dev-name": "uni-id-common",
"origin-plugin-version": "1.0.19",
"plugin-dev-name": "uni-id-common",
"plugin-version": "1.0.19"
}

View File

@ -0,0 +1,129 @@
## 0.9.102026-04-27
- 修复 uni-app-x 项目编译时 warning
## 0.9.92026-02-03
- 修复 安卓端非强制更新 kotlin 报错 `onClick has not been intialized`
## 0.9.82026-01-05
- 更新 移除 vapor 模式不支持的 class 选择器
## 0.9.72025-07-28
- 修复 使用腾讯云时wgt 更新报错的Bug
- 改进 uni-app-x 平台弹窗该用 script setup 实现
## 0.9.62025-04-01
- 新增 升级中心适配鸿蒙 uni-app x **需要 HBuilderX 4.61+**
## 0.9.52025-02-06
- 新增 完善下载失败时的处理逻辑
## 0.9.42024-12-28
- 修复 腾讯云在使用扩展存储时报错的 Bug
## 0.9.32024-12-23
- 修复 升级中心在大屏上的显示效果
## 0.9.22024-11-06
- 更新 部分 ts 类型
## 0.9.12024-11-01
- 更新 支持 HarmonyOS Next 设备整包更新、wgt 更新。需要 `HBuilderX 4.32+` [详情](https://doc.dcloud.net.cn/uniCloud/upgrade-center.html#uni-upgrade-center-app-harmonyos)
## 0.9.02024-10-30
- **重要更新** 在 uni-app x 项目中弃用之前弹窗方案使用[dialogPage](https://doc.dcloud.net.cn/uni-app-x/api/dialog-page.html)实现,需要 `HBuilderX 4.31+`
## 0.8.52024-10-26
- 优化 去除不必要代码
## 0.8.42024-10-26
- 修复 uni-app x 项目升级到 4.31 alpha 后中间有空隙的Bug
## 0.8.32024-07-31
- 修复 部分类型报错
## 0.8.22024-07-15
- 更新 static 下的静态图片放入 static/app 目录下,防止编译除 app 平台以外的平台时带入
## 0.8.12024-04-28
- 修复 在 HX 4.0.3+ uni-app x 项目运行到 Android 调不起安装的Bug
## 0.8.02024-04-15
- 修复 更新弹窗 data 中新增初始化字段
## 0.7.92024-03-15
- 移除无用代码
- 调整 is_silently 类型为可为 null
## 0.7.82024-01-04
- 新增 移除无用代码
## 0.7.72024-01-04
- 新增 uni-app x 项目中新增 @show 回调
## 0.7.62023-12-21
- 修复 iOS使用升级中心云打包时报错使用新版的 [uts-progressNotification](https://ext.dcloud.net.cn/plugin?name=uts-progressNotification) 插件,如果之前下载过请删除 `uts-progressNotification\utssdk\app-ios` 文件夹)
## 0.7.52023-12-12
- 新增 通知栏进度条使用 uts-progressNotification 插件
- 新增 依赖 uni-installApk、uts-progressNotification。使用前要安装插件三方依赖
## 0.7.42023-11-29
- 修复 uni-app-x 项目中由上版引发的无法升级的Bug
## 0.7.32023-11-27
- 修复 在 uni-app x 中无更新时报错的Bug
## 0.7.22023-11-20
- 新增 插件根目录 utils 文件夹中新增 check-update-nvue.js 文件vue2 的 nvue 页面请引用该文件)
## 0.7.12023-11-17
- 修复 运行至浏览器 ts 语法报错
## 0.7.02023-11-10
- 新增 兼容 uni-app x 项目 [详情](https://uniapp.dcloud.net.cn/uniCloud/upgrade-center.html)
## 0.6.52023-10-27
- 修复 安装 wgt 报错 manifest.json 文件不存在的Bug
## 0.6.42023-09-01
chore: 优化代码结构
## 0.6.32023-08-30
- 修复 下载 wgt 时如果后缀名不正确,重命名后安装
## 0.6.22022-11-21
- 处理 cloudfunctions 目录
## 0.6.12022-08-17
- 修复 后台添加应用市场但都没有启用的情况下报错的Bug (需要 uni-admin 1.9.3+
## 0.6.02022-07-19
- 新增 支持多应用商店配置(需要 uni-admin 1.9.3+
## 0.4.12022-05-27
- 修复 上版引出的报错问题
## 0.4.02022-05-27
- 新增 Android 支持跳转手机自带商店,填写升级包地址时请填写跳转商店链接
- 新增 改为云对象调用方式,使用更直观
## 0.3.32022-04-14
- 修复 调用 check-update当 code 为 0 时没有回调
## 0.3.22022-01-12
- 优化显示逻辑
## 0.3.12021-11-24
- 修复 vue3 上图片不显示的Bug
## 0.3.02021-11-18
- 移除 wgt 安装成功后提示,防止重启过快弹框不消失
## 0.2.22021-08-25
- 兼容vue3.0
## 0.2.12021-07-26
- 修复 使用腾讯云并手动填写地址时导致下载链接失效的bug
## 0.2.02021-07-13
- 更新文档 关于报错local_storage_key 为空请不要将页面路径设置为pages.json中第一项
## 0.1.92021-06-28
- 更新文档
- 修复 wgt安装失败时按钮状态不对
## 0.1.82021-06-16
- 修复 跳转安装时导致上次下载的apk还没安装就被删掉的bug
## 0.1.72021-06-03
- 修改 移除static中的图片
## 0.1.62021-06-03
- 修改 下载更新按钮使用CSS渐变色
## 0.1.52021-04-22
- 更新check-update函数。现在返回一个Promise有更新时成功回调其他情况错误回调
## 0.1.42021-04-13
- 更新文档。明确云函数调用结果
## 0.1.32021-04-13
- 解耦云函数与弹框处理。utils中新增 call-check-version.js可用于单独检测是否有更新
## 0.1.22021-04-07
- 更新版本对比函数 compare
## 0.1.12021-04-07
- 修复 腾讯云空间下载链接不能下载问题
## 0.1.02021-04-07
- 新增使用uni.showModal提示升级示例
- 修改iOS升级提示方式
## 0.0.72021-04-02
- 修复在iOS上打开弹框报错
## 0.0.62021-04-01
- 兼容旧版本安卓
## 0.0.52021-04-01
- 修复低版本安卓上进度条错位
## 0.0.42021-04-01
- 更新readme
- 修复check-update语法错误
## 0.0.32021-04-01
- 新增前台更新弹框详见readme
- 更新前台检查更新方法
## 0.0.22021-03-29
- 更新文档
- 移除 dependencies
## 0.0.12021-03-25
- 升级中心前台检查更新

View File

@ -0,0 +1,122 @@
{
"id": "uni-upgrade-center-app",
"displayName": "升级中心 uni-upgrade-center - App",
"version": "0.9.10",
"description": "uni升级中心 - 客户端检查更新",
"keywords": [
"uniCloud",
"update",
"升级",
"wgt"
],
"repository": "https://gitee.com/dcloud/uni-upgrade-center/tree/master/uni_modules/uni-upgrade-center-app",
"engines": {
"HBuilderX": "^4.31",
"uni-app": "^4.35",
"uni-app-x": "^4.65"
},
"dcloudext": {
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "插件不采集任何数据",
"permissions": "无"
},
"npmurl": "",
"type": "unicloud-template-page",
"darkmode": "x",
"i18n": "x",
"widescreen": "√"
},
"uni_modules": {
"dependencies": [
"uts-progressNotification",
"uts-openSchema"
],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "√",
"aliyun": "√",
"alipay": "√"
},
"client": {
"uni-app": {
"vue": {
"vue2": "√",
"vue3": "√"
},
"web": {
"safari": "-",
"chrome": "-"
},
"app": {
"vue": "√",
"nvue": {
"extVersion": "0.8.3",
"minVersion": ""
},
"android": {
"extVersion": "0.8.3",
"minVersion": "21"
},
"ios": {
"extVersion": "0.8.3",
"minVersion": "12"
},
"harmony": {
"extVersion": "0.9.1",
"minVersion": "12"
}
},
"mp": {
"weixin": "x",
"alipay": "x",
"toutiao": "x",
"baidu": "x",
"kuaishou": "x",
"jd": "x",
"harmony": "x",
"qq": "x",
"lark": "x",
"xhs": "-"
},
"quickapp": {
"huawei": "x",
"union": "x"
}
},
"uni-app-x": {
"web": {
"safari": "x",
"chrome": "x"
},
"app": {
"android": {
"extVersion": "0.9.0",
"minVersion": "21"
},
"ios": {
"extVersion": "0.9.0",
"minVersion": "12"
},
"harmony": "√"
},
"mp": {
"weixin": "x"
}
}
}
}
}
}

View File

@ -0,0 +1,546 @@
<template>
<view class="mask flex-center">
<view class="content">
<view class="content-top">
<text class="content-top-text">{{title}}</text>
<image class="content-top-image" mode="widthFix"
src="/uni_modules/uni-upgrade-center-app/static/app/bg_top.png"></image>
</view>
<view class="content-space"></view>
<view class="content-body">
<view class="content-body-title">
<text class="text title content-body-title_title">{{subTitle}}</text>
<text class="text version content-body-title_version">v{{version}}</text>
</view>
<view class="body">
<scroll-view class="box-des-scroll">
<text class="text box-des">
{{contents}}
</text>
</scroll-view>
</view>
<view class="footer flex-center">
<template v-if="isiOS || isHarmony">
<button class="content-button" style="border: none;color: #fff;" type="primary" plain
@click="jumpToAppStore">
{{downLoadBtnTextiOS}}
</button>
</template>
<template v-else>
<template v-if="!downloadSuccess">
<view class="progress-box flex-column" v-if="downloading">
<progress class="progress" :percent="downLoadPercent" activeColor="#3DA7FF" :show-info="true"
:stroke-width="10" />
<view style="width:100%;display: flex;justify-content: space-around;flex-direction: row;">
<text class="text" style="font-size: 14px;">{{downLoadingText}}</text>
<text class="text" style="font-size: 14px;">({{downloadedSize}}/{{packageFileSize}}M)</text>
</view>
</view>
<button v-else class="content-button" @click="updateApp">
{{downLoadBtnText}}
</button>
</template>
<button v-else-if="downloadSuccess && !installed" class="content-button" :loading="installing"
:disabled="installing" @click="installPackage">
{{installing ? '正在安装……' : '下载完成,立即安装'}}
</button>
<button v-else-if="installed" class="content-button" @click="installPackage">
安装未完成,点击安装
</button>
</template>
</view>
</view>
<view class="content-bottom">
<image v-if="!is_mandatory" class="close-img" mode="widthFix"
src="/uni_modules/uni-upgrade-center-app/static/app/app_update_close.png" @click="closeUpdate">
</image>
</view>
</view>
</view>
</template>
<script setup lang="uts">
import { openSchema as utsOpenSchema } from '@/uni_modules/uts-openSchema'
import { UniUpgradeCenterResult, StoreListItem } from '../../utils/call-check-version'
import { platform_iOS, platform_Android, platform_Harmony } from '../../utils/utils'
// #ifdef APP-ANDROID
import { createNotificationProgress, cancelNotificationProgress, finishNotificationProgress, CreateNotificationProgressOptions, FinishNotificationProgressOptions } from '@/uni_modules/uts-progressNotification'
// #endif
const requiredKey = ['version', 'url', 'type']
let downloadTask : DownloadTask | null = null;
let openSchemePromise : Promise<boolean> | null = null;
const openSchema = (url : string) : Promise<boolean> => new Promise<boolean>((resolve, reject) => {
try {
utsOpenSchema(url)
resolve(true)
} catch (e) {
reject(false)
}
})
// 从之前下载安装
const installForBeforeFilePath = ref<string>('')
// 安装
const installed = ref<boolean>(false)
const installing = ref<boolean>(false)
// 下载
const downloadSuccess = ref<boolean>(false)
const downloading = ref<boolean>(false)
const downLoadPercent = ref<number>(0)
const downloadedSize = ref<number>(0)
const packageFileSize = ref<number>(0)
// 要安装的本地包地址
const tempFilePath = ref<string>('')
// 默认安装包信息
const title = ref<string>('更新日志')
const contents = ref<string>('')
const version = ref<string>('')
const is_mandatory = ref<boolean>(false)
const url = ref<string>("")
const platform = ref<string[]>([])
const store_list = ref<StoreListItem[] | null>(null)
// 可自定义属性
const subTitle = ref<string>('发现新版本')
const downLoadBtnTextiOS = ref<string>('立即跳转更新')
const downLoadBtnText = ref<string>('立即下载更新')
const downLoadingText = ref<string>('安装包下载中,请稍后')
const isiOS = computed(() : boolean => platform.value.includes(platform_iOS))
const isHarmony = computed(() : boolean => platform.value.includes(platform_Harmony))
const isAndroid = computed(() : boolean => platform.value.includes(platform_Android))
const needNotificationProgress = computed(() : boolean => isAndroid.value && !is_mandatory.value)
function getCurrentDialogPage() : UniPage | null {
const pages = getCurrentPages()
if (pages.length > 0) {
const dialogPages = pages[pages.length - 1].getDialogPages()
if (dialogPages.length > 0) {
return dialogPages[dialogPages.length - 1]
}
}
return null
}
function closePopup() {
downloadSuccess.value = false
downloading.value = false
downLoadPercent.value = 0
downloadedSize.value = 0
packageFileSize.value = 0
tempFilePath.value = ''
installing.value = false
installed.value = false
uni.closeDialogPage({
dialogPage: getCurrentDialogPage(),
fail(e) {
console.log('e: ', e);
}
})
}
function askAbortDownload() {
uni.showModal({
title: '是否取消下载?',
cancelText: '否',
confirmText: '是',
success: res => {
if (res.confirm) {
if (downloadTask !== null) downloadTask!.abort()
if (needNotificationProgress.value) {
// #ifdef APP-ANDROID
cancelNotificationProgress();
// #endif
}
closePopup()
}
}
});
}
function closeUpdate() {
if (downloading.value && !needNotificationProgress.value) {
askAbortDownload()
return;
}
closePopup()
}
function jumpToAppStore() {
openSchema(url.value)
}
function show(localPackageInfo : UniUpgradeCenterResult | null) {
if (localPackageInfo === null) return;
for (let key in localPackageInfo) {
if (requiredKey.indexOf(key) != -1 && localPackageInfo[key] === null) {
console.error(`参数 ${key} 必填,请检查后重试`)
closePopup()
return;
}
}
title.value = localPackageInfo.title
url.value = localPackageInfo.url
contents.value = localPackageInfo.contents
is_mandatory.value = localPackageInfo.is_mandatory
platform.value = localPackageInfo.platform
version.value = localPackageInfo.version
store_list.value = localPackageInfo.store_list
}
function checkStoreScheme() : Promise<boolean> | null {
if (store_list.value !== null) {
const storeList : StoreListItem[] = store_list.value!.filter((item : StoreListItem) : boolean => item.enable)
if (storeList.length > 0) {
if (openSchemePromise === null) {
openSchemePromise = Promise.reject() as Promise<boolean>
}
storeList
.sort((cur : StoreListItem, next : StoreListItem) : number => next.priority - cur.priority)
.map((item : StoreListItem) : string => item.scheme)
.reduce((promise : Promise<boolean>, cur : string) : Promise<boolean> => {
openSchemePromise = promise.catch<boolean>(() : Promise<boolean> => openSchema(cur))
return openSchemePromise!
}, openSchemePromise!)
return openSchemePromise!
}
}
return null
}
function installPackage() {
installing.value = true;
// #ifdef APP
uni.installApk({
filePath: tempFilePath.value,
success: _ => {
installing.value = false;
installed.value = true;
},
fail: err => {
console.error('installApk fail', err);
// 安装失败需要重新下载安装包
installing.value = false;
installed.value = false;
uni.showModal({
title: '更新失败,请重新下载',
content: `uni.installApk 错误码 ${err.errCode}`,
showCancel: false
});
}
});
// 安装跳出覆盖安装,此处直接返回上一页
if (!is_mandatory.value) {
uni.navigateBack()
}
// #endif
}
function downloadFail() {
const errMsg = '下载失败,请点击重试'
downloadSuccess.value = false;
downloading.value = false;
downLoadPercent.value = 0;
downloadedSize.value = 0;
packageFileSize.value = 0;
downLoadBtnText.value = errMsg
downloadTask = null;
if (needNotificationProgress.value) {
// #ifdef APP-ANDROID
finishNotificationProgress({
title: '升级包下载失败',
content: '请重新检查更新',
onClick() { }
} as FinishNotificationProgressOptions);
// #endif
}
}
function downLoadComplete() {
downloadSuccess.value = true;
downloading.value = false;
downLoadPercent.value = 0
downloadedSize.value = 0
packageFileSize.value = 0
downloadTask = null;
if (needNotificationProgress.value) {
// #ifdef APP-ANDROID
finishNotificationProgress({
title: "安装升级包",
content: "下载完成",
onClick() { }
} as FinishNotificationProgressOptions)
installPackage();
// #endif
return
}
// 强制更新,直接安装
if (is_mandatory.value) {
installPackage();
}
}
function downloadPackage() {
//下载包
downloadTask = uni.downloadFile({
url: url.value,
success: res => {
if (res.statusCode == 200) {
tempFilePath.value = res.tempFilePath
downLoadComplete()
} else {
console.log('downloadFile err: ', res);
downloadFail()
}
},
fail: err => {
console.log('downloadFile err: ', err);
downloadFail()
}
});
if (downloadTask !== null) {
downloading.value = true;
if (needNotificationProgress.value) {
closePopup()
}
downloadTask!.onProgressUpdate(res => {
downLoadPercent.value = parseFloat(res.progress.toFixed(0));
downloadedSize.value = parseFloat((res.totalBytesWritten / Math.pow(1024, 2)).toFixed(2));
packageFileSize.value = parseFloat((res.totalBytesExpectedToWrite / Math.pow(1024, 2)).toFixed(2));
if (needNotificationProgress.value) {
// #ifdef APP-ANDROID
createNotificationProgress({
title: "升级中心正在下载安装包……",
content: `${downLoadPercent.value}%`,
progress: downLoadPercent.value,
onClick: () => {
if (!downloadSuccess.value) {
askAbortDownload()
}
}
} as CreateNotificationProgressOptions)
// #endif
}
});
}
}
function updateApp() {
const checkStoreSchemeResult = checkStoreScheme()
if (checkStoreSchemeResult !== null) {
checkStoreSchemeResult
.then(_ => { })
.catch(() => { downloadPackage() })
.finally(() => {
openSchemePromise = null
})
} else { downloadPackage() }
}
onUnload(() => {
if (needNotificationProgress.value) {
// #ifdef APP-ANDROID
cancelNotificationProgress()
// #endif
}
})
onLoad((onLoadOptions : OnLoadOptions) => {
const local_storage_key : string | null = onLoadOptions['local_storage_key']
if (local_storage_key == null) {
console.error('local_storage_key为空请检查后重试')
closePopup()
return;
};
const localPackageInfo = uni.getStorageSync(local_storage_key);
if (localPackageInfo == null) {
console.error('安装包信息为空,请检查后重试')
closePopup()
return;
};
show(JSON.parse<UniUpgradeCenterResult>(JSON.stringify(localPackageInfo)) as UniUpgradeCenterResult)
})
onBackPress((options : OnBackPressOptions) : boolean | null => {
if (is_mandatory.value) return true
if (!needNotificationProgress.value) {
if (downloadTask !== null) {
downloadTask!.abort()
}
}
return false
})
</script>
<style>
.flex-center {
/* #ifndef APP-NVUE | UNI-APP-X */
display: flex;
/* #endif */
justify-content: center;
align-items: center;
}
.mask {
position: fixed;
left: 0;
top: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, .65);
}
.content {
position: relative;
top: 0;
width: 600rpx;
background-color: transparent;
}
.text {
font-family: Source Han Sans CN;
}
.content-top {
width: 100%;
border-bottom-color: #fff;
border-bottom-width: 15px;
border-bottom-style: solid;
}
.content-space {
width: 100%;
height: 120px;
background-color: #fff;
position: absolute;
top: 30%;
z-index: -1;
}
.content-top-image {
width: 100%;
position: relative;
bottom: -10%;
}
.content-top-text {
font-size: 22px;
font-weight: bold;
color: #F8F8FA;
position: absolute;
width: 65%;
top: 50%;
left: 25px;
z-index: 1;
}
.content-body {
box-sizing: border-box;
padding: 0 25px;
width: 100%;
background-color: #fff;
border-bottom-left-radius: 15px;
border-bottom-right-radius: 15px;
}
.content-body-title {
flex-direction: row;
align-items: center;
}
.content-body-title_version {
padding-left: 10px;
color: #fff;
font-size: 10px;
margin-left: 5px;
padding: 2px 4px;
border-radius: 10px;
background: #50aefd;
}
.title {
font-size: 16px;
font-weight: bold;
color: #3DA7FF;
line-height: 38px;
}
.footer {
height: 75px;
display: flex;
align-items: center;
justify-content: space-around;
}
.box-des-scroll {
box-sizing: border-box;
padding: 0 15px;
height: 100px;
}
.box-des {
font-size: 13px;
color: #000000;
line-height: 25px;
}
.progress-box {
width: 100%;
}
.progress {
width: 90%;
height: 20px;
}
.content-bottom {
height: 75px;
}
.close-img {
width: 35px;
height: 35px;
z-index: 1000;
position: relative;
bottom: -30%;
left: 50%;
margin-left: -17px;
}
.content-button {
width: 100%;
height: 40px;
line-height: 40px;
font-size: 15px;
font-weight: 400;
border-radius: 20px;
border: none;
color: #fff;
text-align: center;
background-color: #1785ff;
}
.flex-column {
display: flex;
flex-direction: column;
align-items: center;
}
</style>

View File

@ -0,0 +1,679 @@
<template>
<view class="mask flex-center" v-if="shown">
<view class="content botton-radius">
<view class="content-top">
<text class="content-top-text">{{ title }}</text>
<image class="content-top" style="top: 0" width="100%" height="100%" src="/uni_modules/uni-upgrade-center-app/static/app/bg_top.png"></image>
</view>
<view class="content-header"></view>
<view class="content-body">
<view class="title">
<text>{{ subTitle }}</text>
<text class="content-body-version">{{ version }}</text>
</view>
<view class="body">
<scroll-view class="box-des-scroll" scroll-y="true">
<text class="box-des">
{{ contents }}
</text>
</scroll-view>
</view>
<view class="footer flex-center">
<template v-if="isApplicationStore">
<button class="content-button" style="border: none; color: #fff" plain @click="jumpToApplicationStore">
{{ downLoadBtnTextiOS }}
</button>
</template>
<template v-else>
<template v-if="!downloadSuccess">
<view class="progress-box flex-column" v-if="downloading">
<progress class="progress" :percent="downLoadPercent" activeColor="#3DA7FF" show-info stroke-width="10" />
<view style="width: 100%; font-size: 28rpx; display: flex; justify-content: space-around">
<text>{{ downLoadingText }}</text>
<text>({{ downloadedSize }}/{{ packageFileSize }}M)</text>
</view>
</view>
<button v-else class="content-button" style="border: none; color: #fff" plain @click="updateApp">
{{ downLoadBtnText }}
</button>
</template>
<button
v-else-if="downloadSuccess && !installed"
class="content-button"
style="border: none; color: #fff"
plain
:loading="installing"
:disabled="installing"
@click="installPackage"
>
{{ installing ? '正在安装……' : '下载完成,立即安装' }}
</button>
<button
v-else-if="installed && !isWGT"
class="content-button"
style="border: none; color: #fff"
plain
:loading="installing"
:disabled="installing"
@click="installPackage"
>
安装未完成点击安装
</button>
<button v-else-if="installed && isWGT" class="content-button" style="border: none; color: #fff" plain @click="restart">安装完毕点击重启</button>
</template>
</view>
</view>
<image v-if="!is_mandatory" class="close-img" src="/uni_modules/uni-upgrade-center-app/static/app/app_update_close.png" @click.stop="closeUpdate"></image>
</view>
</view>
</template>
<script>
// #ifdef APP-PLUS
import { createNotificationProgress, cancelNotificationProgress, finishNotificationProgress } from '@/uni_modules/uts-progressNotification';
// #endif
import { compare, platform_iOS, platform_Android, platform_Harmony } from '../utils/utils'
const localFilePathKey = 'UNI_ADMIN_UPGRADE_CENTER_LOCAL_FILE_PATH';
let downloadTask = null;
let openSchemePromise;
export default {
emits: ['close', 'show'],
data() {
return {
//
installForBeforeFilePath: '',
//
installed: false,
installing: false,
//
downloadSuccess: false,
downloading: false,
downLoadPercent: 0,
downloadedSize: 0,
packageFileSize: 0,
tempFilePath: '', //
//
title: '更新日志',
contents: '',
version: '',
is_mandatory: false,
url: '',
platform: [],
store_list: null,
//
subTitle: '发现新版本',
downLoadBtnTextiOS: '立即跳转更新',
downLoadBtnText: '立即下载更新',
downLoadingText: '安装包下载中,请稍后',
// #ifdef APP-PLUS
shown: true,
// #endif
// #ifdef APP-HARMONY
shown: false,
// #endif
};
},
onLoad({ local_storage_key }) {
if (!local_storage_key) {
console.error('local_storage_key为空请检查后重试');
uni.navigateBack();
return;
}
const localPackageInfo = uni.getStorageSync(local_storage_key);
if (!localPackageInfo) {
console.error('安装包信息为空,请检查后重试');
uni.navigateBack();
return;
}
this.setLocalPackageInfo(localPackageInfo)
},
onBackPress() {
//
if (this.is_mandatory) return true;
if (!this.needNotificationProgress) downloadTask && downloadTask.abort();
},
onHide() {
openSchemePromise = null;
},
computed: {
isWGT() {
return this.type === 'wgt';
},
isNativeApp() {
return this.type === 'native_app';
},
isiOS() {
return this.platform.indexOf(platform_iOS) !== -1;
},
isAndroid() {
return this.platform.indexOf(platform_Android) !== -1;
},
isHarmony() {
return this.platform.indexOf(platform_Harmony) !== -1;
},
isApplicationStore() {
return !this.isWGT && this.isNativeApp && (
this.isiOS ||
this.isHarmony
)
// return this.isiOS || (!this.isiOS && !this.isWGT && this.url.indexOf('.apk') === -1);
},
needNotificationProgress() {
return this.platform.indexOf(platform_iOS) === -1 && !this.is_mandatory && !this.isHarmony;
}
},
methods: {
show(shown, localPackageInfo) {
// #ifdef APP-HARMONY
this.$emit('show')
if (localPackageInfo) {
this.shown = shown
this.setLocalPackageInfo(localPackageInfo)
} else {
console.error(`安装包信息为空,请检查后重试`);
}
// #endif
},
setLocalPackageInfo(localPackageInfo) {
const requiredKey = ['version', 'url', 'type'];
for (let key in localPackageInfo) {
if (requiredKey.indexOf(key) !== -1 && !localPackageInfo[key]) {
console.error(`参数 ${key} 必填,请检查后重试`);
// #ifdef APP-PLUS
uni.navigateBack();
// #endif
// #ifdef APP-HARMONY
this.shown = false
// #endif
return;
}
}
Object.assign(this, localPackageInfo);
this.checkLocalStoragePackage();
},
checkLocalStoragePackage() {
//
const localFilePathRecord = uni.getStorageSync(localFilePathKey);
if (localFilePathRecord) {
const { version, savedFilePath, installed } = localFilePathRecord;
//
if (!installed && compare(version, this.version) === 0) {
this.downloadSuccess = true;
this.installForBeforeFilePath = savedFilePath;
this.tempFilePath = savedFilePath;
} else {
//
this.deleteSavedFile(savedFilePath);
}
}
},
askAbortDownload() {
uni.showModal({
title: '是否取消下载?',
cancelText: '否',
confirmText: '是',
success: (res) => {
if (res.confirm) {
downloadTask && downloadTask.abort();
if (this.needNotificationProgress) {
cancelNotificationProgress();
}
uni.navigateBack();
}
}
});
},
async closeUpdate() {
if (this.downloading) {
if (this.is_mandatory) {
return uni.showToast({
title: '下载中,请稍后……',
icon: 'none',
duration: 500
});
}
if (!this.needNotificationProgress) {
this.askAbortDownload();
return;
}
}
if (!this.needNotificationProgress && this.downloadSuccess && this.tempFilePath) {
//
await this.saveFile(this.tempFilePath, this.version);
}
// #ifdef APP-PLUS
uni.navigateBack();
// #endif
// #ifdef APP-HARMONY
this.shown = false
this.$emit('close')
// #endif
},
updateApp() {
this.checkStoreScheme()
.catch(() => {
this.downloadPackage();
})
.finally(() => {
openSchemePromise = null;
});
},
//
checkStoreScheme() {
const storeList = (this.store_list || []).filter((item) => item.enable);
if (storeList && storeList.length) {
storeList
.sort((cur, next) => next.priority - cur.priority)
.map((item) => item.scheme)
.reduce((promise, cur, curIndex) => {
openSchemePromise = (promise || (promise = Promise.reject())).catch(() => {
return new Promise((resolve, reject) => {
plus.runtime.openURL(cur, (err) => {
reject(err);
});
});
});
return openSchemePromise;
}, openSchemePromise);
return openSchemePromise;
}
return Promise.reject();
},
downloadPackage() {
this.downloading = true;
//
downloadTask = uni.downloadFile({
url: this.url,
success: (res) => {
if (res.statusCode == 200) {
// fix: wgt wgt
if (this.isWGT && res.tempFilePath.split('.').slice(-1)[0] !== 'wgt') {
const failCallback = (e) => {
console.log('[FILE RENAME FAIL]', JSON.stringify(e));
};
// #ifndef APP-HARMONY
plus.io.resolveLocalFileSystemURL(
res.tempFilePath,
(entry) => {
entry.getParent((parent) => {
const newName = `new_wgt_${Date.now()}.wgt`;
entry.copyTo(
parent,
newName,
(res) => {
this.tempFilePath = res.fullPath;
this.downLoadComplete();
},
failCallback
);
}, failCallback);
},
failCallback
);
// #endif
// #ifdef APP-HARMONY
failCallback({code: -1, message: 'Download content error, is not wgt.'})
// #endif
} else {
this.tempFilePath = res.tempFilePath;
this.downLoadComplete();
}
} else {
console.log('下载错误:' + JSON.stringify(res))
this.downloadFail()
}
},
fail: (err) => {
console.log('下载错误:' + JSON.stringify(err))
this.downloadFail()
}
});
downloadTask.onProgressUpdate((res) => {
this.downLoadPercent = res.progress;
this.downloadedSize = (res.totalBytesWritten / Math.pow(1024, 2)).toFixed(2);
this.packageFileSize = (res.totalBytesExpectedToWrite / Math.pow(1024, 2)).toFixed(2);
if (this.needNotificationProgress && !this.downloadSuccess) {
createNotificationProgress({
title: '升级中心正在下载安装包……',
content: `${this.downLoadPercent}%`,
progress: this.downLoadPercent,
onClick: () => {
this.askAbortDownload();
}
});
}
});
if (this.needNotificationProgress) {
uni.navigateBack();
}
},
downloadFail() {
const errMsg = '下载失败,请点击重试'
this.downloadSuccess = false;
this.downloading = false;
this.downLoadPercent = 0;
this.downloadedSize = 0;
this.packageFileSize = 0;
this.downLoadBtnText = errMsg
downloadTask = null;
if (this.needNotificationProgress) {
finishNotificationProgress({
title: '升级包下载失败',
content: '请重新检查更新',
onClick: () => {}
});
}
},
downLoadComplete() {
this.downloadSuccess = true;
this.downloading = false;
this.downLoadPercent = 0;
this.downloadedSize = 0;
this.packageFileSize = 0;
downloadTask = null;
if (this.needNotificationProgress) {
finishNotificationProgress({
title: '安装升级包',
content: '下载完成',
onClick: () => {}
});
this.installPackage();
return;
}
//
if (this.is_mandatory) {
this.installPackage();
}
},
installPackage() {
// #ifdef APP-PLUS || APP-HARMONY
// wgt
if (this.isWGT) {
this.installing = true;
}
plus.runtime.install(
this.tempFilePath,
{
force: false
},
async (res) => {
this.installing = false;
this.installed = true;
// wgt
if (this.isWGT) {
//
if (this.is_mandatory) {
// #ifdef APP-PLUS
uni.showLoading({
icon: 'none',
title: '安装成功,正在重启……'
});
// #endif
setTimeout(() => {
// #ifdef APP-PLUS
uni.hideLoading();
// #endif
this.restart();
}, 1000);
}
} else {
const localFilePathRecord = uni.getStorageSync(localFilePathKey);
uni.setStorageSync(localFilePathKey, {
...localFilePathRecord,
installed: true
});
}
},
async (err) => {
//
if (this.installForBeforeFilePath) {
await this.deleteSavedFile(this.installForBeforeFilePath);
this.installForBeforeFilePath = '';
}
//
this.installing = false;
this.installed = false;
uni.showModal({
title: '更新失败,请重新下载',
content: err.message,
showCancel: false
});
}
);
// wgt
if (!this.isWGT && !this.is_mandatory) {
uni.navigateBack();
}
// #endif
},
restart() {
this.installed = false;
// #ifdef APP-HARMONY
uni.showModal({
title: '更新完毕',
content: '请手动重启',
showCancel: false,
success(res) {
plus.runtime.quit()
}
})
// #endif
// #ifdef APP-PLUS
//app
plus.runtime.restart();
// #endif
},
saveFile(tempFilePath, version) {
return new Promise((resolve, reject) => {
uni.saveFile({
tempFilePath,
success({ savedFilePath }) {
uni.setStorageSync(localFilePathKey, {
version,
savedFilePath
});
},
complete() {
resolve();
}
});
});
},
deleteSavedFile(filePath) {
uni.removeStorageSync(localFilePathKey);
return uni.removeSavedFile({
filePath
});
},
jumpToApplicationStore() {
plus.runtime.openURL(this.url);
}
}
};
</script>
<style>
page {
background: transparent;
}
.flex-center {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
justify-content: center;
align-items: center;
}
.mask {
position: fixed;
left: 0;
top: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.65);
}
.botton-radius {
border-bottom-left-radius: 30rpx;
border-bottom-right-radius: 30rpx;
}
.content {
position: relative;
top: 0;
width: 600rpx;
background-color: #fff;
box-sizing: border-box;
padding: 0 50rpx;
font-family: Source Han Sans CN;
}
.text {
/* #ifndef APP-NVUE */
display: block;
/* #endif */
line-height: 200px;
text-align: center;
color: #ffffff;
}
.content-top {
position: absolute;
top: -195rpx;
left: 0;
width: 600rpx;
height: 270rpx;
}
.content-top-text {
font-size: 45rpx;
font-weight: bold;
color: #f8f8fa;
position: absolute;
top: 120rpx;
left: 50rpx;
z-index: 1;
}
.content-header {
height: 70rpx;
}
.title {
font-size: 33rpx;
font-weight: bold;
color: #3da7ff;
line-height: 38px;
}
.content-body {
width: 100%;
}
.content-body-version {
padding-left: 20rpx;
color: #fff;
font-size: 20rpx;
margin-left: 10rpx;
padding: 4rpx 8rpx;
border-radius: 20rpx;
background: #50aefd;
}
.footer {
height: 150rpx;
display: flex;
align-items: center;
justify-content: space-around;
}
.box-des-scroll {
box-sizing: border-box;
padding: 0 40rpx;
height: 200rpx;
text-align: left;
}
.box-des {
font-size: 26rpx;
color: #000000;
line-height: 50rpx;
}
.progress-box {
width: 100%;
}
.progress {
width: 90%;
height: 40rpx;
/* border-radius: 35px; */
}
.close-img {
width: 70rpx;
height: 70rpx;
z-index: 1000;
position: absolute;
bottom: -120rpx;
left: calc(50% - 70rpx / 2);
}
.content-button {
text-align: center;
flex: 1;
font-size: 30rpx;
font-weight: 400;
color: #ffffff;
border-radius: 40rpx;
margin: 0 18rpx;
height: 80rpx;
line-height: 80rpx;
background: linear-gradient(to right, #1785ff, #3da7ff);
}
.flex-column {
display: flex;
flex-direction: column;
align-items: center;
}
</style>

View File

@ -0,0 +1 @@
文档已移至 [uni-upgrade-center](https://uniapp.dcloud.net.cn/uniCloud/upgrade-center.html)

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

View File

@ -0,0 +1,120 @@
export type StoreListItem = {
enable : boolean
id : string
name : string
scheme : string
priority : number // 优先级
}
export type UniUpgradeCenterResult = {
_id : string
appid : string
name : string
title : string
contents : string
url : string // 安装包下载地址
platform : Array<string> // Array<'Android' | 'iOS' | 'Harmony'>
version : string // 版本号 1.0.0
uni_platform : string // "android" | "ios" | 'harmony'
stable_publish : boolean // 是否是稳定版
is_mandatory : boolean // 是否强制更新
is_silently : boolean | null // 是否静默更新
create_env : string // "upgrade-center"
create_date : number
message : string
code : number
type : string // "native_app" | "wgt"
store_list : StoreListItem[] | null
min_uni_version : string | null // 升级 wgt 的最低 uni-app 版本
}
export default function () : Promise<UniUpgradeCenterResult> {
// #ifdef APP
return new Promise<UniUpgradeCenterResult>((resolve, reject) => {
const systemInfo = uni.getSystemInfoSync()
const appId = systemInfo.appId
const appVersion = systemInfo.appVersion //systemInfo.appVersion
// #ifndef UNI-APP-X
if (typeof appId === 'string' && typeof appVersion === 'string' && appId.length > 0 && appVersion.length > 0) {
plus.runtime.getProperty(appId, function (widgetInfo) {
if (widgetInfo.version) {
let data = {
action: 'checkVersion',
appid: appId,
appVersion: appVersion,
wgtVersion: widgetInfo.version
}
uniCloud.callFunction({
name: 'uni-upgrade-center',
data,
success: (e) => {
resolve(e.result as UniUpgradeCenterResult)
},
fail: (error) => {
reject(error)
}
})
} else {
reject('widgetInfo.version is EMPTY')
}
})
} else {
reject('plus.runtime.appid is EMPTY')
}
// #endif
// #ifdef UNI-APP-X
if (typeof appId === 'string' && typeof appVersion === 'string' && appId.length > 0 && appVersion.length > 0) {
let data = {
action: 'checkVersion',
appid: appId,
appVersion: appVersion,
is_uniapp_x: true,
wgtVersion: '0.0.0.0.0.1'
}
try {
uniCloud.callFunction({
name: 'uni-upgrade-center',
data: data
}).then(res => {
const code = res.result['code']
const codeIsNumber = ['Int', 'Long', 'number'].includes(typeof code)
if (codeIsNumber) {
if ((code as number) == 0) {
reject({
code: res.result['code'],
message: res.result['message']
})
} else if ((code as number) < 0) {
reject({
code: res.result['code'],
message: res.result['message']
})
} else {
const result = JSON.parse<UniUpgradeCenterResult>(JSON.stringify(res.result)) as UniUpgradeCenterResult
resolve(result)
}
}
}).catch<void>((err : any | null) => {
const error = err as UniCloudError
if (error.errMsg == '未匹配到云函数[uni-upgrade-center]')
error.errMsg = '【uni-upgrade-center-app】未配置uni-upgrade-center无法升级。参考: https://uniapp.dcloud.net.cn/uniCloud/upgrade-center.html'
reject(error.errMsg)
})
} catch (e) {
reject(e.message)
}
} else {
reject('invalid appid or appVersion')
}
// #endif
})
// #endif
// #ifndef APP
return new Promise((resolve, reject) => {
reject({
message: '请在App中使用'
})
})
// #endif
}

View File

@ -0,0 +1,122 @@
export type StoreListItem = {
enable : boolean
id : string
name : string
scheme : string
priority : number // 优先级
}
export type UniUpgradeCenterResult = {
_id : string
appid : string
name : string
title : string
contents : string
url : string // 安装包下载地址
platform : Array<string> // Array<'Android' | 'iOS' | 'Harmony'>
version : string // 版本号 1.0.0
uni_platform : string // "android" | "ios" | 'harmony'
stable_publish : boolean // 是否是稳定版
is_mandatory : boolean // 是否强制更新
is_silently : boolean | null // 是否静默更新
create_env : string // "upgrade-center"
create_date : number
message : string
code : number
type : string // "native_app" | "wgt"
store_list : StoreListItem[] | null
min_uni_version : string | null // 升级 wgt 的最低 uni-app 版本
}
export default function () : Promise<UniUpgradeCenterResult> {
// #ifdef APP
return new Promise<UniUpgradeCenterResult>((resolve, reject) => {
const systemInfo = uni.getSystemInfoSync()
const appId = systemInfo.appId
const appVersion = systemInfo.appWgtVersion //systemInfo.appVersion
// #ifndef UNI-APP-X
if (typeof appId === 'string' && typeof appVersion === 'string' && appId.length > 0 && appVersion.length > 0) {
plus.runtime.getProperty(appId, function (widgetInfo) {
// 使用降级widgetInfo.version 或 appVersionappWgtVersion
const wgtVersion = (widgetInfo.version && widgetInfo.version !== "")
? widgetInfo.version
: appVersion
console.log("版本检查手动日志:"+wgtVersion)
if (wgtVersion) {
let data = {
action: 'checkVersion',
appid: appId,
appVersion: wgtVersion,
wgtVersion: wgtVersion
}
uniCloud.callFunction({
name: 'uni-upgrade-center',
data,
success: (e) => resolve(e.result as UniUpgradeCenterResult),
fail: (error) => reject(error)
})
} else {
reject('widgetInfo.version is EMPTY')
}
})
} else {
reject('plus.runtime.appid is EMPTY')
}
// #endif
// #ifdef UNI-APP-X
if (typeof appId === 'string' && typeof appVersion === 'string' && appId.length > 0 && appVersion.length > 0) {
let data = {
action: 'checkVersion',
appid: appId,
appVersion: appVersion,
is_uniapp_x: true,
wgtVersion: '0.0.0.0.0.1'
}
try {
uniCloud.callFunction({
name: 'uni-upgrade-center',
data: data
}).then(res => {
const code = res.result['code']
const codeIsNumber = ['Int', 'Long', 'number'].includes(typeof code)
if (codeIsNumber) {
if ((code as number) == 0) {
reject({
code: res.result['code'],
message: res.result['message']
})
} else if ((code as number) < 0) {
reject({
code: res.result['code'],
message: res.result['message']
})
} else {
const result = JSON.parse<UniUpgradeCenterResult>(JSON.stringify(res.result)) as UniUpgradeCenterResult
resolve(result)
}
}
}).catch<void>((err : any | null) => {
const error = err as UniCloudError
if (error.errMsg == '未匹配到云函数[uni-upgrade-center]')
error.errMsg = '【uni-upgrade-center-app】未配置uni-upgrade-center无法升级。参考: https://uniapp.dcloud.net.cn/uniCloud/upgrade-center.html'
reject(error.errMsg)
})
} catch (e) {
reject(e.message)
}
} else {
reject('invalid appid or appVersion')
}
// #endif
})
// #endif
// #ifndef APP
return new Promise((resolve, reject) => {
reject({
message: '请在App中使用'
})
})
// #endif
}

View File

@ -0,0 +1,184 @@
function callCheckVersion() {
// #ifdef APP-PLUS
return new Promise((resolve, reject) => {
plus.runtime.getProperty(plus.runtime.appid, function(widgetInfo) {
let data = {
action: 'checkVersion',
appid: plus.runtime.appid,
appVersion: plus.runtime.version,
wgtVersion: widgetInfo.version
}
uniCloud.callFunction({
name: 'uni-upgrade-center',
data,
success: (e) => {
resolve(e)
},
fail: (error) => {
reject(error)
}
})
})
})
// #endif
// #ifndef APP-PLUS
return new Promise((resolve, reject) => {})
// #endif
}
// 推荐再App.vue中使用
const PACKAGE_INFO_KEY = '__package_info__'
export default function() {
// #ifdef APP-PLUS
return new Promise((resolve, reject) => {
callCheckVersion().then(async (e) => {
if (!e.result) return;
const {
code,
message,
is_silently, // 是否静默更新
url, // 安装包下载地址
platform, // 安装包平台
type // 安装包类型
} = e.result;
// 此处逻辑仅为实例,可自行编写
if (code > 0) {
// 腾讯云和阿里云下载链接不同,需要处理一下,阿里云会原样返回
const {
fileList
} = await uniCloud.getTempFileURL({
fileList: [url]
});
if (fileList[0].tempFileURL)
e.result.url = fileList[0].tempFileURL;
resolve(e)
// 静默更新只有wgt有
if (is_silently) {
uni.downloadFile({
url: e.result.url,
success: res => {
if (res.statusCode == 200) {
// 下载好直接安装,下次启动生效
plus.runtime.install(res.tempFilePath, {
force: false
});
}
}
});
return;
}
/**
* 提示升级一
* 使用 uni.showModal
*/
// return updateUseModal(e.result)
/**
* 提示升级二
* 官方适配的升级弹窗可自行替换资源适配UI风格
*/
uni.setStorageSync(PACKAGE_INFO_KEY, e.result)
uni.navigateTo({
url: `/uni_modules/uni-upgrade-center-app/pages/upgrade-popup?local_storage_key=${PACKAGE_INFO_KEY}`,
fail: (err) => {
console.error('更新弹框跳转失败', err)
uni.removeStorageSync(PACKAGE_INFO_KEY)
}
})
return
} else if (code < 0) {
// TODO 云函数报错处理
console.error(message)
return reject(e)
}
return resolve(e)
}).catch(err => {
// TODO 云函数报错处理
console.error(err.message)
reject(err)
})
});
// #endif
}
/**
* 使用 uni.showModal 升级
*/
function updateUseModal(packageInfo) {
const {
title, // 标题
contents, // 升级内容
is_mandatory, // 是否强制更新
url, // 安装包下载地址
platform, // 安装包平台
type // 安装包类型
} = packageInfo;
let isWGT = type === 'wgt'
let isiOS = !isWGT ? platform.includes('iOS') : false;
let confirmText = isiOS ? '立即跳转更新' : '立即下载更新'
return uni.showModal({
title,
content: contents,
showCancel: !is_mandatory,
confirmText,
success: res => {
if (res.cancel) return;
// 安装包下载
if (isiOS) {
plus.runtime.openURL(url);
return;
}
uni.showToast({
title: '后台下载中……',
duration: 1000
});
// wgt 和 安卓下载更新
downloadTask = uni.downloadFile({
url,
success: res => {
if (res.statusCode !== 200) {
console.error('下载安装包失败', err);
return;
}
// 下载好直接安装,下次启动生效
plus.runtime.install(res.tempFilePath, {
force: false
}, () => {
if (is_mandatory) {
//更新完重启app
plus.runtime.restart();
return;
}
uni.showModal({
title: '安装成功是否重启?',
success: res => {
if (res.confirm) {
//更新完重启app
plus.runtime.restart();
}
}
});
}, err => {
uni.showModal({
title: '更新失败',
content: err
.message,
showCancel: false
});
});
}
});
}
});
}

View File

@ -0,0 +1,228 @@
import callCheckVersion, { UniUpgradeCenterResult } from "./call-check-version"
import { platform_iOS } from './utils'
// #ifdef UNI-APP-X
import { openSchema } from '@/uni_modules/uts-openSchema'
// #endif
// 推荐再App.vue中使用
const PACKAGE_INFO_KEY = '__package_info__'
// #ifdef APP-HARMONY
export default function (component?: any) : Promise<UniUpgradeCenterResult> {
// #endif
// #ifndef APP-HARMONY
export default function () : Promise<UniUpgradeCenterResult> {
// #endif
return new Promise<UniUpgradeCenterResult>((resolve, reject) => {
callCheckVersion().then(async (uniUpgradeCenterResult) => {
// NOTE uni-app x 3.96 解构有问题
const code = uniUpgradeCenterResult.code
const message = uniUpgradeCenterResult.message
const url = uniUpgradeCenterResult.url // 安装包下载地址
// 此处逻辑仅为示例,可自行编写
if (code > 0) {
// 腾讯云获取下载链接
if (/^cloud:\/\//.test(url)) {
const tcbRes = await uniCloud.getTempFileURL({ fileList: [url] });
if (typeof tcbRes.fileList[0].tempFileURL !== 'undefined') uniUpgradeCenterResult.url = tcbRes.fileList[0].tempFileURL;
}
/**
*
* 使 uni.showModal
*/
// return updateUseModal(uniUpgradeCenterResult)
// #ifndef UNI-APP-X
// 静默更新只有wgt有
if (uniUpgradeCenterResult.is_silently) {
uni.downloadFile({
url: uniUpgradeCenterResult.url,
success: res => {
if (res.statusCode == 200) {
// 下载好直接安装,下次启动生效
plus.runtime.install(res.tempFilePath, {
force: false
});
}
}
});
return;
}
// #endif
/**
*
* UI风格
*/
// #ifndef UNI-APP-X
// #ifdef APP-PLUS
uni.setStorageSync(PACKAGE_INFO_KEY, uniUpgradeCenterResult)
uni.navigateTo({
url: `/uni_modules/uni-upgrade-center-app/pages/upgrade-popup?local_storage_key=${PACKAGE_INFO_KEY}`,
fail: (err) => {
console.error('更新弹框跳转失败', err)
uni.removeStorageSync(PACKAGE_INFO_KEY)
}
})
// #endif
// #ifdef APP-HARMONY
if (component) {
component.show(true, uniUpgradeCenterResult)
} else {
reject({
code: -1,
message: '在 HarmonyOS Next 平台请传递组件使用'
})
}
// #endif
// #endif
// #ifdef UNI-APP-X
uni.setStorageSync(PACKAGE_INFO_KEY, uniUpgradeCenterResult)
uni.openDialogPage({
url: `/uni_modules/uni-upgrade-center-app/pages/uni-app-x/upgrade-popup?local_storage_key=${PACKAGE_INFO_KEY}`,
disableEscBack: true,
fail: (err) => {
console.error('更新弹框跳转失败', err)
uni.removeStorageSync(PACKAGE_INFO_KEY)
}
})
// #endif
return resolve(uniUpgradeCenterResult)
} else if (code < 0) {
console.error(message)
return reject(uniUpgradeCenterResult)
}
return resolve(uniUpgradeCenterResult)
}).catch((err) => {
reject(err)
})
});
}
/**
* 使 uni.showModal
*/
function updateUseModal(packageInfo : UniUpgradeCenterResult) : void {
// #ifdef APP
const {
title, // 标题
contents, // 升级内容
is_mandatory, // 是否强制更新
url, // 安装包下载地址
type,
platform
} = packageInfo;
let isWGT = type === 'wgt'
let isiOS = !isWGT ? platform.includes(platform_iOS) : false;
// #ifndef UNI-APP-X
let confirmText = isiOS ? '立即跳转更新' : '立即下载更新'
// #endif
// #ifdef UNI-APP-X
let confirmText = '立即下载更新'
// #endif
uni.showModal({
title,
content: contents,
showCancel: !is_mandatory,
confirmText,
success: res => {
if (res.cancel) return;
if (isiOS) {
// iOS 平台跳转 AppStore
// #ifndef UNI-APP-X
plus.runtime.openURL(url);
// #endif
// #ifdef UNI-APP-X
openSchema(url)
// #endif
return;
}
uni.showToast({
title: '后台下载中……',
duration: 1000
});
// wgt 和 安卓下载更新
uni.downloadFile({
url,
success: res => {
if (res.statusCode !== 200) {
console.error('下载安装包失败');
return;
}
// 下载好直接安装,下次启动生效
// uni-app x 项目没有 plus5+ 故使用条件编译
// #ifndef UNI-APP-X
plus.runtime.install(res.tempFilePath, {
force: false
}, () => {
if (is_mandatory) {
//更新完重启app
// #ifdef APP-PLUS
plus.runtime.restart();
// #endif
// #ifdef APP-HARMONY
uni.showModal({
title: '安装成功',
content: '请手动重启应用',
showCancel: false,
success: res => {
plus.runtime.quit();
}
});
// #endif
return;
}
uni.showModal({
title: '安装成功是否重启?',
success: res => {
if (res.confirm) {
//更新完重启app
// #ifdef APP-PLUS
plus.runtime.restart();
// #endif
// #ifdef APP-HARMONY
plus.runtime.quit();
// #endif
}
}
});
}, err => {
uni.showModal({
title: '更新失败',
content: err
.message,
showCancel: false
});
});
// #endif
// #ifdef UNI-APP-X
uni.installApk({
filePath: res.tempFilePath,
success: () => {
uni.showModal({
title: '安装成功请手动重启'
});
},
fail: err => {
uni.showModal({
title: '更新失败',
content: err.errMsg,
showCancel: false
});
}
});
// #endif
}
});
}
});
// #endif
}

View File

@ -0,0 +1,46 @@
export const platform_iOS: string = 'iOS';
export const platform_Android: string = 'Android';
export const platform_Harmony: string = 'Harmony';
/**
*
* ("3.0.0.0.0.1.0.1", "3.0.0.0.0.1") ("3.0.0.1", "3.0") ("3.1.1", "3.1.1.1")
* @param {Object} v1
* @param {Object} v2
* v1 > v2 return 1
* v1 < v2 return -1
* v1 == v2 return 0
*/
export function compare(v_1: string = '0', v_2: string = '0') {
const v1: string[] = String(v_1).split('.');
const v2: string[] = String(v_2).split('.');
const minVersionLens = Math.min(v1.length, v2.length);
let result = 0;
for (let i = 0; i < minVersionLens; i++) {
const curV1 = Number(v1[i]);
const curV2 = Number(v2[i]);
if (curV1 > curV2) {
result = 1;
break;
} else if (curV1 < curV2) {
result = -1;
break;
}
}
if (result === 0 && v1.length !== v2.length) {
const v1BiggerThenv2 = v1.length > v2.length;
const maxLensVersion = v1BiggerThenv2 ? v1 : v2;
for (let i = minVersionLens; i < maxLensVersion.length; i++) {
const curVersion = Number(maxLensVersion[i]);
if (curVersion > 0) {
v1BiggerThenv2 ? (result = 1) : (result = -1);
break;
}
}
}
return result;
}

View File

@ -0,0 +1,13 @@
## 1.1.32025-09-12
- 鸿蒙平台 新增 打开 url 错误时输出
- iOS平台 修复 语法报黄问题
## 1.1.22025-03-20
- 更新 支持鸿蒙
## 1.1.12024-12-16
- 修复 canOpenURL 在安卓端可能会报类型错误的问题
## 1.1.02024-12-06
- 新增 canOpenURL UTS API可用此API判断url是否可以跳转
## 1.0.12024-11-13
- 修复 Android 打开部分 schema 时没有跳转到目标应用的 Bug
## 1.0.02024-04-25
- 更新 在 Android 和 iOS 上打开链接的 UTS API

View File

@ -0,0 +1,124 @@
{
"id": "uts-openSchema",
"displayName": "uts-openSchema",
"version": "1.1.3",
"description": "在 Android、iOS、HarmonyOS 上打开链接的 UTS API",
"keywords": [
"uts-openSchema"
],
"repository": "",
"engines": {
"HBuilderX": "^4.0",
"uni-app": "^4.75",
"uni-app-x": "^4.75"
},
"dcloudext": {
"type": "uts",
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": "",
"darkmode": "x",
"i18n": "x",
"widescreen": "x"
},
"uni_modules": {
"dependencies": [],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "√",
"aliyun": "√",
"alipay": "√"
},
"client": {
"uni-app": {
"vue": {
"vue2": {
"extVersion": "1.0.0",
"minVersion": ""
},
"vue3": {
"extVersion": "1.0.0",
"minVersion": ""
}
},
"web": {
"safari": "x",
"chrome": "x"
},
"app": {
"vue": {
"extVersion": "1.0.0",
"minVersion": ""
},
"nvue": "-",
"android": {
"extVersion": "1.0.0",
"minVersion": "21"
},
"ios": {
"extVersion": "1.0.0",
"minVersion": "12"
},
"harmony": {
"extVersion": "1.1.2",
"minVersion": "5.0.0"
}
},
"mp": {
"weixin": "x",
"alipay": "x",
"toutiao": "x",
"baidu": "x",
"kuaishou": "x",
"jd": "x",
"harmony": "x",
"qq": "x",
"lark": "x"
},
"quickapp": {
"huawei": "x",
"union": "x"
}
},
"uni-app-x": {
"web": {
"safari": "x",
"chrome": "x"
},
"app": {
"android": {
"extVersion": "1.0.0",
"minVersion": "21"
},
"ios": {
"extVersion": "1.0.0",
"minVersion": "12"
},
"harmony": {
"extVersion": "1.1.2",
"minVersion": "5.0.0"
}
},
"mp": {
"weixin": "x"
}
}
}
}
}
}

View File

@ -0,0 +1,59 @@
# uts-openSchema
打开链接,支持:
1. 打开外部 App
2. 使用浏览器打开链接
3. 打开地图到指定地点
4. ...
## 使用
1. 安装此插件
2. 在要使用的地方 `import` 导入
```ts
import { openSchema, canOpenURL } from '@/uni_modules/uts-openSchema'
```
3. 直接调用 `openSchema` 方法:
```ts
// #ifdef UNI-APP-X
// 使用外部浏览器打开指定URL
openSchema('https://uniapp.dcloud.io/uni-app-x')
// #ifdef APP-ANDROID
// Android 使用应用商店打开指定App
openSchema('market://details?id=com.tencent.mm')
// Android 打开地图坐标
// 可以先用canOpenURL判断是否安装了地图软件
if (canOpenURL('androidamap://')) {
openSchema('androidamap://viewMap?sourceApplication=Hello%20uni-app&poiname=DCloud&lat=39.9631018208&lon=116.3406135236&dev=0')
} else {
console.log('未安装高德地图')
}
// #endif -->
// #ifdef APP-IOS
// 打开 AppStore 到搜索页
openSchema('itms-apps://search.itunes.apple.com//WebObjects//MZSearch.woa/wa/search?media=software&lterm=')
// 打开 iOS 地图坐标
openSchema('http://maps.apple.com/?q=Mexican+Restaurant&sll=50.894967,4.341626&z=10&t=s')
// #endif -->
// #endif -->
```
### 参数
- openSchema(url: string) // `url`:要打开的链接 `必填` `不为空字符串`
## 相关开发文档
[UTS 语法](https://uniapp.dcloud.net.cn/tutorial/syntax-uts.html)
[UTS API插件](https://uniapp.dcloud.net.cn/plugin/uts-plugin.html)
[UTS 组件插件](https://uniapp.dcloud.net.cn/plugin/uts-component.html)
[Hello UTS](https://gitcode.net/dcloud/hello-uts)

View File

@ -0,0 +1,3 @@
{
"minSdkVersion": "21"
}

View File

@ -0,0 +1,27 @@
import Intent from 'android.content.Intent'
import Uri from 'android.net.Uri'
import { OpenSchema, CanOpenURL } from '../interface.uts'
export const openSchema : OpenSchema = function (url : string) {
if (canOpenURL(url)) {
const context = UTSAndroid.getUniActivity()!
const uri = Uri.parse(url)
const intent = new Intent(Intent.ACTION_VIEW, uri)
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
intent.setData(uri)
context.startActivity(intent)
} else {
console.error('[uts-openSchema] url param Error', JSON.stringify(url))
}
}
export const canOpenURL : CanOpenURL = function (url : string) : boolean {
if (typeof url === 'string' && url.length > 0) {
const context = UTSAndroid.getUniActivity()!
const uri = Uri.parse(url)
const intent = new Intent(Intent.ACTION_VIEW, uri)
return intent.resolveActivity(context.packageManager) != null ? true : false
} else {
return false
}
}

View File

@ -0,0 +1,21 @@
import { bundleManager, common } from '@kit.AbilityKit';
import OpenLinkOptions from '@ohos.app.ability.OpenLinkOptions'
import { getAbilityContext } from '@dcloudio/uni-runtime'
import { OpenSchema, CanOpenURL } from '../interface.uts'
export const openSchema : OpenSchema = function (url : string) : void {
(getAbilityContext() as common.UIAbilityContext)?.openLink(url, {
appLinkingOnly: false
} as OpenLinkOptions)
}
export const canOpenURL : CanOpenURL = function (url : string) : boolean {
try {
return bundleManager.canOpenLink(url)
} catch (error) {
console.error('[uts-openSchema] url param Error', JSON.stringify(url))
return false
}
}

View File

@ -0,0 +1,3 @@
{
"deploymentTarget": "12.0"
}

View File

@ -0,0 +1,22 @@
import { UIApplication } from 'UIKit'
import { URL } from 'Foundation'
import { OpenSchema, CanOpenURL } from '../interface.uts'
export const openSchema : OpenSchema = function (url : string) : void {
if (canOpenURL(url)) {
let uri = new URL(string = url)
UIApplication.shared.open(uri!)
} else {
console.error('[uts-openSchema] url param Error: ', url)
}
}
export const canOpenURL : CanOpenURL = function (url : string) : boolean {
if (typeof url == 'string' && url.length > 0) {
let uri = new URL(string = url)
if (uri != null && UIApplication.shared.canOpenURL(uri!)) {
return true
}
}
return false
}

View File

@ -0,0 +1,2 @@
export type OpenSchema = (url : string) => void
export type CanOpenURL = (url : string) => boolean

View File

@ -0,0 +1,12 @@
import { OpenSchema, CanOpenURL } from '../interface.uts'
export const openSchema : OpenSchema = function (url : string) : void {
location.href = url;
}
export const canOpenURL : CanOpenURL = function (url : string) : boolean {
if (url != "") {
return true;
}
return false;
}

View File

@ -0,0 +1,28 @@
## 1.1.22025-02-10
修复某些情况通过点击通知消息无法拉起App的bug
## 1.1.12024-09-03
去除TypeScript警告
## 1.1.02024-03-08
修复uniapp打包报错问题
## 1.0.92024-02-29
去除代码过时警告
## 1.0.82023-12-21
去除app-ios目录
## 1.0.72023-12-11
去除无用代码
## 1.0.62023-12-11
修改文档
## 1.0.52023-12-11
1.修改插件名称
2.修改插件引入方式为import导入
## 1.0.42023-11-30
1. createNotificationProgress增加`onClick`回调
2.修复在小米部分系统上通知消息会归类于不重要通知的bug
## 1.0.32023-11-28
更新截图
## 1.0.22023-11-28
修改资源的包名
## 1.0.12023-11-28
更新文档
## 1.0.02023-11-28
Android通知栏显示进度插件

View File

@ -0,0 +1,85 @@
{
"id": "uts-progressNotification",
"displayName": "uts-progressNotification",
"version": "1.1.2",
"description": "uts-progressNotification",
"keywords": [
"progressNotification"
],
"repository": "",
"engines": {
"HBuilderX": "^3.91"
},
"dcloudext": {
"type": "uts",
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "插件不采集任何数据",
"permissions": "TargetSDKVersion33以上时需配置\n`android.permission.POST_NOTIFICATIONS`"
},
"npmurl": ""
},
"uni_modules": {
"dependencies": [],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y",
"alipay": "n"
},
"client": {
"Vue": {
"vue2": "y",
"vue3": "y"
},
"App": {
"app-android": {
"minVersion": "19"
},
"app-ios": "n",
"app-harmony": "u"
},
"H5-mobile": {
"Safari": "n",
"Android Browser": "n",
"微信浏览器(Android)": "n",
"QQ浏览器(Android)": "n"
},
"H5-pc": {
"Chrome": "n",
"IE": "n",
"Edge": "n",
"Firefox": "n",
"Safari": "n"
},
"小程序": {
"微信": "n",
"阿里": "n",
"百度": "n",
"字节跳动": "n",
"QQ": "n",
"钉钉": "n",
"快手": "n",
"飞书": "n",
"京东": "n"
},
"快应用": {
"华为": "n",
"联盟": "n"
}
}
}
}
}

View File

@ -0,0 +1,71 @@
# uts-progressNotification
## 使用说明
Android平台创建显示进度的通知栏消息
**注意: 需要自定义基座,否则点击通知栏消息不会拉起应用**
### 导入
需要import导入插件
### createNotificationProgress(options : CreateNotificationProgressOptions) : void,
创建显示进度的通知栏消息
参数说明
```
export type CreateNotificationProgressOptions = {
/**
* 通知标题
* @defaultValue 应用名称
*/
title ?: string | null
/**
* 通知内容
*/
content : string,
/**
* 进度
*/
progress : number,
/**
* 点击通知消息回调
* @defaultValue null
*/
onClick? : (() => void) | null
}
```
### finishNotificationProgress(options: FinishNotificationProgressOptions) : void
完成时调用的API比如下载完成后需要显示下载完成并隐藏进度时调用。
参数说明
```
export type FinishNotificationProgressOptions = {
/**
* 通知标题
* @defaultValue 应用名称
*/
title ?: string | null
/**
* 通知内容
*/
content : string,
/**
* 点击通知消息回调
*/
onClick : () => void
}
```
### cancelNotificationProgress() : void
取消通知消息显示

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"
package="uts.sdk.modules.utsProgressNotification">
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
<application>
<activity android:name="uts.sdk.modules.utsProgressNotification.TransparentActivity"
android:theme="@style/DCNotificationProgressTranslucentTheme" android:hardwareAccelerated="true"
android:screenOrientation="user" android:exported="true">
</activity>
</application>
</manifest>

View File

@ -0,0 +1,62 @@
import Activity from "android.app.Activity";
import Bundle from 'android.os.Bundle';
import Build from 'android.os.Build';
import View from 'android.view.View';
import Color from 'android.graphics.Color';
import WindowManager from 'android.view.WindowManager';
import { getGlobalNotificationProgressCallBack, getGlobalNotificationProgressFinishCallBack, setGlobalNotificationProgressCallBack, setGlobalNotificationProgressFinishCallBack} from './callbacks.uts';
import { ACTION_DOWNLOAD_FINISH, ACTION_DOWNLOAD_PROGRESS } from "./constant.uts"
export class TransparentActivity extends Activity {
constructor() {
super()
}
@Suppress("DEPRECATION")
override onCreate(savedInstanceState : Bundle | null) {
super.onCreate(savedInstanceState)
this.fullScreen(this)
const action = this.getIntent().getAction()
if (action == ACTION_DOWNLOAD_FINISH) {
setTimeout(() => {
getGlobalNotificationProgressFinishCallBack()?.()
setGlobalNotificationProgressFinishCallBack(() => { })
}, 100)
this.overridePendingTransition(0, 0)
}
if (action == ACTION_DOWNLOAD_PROGRESS) {
setTimeout(() => {
getGlobalNotificationProgressCallBack()?.()
setGlobalNotificationProgressCallBack(() => { })
}, 100)
this.overridePendingTransition(0, 0)
}
setTimeout(() => {
this.finish()
}, 20)
}
@Suppress("DEPRECATION")
private fullScreen(activity : Activity) {
if (Build.VERSION.SDK_INT >= 19) {
if (Build.VERSION.SDK_INT >= 21) {
const window = activity.getWindow();
const decorView = window.getDecorView();
const option = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
decorView.setSystemUiVisibility(option);
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
window.setStatusBarColor(Color.TRANSPARENT);
} else {
const window = activity.getWindow();
const attributes = window.getAttributes();
const flagTranslucentStatus = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
attributes.flags |= flagTranslucentStatus;
window.setAttributes(attributes);
}
}
}
}

View File

@ -0,0 +1,19 @@
let globalNotificationProgressCallBack : (() => void) | null = () => { }
let globalNotificationProgressFinishCallBack : (() => void) | null = () => { }
export function setGlobalNotificationProgressCallBack(callBack : (() => void) | null) : void {
globalNotificationProgressCallBack = callBack
}
export function getGlobalNotificationProgressCallBack() : (() => void) | null {
return globalNotificationProgressCallBack
}
export function setGlobalNotificationProgressFinishCallBack(callBack : (() => void) | null) : void {
globalNotificationProgressFinishCallBack = callBack
}
export function getGlobalNotificationProgressFinishCallBack() : (() => void) | null {
return globalNotificationProgressFinishCallBack
}

View File

@ -0,0 +1,3 @@
{
"minSdkVersion": "19"
}

View File

@ -0,0 +1,2 @@
export const ACTION_DOWNLOAD_FINISH = "ACTION_DOWNLOAD_FINISH"
export const ACTION_DOWNLOAD_PROGRESS = "ACTION_DOWNLOAD_PROGRESS"

View File

@ -0,0 +1,156 @@
import Build from 'android.os.Build';
import Context from 'android.content.Context';
import NotificationManager from 'android.app.NotificationManager';
import NotificationChannel from 'android.app.NotificationChannel';
import Notification from 'android.app.Notification';
import Intent from 'android.content.Intent';
import ComponentName from 'android.content.ComponentName';
import PendingIntent from 'android.app.PendingIntent';
import { CreateNotificationProgressOptions, FinishNotificationProgressOptions } from '../interface.uts';
import { ACTION_DOWNLOAD_FINISH, ACTION_DOWNLOAD_PROGRESS } from "./constant.uts"
import { setGlobalNotificationProgressCallBack, setGlobalNotificationProgressFinishCallBack } from './callbacks.uts';
export { TransparentActivity } from './TransparentActivity.uts';
const DOWNLOAD_PROGRESS_NOTIFICATION_ID : Int = 7890
const DC_DOWNLOAD_CHANNEL_ID = "下载文件"
const DC_DOWNLOAD_CHANNEL_NAME = "用于显示现在进度的渠道"
let notificationBuilder : Notification.Builder | null = null
let timeId = -1
let histroyProgress = 0
let isProgress = false
export function createNotificationProgress(options : CreateNotificationProgressOptions) : void {
const { content, progress, onClick } = options
if (progress == 100) {
clearTimeout(timeId)
const context = UTSAndroid.getAppContext() as Context
realCreateNotificationProgress(options.title ?? getAppName(context), content, progress, onClick)
reset()
return
}
histroyProgress = progress
if (timeId != -1) {
return
}
const context = UTSAndroid.getAppContext() as Context
if (!isProgress) {
realCreateNotificationProgress(options.title ?? getAppName(context), content, histroyProgress, onClick)
isProgress = true
} else {
timeId = setTimeout(() => {
realCreateNotificationProgress(options.title ?? getAppName(context), content, histroyProgress, onClick)
timeId = -1
}, 1000)
}
}
export function cancelNotificationProgress() : void {
const context = UTSAndroid.getAppContext() as Context
const notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.cancel(DOWNLOAD_PROGRESS_NOTIFICATION_ID)
reset()
}
function realCreateNotificationProgress(title : string, content : string, progress : number, cb : (() => void) | null) : void {
setGlobalNotificationProgressCallBack(cb)
const context = UTSAndroid.getAppContext() as Context
const notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
createDownloadChannel(notificationManager)
const builder = createNotificationBuilder(context)
builder.setProgress(100, progress.toInt(), false)
builder.setContentTitle(title)
builder.setContentText(content)
builder.setContentIntent(createPendingIntent(context, ACTION_DOWNLOAD_PROGRESS));
notificationManager.notify(DOWNLOAD_PROGRESS_NOTIFICATION_ID, builder.build())
}
export function finishNotificationProgress(options : FinishNotificationProgressOptions) {
setGlobalNotificationProgressFinishCallBack(options.onClick)
const context = UTSAndroid.getAppContext() as Context
const notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
createDownloadChannel(notificationManager)
const builder = createNotificationBuilder(context)
builder.setProgress(0, 0, false)
builder.setContentTitle(options.title ?? getAppName(context))
builder.setContentText(options.content)
//小米rom setOngoing未false的时候会被通知管理器归为不重要通知
// builder.setOngoing(false)
builder.setAutoCancel(true);
builder.setContentIntent(createPendingIntent(context, ACTION_DOWNLOAD_FINISH));
notificationManager.notify(DOWNLOAD_PROGRESS_NOTIFICATION_ID, builder.build())
reset()
}
function reset() {
isProgress = false
notificationBuilder = null
histroyProgress = 0
if (timeId != -1) {
clearTimeout(timeId)
timeId = -1
}
}
function createPendingIntent(context : Context, action : string) : PendingIntent {
const intent = new Intent(action);
intent.setComponent(new ComponentName(context.getPackageName(), "uts.sdk.modules.utsProgressNotification.TransparentActivity"));
let flags = PendingIntent.FLAG_UPDATE_CURRENT;
if (Build.VERSION.SDK_INT >= 23) {
flags = PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE;
}
return PendingIntent.getActivity(context, DOWNLOAD_PROGRESS_NOTIFICATION_ID, intent, flags);
}
function createDownloadChannel(notificationManager : NotificationManager) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
const channel = new NotificationChannel(
DC_DOWNLOAD_CHANNEL_ID,
DC_DOWNLOAD_CHANNEL_NAME,
NotificationManager.IMPORTANCE_LOW
)
notificationManager.createNotificationChannel(channel)
}
}
@Suppress("DEPRECATION")
function createNotificationBuilder(context : Context) : Notification.Builder {
if (notificationBuilder == null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
notificationBuilder = new Notification.Builder(context, DC_DOWNLOAD_CHANNEL_ID)
} else {
notificationBuilder = new Notification.Builder(context)
}
notificationBuilder!.setSmallIcon(context.getApplicationInfo().icon)
notificationBuilder!.setOngoing(true)
notificationBuilder!.setSound(null)
}
return notificationBuilder!
}
@Suppress("DEPRECATION")
function getAppName(context : Context) : string {
let appName = ""
try {
const packageManager = context.getPackageManager()
const applicationInfo = packageManager.getApplicationInfo(context.getPackageName(), 0)
appName = packageManager.getApplicationLabel(applicationInfo) as string
} catch (e : Exception) {
e.printStackTrace()
}
return appName
}

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="DCNotificationProgressTranslucentTheme">
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:colorBackgroundCacheHint">@null</item>
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowAnimationStyle">@android:style/Animation</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowContentOverlay">@null</item>
</style>
</resources>

View File

@ -0,0 +1,46 @@
export type CreateNotificationProgressOptions = {
/**
* 通知标题
* @defaultValue 应用名称
*/
title ?: string | null
/**
* 通知内容
*/
content : string,
/**
* 进度
*/
progress : number,
/**
* 点击通知消息回调
* @defaultValue null
*/
onClick? : (() => void) | null
}
export type FinishNotificationProgressOptions = {
/**
* 通知标题
* @defaultValue 应用名称
*/
title ?: string | null
/**
* 通知内容
*/
content : string,
/**
* 点击通知消息回调
*/
onClick : () => void
}
export type CreateNotificationProgress = (options : CreateNotificationProgressOptions) => void;
export type CancelNotificationProgress = () => void;
export type FinishNotificationProgress = (options: FinishNotificationProgressOptions) => void

View File

@ -114,6 +114,9 @@ export function searchFacet(keyword, options = {}) {
})
const totalFound = parseInt(res.data.data.totalFoundText || res.data.data.matchInfo?.totalFound || 0, 10)
resolve({ newCount, oldCount, totalFound })
} else if (res.statusCode === 200 && res.data && res.data.status === 0 && res.data.errType === '102') {
console.warn('孔夫子统计-会话过期,需要重新登录')
reject(new Error('KONGZ_SESSION_EXPIRED'))
} else {
resolve({ newCount: 0, oldCount: 0, totalFound: 0 })
}
@ -236,6 +239,9 @@ export function searchProducts(keyword, options = {}) {
} else {
resolve({ total: 0, list: [] })
}
} else if (res.statusCode === 200 && res.data && res.data.status === 0 && res.data.errType === '102') {
console.warn('孔夫子搜索-会话过期,需要重新登录')
reject(new Error('KONGZ_SESSION_EXPIRED'))
} else {
resolve({ total: 0, list: [] })
}