+
-
-
\ No newline at end of file
+ }
+ }
+
+ if (me.curIndex == 0) {
+ me.playLocalStatus = true;
+ }
+ if (me.curIndex == 1) {
+ me.playFollowStatus = true;
+ }
+ if (me.curIndex == 2) {
+ me.playStatus = true;
+ }
+ },
+ onHide() {
+ var me = this;
+ // 显示和隐藏,需要判断根据不同tab做暂停或者隐藏
+ if (me.curIndex == 0) {
+ me.playLocalStatus = false;
+ me.isDraw_lo = false;
+ }
+ if (me.curIndex == 1) {
+ me.playFollowStatus = false;
+ me.isDraw_gz = false;
+ }
+ if (me.curIndex == 2) {
+ me.playStatus = false;
+ me.isDraw_tj = false;
+ }
+ },
+
+ // 当前页下拉刷新
+ // onPullDownRefresh() {
+ // var me = this;
+ // // 下拉刷新判断,如果是不同tab,那么组件中刷新的请求也不同
+ // if (me.curIndex == 0) {
+ // this.$refs.videoFollowComp.displayVideoPaging(1, true);
+ // } else if (me.curIndex == 1) {
+ // this.$refs.videoComp.displayVideoPaging(1, true);
+ // }
+
+ // },
+ methods: {
+ getLocation() {
+ uni.getLocation({
+ type: 'wg84',
+ success: (res) => {
+ console.log(res);
+ var latitude = res.latitude;
+ var longitude = res.longitude;
+ var location = latitude + ',' + longitude;
+ var key = config.aMapKey;
+ uni.request({
+ url: 'https://apis.map.qq.com/ws/geocoder/v1/',
+ method: 'GET',
+ data: {
+ location,
+ key
+ },
+ success: (address) => {
+ console.log(address);
+ var ad_info = address.data.result.ad_info;
+ var cityCode = ad_info.adcode; // 城市编码cityCode
+ storage.setCityCode(cityCode);
+ this.cityCode = cityCode;
+ var address_name = ad_info.district || ad_info.city;
+ this.tabList.forEach((i, index) => {
+ if (index == 0) {
+ i.name = address_name;
+ // this.selectorQuery();
+ var timer = setTimeout(() => {
+ this.selectorQuery();
+ clearTimeout(timer);
+ }, 300);
+ }
+ });
+ }
+ });
+ },
+ fail: (err) => {
+ console.log(err);
+ uni.showToast({
+ icon: 'none',
+ title: '获取位置信息失败'
+ });
+ // uni.showModal({
+ // title:'提示',
+ // content:'获取位置信息失败',
+ // showCancel:false,
+ // success: (res) => {
+ // if(res.confirm){
+ // }
+ // }
+ // })
+ }
+ });
+ },
+
+ // 前往搜索页面
+ goSearch() {
+ uni.navigateTo({
+ url: '/pages/search/search'
+ });
+ },
+ // ----------头部区域点击tabs
+ ontabtap(e) {
+ console.log(e);
+ let index = e.target.dataset.current || e.currentTarget.dataset.current;
+ this.isTap = true;
+ var currentSize = this.tabListSize[index];
+
+ this.updateIndicator(currentSize.left, currentSize.width);
+ this._touchTabIndex = index;
+ this.switchTab(index);
+ },
+ //
+ selectorQuery() {
+ var dm = uni.createSelectorQuery().in(this);
+ dm.select('#head')
+ .boundingClientRect()
+ .exec((rect) => {
+ this._headHeight = rect[0].height;
+ });
+
+ // 查询 tabbar 宽度
+ dm.in(this)
+ .select('#tab-bar')
+ .boundingClientRect()
+ .exec((rect) => {
+ this.tabbarWidth = rect[0].width;
+ console.log(this.tabbarWidth);
+ });
+ // 查询 tabview 宽度
+ dm.in(this)
+ .select('#tab-bar-view')
+ .boundingClientRect()
+ .exec((rect) => {
+ this.swiperWidth = rect[0].width;
+ console.log(this.swiperWidth);
+ });
+
+ // 因 nvue 暂不支持 class 查询
+ // var queryTabSize = uni.createSelectorQuery().in(this);
+ var queryTabSize = dm;
+ for (var i = 0; i < this.tabList.length; i++) {
+ queryTabSize.select('#' + this.tabList[i].id).boundingClientRect();
+ }
+ queryTabSize.exec((rects) => {
+ rects.forEach((rect) => {
+ rect.left = rect.left - 40; //修正 left 值,减去 padding-left: 40px
+ this.tabListSize[rect.dataset.id] = rect;
+ });
+ console.log(this.tabListSize[this.tabIndex]);
+ this.updateIndicator(this.tabListSize[this.tabIndex].left, this.tabListSize[this.tabIndex].width);
+ this.switchTab(this.tabIndex);
+ });
+ },
+
+ onswiperscroll(e) {
+ this.isDraw_gz = false;
+ this.isDraw_lo = false;
+ this.isDraw_tj = false;
+ // if (this.playStatus == true) {
+ // this.playStatus = this._lastTabIndex == 2 ? false : true;
+ // }
+
+ // this.playFollowStatus = this._lastTabIndex == 1 ? false : true;
+ // this.playLocalStatus = this._lastTabIndex == 0 ? false : true;
+
+ var offsetX = e.detail.dx;
+ var preloadIndex = this._lastTabIndex;
+ if (offsetX > TAB_PRELOAD_OFFSET) {
+ preloadIndex++;
+ } else if (offsetX < -TAB_PRELOAD_OFFSET) {
+ preloadIndex--;
+ }
+ let prop = this.pageList[preloadIndex];
+ let obj = this.$refs[prop];
+ if (!obj) return;
+ // 点击切换
+ if (this.isTap) {
+ return;
+ }
+ // 切换失败
+ if (preloadIndex === this._lastTabIndex || preloadIndex < 0 || preloadIndex > this.pageList.length - 1) {
+ // 是否有视频数据
+ if (obj.playerList.length === 0) {
+ // this.loadTabData(preloadIndex);
+ 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;
+ }
+ return;
+ }
+
+ // console.log(this.tabListSize)
+ var percentage = Math.abs(this.swiperWidth / offsetX);
+ var currentSize = this.tabListSize[this._lastTabIndex];
+ var preloadSize = this.tabListSize[preloadIndex];
+ var lineL = currentSize.left + (preloadSize.left - currentSize.left) / percentage;
+ var lineW = currentSize.width + (preloadSize.width - currentSize.width) / percentage;
+ this.updateIndicator(lineL, lineW);
+ },
+ animationfinish(e) {
+ let index = e.detail.current;
+ console.log('当前索引' + index);
+ console.log('之前的索引' + this._lastTabIndex);
+ this._lastTabIndex = index;
+ if (this._touchTabIndex === index) {
+ this.isTap = false;
+ }
+ this.switchTab(index);
+ if (!this.tabListSize[index]) {
+ return;
+ } else {
+ // this.playStatus = index == 2 ? false : true;
+ // this.playFollowStatus = index == 1 ? true : false;
+ // this.playLocalStatus = index == 0 ? true : false;
+ this.isDraw_gz = index == 1 ? true : false;
+ this.isDraw_lo = index == 0 ? true : false;
+ this.isDraw_tj = index == 2 ? true : false;
+
+ this.updateIndicator(this.tabListSize[index].left, this.tabListSize[index].width);
+ }
+ },
+ updateIndicator(left, width) {
+ // console.log(left)
+ this.indicatorLineLeft = left;
+ this.indicatorLineWidth = width;
+ },
+
+ switchTab(index) {
+ if (this.tabIndex === index) {
+ return;
+ }
+ // console.dir(this.$refs)
+ let props = this.pageList[index];
+ console.log(props);
+ console.log(index);
+ let obj = this.$refs[props];
+ // if (obj.playerList.length === 0) {
+ // var info = storage.getVlogUserInfo() || null
+ // if(info!=null&&index==0){
+ // obj.displayVideoPaging(this.page + 1, true);
+ // }
+ // }
+
+ obj.setScrollRef(this._headHeight);
+
+ console.log(this.cacheTab);
+ // 缓存 tabId
+ if (obj.playerList.length > MAX_CACHE_DATA) {
+ let isExist = this.cacheTab.indexOf(this.tabIndex);
+ if (isExist < 0) {
+ this.cacheTab.push(this.tabIndex);
+ }
+ }
+ this.tabIndex = index;
+ this.curIndex = index;
+ this.scrollTabTo(index);
+ this.scrollInto = this.tabList[index].id;
+
+ // 释放 tabId
+ if (this.cacheTab.length > MAX_CACHE_PAGE) {
+ let cacheIndex = this.cacheTab[0];
+ this.clearTabData(cacheIndex);
+ this.cacheTab.splice(0, 1);
+ }
+ // const el = this.$refs['tabitem' + index][0];
+ // animation.transition(el, {
+ // duration: 3000, //ms
+ // timingFunction: 'ease',
+ // delay: 1000 //ms
+ // });
+ },
+ scrollTabTo(index) {
+ console.log(index);
+ const el = this.$refs['tabitem' + index][0];
+ let offset = 0;
+ // TODO fix ios offset
+ if (index > 0) {
+ offset = this.tabbarWidth / 2 - this.tabListSize[index].width / 2;
+ if (this.tabListSize[index].right < this.tabbarWidth / 2) {
+ offset = this.tabListSize[0].width;
+ }
+ }
+ dom.scrollToElement(el, {
+ offset: -offset
+ });
+ },
+
+ //----------------------------
+
+ // 左滑右滑选项卡改变选中状态
+ changeTopTab: function (e) {
+ var current = e.detail.current;
+ this.curIndex = current;
+ this.tabIndex = current;
+ let timer = setTimeout(() => {
+ this.playLocalStatus = this.curIndex === 0 ? true : false;
+ this.playFollowStatus = this.curIndex === 1 ? true : false;
+ this.playStatus = this.curIndex === 2 ? true : false;
+ clearTimeout(timer);
+ }, 10);
+ },
+
+ // 下拉刷新,改变head的字样显示
+ showLoading() {
+ this.isLoading = true;
+ },
+ hideLoading() {
+ this.isLoading = false;
+ },
+ letFollowVideoPause() {
+ this.playFollowStatus = false;
+ }
+ }
+};
+
+
+
diff --git a/static/images/playvd.png b/static/images/playvd.png
new file mode 100644
index 00000000..4dba79b4
Binary files /dev/null and b/static/images/playvd.png differ
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/pages/me/vlogerInfo.vue b/uni_modules/TencentCloud-Push/index.js
old mode 100755
new mode 100644
similarity index 100%
rename from pages/me/vlogerInfo.vue
rename to uni_modules/TencentCloud-Push/index.js
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) ,单击创建应用,填写应用名称,选择数据中心,单击确定,完成应用创建。
+
+
+
+### 步骤2:开通推送服务 Push
+
+进入 [推送服务 Push](https://console.cloud.tencent.com/im/push-plugin-push-identifier),单击立即购买或免费试用 。(每个应用可免费试用一次,有效期7天)
+
+
+
+### 步骤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 - 接入设置页面 获取的应用的信息。如图所示:
+
+
+
+```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://console.cloud.tencent.com/im/push-plugin-push-check) 控制台,使用测试工具进行在线推送测试。
+
+
+## 厂商推送配置
+> - 请注意!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) ,单击创建应用,填写应用名称,选择数据中心,单击确定,完成应用创建。
+
+
+
+### 步骤2:开通推送服务 Push
+
+进入 [推送服务 Push](https://console.cloud.tencent.com/im/push-plugin-push-identifier),单击立即购买或免费试用 。(每个应用可免费试用一次,有效期7天)
+
+
+
+### 步骤3:将 [uni-app 腾讯云推送服务(Push)](https://ext.dcloud.net.cn/plugin?id=20169)插件导入 HbuilderX 中的工程。如图所示:
+
+
+
+
+
+### 步骤4:在 App.vue 中引入并注册腾讯云推送服务(Push)
+
+将 SDKAppID 和 appKey 替换为您在IM 控制台 - 推送服务 Push - 接入设置页面 获取的应用的信息。如图所示:
+
+
+
+```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://console.cloud.tencent.com/im/push-plugin-push-check) 控制台,使用测试工具进行在线推送测试。
+
+
+
+## 厂商推送配置
+
+> - 请注意!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 db0f2ad5..f3040e90 100644
--- a/utils/request.js
+++ b/utils/request.js
@@ -17,17 +17,20 @@ function cleanStorage() {
uni.hideLoading();
}
- storage.setHasLogin(false);
- storage.setAccessToken("");
- storage.setRefreshToken("");
- console.log("清空token");
- storage.setUuid("");
- storage.setUserInfo({});
- // 清理vlog信息
- storage.setVlogToken("");
- storage.setVlogUserInfo({});
- // 清除初始化数据内容
- storage.setRefreshVlogIndex("0"); //不需要刷新
+ storage.setHasLogin(false);
+ storage.setAccessToken("");
+ storage.setRefreshToken("");
+ console.log("清空token");
+ storage.setUuid("");
+ storage.setUserInfo({});
+ // 清理vlog信息
+ storage.setVlogToken("")
+ storage.setVlogUserInfo(null)
+ // 清除初始化数据内容
+ storage.setRefreshVlogIndex('0') //不需要刷新
+
+ // 防抖处理跳转
+ // #ifdef MP-WEIXIN
// 防抖处理跳转
// #ifdef MP-WEIXIN
@@ -94,28 +97,29 @@ http.interceptors.request.use(
..._params,
};
- config.params = params;
- 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;
- }
- config.header = {
- ...config.header,
- uuid: storage.getUuid() || uuid.v1(),
- };
- // console.log(config)
- return config;
- },
- (config) => {
- return Promise.reject(config);
- }
+ config.params = params;
+ 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;
+ }
+ config.header = {
+ ...config.header,
+ uuid: storage.getUuid() || uuid.v1(),
+ };
+ // console.log(config)
+ return config;
+ },
+ (config) => {
+ return Promise.reject(config);
+ }
);
// 是否正在刷新的标记
@@ -124,15 +128,15 @@ let isRefreshing = false;
let requests = [];
// 必须使用异步函数,注意
http.interceptors.response.use(
- async (response) => {
- // console.log(isRefreshing)
- // console.log(response)
- /* 请求之后拦截器。可以使用async await 做异步操作 */
- // token存在并且token过期
- if (isRefreshing && response.statusCode === 403) {
- cleanStorage();
- isRefreshing = false;
- }
+ async (response) => {
+ // console.log(isRefreshing)
+ // console.log(response)
+ /* 请求之后拦截器。可以使用async await 做异步操作 */
+ // token存在并且token过期
+ if (isRefreshing && response.statusCode === 403) {
+ cleanStorage();
+ isRefreshing = false;
+ }
let token = storage.getAccessToken();
if (
@@ -179,26 +183,26 @@ http.interceptors.response.use(
) {
cleanStorage();
- // 如果当前状态码为正常但是success为不正常时
- } else if (
- (response.statusCode == 200 && !response.data.success) ||
- response.statusCode == 400
- ) {
- if (response.data.message) {
- uni.showToast({
- title: response.data.message,
- icon: "none",
- duration: 1500,
- });
- }
- } else if (response.data.code == 502) {
- cleanStorage();
- }
- return response;
- },
- (error) => {
- return error;
- }
+ // 如果当前状态码为正常但是success为不正常时
+ } else if (
+ (response.statusCode == 200 && !response.data.success) ||
+ response.statusCode == 400
+ ) {
+ if (response.data.message) {
+ uni.showToast({
+ title: response.data.message,
+ icon: "none",
+ duration: 1500,
+ });
+ }
+ } else if (response.data.code == 502) {
+ cleanStorage();
+ }
+ return response;
+ },
+ (error) => {
+ return error;
+ }
);
export { http };
diff --git a/utils/storage.js b/utils/storage.js
index b2a14228..ba5ce864 100644
--- a/utils/storage.js
+++ b/utils/storage.js
@@ -10,7 +10,13 @@ const FACE_LOGIN = isDev ? "face_login_dev" : "face_login";
const FINGER_LOGIN = isDev ? "finger_login_dev" : "finger_login";
const CART_BACKBTN = isDev ? "cart_backbtn_dev" : "cart_backbtn";
const AFTERSALE_DATA = isDev ? "aftersale_data_dev" : "aftersale_data";
-export default {
+export default {
+ setCityCode(val) {
+ return uni.setStorageSync('cityCode',val)
+ },
+ getCityCode(){
+ return uni.getStorageSync('cityCode')
+ },
/**
* 写入RefreshVlogIndex
*/
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 904355d0..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