From 18bdb4d4d52362ee8812a5618e7ae04e1d809bbf Mon Sep 17 00:00:00 2001 From: abu <3109389044@qq.com> Date: Mon, 21 Apr 2025 17:35:54 +0800 Subject: [PATCH] push --- App.vue | 531 ++- TUIKit/assets/styles/common.scss | 120 +- TUIKit/components/TUIChat/index.vue | 649 +-- .../TUIChat/message-input/index.vue | 486 +- .../message-input/message-input-editor.vue | 570 +-- .../TUIContact/contact-info/index.vue | 860 ++-- TUIKit/components/TUIContact/index.vue | 276 +- TUIKit/components/TUIContact/indexsea.vue | 280 +- api/vlog.js | 828 ++-- components/vlog/videoComp.vue | 18 +- components/vlog/videoDetail.vue | 30 +- components/vlog/videoFollowComp.vue | 22 +- components/vlog/videoLocal.vue | 14 +- config/api.js | 14 +- .../android/assets/agconnect-services.json | 1 + .../android/assets/timpush-configs.json | 1 + .../android/manifestPlaceholders.json | 5 + nativeResources/android/mcs-services.json | 6 + .../ios/Resources/timpush-configs.json | 3 + package-lock.json | 4096 ++++++++++++----- package.json | 20 +- pages/publish/publish.nvue | 791 ++-- pages/search/search.nvue | 274 -- pages/search/search.vue | 296 ++ pages/search/searchList.nvue | 260 -- pages/search/searchList.vue | 399 ++ pages/search/searchVd.vue | 243 + pages/search/shop.vue | 818 ++++ pages/search/tuangou.vue | 288 ++ pages/search/user.vue | 220 + pages/tabbar/im/index.vue | 54 +- pages/tabbar/vlog/index.nvue | 16 +- uni_modules/TencentCloud-Push/changelog.md | 29 + uni_modules/TencentCloud-Push/index.js | 0 uni_modules/TencentCloud-Push/package.json | 90 + uni_modules/TencentCloud-Push/readme-npm.md | 299 ++ uni_modules/TencentCloud-Push/readme.md | 285 ++ .../utssdk/app-android/config.json | 29 + .../utssdk/app-android/index.uts | 152 + .../app-android/push-callback-options.uts | 5 + .../utssdk/app-android/push-callback.uts | 28 + .../app-android/push-listener-options.uts | 3 + .../utssdk/app-android/push-listener.uts | 25 + .../utssdk/app-ios/UTS.entitlements | 8 + .../utssdk/app-ios/config.json | 11 + .../utssdk/app-ios/index.uts | 125 + .../utssdk/app-ios/push-listener-options.uts | 3 + .../utssdk/app-ios/push-listener.uts | 24 + .../TencentCloud-Push/utssdk/interface.uts | 11 + utils/request.js | 41 +- utils/tools.js | 28 +- vue.config.js | 68 +- 52 files changed, 9284 insertions(+), 4469 deletions(-) create mode 100644 nativeResources/android/assets/agconnect-services.json create mode 100644 nativeResources/android/assets/timpush-configs.json create mode 100644 nativeResources/android/manifestPlaceholders.json create mode 100644 nativeResources/android/mcs-services.json create mode 100644 nativeResources/ios/Resources/timpush-configs.json delete mode 100755 pages/search/search.nvue create mode 100755 pages/search/search.vue delete mode 100755 pages/search/searchList.nvue create mode 100755 pages/search/searchList.vue create mode 100644 pages/search/searchVd.vue create mode 100644 pages/search/shop.vue create mode 100644 pages/search/tuangou.vue create mode 100644 pages/search/user.vue create mode 100644 uni_modules/TencentCloud-Push/changelog.md create mode 100644 uni_modules/TencentCloud-Push/index.js create mode 100644 uni_modules/TencentCloud-Push/package.json create mode 100644 uni_modules/TencentCloud-Push/readme-npm.md create mode 100644 uni_modules/TencentCloud-Push/readme.md create mode 100644 uni_modules/TencentCloud-Push/utssdk/app-android/config.json create mode 100644 uni_modules/TencentCloud-Push/utssdk/app-android/index.uts create mode 100644 uni_modules/TencentCloud-Push/utssdk/app-android/push-callback-options.uts create mode 100644 uni_modules/TencentCloud-Push/utssdk/app-android/push-callback.uts create mode 100644 uni_modules/TencentCloud-Push/utssdk/app-android/push-listener-options.uts create mode 100644 uni_modules/TencentCloud-Push/utssdk/app-android/push-listener.uts create mode 100644 uni_modules/TencentCloud-Push/utssdk/app-ios/UTS.entitlements create mode 100644 uni_modules/TencentCloud-Push/utssdk/app-ios/config.json create mode 100644 uni_modules/TencentCloud-Push/utssdk/app-ios/index.uts create mode 100644 uni_modules/TencentCloud-Push/utssdk/app-ios/push-listener-options.uts create mode 100644 uni_modules/TencentCloud-Push/utssdk/app-ios/push-listener.uts create mode 100644 uni_modules/TencentCloud-Push/utssdk/interface.uts diff --git a/App.vue b/App.vue index b7b6629f..d9d18293 100644 --- a/App.vue +++ b/App.vue @@ -1,273 +1,270 @@ - + + +/************************ */ +.w200 { + width: 200rpx !important; +} + +.flex1 { + flex: 1; //必须父级设置flex +} +.activate-line { + background-color: #ffffff; + + transition-duration: 300ms; +} +// uni-page-body, +// html, +// body, +// page { +// width: 100% ; +// height: 100% ; +// overflow: hidden; +// } + diff --git a/TUIKit/assets/styles/common.scss b/TUIKit/assets/styles/common.scss index 40ce2f71..90a0c8b5 100644 --- a/TUIKit/assets/styles/common.scss +++ b/TUIKit/assets/styles/common.scss @@ -1,60 +1,60 @@ -body, div, ul, ol, dt, dd, li, dl, h1, h2, h3, h4, p { - margin:0; - padding:0; - font-style:normal; - - /* font:12px/22px"\5B8B\4F53",Arial,Helvetica,sans-serif; */ -} - -ol, ul, li { - list-style:none; -} - -img { - border:0; - vertical-align:middle; - pointer-events:none; -} - -body{ - height: 100% important; - color:#000; - background:#FFF; -} - -.clear { - clear:both; - height:1px; - width:100%; - overflow:hidden; - margin-top:-1px; -} - -a { - color:#000; - text-decoration:none; - cursor: pointer; -} - -a:hover { - text-decoration:none; -} - -input, textarea { - user-select: auto; -} - -input:focus, input:active, textarea:focus, textarea:active { - outline: none; -} - -.chat-aside { - position: absolute; - top: 50px; - right: 0; - box-sizing: border-box; - width: 360px !important; - border-radius: 8px 0 0 8px; - z-index: 9999; - max-height: calc(100% - 50px); -} +body, div, ul, ol, dt, dd, li, dl, h1, h2, h3, h4, p { + margin:0; + padding:0; + font-style:normal; + + /* font:12px/22px"\5B8B\4F53",Arial,Helvetica,sans-serif; */ +} + +ol, ul, li { + list-style:none; +} + +img { + border:0; + vertical-align:middle; + pointer-events:none; +} + +body{ + height: 100% important; + color:#000; + background:#FFF; +} + +.clear { + clear:both; + height:1px; + width:100%; + overflow:hidden; + margin-top:-1px; +} + +a { + color:#000; + text-decoration:none; + cursor: pointer; +} + +a:hover { + text-decoration:none; +} + +input, textarea { + user-select: auto; +} + +input:focus, input:active, textarea:focus, textarea:active { + outline: none; +} + +.chat-aside { + position: absolute; + top: 50px; + right: 0; + box-sizing: border-box; + width: 360px !important; + border-radius: 8px 0 0 8px; + z-index: 9999; + max-height: calc(100% - 50px); +} diff --git a/TUIKit/components/TUIChat/index.vue b/TUIKit/components/TUIChat/index.vue index 4dcbac60..64b4074b 100644 --- a/TUIKit/components/TUIChat/index.vue +++ b/TUIKit/components/TUIChat/index.vue @@ -1,324 +1,325 @@ - - - - + + + + diff --git a/TUIKit/components/TUIChat/message-input/index.vue b/TUIKit/components/TUIChat/message-input/index.vue index a32fbe28..d8846bc3 100644 --- a/TUIKit/components/TUIChat/message-input/index.vue +++ b/TUIKit/components/TUIChat/message-input/index.vue @@ -1,243 +1,243 @@ - - - - + + + + diff --git a/TUIKit/components/TUIChat/message-input/message-input-editor.vue b/TUIKit/components/TUIChat/message-input/message-input-editor.vue index dff1ac43..02825a3e 100644 --- a/TUIKit/components/TUIChat/message-input/message-input-editor.vue +++ b/TUIKit/components/TUIChat/message-input/message-input-editor.vue @@ -1,285 +1,285 @@ - - - - + + + + diff --git a/TUIKit/components/TUIContact/contact-info/index.vue b/TUIKit/components/TUIContact/contact-info/index.vue index ef02c343..0a9c5f56 100644 --- a/TUIKit/components/TUIContact/contact-info/index.vue +++ b/TUIKit/components/TUIContact/contact-info/index.vue @@ -1,430 +1,430 @@ - + + + + diff --git a/pages/search/search.nvue b/pages/search/search.nvue deleted file mode 100755 index 13f3d456..00000000 --- a/pages/search/search.nvue +++ /dev/null @@ -1,274 +0,0 @@ - - - - - diff --git a/pages/search/search.vue b/pages/search/search.vue new file mode 100755 index 00000000..922c25da --- /dev/null +++ b/pages/search/search.vue @@ -0,0 +1,296 @@ + + + + + diff --git a/pages/search/searchList.nvue b/pages/search/searchList.nvue deleted file mode 100755 index 7b82b210..00000000 --- a/pages/search/searchList.nvue +++ /dev/null @@ -1,260 +0,0 @@ - - - - - diff --git a/pages/search/searchList.vue b/pages/search/searchList.vue new file mode 100755 index 00000000..a5dc65c3 --- /dev/null +++ b/pages/search/searchList.vue @@ -0,0 +1,399 @@ + + + + + diff --git a/pages/search/searchVd.vue b/pages/search/searchVd.vue new file mode 100644 index 00000000..31e19a0b --- /dev/null +++ b/pages/search/searchVd.vue @@ -0,0 +1,243 @@ + + + + + diff --git a/pages/search/shop.vue b/pages/search/shop.vue new file mode 100644 index 00000000..e8ffaf02 --- /dev/null +++ b/pages/search/shop.vue @@ -0,0 +1,818 @@ + + + + + diff --git a/pages/search/tuangou.vue b/pages/search/tuangou.vue new file mode 100644 index 00000000..321280e0 --- /dev/null +++ b/pages/search/tuangou.vue @@ -0,0 +1,288 @@ + + + + + diff --git a/pages/search/user.vue b/pages/search/user.vue new file mode 100644 index 00000000..d21e7149 --- /dev/null +++ b/pages/search/user.vue @@ -0,0 +1,220 @@ + + + + + diff --git a/pages/tabbar/im/index.vue b/pages/tabbar/im/index.vue index bf034508..1efdbbd2 100644 --- a/pages/tabbar/im/index.vue +++ b/pages/tabbar/im/index.vue @@ -117,6 +117,11 @@ import SelectFriendqlioa from '@/TUIKit/components/TUIGroup/index.vue'; import TUICore, { ExtensionInfo, TUIConstants } from '@tencentcloud/tui-core'; import storage from '@/utils/storage.js'; import { getUserimInfo, getMember, getMemberstate, getMemberdelete } from '@/api/members'; + +// push +import { TUIConversationService } from '@tencentcloud/chat-uikit-engine'; +import * as Push from '@/uni_modules/TencentCloud-Push'; + TUIChatKit.init(); let vueVersion = 2; // vueVersion = 3; @@ -161,8 +166,53 @@ export default { SDKAppID: par.sdkAppId, userID: par.userID, userSig: par.userSig, - useUploadPlugin: true, // If you need to send rich media messages, please set to true. - framework: `vue${vueVersion}` // framework used vue2 / vue3 + useUploadPlugin: true, + framework: `vue${vueVersion}` + }).then(() => { + Push.setRegistrationID(par.userID, () => { + console.log('设置id设置id设置id设置id设置id设置id设置id设置id设置id设置id', par.userID); + + Push.registerPush( + par.sdkAppId, + 'vkFpe55aYqfV7Sk5uGaoxhEstJ3tcI9dquk7JwG1GloDSLD2HeMWeQweWWXgNlhC', + (data) => { + console.log('registerPush ok', data); + Push.getRegistrationID((registrationID) => { + console.log('getRegistrationID ok', registrationID); + }); + }, + (errCode, errMsg) => { + console.error('registerPush failed', errCode, errMsg); + } + ); + }); + // 监听通知栏点击事件,获取推送扩展信息 + Push.addPushListener(Push.EVENT.NOTIFICATION_CLICKED, (res) => { + console.log('notification clicked', res); + // 解析扩展信息,跳转到相应的会话(代码仅供参考,发布前需要完善) + try { + const data = JSON.parse(res.data); + const conv_type = data?.entity?.chatType === 1 ? 'C2C' : 'GROUP'; + // 根据推送信息拼的 conversationID + const conversationID = `${conv_type}${data.entity.sender}`; + // 切换会话 + TUIConversationService.switchConversation(conversationID); + const chatPath = '/TUIKit/components/TUIChat/index'; + uni.navigateTo({ url: chatPath }); + } catch (error) { + console.log('error', error); + } + }); + // 监听在线推送 + Push.addPushListener(Push.EVENT.MESSAGE_RECEIVED, (res) => { + // res 为消息内容 + console.log('message received', res); + }); + // 监听在线推送被撤回 + Push.addPushListener(Push.EVENT.MESSAGE_REVOKED, (res) => { + // res 为被撤回的消息 ID + console.log('message revoked', res); + }); }); } else { // 接口返回非 200 状态码,跳转登录页面 diff --git a/pages/tabbar/vlog/index.nvue b/pages/tabbar/vlog/index.nvue index a59236cc..b8bb88b4 100644 --- a/pages/tabbar/vlog/index.nvue +++ b/pages/tabbar/vlog/index.nvue @@ -229,7 +229,7 @@ export default { }, 300); }, onTabItemTap: function (e) { - console.log(e); + // console.log(e); // let tabIndex = e.index; // this.playStatus = tabIndex === 0 ? true : false; // 切换视频要做暂停或播放的判断 @@ -343,7 +343,8 @@ export default { } }); }, - fail: () => { + fail: (err) => { + console.log(err); uni.showToast({ icon: 'none', title: '获取位置信息失败' @@ -373,15 +374,7 @@ export default { let index = e.target.dataset.current || e.currentTarget.dataset.current; this.isTap = true; var currentSize = this.tabListSize[index]; - // if (obj.playerList.length === 0) { - // this.isDraw_gz = false; - // this.isDraw_lo = false; - // this.isDraw_tj = false; - // } else { - // this.isDraw_gz = preloadIndex == 1 ? true : false; - // this.isDraw_lo = preloadIndex == 0 ? true : false; - // this.isDraw_tj = preloadIndex == 2 ? true : false; - // } + this.updateIndicator(currentSize.left, currentSize.width); this._touchTabIndex = index; this.switchTab(index); @@ -433,7 +426,6 @@ export default { this.isDraw_gz = false; this.isDraw_lo = false; this.isDraw_tj = false; - console.log(this.playStatus); // if (this.playStatus == true) { // this.playStatus = this._lastTabIndex == 2 ? false : true; // } diff --git a/uni_modules/TencentCloud-Push/changelog.md b/uni_modules/TencentCloud-Push/changelog.md new file mode 100644 index 00000000..c5e53f6a --- /dev/null +++ b/uni_modules/TencentCloud-Push/changelog.md @@ -0,0 +1,29 @@ +## 1.2.0(2025-03-31) +- 适配出海手机支持 FCM 推送。 +## 1.1.0(2024-12-11) +- 大幅减小插件包体积,优化产品体验。 +- 兼容 HBuilderX 4.36 的 Breaking changes。如果您需要 vivo/荣耀 的厂商推送,请参考 [文档](https://cloud.tencent.com/document/product/269/103522),正确配置 `manifestPlaceholders.json` 和 `mcn-services.json`。 + +## 1.0.0(2024-11-29) +- 优化和 [TencentCloud-TUICallKit 插件](https://ext.dcloud.net.cn/plugin?id=9035) 融合时的产品体验。 +- 新增点击通知栏事件 NOTIFICATION_CLICKED,支持获取推送扩展信息。 +- 在线通道支持自定义铃音功能。 + +## 0.5.1(2024-11-07) +- 优化和 [@tencentcloud/chat-uikit-uniapp](https://cloud.tencent.com/document/product/269/64507) 融合时的产品体验。 +- 优化和 [TencentCloud-TUICallKit 插件](https://ext.dcloud.net.cn/plugin?id=9035) 融合时的产品体验。 +- 新增接口 disablePostNotificationInForeground,此接口可实现应用在前台时,开/关通知栏通知(默认开)。 +- 新增接口 createNotificationChannel,支持 FCM/OPPO 自定义铃音。 + +## 0.4.0(2024-10-17) +- 支持与 [TencentCloud-TUICallKit 插件](https://ext.dcloud.net.cn/plugin?id=9035) 融合打包。 + +## 0.3.0(2024-10-12) +- 新增接口 addPushListener/removePushListener,支持获取在线推送消息,支持推送消息撤回通知。 + +## 0.2.0(2024-09-18) +- 支持 FCM +- 支持 hihonor + +## 0.1.0(2024-09-10) + - 使用 uts 开发,基于腾讯云推送服务(Push),支持 iOS 和 Android 推送,同时适配各大厂商推送。 \ No newline at end of file diff --git a/uni_modules/TencentCloud-Push/index.js b/uni_modules/TencentCloud-Push/index.js new file mode 100644 index 00000000..e69de29b diff --git a/uni_modules/TencentCloud-Push/package.json b/uni_modules/TencentCloud-Push/package.json new file mode 100644 index 00000000..11c43552 --- /dev/null +++ b/uni_modules/TencentCloud-Push/package.json @@ -0,0 +1,90 @@ +{ + "name": "@tencentcloud/uni-app-push", + "id": "TencentCloud-Push", + "main": "index.js", + "displayName": "【官方】uni-app 腾讯云推送服务(Push)", + "version": "1.2.0", + "description": "使用 uts 开发,基于腾讯云推送服务(Push),支持 iOS 和 Android 推送,同时适配各大厂商推送。", + "license": "ISC", + "keywords": [ + "腾讯云", + "Push", + "推送", + "Android/iOS", + "谷歌FCM" +], + "repository": "", + "engines": { + "HBuilderX": "^3.6.8" + }, + "dcloudext": { + "type": "uts", + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "腾讯云即时通信IM隐私保护指引: https://web.sdk.qcloud.com/document/Tencent-IM-Privacy-Protection-Guidelines.html\n移动推送隐私保护指引: https://privacy.qq.com/document/preview/8565a4a2d26e480187ed86b0cc81d727", + "permissions": "本地存储空间" + }, + "npmurl": "" + }, + "uni_modules": { + "dependencies": [], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y", + "alipay": "y" + }, + "client": { + "Vue": { + "vue2": "y", + "vue3": "y" + }, + "App": { + "app-android": "y", + "app-ios": "y", + "app-harmony": "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", + "飞书": "u", + "京东": "u" + }, + "快应用": { + "华为": "u", + "联盟": "u" + } + } + } + } +} \ No newline at end of file diff --git a/uni_modules/TencentCloud-Push/readme-npm.md b/uni_modules/TencentCloud-Push/readme-npm.md new file mode 100644 index 00000000..e3cba80a --- /dev/null +++ b/uni_modules/TencentCloud-Push/readme-npm.md @@ -0,0 +1,299 @@ +# TencentCloud-Push + +## 简介 + +使用 uts 开发,基于腾讯云推送服务(Push),支持 iOS 和 Android 推送,同时适配各大厂商推送。 + +腾讯云推送服务(Push)提供一站式 App 推送解决方案,助您轻松提升用户留存和互动活跃度,支持与腾讯云即时通信 IM SDK、实时音视频 TRTC SDK、音视频通话 SDK、直播 SDK等音视频终端产品协同集成,在不同场景联合使用,提升业务整体功能体验。 + + + + + +#### 数据可视化,辅助运营策略 + + + +#### 支持推送消息全链路问题排查 + + + +#### 六地服务部署,严守数据安全 + +提供了中国、东南亚(新加坡、印尼雅加达)、东北亚(韩国首尔)、欧洲(德国法兰克福)以及北美(美国硅谷)数据存储中心供选择,每个数据中心均支持全球接入。如果您的应用在境外上线且用户主要在境外,您可以根据消息传输需求及合规要求,选择适合您业务的境外数据中心,保障您的数据安全。 + + +## 快速跑通 + +### 步骤1:创建应用 + +进入 [控制台](https://console.cloud.tencent.com/im) ,单击创建应用,填写应用名称,选择数据中心,单击确定,完成应用创建。 + +![](https://qcloudimg.tencent-cloud.cn/image/document/e2761226f7d2bbdfb0a301192316c7d3.png) + +### 步骤2:开通推送服务 Push + +进入 [推送服务 Push](https://console.cloud.tencent.com/im/push-plugin-push-identifier),单击立即购买或免费试用 。(每个应用可免费试用一次,有效期7天) + +![](https://qcloudimg.tencent-cloud.cn/image/document/a7e1f3847c91a807ec9be3a586f1290f.png) + +### 步骤3:下载腾讯云推送服务(Push)并复制 Push SDK 到您的项目中 + +1. 下载腾讯云推送服务(Push)。 +``` +npm install @tencentcloud/uni-app-push +``` + +2. 复制 Push SDK 到您的项目中。 + +【macOS 端】 + +``` bash +mkdir -p ./uni_modules/TencentCloud-Push && rsync -av ./node_modules/@tencentcloud/uni-app-push/ ./uni_modules/TencentCloud-Push +``` +【Window 端】 + +``` bash +xcopy .\node_modules\@tencentcloud\uni-app-push .\uni_modules\TencentCloud-Push /i /e +``` + +### 步骤4:在 App.vue 中引入并注册腾讯云推送服务(Push) + +将 SDKAppID 和 appKey 替换为您在IM 控制台 - 推送服务 Push - 接入设置页面 获取的应用的信息。如图所示: + +![](https://sdk-web-1252463788.cos.ap-hongkong.myqcloud.com/im/assets/push/push.png) + +```ts +// 集成 TencentCloud-Push +import * as Push from '@/uni_modules/TencentCloud-Push'; +const SDKAppID = 0; // 您的 SDKAppID +const appKey = ''; // 客户端密钥 +Push.registerPush(SDKAppID, appKey, (data) => { + console.log('registerPush ok', data); + Push.getRegistrationID((registrationID) => { + console.log('getRegistrationID ok', registrationID); + }); + }, (errCode, errMsg) => { + console.error('registerPush failed', errCode, errMsg); + } +); + +// 监听通知栏点击事件,获取推送扩展信息 +Push.addPushListener(Push.EVENT.NOTIFICATION_CLICKED, (res) => { + // res 为推送扩展信息 + console.log('notification clicked', res); +}); + +// 监听在线推送 +Push.addPushListener(Push.EVENT.MESSAGE_RECEIVED, (res) => { + // res 为消息内容 + console.log('message received', res); +}); + +// 监听在线推送被撤回 +Push.addPushListener(Push.EVENT.MESSAGE_REVOKED, (res) => { + // res 为被撤回的消息 ID + console.log('message revoked', res); +}); +``` + +### 步骤5:测试推送(测试前请务必打开手机通知权限,允许应用通知。) + +单击 HBuilderX 的 【运行 > 运行到手机或模拟器 > 制作自定义调试基座】,使用云端证书制作 Android 或 iOS 自定义调试基座。 + +![](https://qcloudimg.tencent-cloud.cn/image/document/742b7c05364e8ff9a16d5d5601aa038b.png) + +自定义调试基座打好后,安装到手机运行。 + +[登录](https://console.cloud.tencent.com/im/push-plugin-push-check) 控制台,使用测试工具进行在线推送测试。 +![](https://sdk-web-1252463788.cos.ap-hongkong.myqcloud.com/im/assets/push/test-online-push.png) + +## 厂商推送配置 +> - 请注意!HBuilderX 4.36 发布了不向下兼容的更新,如果您使用的是 HBuilderX 4.36 或者更高版本,且需要 vivo/荣耀 的厂商推送, +请升级推送版本到 1.1.0 或更高版本,并参考文档正确配置 `manifestPlaceholders.json` 和 `mcs-services.json`。 +> - 请在 `nativeResources` 目录下进行推送配置。若项目根目录尚未创建该文件夹,请新建一个名为 `nativeResources` 的文件夹。 +> - 离线推送厂商配置完成后,需要打包自定义基座。参考:[[快速跑通]>[步骤5:测试推送(测试前请务必打开手机通知权限,允许应用通知。)]](#user-content-step5) + +### 【Android】 + +1. 新建 nativeResources/android/assets 目录。 + +2. 在 [推送服务 Push > 接入设置 > 一键式快速配置](https://console.cloud.tencent.com/im/push-plugin-push-identifier) 下载 `timpush-configs.json` 文件,配置到 nativeResources/android/assets 目录下。 + +3. For 华为: + + 配置 `agconnect-services.json` (此文件获取详见 [厂商配置 > uniapp > 华为 > 步骤4:获取应用信息](https://cloud.tencent.com/document/product/269/103769))到 nativeResources/android 目录下。 + +4. For Google FCM: + + 4.1. 编辑 uni_modules/TencentCloud-Push/utssdk/app-android/config.json 的 `project.plugins`,添加 `"com.google.gms.google-services"`,如下: + ``` + { + ... + "project": { + "plugins": [ + ... + "com.google.gms.google-services" + ] + } + } + ``` + + 4.2. 配置 `google-services.json` 文件到 nativeResources/android/ 目录。 + +5. For 荣耀: + + 5.1. 编辑 uni_modules/TencentCloud-Push/utssdk/app-android/config.json 的 `dependencies`,添加 `"com.tencent.timpush:honor:8.3.6498"`,如下: + ``` + { + ... + "dependencies": [ + ... + "com.tencent.timpush:honor:8.3.6498" + ] + } + ``` + + 5.2. 配置 `mcs-services.json` 文件到 nativeResources/android 目录下。 + + 5.3. 配置 `appID` 到 nativeResources/android/manifestPlaceholders.json 中的 `"HONOR_APPID"`,如下: + ``` + { + "HONOR_APPID": "" + } + ``` + +6. For vivo: + + 6.1. 编辑 uni_modules/TencentCloud-Push/utssdk/app-android/config.json 的 `dependencies`,添加 `"com.tencent.timpush:vivo:8.3.6498"`,如下: + ``` + { + ... + "dependencies": [ + ... + "com.tencent.timpush:vivo:8.3.6498" + ] + } + ``` + + 6.2. 配置 `appID` 和 `appKey` 到 nativeResources/android/manifestPlaceholders.json 中的 `VIVO_APPKEY` 和 `VIVO_APPID`,如下: + ``` + { + "VIVO_APPKEY": "", + "VIVO_APPID": "", + } + ``` + +### 【iOS】 + +1. 新建 nativeResources/ios/Resources 目录。 + +2. 在 nativeResources/ios/Resources 中**新建 timpush-configs.json 文件**。 + +3. 并将在 [IM控制台 > 推送服务 Push > 接入设置](https://console.cloud.tencent.com/im/push-plugin-push-identifier) 获取的证书ID,补充到 timpush-configs.json 文件中。 + + ``` + { + "businessID":"xxx" + } + ``` + +## 接口 + +| API | 描述| +|----|---| +| registerPush | 注册推送服务 (必须在 App 用户同意了隐私政策,并且允许为 App 用户提供推送服务后,再调用该接口使用推送服务)。
首次注册成功后,TencentCloud-Push SDK 生成该设备的标识 - RegistrationID。
业务侧可以把这个 RegistrationID 保存到业务服务器。业务侧根据 RegistrationID 向设备推送消息或者通知。| +| unRegisterPush | 反注册关闭推送服务。| +| setRegistrationID | 设置注册推送服务使用的推送 ID 标识,即 RegistrationID。
如果业务侧期望业务账号 ID 和推送 ID 一致,方便使用,可使用此接口,此时需注意,此接口需在 registerPush(注册推送服务)之前调用。| +| getRegistrationID | 注册推送服务成功后,获取推送 ID 标识,即 RegistrationID。| +| getNotificationExtInfo | 获取推送扩展信息。| +| getNotificationExtInfo | 收到离线推送时,点击通知栏拉起 app,调用此接口可获取推送扩展信息。| +| addPushListener | 添加 Push 监听器。| +| removePushListener | 移除 Push 监听器。| +| disablePostNotificationInForeground | 应用在前台时,开/关通知栏通知。| +| createNotificationChannel | 创建客户端通知 channel。| + + +```ts +registerPush(SDKAppID: number, appKey: string, onSuccess: (data: string) => void, onError?: (errCode: number, errMsg: string) => void); +``` + +|属性|类型|必填|说明| +|----|---|----|----| +|SDKAppID|number|是|推送(Push)应用 ID| +|appKey|string|是|推送(Push)应用客户端密钥| +|onSuccess|function|是|接口调用成功的回调函数| +|onError|function|否|接口调用失败的回调函数| + +```ts +unRegisterPush(onSuccess: () => void, onError?: (errCode: number, errMsg: string) => void): void; +``` + +|属性|类型|必填|说明| +|----|---|----|----| +|onSuccess|function|是|接口调用成功的回调函数| +|onError|function|否|接口调用失败的回调函数| + +```ts +setRegistrationID(registrationID: string, onSuccess: () => void): void; +``` + +|属性|类型|必填|说明| +|----|---|----|----| +|registrationID|string|是|设备的推送标识 ID,卸载重装会改变。| +|onSuccess|function|是|接口调用成功的回调函数| + + +```ts +getRegistrationID(onSuccess: (registrationID: string) => void): void; +``` + +|属性|类型|必填|说明| +|----|---|----|----| +|onSuccess|function|是|接口调用成功的回调函数| + +```ts +getNotificationExtInfo(onSuccess: (extInfo: string) => void): void; +``` + +|属性|类型|必填|说明| +|----|---|----|----| +|onSuccess|function|是|接口调用成功的回调函数| + +```ts +addPushListener(eventName: string, listener: (data: any) => void); +``` + +|属性|类型|必填|说明| +|----|---|----|----| +|eventName|string|是|推送事件类型| +|listener|function|是|推送事件处理方法| + +```ts +removePushListener(eventName: string, listener?: (data: any) => void); +``` + +|属性|类型|必填|说明| +|----|---|----|----| +|eventName|string|是|推送事件类型| +|listener|function|否|推送事件处理方法| + +```ts +disablePostNotificationInForeground(disable: boolean); +``` + +|属性|类型|必填|说明| +|----|---|----|----| +|disable|boolean|是|应用在前台时,开/关通知栏通知,默认开
- true: 应用在前台时,关闭通知栏通知。
- false: 应用在前台时,开启通知栏通知。| + +```ts +createNotificationChannel(options: any, listener: (data: any) => void); +``` + +|属性|类型|必填|说明| +|----|---|----|----| +|options.channelID|string|是|自定义 channel 的 ID| +|options.channelName|string|是|自定义 channel 的名称| +|options.channelDesc|string|否|自定义 channel 的描述| +|options.channelSound|string|否|自定义 channel 的铃音,音频文件名,不带后缀,音频文件需要放到 xxx/nativeResources/android/res/raw 中。
例如:
`options.channelSound = private_ring`,即设置 `xxx/nativeResources/android/res/raw/private_ring.mp3` 为自定义铃音| +|listener|function|是|接口调用成功的回调函数| diff --git a/uni_modules/TencentCloud-Push/readme.md b/uni_modules/TencentCloud-Push/readme.md new file mode 100644 index 00000000..f49324ed --- /dev/null +++ b/uni_modules/TencentCloud-Push/readme.md @@ -0,0 +1,285 @@ +# TencentCloud-Push + +## 简介 + +使用 uts 开发,基于腾讯云推送服务(Push),支持 iOS 和 Android 推送,同时适配各大厂商推送。 + +腾讯云推送服务(Push)提供一站式 App 推送解决方案,助您轻松提升用户留存和互动活跃度,支持与腾讯云即时通信 IM SDK、实时音视频 TRTC SDK、音视频通话 SDK、直播 SDK等音视频终端产品协同集成,在不同场景联合使用,提升业务整体功能体验。 + + + + + +#### 数据可视化,辅助运营策略 + + + +#### 支持推送消息全链路问题排查 + + + +#### 六地服务部署,严守数据安全 + +提供了中国、东南亚(新加坡、印尼雅加达)、东北亚(韩国首尔)、欧洲(德国法兰克福)以及北美(美国硅谷)数据存储中心供选择,每个数据中心均支持全球接入。如果您的应用在境外上线且用户主要在境外,您可以根据消息传输需求及合规要求,选择适合您业务的境外数据中心,保障您的数据安全。 + + +## 快速跑通 + +### 步骤1:创建应用 + +进入 [控制台](https://console.cloud.tencent.com/im) ,单击创建应用,填写应用名称,选择数据中心,单击确定,完成应用创建。 + +![](https://qcloudimg.tencent-cloud.cn/image/document/e2761226f7d2bbdfb0a301192316c7d3.png) + +### 步骤2:开通推送服务 Push + +进入 [推送服务 Push](https://console.cloud.tencent.com/im/push-plugin-push-identifier),单击立即购买或免费试用 。(每个应用可免费试用一次,有效期7天) + +![](https://qcloudimg.tencent-cloud.cn/image/document/a7e1f3847c91a807ec9be3a586f1290f.png) + +### 步骤3:将 [uni-app 腾讯云推送服务(Push)](https://ext.dcloud.net.cn/plugin?id=20169)插件导入 HbuilderX 中的工程。如图所示: + +![](https://qcloudimg.tencent-cloud.cn/image/document/ab8061fea2bf6659f571c2c11aa0d8f4.png) +![](https://qcloudimg.tencent-cloud.cn/image/document/13a3e33564e6ab79d3e609b36e8ba0d5.png) +![](https://qcloudimg.tencent-cloud.cn/image/document/3c7060f9db637c826009926c5f34a1b8.png) + +### 步骤4:在 App.vue 中引入并注册腾讯云推送服务(Push) + +将 SDKAppID 和 appKey 替换为您在IM 控制台 - 推送服务 Push - 接入设置页面 获取的应用的信息。如图所示: + +![](https://sdk-web-1252463788.cos.ap-hongkong.myqcloud.com/im/assets/push/push.png) + +```ts +// 集成 TencentCloud-Push +import * as Push from '@/uni_modules/TencentCloud-Push'; +const SDKAppID = 0; // 您的 SDKAppID +const appKey = ''; // 客户端密钥 +Push.registerPush(SDKAppID, appKey, (data) => { + console.log('registerPush ok', data); + Push.getRegistrationID((registrationID) => { + console.log('getRegistrationID ok', registrationID); + }); + }, (errCode, errMsg) => { + console.error('registerPush failed', errCode, errMsg); + } +); + +// 监听通知栏点击事件,获取推送扩展信息 +Push.addPushListener(Push.EVENT.NOTIFICATION_CLICKED, (res) => { + // res 为推送扩展信息 + console.log('notification clicked', res); +}); + +// 监听在线推送 +Push.addPushListener(Push.EVENT.MESSAGE_RECEIVED, (res) => { + // res 为消息内容 + console.log('message received', res); +}); + +// 监听在线推送被撤回 +Push.addPushListener(Push.EVENT.MESSAGE_REVOKED, (res) => { + // res 为被撤回的消息 ID + console.log('message revoked', res); +}); +``` + +### 步骤5:测试推送(测试前请务必打开手机通知权限,允许应用通知。) + +单击 HBuilderX 的 【运行 > 运行到手机或模拟器 > 制作自定义调试基座】,使用云端证书制作 Android 或 iOS 自定义调试基座。 + +![](https://qcloudimg.tencent-cloud.cn/image/document/742b7c05364e8ff9a16d5d5601aa038b.png) + +自定义调试基座打好后,安装到手机运行。 + +[登录](https://console.cloud.tencent.com/im/push-plugin-push-check) 控制台,使用测试工具进行在线推送测试。 +![](https://sdk-web-1252463788.cos.ap-hongkong.myqcloud.com/im/assets/push/test-online-push.png) + + +## 厂商推送配置 + +> - 请注意!HBuilderX 4.36 发布了不向下兼容的更新,如果您使用的是 HBuilderX 4.36 或者更高版本,且需要 vivo/荣耀 的厂商推送, +请升级推送版本到 1.1.0 或更高版本,并参考文档正确配置 `manifestPlaceholders.json` 和 `mcs-services.json`。 +> - 请在 `nativeResources` 目录下进行推送配置。若项目根目录尚未创建该文件夹,请新建一个名为 `nativeResources` 的文件夹。 +> - 厂商推送配置完成后,需要打包自定义基座。参考:[[快速跑通]>[步骤5:测试推送(测试前请务必打开手机通知权限,允许应用通知。)]](#step5) + +#### 【Android】 + +1. 新建 nativeResources/android/assets 目录。 + +2. 在 [推送服务 Push > 接入设置 > 一键式快速配置](https://console.cloud.tencent.com/im/push-plugin-push-identifier) 下载 `timpush-configs.json` 文件,配置到 nativeResources/android/assets 目录下。 + +3. For 华为: + + 配置 `agconnect-services.json` (此文件获取详见 [厂商配置 > uniapp > 华为 > 步骤4:获取应用信息](https://cloud.tencent.com/document/product/269/103769))到 nativeResources/android 目录下。 + +4. For Google FCM: + + 4.1. 编辑 uni_modules/TencentCloud-Push/utssdk/app-android/config.json 的 `project.plugins`,添加 `"com.google.gms.google-services"`,如下: + ``` + { + ... + "project": { + "plugins": [ + ... + "com.google.gms.google-services" + ] + } + } + ``` + + 4.2. 配置 `google-services.json` 文件到 nativeResources/android/ 目录。 + +5. For 荣耀: + + 5.1. 编辑 uni_modules/TencentCloud-Push/utssdk/app-android/config.json 的 `dependencies`,添加 `"com.tencent.timpush:honor:8.3.6498"`,如下: + ``` + { + ... + "dependencies": [ + ... + "com.tencent.timpush:honor:8.3.6498" + ] + } + ``` + + 5.2. 配置 `mcs-services.json` 文件到 nativeResources/android 目录下。 + + 5.3. 配置 `appID` 到 nativeResources/android/manifestPlaceholders.json 中的 `"HONOR_APPID"`,如下: + ``` + { + "HONOR_APPID": "" + } + ``` + +6. For vivo: + + 6.1. 编辑 uni_modules/TencentCloud-Push/utssdk/app-android/config.json 的 `dependencies`,添加 `"com.tencent.timpush:vivo:8.3.6498"`,如下: + ``` + { + ... + "dependencies": [ + ... + "com.tencent.timpush:vivo:8.3.6498" + ] + } + ``` + + 6.2. 配置 `appID` 和 `appKey` 到 nativeResources/android/manifestPlaceholders.json 中的 `VIVO_APPKEY` 和 `VIVO_APPID`,如下: + ``` + { + "VIVO_APPKEY": "", + "VIVO_APPID": "", + } + ``` + +#### 【iOS】 + +1. 新建 nativeResources/ios/Resources 目录。 + +2. 在 nativeResources/ios/Resources 目录下新建 `timpush-configs.json` 文件。 + +3. 将在 [IM控制台 > 推送服务 Push > 接入设置](https://console.cloud.tencent.com/im/push-plugin-push-identifier) 获取的证书ID,补充到 `timpush-configs.json` 文件中。 + + ``` + { + "businessID":"xxx" + } + ``` + +## 接口 + +| API | 描述| +|----|---| +| registerPush | 注册推送服务 (必须在 App 用户同意了隐私政策,并且允许为 App 用户提供推送服务后,再调用该接口使用推送服务)。
首次注册成功后,TencentCloud-Push SDK 生成该设备的标识 - RegistrationID。
业务侧可以把这个 RegistrationID 保存到业务服务器。业务侧根据 RegistrationID 向设备推送消息或者通知。| +| unRegisterPush | 反注册关闭推送服务。| +| setRegistrationID | 设置注册推送服务使用的推送 ID 标识,即 RegistrationID。
如果业务侧期望业务账号 ID 和推送 ID 一致,方便使用,可使用此接口,此时需注意,此接口需在 registerPush(注册推送服务)之前调用。| +| getRegistrationID | 注册推送服务成功后,获取推送 ID 标识,即 RegistrationID。| +| getNotificationExtInfo | 收到离线推送时,点击通知栏拉起 app,调用此接口可获取推送扩展信息。| +| addPushListener | 添加 Push 监听器。| +| removePushListener | 移除 Push 监听器。| +| disablePostNotificationInForeground | 应用在前台时,开/关通知栏通知(默认开)。| +| createNotificationChannel | 创建客户端通知 channel。| + +```ts +registerPush(SDKAppID: number, appKey: string, onSuccess: (data: string) => void, onError?: (errCode: number, errMsg: string) => void); +``` + +|属性|类型|必填|说明| +|----|---|----|----| +|SDKAppID|number|是|推送(Push)应用 ID| +|appKey|string|是|推送(Push)应用客户端密钥| +|onSuccess|function|是|接口调用成功的回调函数| +|onError|function|否|接口调用失败的回调函数| + +```ts +unRegisterPush(onSuccess: () => void, onError?: (errCode: number, errMsg: string) => void): void; +``` + +|属性|类型|必填|说明| +|----|---|----|----| +|onSuccess|function|是|接口调用成功的回调函数| +|onError|function|否|接口调用失败的回调函数| + +```ts +setRegistrationID(registrationID: string, onSuccess: () => void): void; +``` + +|属性|类型|必填|说明| +|----|---|----|----| +|registrationID|string|是|设备的推送标识 ID,卸载重装会改变。| +|onSuccess|function|是|接口调用成功的回调函数| + + +```ts +getRegistrationID(onSuccess: (registrationID: string) => void): void; +``` + +|属性|类型|必填|说明| +|----|---|----|----| +|onSuccess|function|是|接口调用成功的回调函数| + +```ts +getNotificationExtInfo(onSuccess: (extInfo: string) => void): void; +``` + +|属性|类型|必填|说明| +|----|---|----|----| +|onSuccess|function|是|接口调用成功的回调函数| + +```ts +addPushListener(eventName: string, listener: (data: any) => void); +``` + +|属性|类型|必填|说明| +|----|---|----|----| +|eventName|string|是|推送事件类型| +|listener|function|是|推送事件处理方法| + +```ts +removePushListener(eventName: string, listener?: (data: any) => void); +``` + +|属性|类型|必填|说明| +|----|---|----|----| +|eventName|string|是|推送事件类型| +|listener|function|否|推送事件处理方法| + +```ts +disablePostNotificationInForeground(disable: boolean); +``` + +|属性|类型|必填|说明| +|----|---|----|----| +|disable|boolean|是|应用在前台时,开/关通知栏通知,默认开
- true: 应用在前台时,关闭通知栏通知。
- false: 应用在前台时,开启通知栏通知。| + +```ts +createNotificationChannel(options: any, listener: (data: any) => void); +``` + +|属性|类型|必填|说明| +|----|---|----|----| +|options.channelID|string|是|自定义 channel 的 ID| +|options.channelName|string|是|自定义 channel 的名称| +|options.channelDesc|string|否|自定义 channel 的描述| +|options.channelSound|string|否|自定义 channel 的铃音,音频文件名,不带后缀,音频文件需要放到 xxx/nativeResources/android/res/raw 中。
例如:
`options.channelSound = private_ring`,即设置 `xxx/nativeResources/android/res/raw/private_ring.mp3` 为自定义铃音| +|listener|function|是|接口调用成功的回调函数| diff --git a/uni_modules/TencentCloud-Push/utssdk/app-android/config.json b/uni_modules/TencentCloud-Push/utssdk/app-android/config.json new file mode 100644 index 00000000..ff8cfffd --- /dev/null +++ b/uni_modules/TencentCloud-Push/utssdk/app-android/config.json @@ -0,0 +1,29 @@ +{ + "minSdkVersion": "21", + "dependencies": [ + "com.google.android.material:material:1.3.0", + "com.google.code.gson:gson:2.9.1", + "commons-codec:commons-codec:1.15", + "com.github.bumptech.glide:glide:4.12.0", + "com.tencent.timpush:timpush:8.5.6864", + "com.tencent.liteav.tuikit:tuicore:8.5.6864", + "com.tencent.timpush:huawei:8.5.6864", + "com.tencent.timpush:xiaomi:8.5.6864", + "com.tencent.timpush:oppo:8.5.6864", + "com.tencent.timpush:meizu:8.5.6864", + "com.tencent.timpush:fcm:8.5.6864", + "com.tencent.timpush:honor:8.5.6864", + "com.tencent.timpush:vivo:8.5.6864" + ], + "project": { + "plugins": [ + "com.huawei.agconnect", + "com.hihonor.mcs.asplugin" + ], + "dependencies": [ + "com.huawei.agconnect:agcp:1.9.1.301", + "com.google.gms:google-services:4.3.15", + "com.hihonor.mcs:asplugin:2.0.1.300" + ] + } +} \ No newline at end of file diff --git a/uni_modules/TencentCloud-Push/utssdk/app-android/index.uts b/uni_modules/TencentCloud-Push/utssdk/app-android/index.uts new file mode 100644 index 00000000..ebba8512 --- /dev/null +++ b/uni_modules/TencentCloud-Push/utssdk/app-android/index.uts @@ -0,0 +1,152 @@ +import { UTSAndroid } from 'io.dcloud.uts'; +import Context from 'android.content.Context'; +import TIMPushManager from 'com.tencent.qcloud.tim.push.TIMPushManager'; +import TIMPushConfig from 'com.tencent.qcloud.tim.push.config.TIMPushConfig'; +import { PushCallbackOptions } from './push-callback-options.uts'; +import { PushListenerOptions } from './push-listener-options.uts'; +import PushCallback from './push-callback.uts'; +import PushListener from './push-listener.uts'; + +const context: Context | null = UTSAndroid.getAppContext(); +console.warn('Push | package.name:', context?.getPackageName()); +TIMPushConfig.getInstance().setRunningPlatform(2); +const Push = TIMPushManager.getInstance(); + +export class EVENT { + static MESSAGE_RECEIVED: string = 'message_received' + static MESSAGE_REVOKED: string = 'message_revoked' + static NOTIFICATION_CLICKED: string = 'notification_clicked' +} + +let disableNotification = false; +export function disablePostNotificationInForeground(disable: boolean): void { + console.log('Push | disablePostNotificationInForeground', disable); + disableNotification = disable; + Push.disablePostNotificationInForeground(disableNotification); +} + +export function registerPush(SDKAppID: number, appKey: string, onSuccess: (data: string) => void, onError?: (errCode: number, errMsg: string) => void): void { + if (SDKAppID == 0) { + onError?.(9010001, 'Invalid SDKAppID'); + } else if (appKey == '') { + onError?.(9010002, 'Invalid appKey'); + } + const pushCbOptions: PushCallbackOptions = { + apiName: 'registerPush', + success: (res?: any) => { + Push.disablePostNotificationInForeground(disableNotification); + // 强转下类型,避免类型推断错误 + let token: string = res as string; + onSuccess(token); + }, + fail: (errCode: number, errMsg: string) => { + onError?.(errCode, errMsg); + } + }; + // 注意!!! 这里不要写成 new PushCallback({ api, success, fail }),否则会因类型推断不一致导致编译错误 + Push.registerPush(context, SDKAppID.toInt(), appKey, new PushCallback(pushCbOptions)); +} + +export function setRegistrationID(registrationID: string, onSuccess: () => void): void { + const pushCbOptions: PushCallbackOptions = { + apiName: 'setRegistrationID', + success: (res?: any) => { + onSuccess(); + }, + fail: (errCode: number, errMsg: string) => { + // 空实现 + } + }; + // 注意!!! 这里不要写成 new PushCallback({ api, success, fail }),否则会因类型推断不一致导致编译错误 + Push.setRegistrationID(registrationID, new PushCallback(pushCbOptions)); +} + +export function getRegistrationID(onSuccess: (registrationID: string) => void): void { + const pushCbOptions: PushCallbackOptions = { + apiName: 'getRegistrationID', + success: (res?: any) => { + // 强转下类型,避免类型推断错误 + let registrationID: string = res as string; + onSuccess(registrationID); + }, + fail: (errCode: number, errMsg: string) => { + // 空实现 + } + }; + // 注意!!! 这里不要写成 new PushCallback({ api, success, fail }),否则会因类型推断不一致导致编译错误 + Push.getRegistrationID(new PushCallback(pushCbOptions)); +} + +export function unRegisterPush(onSuccess: () => void, onError?: (errCode: number, errMsg: string) => void): void { + const pushCbOptions: PushCallbackOptions = { + apiName: 'unRegisterPush', + success: (res?: any) => { + onSuccess(); + }, + fail: (errCode: number, errMsg: string) => { + // 空实现 + }, + }; + // 注意!!! 这里不要写成 new PushCallback({ api, success, fail }),否则会因类型推断不一致导致编译错误 + Push.unRegisterPush(new PushCallback(pushCbOptions)); +} + +export function createNotificationChannel(options: any, onSuccess: (extInfo: string) => void): void { + const pushCbOptions: PushCallbackOptions = { + apiName: 'createNotificationChannel', + success: (res?: any) => { + let ret: string = res as string; + onSuccess(ret); + }, + fail: (errCode: number, errMsg: string) => { + // 空实现 + }, + }; + Push.callExperimentalAPI('createNotificationChannel', JSON.stringify(options), new PushCallback(pushCbOptions)); +} + +export function getNotificationExtInfo(onSuccess: (extInfo: string) => void): void { + const pushCbOptions: PushCallbackOptions = { + apiName: 'getNotificationExtInfo', + success: (res?: any) => { + let ret: string = res as string; + onSuccess(ret); + }, + fail: (errCode: number, errMsg: string) => { + // 空实现 + }, + }; + Push.callExperimentalAPI('getNotificationExtInfo', null, new PushCallback(pushCbOptions)); +} + +const listenerMap = new Map void>>(); + +const pushListenerOptions: PushListenerOptions = { + listener: (eventName: string, data: any) => { + listenerMap.get(eventName)?.forEach(item => { + item(data); + }); + }, +}; + +const pushListener = new PushListener(pushListenerOptions); + +@UTSJS.keepAlive +export function addPushListener(eventName: string, listener: (res: any) => void): void { + if(listenerMap.size === 0) { + Push.addPushListener(pushListener); + } + const listeners:Array<(res: any) => void> = [listener]; + listenerMap.get(eventName)?.forEach(item => { + listeners.push(item); + }) + listenerMap.set(eventName, listeners); +} + + +export function removePushListener(eventName: string, listener?: (res: any) => void): void { + listenerMap.delete(eventName); + if(listenerMap.size === 0) { + Push.removePushListener(pushListener); + } +} diff --git a/uni_modules/TencentCloud-Push/utssdk/app-android/push-callback-options.uts b/uni_modules/TencentCloud-Push/utssdk/app-android/push-callback-options.uts new file mode 100644 index 00000000..ab6f7bf1 --- /dev/null +++ b/uni_modules/TencentCloud-Push/utssdk/app-android/push-callback-options.uts @@ -0,0 +1,5 @@ +export type PushCallbackOptions = { + apiName: string + success: (res?: any) => void + fail: (errCode: number, errMsg: string) => void +} diff --git a/uni_modules/TencentCloud-Push/utssdk/app-android/push-callback.uts b/uni_modules/TencentCloud-Push/utssdk/app-android/push-callback.uts new file mode 100644 index 00000000..32c9f572 --- /dev/null +++ b/uni_modules/TencentCloud-Push/utssdk/app-android/push-callback.uts @@ -0,0 +1,28 @@ +import TIMPushCallback from 'com.tencent.qcloud.tim.push.TIMPushCallback'; +import { PushCallbackOptions } from './push-callback-options.uts'; + +const LOG_PREFIX: string = 'Push |'; +export default class PushCallback implements TIMPushCallback { + private apiName: string; + private success: (data?: any) => void; + private fail: (errCode: number, errMsg: string) => void; + + constructor(options: PushCallbackOptions) { + this.apiName = options.apiName; + this.success = options.success; + this.fail = options.fail; + } + + override onSuccess(data?: any) { + console.log(`${LOG_PREFIX} ${this.apiName} ok, data:`, data); + if (data == null) { + this.success?.(''); + } else { + this.success?.(data); + } + } + + override onError(errCode: Int, errMsg: string, data?: any) { + this.fail?.(errCode as number, errMsg); + } +} \ No newline at end of file diff --git a/uni_modules/TencentCloud-Push/utssdk/app-android/push-listener-options.uts b/uni_modules/TencentCloud-Push/utssdk/app-android/push-listener-options.uts new file mode 100644 index 00000000..a155ba25 --- /dev/null +++ b/uni_modules/TencentCloud-Push/utssdk/app-android/push-listener-options.uts @@ -0,0 +1,3 @@ +export type PushListenerOptions = { + listener: (eventType: string, data: any) => void +} diff --git a/uni_modules/TencentCloud-Push/utssdk/app-android/push-listener.uts b/uni_modules/TencentCloud-Push/utssdk/app-android/push-listener.uts new file mode 100644 index 00000000..5c39c248 --- /dev/null +++ b/uni_modules/TencentCloud-Push/utssdk/app-android/push-listener.uts @@ -0,0 +1,25 @@ +import TIMPushListener from 'com.tencent.qcloud.tim.push.TIMPushListener'; +import TIMPushMessage from 'com.tencent.qcloud.tim.push.TIMPushMessage'; +import { PushListenerOptions } from './push-listener-options.uts'; + +const LOG_PREFIX: string = 'Push | PushListener'; +export default class PushListener implements TIMPushListener { + private listener: (eventType: string, data: any) => void; + + constructor(options: PushListenerOptions) { + this.listener = options.listener; + console.log(`${LOG_PREFIX} ok`); + } + + override onRecvPushMessage(message: TIMPushMessage) { + this.listener('message_received', { data: message }); + } + + override onRevokePushMessage(messageID: string) { + this.listener('message_revoked', { data: messageID }); + } + + override onNotificationClicked(ext: string) { + this.listener('notification_clicked', { data: ext }); + } +} \ No newline at end of file diff --git a/uni_modules/TencentCloud-Push/utssdk/app-ios/UTS.entitlements b/uni_modules/TencentCloud-Push/utssdk/app-ios/UTS.entitlements new file mode 100644 index 00000000..903def2a --- /dev/null +++ b/uni_modules/TencentCloud-Push/utssdk/app-ios/UTS.entitlements @@ -0,0 +1,8 @@ + + + + + aps-environment + development + + diff --git a/uni_modules/TencentCloud-Push/utssdk/app-ios/config.json b/uni_modules/TencentCloud-Push/utssdk/app-ios/config.json new file mode 100644 index 00000000..f4b471db --- /dev/null +++ b/uni_modules/TencentCloud-Push/utssdk/app-ios/config.json @@ -0,0 +1,11 @@ +{ + "deploymentTarget": "9.0", + "dependencies-pods": [ + { + "name": "TXIMSDK_Plus_iOS_XCFramework", + "version": "8.5.6864" + }, { + "name": "TIMPush", + "version": "8.5.6864" + }] +} diff --git a/uni_modules/TencentCloud-Push/utssdk/app-ios/index.uts b/uni_modules/TencentCloud-Push/utssdk/app-ios/index.uts new file mode 100644 index 00000000..0d58ad2f --- /dev/null +++ b/uni_modules/TencentCloud-Push/utssdk/app-ios/index.uts @@ -0,0 +1,125 @@ +import { TIMPushManager } from "TIMPush" +import { NSObject } from "DCloudUTSFoundation" +import PushListener from './push-listener.uts' +import { PushListenerOptions } from './push-listener-options.uts' + +const LOG_PREFIX = 'Push |'; + +export class EVENT { + static MESSAGE_RECEIVED: string = 'message_received' + static MESSAGE_REVOKED: string = 'message_revoked' + static NOTIFICATION_CLICKED: string = 'notification_clicked' +} + +function setRunningPlatform(): void { + console.log(LOG_PREFIX, 'setRunningPlatform'); + const param = new NSString("{\"runningPlatform\":2}"); + TIMPushManager.callExperimentalAPI('setPushConfig', param = param, succ = (ext?: NSObject): void => { + let platform: string = ext as string; + console.log(LOG_PREFIX, 'setRunningPlatform ok. platform:', platform); + }, fail = (code?: Int32 ,desc?:String): void => { + console.log(LOG_PREFIX, `setRunningPlatform fail. code: ${code}, desc: ${desc}`); + } + ); +} + +let disableNotification = false; + +export function disablePostNotificationInForeground(_disable: boolean): void { + console.log(LOG_PREFIX, 'disablePostNotificationInForeground', _disable); + disableNotification = _disable; + TIMPushManager.disablePostNotificationInForeground(disable = disableNotification); +} + +export function registerPush(SDKAppID: number, appKey: string, onSuccess: (data: string) => void, onError?: (errCode: number, errMsg: string) => void): void { + if (SDKAppID == 0) { + onError?.(9010001, 'Invalid SDKAppID'); + } else if (appKey == '') { + onError?.(9010002, 'Invalid appKey'); + } + setRunningPlatform(); + TIMPushManager.registerPush(SDKAppID.toInt32(), appKey = appKey, succ = (deviceToken?: Data): void => { + TIMPushManager.disablePostNotificationInForeground(disable = disableNotification); + console.log('devicetoken ->', deviceToken, deviceToken?.count); + onSuccess(''); + }, fail = (code?: Int32 ,desc?:String): void => { + onError?.(code as number, desc as string); + } + ); +} + +export function unRegisterPush(onSuccess: () => void, onError: (errCode: number, errMsg: string) => void): void { + TIMPushManager.unRegisterPush((): void => { + onSuccess(); + }, fail = (code?: Int32 ,desc?:String): void => { + onError(code as number, desc as string); + } + ); +} + +export function setRegistrationID(registrationID: string, onSuccess: () => void): void { + console.log(LOG_PREFIX, 'setRegistrationID', `registrationID:${registrationID}`); + TIMPushManager.setRegistrationID(registrationID, callback = (): void => { + console.log(LOG_PREFIX, 'setRegistrationID ok'); + onSuccess(); + }); +} + +export function getRegistrationID(onSuccess: (registrationID: string) => void): void { + TIMPushManager.getRegistrationID((value ?: string): void => { + // 这里需要转一下,否则会有问题 + let ret: string = value as string; + onSuccess(ret); + }); +} + +export function createNotificationChannel(options: any, onSuccess: (data: string) => void): void { + // 空实现 +} + +// 注意!!!这里的 extInfo 不能写成 ext,否则会跟内部的 ext?:NSObject 有冲突;也不能写成 extension,否则会导致编译错误 +export function getNotificationExtInfo(onSuccess: (extInfo: string) => void): void { + console.log(LOG_PREFIX, 'getNotificationExtInfo'); + TIMPushManager.callExperimentalAPI('getNotificationExtInfo', param = {}, succ = (ext?: NSObject): void => { + let str: string = ext as string; + console.log(LOG_PREFIX, 'getNotificationExtInfo ok. ext:', str); + onSuccess(str); + }, fail = (code?: Int32 ,desc?:String): void => { + // 空实现 + } + ); +} + + +const listenerMap = new Map void>>(); + +const pushListenerOptions: PushListenerOptions = { + listener: (eventName: string, data: any) => { + listenerMap.get(eventName)?.forEach(item => { + item(data); + }); + }, +}; + +const pushListener = new PushListener(pushListenerOptions); + +@UTSJS.keepAlive +export function addPushListener(eventName: string, _listener: (res: any) => void): void { + console.log(LOG_PREFIX, 'addPushListener', eventName); + if(listenerMap.size === 0) { + TIMPushManager.addPushListener(listener = pushListener); + } + const listeners:Array<(res: any) => void> = [_listener]; + listenerMap.get(eventName)?.forEach(item => { + listeners.push(item); + }) + listenerMap.set(eventName, listeners); +} + +export function removePushListener(eventName: string, _listener?: (res: any) => void): void { + console.log(LOG_PREFIX, 'removePushListener', eventName); + listenerMap.delete(eventName); + if(listenerMap.size === 0) { + TIMPushManager.removePushListener(listener = pushListener); + } +} \ No newline at end of file diff --git a/uni_modules/TencentCloud-Push/utssdk/app-ios/push-listener-options.uts b/uni_modules/TencentCloud-Push/utssdk/app-ios/push-listener-options.uts new file mode 100644 index 00000000..db8c8ffa --- /dev/null +++ b/uni_modules/TencentCloud-Push/utssdk/app-ios/push-listener-options.uts @@ -0,0 +1,3 @@ +export type PushListenerOptions = { + listener: (eventType: string, data: any) => void +} diff --git a/uni_modules/TencentCloud-Push/utssdk/app-ios/push-listener.uts b/uni_modules/TencentCloud-Push/utssdk/app-ios/push-listener.uts new file mode 100644 index 00000000..5e87c347 --- /dev/null +++ b/uni_modules/TencentCloud-Push/utssdk/app-ios/push-listener.uts @@ -0,0 +1,24 @@ +import { TIMPushListener, TIMPushMessage} from "TIMPush" +import { PushListenerOptions } from './push-listener-options.uts'; + +const LOG_PREFIX: string = 'Push | PushListener'; +export default class PushListener implements TIMPushListener { + private listener: (eventType: string, data: any) => void; + + constructor(options: PushListenerOptions) { + this.listener = options.listener; + console.log(`${LOG_PREFIX} ok`); + } + + onRecvPushMessage(message: TIMPushMessage) { + this.listener('message_received', { data: message }); + } + + onRevokePushMessage(messageID: string) { + this.listener('message_revoked', { data: messageID }); + } + + onNotificationClicked(ext: string) { + this.listener('notification_clicked', { data: ext }); + } +} \ No newline at end of file diff --git a/uni_modules/TencentCloud-Push/utssdk/interface.uts b/uni_modules/TencentCloud-Push/utssdk/interface.uts new file mode 100644 index 00000000..ecf8da4b --- /dev/null +++ b/uni_modules/TencentCloud-Push/utssdk/interface.uts @@ -0,0 +1,11 @@ +interface Push { + setRegistrationID(registrationID: string, onSuccess: () => void): void, + registerPush(SDKAppID: number, appKey: string, onSuccess: (data: string) => void, onError?: (errCode: number, errMsg: string) => void): void, + getRegistrationID(onSuccess: (registrationID: string) => void): void, + unRegisterPush(onSuccess: () => void, onError?: (errCode: number, errMsg: string) => void): void, + getNotificationExtInfo(onSuccess: (extInfo: string) => void): void + addPushListener(eventName: string, listener: (res: any) => void): void + removePushListener(eventName: string, listener?: (res: any) => void): void + disablePostNotificationInForeground(disable: boolean): void + createNotificationChannel(options: any, onSuccess: (data: string) => void): void +} diff --git a/utils/request.js b/utils/request.js index 0e86b214..4c51c601 100644 --- a/utils/request.js +++ b/utils/request.js @@ -26,13 +26,13 @@ function cleanStorage() { storage.setRefreshToken(""); console.log("清空token"); storage.setUuid(""); - storage.setUserInfo({}); - // 清理vlog信息 - storage.setVlogToken("") - storage.setVlogUserInfo({}) - // 清除初始化数据内容 + storage.setUserInfo({}); + // 清理vlog信息 + storage.setVlogToken("") + storage.setVlogUserInfo(null) + // 清除初始化数据内容 storage.setRefreshVlogIndex('0') //不需要刷新 - + // 防抖处理跳转 // #ifdef MP-WEIXIN @@ -96,23 +96,23 @@ http.interceptors.request.use( config.header.accessToken = accessToken; } - // 配置vlog所需参数 - let vlogToken = storage.getVlogToken(); - let vlogId = storage.getVlogUserInfo(); - // console.log(vlogId) - // console.log(vlogToken) - if(vlogToken){ - config.header.headerUserToken = vlogToken; - config.header.headerUserId = vlogId.id; + // 配置vlog所需参数 + let vlogToken = storage.getVlogToken(); + let vlogId = storage.getVlogUserInfo(); + // console.log(vlogId) + // console.log(vlogToken) + if (vlogToken) { + config.header.headerUserToken = vlogToken; + config.header.headerUserId = vlogId.id; } config.header = { ...config.header, uuid: storage.getUuid() || uuid.v1(), - }; + }; // console.log(config) return config; }, - (config) => { + (config) => { return Promise.reject(config); } ); @@ -124,8 +124,8 @@ let isRefreshing = false; let requests = []; // 必须使用异步函数,注意 http.interceptors.response.use( - async (response) => { - // console.log(isRefreshing) + async (response) => { + // console.log(isRefreshing) // console.log(response) /* 请求之后拦截器。可以使用async await 做异步操作 */ // token存在并且token过期 @@ -194,9 +194,8 @@ http.interceptors.response.use( duration: 1500, }); } - } - else if (response.data.code==502){ - cleanStorage(); + } else if (response.data.code == 502) { + cleanStorage(); } return response; }, diff --git a/utils/tools.js b/utils/tools.js index 5b254718..06497172 100644 --- a/utils/tools.js +++ b/utils/tools.js @@ -95,16 +95,28 @@ const theNextDayTime = () => { }; const graceNumber = (number) => { + // if (number == 0) { + // return "0"; + // } else if (number > 999 && number <= 9999) { + // return (number / 1000).toFixed(1) + "k"; + // } else if (number > 9999 && number <= 99999) { + // return (number / 10000).toFixed(1) + "w"; + // } else if (number > 99999) { + // return "10w+"; + // } + // return number; if (number == 0) { return "0"; - } else if (number > 999 && number <= 9999) { - return (number / 1000).toFixed(1) + "k"; - } else if (number > 9999 && number <= 99999) { - return (number / 10000).toFixed(1) + "w"; - } else if (number > 99999) { - return "10w+"; } - return number; + if (number < 1000) { + return number.toString(); + } else if (number < 10000) { + return (number / 1000).toFixed(1).replace(/\.0$/, '') + "k"; + } else if (number < 100000000) { + return (number / 10000).toFixed(1).replace(/\.0$/, '') + "w"; + } else { + return (number / 100000000).toFixed(1).replace(/\.0$/, '') + "亿+"; + } } // 时间格式化时间为: 多少分钟前、多少天前 @@ -237,6 +249,6 @@ export { getDateBeforeNow, isStrEmpty, getAstro, - getAnimal, + getAnimal, dateFormat }; \ No newline at end of file diff --git a/vue.config.js b/vue.config.js index 0b0be2f1..7f91f533 100644 --- a/vue.config.js +++ b/vue.config.js @@ -1,35 +1,35 @@ -// const ScriptSetup = require('unplugin-vue2-script-setup/webpack').default; - -module.exports = { - parallel: false, - configureWebpack: { - plugins: [ - // ScriptSetup({ - // /* options */ - // }), - ], - }, - chainWebpack(config) { - // disable type check and let `vue-tsc` handles it - config.plugins.delete('fork-ts-checker'); - }, -}; -// module.exports = { -// /** -// * 此处为发行h5,微信小程序,app中删除console -// * 如需显示console 需要注释此处重新运行 -// */ -// chainWebpack: (config) => { -// // 发行或运行时启用了压缩时会生效 -// config.optimization.minimizer('terser').tap((args) => { -// const compress = args[0].terserOptions.compress -// // 非 App 平台移除 console 代码(包含所有 console 方法,如 log,debug,info...) -// compress.drop_console = true -// compress.pure_funcs = [ -// '__f__', // App 平台 vue 移除日志代码 -// // 'console.debug' // 可移除指定的 console 方法 -// ] -// return args -// }) -// } +const ScriptSetup = require('unplugin-vue2-script-setup/webpack').default; + +module.exports = { + parallel: false, + configureWebpack: { + plugins: [ + ScriptSetup({ + /* options */ + }), + ], + }, + chainWebpack(config) { + // disable type check and let `vue-tsc` handles it + config.plugins.delete('fork-ts-checker'); + }, +}; +// module.exports = { +// /** +// * 此处为发行h5,微信小程序,app中删除console +// * 如需显示console 需要注释此处重新运行 +// */ +// chainWebpack: (config) => { +// // 发行或运行时启用了压缩时会生效 +// config.optimization.minimizer('terser').tap((args) => { +// const compress = args[0].terserOptions.compress +// // 非 App 平台移除 console 代码(包含所有 console 方法,如 log,debug,info...) +// compress.drop_console = true +// compress.pure_funcs = [ +// '__f__', // App 平台 vue 移除日志代码 +// // 'console.debug' // 可移除指定的 console 方法 +// ] +// return args +// }) +// } // } \ No newline at end of file