diff --git a/db/im-platform.sql b/db/im-platform.sql index d90976f..003b6f8 100644 --- a/db/im-platform.sql +++ b/db/im-platform.sql @@ -10,6 +10,7 @@ create table `im_user`( `reason` varchar(255) default '' comment '被封禁原因', `type` smallint default 1 comment '用户类型 1:普通用户 2:审核账户', `signature` varchar(1024) default '' comment '个性签名', + `cid` varchar(255) default '' comment '客户端id,用于uni-push推送', `last_login_time` datetime DEFAULT null comment '最后登录时间', `created_time` datetime DEFAULT CURRENT_TIMESTAMP comment '创建时间', unique key `idx_user_name`(user_name), diff --git a/im-platform/pom.xml b/im-platform/pom.xml index 65ef8ab..8aaab0a 100644 --- a/im-platform/pom.xml +++ b/im-platform/pom.xml @@ -91,6 +91,11 @@ knife4j-openapi3-jakarta-spring-boot-starter ${knife4j.version} + + com.getui.push + restful-sdk + 1.0.3.0 + ${project.artifactId} diff --git a/im-platform/src/main/java/com/bx/implatform/config/UniPushConfig.java b/im-platform/src/main/java/com/bx/implatform/config/UniPushConfig.java new file mode 100644 index 0000000..641c3f6 --- /dev/null +++ b/im-platform/src/main/java/com/bx/implatform/config/UniPushConfig.java @@ -0,0 +1,44 @@ +package com.bx.implatform.config; + +import com.getui.push.v2.sdk.ApiHelper; +import com.getui.push.v2.sdk.GtApiConfiguration; +import com.getui.push.v2.sdk.api.PushApi; +import lombok.Data; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.stereotype.Component; + +/** + * @author: 谢绍许 + * @date: 2024-07-06 + * @version: 1.0 + */ +@Data +@Component +public class UniPushConfig { + + @Value("${notify.uniPush.appId}") + private String appId; + @Value("${notify.uniPush.appKey}") + private String appKey; + @Value("${notify.uniPush.masterSecret}") + private String masterSecret; + + @Bean + public GtApiConfiguration uniPushConfiguration(){ + GtApiConfiguration apiConfiguration = new GtApiConfiguration(); + apiConfiguration.setAppId(appId); + apiConfiguration.setAppKey(appKey); + apiConfiguration.setMasterSecret(masterSecret); + return apiConfiguration; + } + + @Bean + public PushApi uniPushApi(GtApiConfiguration configuration){ + // 实例化ApiHelper对象,用于创建接口对象 + ApiHelper apiHelper = ApiHelper.build(configuration); + // 创建对象,建议复用。目前有PushApi、StatisticApi、UserApi + PushApi pushApi = apiHelper.creatApi(PushApi.class); + return pushApi; + } +} diff --git a/im-platform/src/main/java/com/bx/implatform/contant/RedisKey.java b/im-platform/src/main/java/com/bx/implatform/contant/RedisKey.java index 17ddd9f..221ddbf 100644 --- a/im-platform/src/main/java/com/bx/implatform/contant/RedisKey.java +++ b/im-platform/src/main/java/com/bx/implatform/contant/RedisKey.java @@ -10,6 +10,11 @@ public final class RedisKey { * 已读群聊消息位置(已读最大id) */ public static final String IM_GROUP_READED_POSITION = "im:readed:group:position"; + + /** + * 私聊离线通知 + */ + public static final String IM_OFFLINE_NOTIFY_PRIVATE = "im:notify:private"; /** * webrtc 单人通话 */ @@ -52,4 +57,5 @@ public final class RedisKey { */ public static final String IM_LOCK_RTC_GROUP = "im:lock:rtc:group"; + } diff --git a/im-platform/src/main/java/com/bx/implatform/dto/LoginDTO.java b/im-platform/src/main/java/com/bx/implatform/dto/LoginDTO.java index 30b240e..5470fac 100644 --- a/im-platform/src/main/java/com/bx/implatform/dto/LoginDTO.java +++ b/im-platform/src/main/java/com/bx/implatform/dto/LoginDTO.java @@ -25,4 +25,7 @@ public class LoginDTO { @Schema(description = "用户密码") private String password; + @ApiModelProperty(value = "用户客户端id") + private String cid; + } diff --git a/im-platform/src/main/java/com/bx/implatform/dto/LogoutDTO.java b/im-platform/src/main/java/com/bx/implatform/dto/LogoutDTO.java new file mode 100644 index 0000000..4b252af --- /dev/null +++ b/im-platform/src/main/java/com/bx/implatform/dto/LogoutDTO.java @@ -0,0 +1,19 @@ +package com.bx.implatform.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +@Data +@ApiModel("用户登录DTO") +public class LogoutDTO { + + @ApiModelProperty(value = "用户客户端id") + private String cid; + +} diff --git a/im-platform/src/main/java/com/bx/implatform/entity/User.java b/im-platform/src/main/java/com/bx/implatform/entity/User.java index ca292e6..3960601 100644 --- a/im-platform/src/main/java/com/bx/implatform/entity/User.java +++ b/im-platform/src/main/java/com/bx/implatform/entity/User.java @@ -69,6 +69,11 @@ public class User { */ private String reason; + /** + * 客户端id,用于uni-push推送 + */ + @TableField("cid") + private String cid; /** * 最后登录时间 */ diff --git a/im-platform/src/main/java/com/bx/implatform/listener/PrivateMessageListener.java b/im-platform/src/main/java/com/bx/implatform/listener/PrivateMessageListener.java index 2a2f44f..d60fa46 100644 --- a/im-platform/src/main/java/com/bx/implatform/listener/PrivateMessageListener.java +++ b/im-platform/src/main/java/com/bx/implatform/listener/PrivateMessageListener.java @@ -6,10 +6,12 @@ import com.bx.imclient.annotation.IMListener; import com.bx.imclient.listener.MessageListener; import com.bx.imcommon.enums.IMListenerType; import com.bx.imcommon.enums.IMSendCode; +import com.bx.imcommon.enums.IMTerminalType; import com.bx.imcommon.model.IMSendResult; import com.bx.implatform.entity.PrivateMessage; import com.bx.implatform.enums.MessageStatus; import com.bx.implatform.service.PrivateMessageService; +import com.bx.implatform.service.INotifyPrivateService; import com.bx.implatform.vo.PrivateMessageVO; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; @@ -22,27 +24,53 @@ import java.util.Set; @Slf4j @IMListener(type = IMListenerType.PRIVATE_MESSAGE) public class PrivateMessageListener implements MessageListener { + @Lazy @Autowired private PrivateMessageService privateMessageService; + + @Lazy + @Autowired + private NotifyPrivateService uniPushService; + @Override public void process(List> results) { + // 更新消息状态 + updateMessageStatus(results); + // 推送离线通知 + sendOfflineNotify(results); + } + + private void updateMessageStatus(List> results) { Set messageIds = new HashSet<>(); - for(IMSendResult result : results){ + for (IMSendResult result : results) { PrivateMessageVO messageInfo = result.getData(); // 更新消息状态,这里只处理成功消息,失败的消息继续保持未读状态 if (result.getCode().equals(IMSendCode.SUCCESS.code())) { messageIds.add(messageInfo.getId()); - log.info("消息送达,消息id:{},发送者:{},接收者:{},终端:{}", messageInfo.getId(), result.getSender().getId(), result.getReceiver().getId(), result.getReceiver().getTerminal()); + log.info("消息送达,消息id:{},发送者:{},接收者:{},终端:{}", messageInfo.getId(), + result.getSender().getId(), result.getReceiver().getId(), result.getReceiver().getTerminal()); } } - // 批量修改状态 - if(CollUtil.isNotEmpty(messageIds)){ + // 对发送成功的消息修改状态 + if (CollUtil.isNotEmpty(messageIds)) { UpdateWrapper updateWrapper = new UpdateWrapper<>(); updateWrapper.lambda().in(PrivateMessage::getId, messageIds) - .eq(PrivateMessage::getStatus, MessageStatus.UNSEND.code()) - .set(PrivateMessage::getStatus, MessageStatus.SENDED.code()); + .eq(PrivateMessage::getStatus, MessageStatus.UNSEND.code()) + .set(PrivateMessage::getStatus, MessageStatus.SENDED.code()); privateMessageService.update(updateWrapper); } } + + private void sendOfflineNotify(List> results) { + for (IMSendResult result : results) { + PrivateMessageVO messageInfo = result.getData(); + if (result.getCode().equals(IMSendCode.SUCCESS.code()) && result.getReceiver().getTerminal() + .equals(IMTerminalType.APP.code())) { + uniPushService.sendMessage(messageInfo.getSendId(), messageInfo.getRecvId(), messageInfo.getContent()); + log.info("推送离线通知,消息id:{},发送者:{},接收者:{}", messageInfo.getId(), result.getSender().getId(), + result.getReceiver().getId()); + } + } + } } diff --git a/im-platform/src/main/java/com/bx/implatform/service/INotifyPrivateService.java b/im-platform/src/main/java/com/bx/implatform/service/INotifyPrivateService.java new file mode 100644 index 0000000..323d889 --- /dev/null +++ b/im-platform/src/main/java/com/bx/implatform/service/INotifyPrivateService.java @@ -0,0 +1,107 @@ +package com.bx.implatform.service; + +import cn.hutool.core.util.StrUtil; +import com.bx.implatform.contant.RedisKey; +import com.bx.implatform.entity.User; +import com.bx.implatform.session.NotifySession; +import com.bx.implatform.service.thirdparty.UniPushService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Lazy; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +/** + * 私聊离线通知服务 + * + * @author: blue + * @date: 2024-07-06 + * @version: 1.0 + */ +@Slf4j +@Service +@RequiredArgsConstructor +public class INotifyPrivateService { + @Lazy + @Autowired + private IUserService userService; + private final UniPushService uniPushService; + private final RedisTemplate redisTemplate; + @Value("${notify.enable}") + private Boolean enable = false; + @Value("${notify.max.private}") + private Integer max = -1; + public void sendMessage(Long sendId, Long recvId, String content) { + if(!enable){ + return; + } + NotifySession session = findNotifySession(sendId, recvId); + if (Objects.isNull(session)) { + session = createNotifySession(sendId, recvId); + } + // 未上报cid,无法推送 + if (StrUtil.isEmpty(session.getCid())) { + log.info("用户'{}'未上报cid,无法推送离线通知", recvId); + return; + } + // 已达到最大数量 + if (max > 0 && session.getCount() >= max) { + log.info("用户'{}'已到达推送数量上线,不再推送离线通知", recvId); + return; + } + // 消息数量加1 + session.setCount(session.getCount()+1); + String body = String.format("%s:%s", session.getSendNickName(),content); + // 大于1条时需要展示数量 + if (session.getCount() > 1) { + body = String.format("[%d条] ", session.getCount()) + body; + } + uniPushService.pushByCid(session,body); + // 保存会话 + saveNotifySession(session,sendId,recvId); + } + + public void removeNotifySession( Long recvId){ + String key = StrUtil.join(":", RedisKey.IM_OFFLINE_NOTIFY_PRIVATE, "*", recvId); + Set keys = redisTemplate.keys(key); + redisTemplate.delete(keys); + } + + public void removeNotifySession(Long sendId, Long recvId){ + String key = StrUtil.join(":", RedisKey.IM_OFFLINE_NOTIFY_PRIVATE, sendId, recvId); + redisTemplate.delete(key); + } + + private NotifySession createNotifySession(Long sendId, Long recvId) { + String key = StrUtil.join(":", RedisKey.IM_OFFLINE_NOTIFY_PRIVATE, sendId, recvId); + User sendUser = userService.getById(sendId); + User recvUser = userService.getById(recvId); + NotifySession session = new NotifySession(); + session.setCount(0); + session.setCid(recvUser.getCid()); + session.setTitle(sendUser.getNickName()); + session.setSendNickName(sendUser.getNickName()); + session.setNotifyId(Math.abs(key.hashCode())); + session.setLogo(sendUser.getHeadImageThumb()); + redisTemplate.opsForValue().set(key, session, 30, TimeUnit.DAYS); + return session; + } + + private NotifySession findNotifySession(Long sendId, Long recvId) { + String key = StrUtil.join(":", RedisKey.IM_OFFLINE_NOTIFY_PRIVATE, sendId, recvId); + return (NotifySession)redisTemplate.opsForValue().get(key); + } + + private void saveNotifySession(NotifySession session, Long sendId, Long recvId) { + String key = StrUtil.join(":", RedisKey.IM_OFFLINE_NOTIFY_PRIVATE, sendId, recvId); + redisTemplate.opsForValue().set(key, session); + } + +} diff --git a/im-platform/src/main/java/com/bx/implatform/service/UserService.java b/im-platform/src/main/java/com/bx/implatform/service/UserService.java index 37bcc8b..b5f28e5 100644 --- a/im-platform/src/main/java/com/bx/implatform/service/UserService.java +++ b/im-platform/src/main/java/com/bx/implatform/service/UserService.java @@ -2,6 +2,7 @@ package com.bx.implatform.service; import com.baomidou.mybatisplus.extension.service.IService; import com.bx.implatform.dto.LoginDTO; +import com.bx.implatform.dto.LogoutDTO; import com.bx.implatform.dto.ModifyPwdDTO; import com.bx.implatform.dto.RegisterDTO; import com.bx.implatform.entity.User; @@ -21,6 +22,14 @@ public interface UserService extends IService { */ LoginVO login(LoginDTO dto); + /** + * 用户退出登陆 + * + * @param dto 退出登陆dto + * @return + */ + void logout(LogoutDTO dto); + /** * 修改用户密码 * diff --git a/im-platform/src/main/java/com/bx/implatform/service/impl/PrivateMessageServiceImpl.java b/im-platform/src/main/java/com/bx/implatform/service/impl/PrivateMessageServiceImpl.java index 995e97d..132d4db 100644 --- a/im-platform/src/main/java/com/bx/implatform/service/impl/PrivateMessageServiceImpl.java +++ b/im-platform/src/main/java/com/bx/implatform/service/impl/PrivateMessageServiceImpl.java @@ -20,6 +20,7 @@ import com.bx.implatform.exception.GlobalException; import com.bx.implatform.mapper.PrivateMessageMapper; import com.bx.implatform.service.FriendService; import com.bx.implatform.service.PrivateMessageService; +import com.bx.implatform.service.NotifyPrivateService; import com.bx.implatform.session.SessionContext; import com.bx.implatform.session.UserSession; import com.bx.implatform.util.BeanUtils; @@ -43,7 +44,7 @@ public class PrivateMessageServiceImpl extends ServiceImpl implements Us private final FriendService friendService; private final JwtProperties jwtProperties; private final IMClient imClient; + private final INotifyPrivateService notifyPrivateService; @Override public LoginVO login(LoginDTO dto) { @@ -60,6 +66,14 @@ public class UserServiceImpl extends ServiceImpl implements Us if (!passwordEncoder.matches(dto.getPassword(), user.getPassword())) { throw new GlobalException(ResultCode.PASSWOR_ERROR); } + // 更新用户登陆时间和cid + user.setLastLoginTime(new Date()); + // 用户更换了设备,记录新的cid + if(StrUtil.isNotEmpty(dto.getCid()) && dto.getCid().equals(user.getCid())){ + user.setCid(dto.getCid()); + notifyPrivateService.removeNotifySession(user.getId()); + } + this.updateById(user); // 生成token UserSession session = BeanUtils.copyProperties(user, UserSession.class); session.setUserId(user.getId()); @@ -77,6 +91,20 @@ public class UserServiceImpl extends ServiceImpl implements Us return vo; } + @Override + public void logout(LogoutDTO dto) { + UserSession session = SessionContext.getSession(); + if(StrUtil.isNotEmpty(dto.getCid())){ + // 清除cid,不再推送离线通知 + notifyPrivateService.removeNotifySession(session.getUserId()); + LambdaUpdateWrapper wrapper = Wrappers.lambdaUpdate(); + wrapper.eq(User::getId,session.getUserId()); + wrapper.eq(User::getCid,dto.getCid()); + wrapper.set(User::getCid, Strings.EMPTY); + this.update(wrapper); + } + } + @Override public LoginVO refreshToken(String refreshToken) { //验证 token diff --git a/im-platform/src/main/java/com/bx/implatform/service/thirdparty/UniPushService.java b/im-platform/src/main/java/com/bx/implatform/service/thirdparty/UniPushService.java new file mode 100644 index 0000000..f0c367b --- /dev/null +++ b/im-platform/src/main/java/com/bx/implatform/service/thirdparty/UniPushService.java @@ -0,0 +1,122 @@ +package com.bx.implatform.service.thirdparty; + +import com.bx.implatform.session.NotifySession; +import com.getui.push.v2.sdk.api.PushApi; +import com.getui.push.v2.sdk.common.ApiResult; +import com.getui.push.v2.sdk.dto.req.Audience; +import com.getui.push.v2.sdk.dto.req.Settings; +import com.getui.push.v2.sdk.dto.req.message.PushChannel; +import com.getui.push.v2.sdk.dto.req.message.PushDTO; +import com.getui.push.v2.sdk.dto.req.message.PushMessage; +import com.getui.push.v2.sdk.dto.req.message.android.AndroidDTO; +import com.getui.push.v2.sdk.dto.req.message.android.GTNotification; +import com.getui.push.v2.sdk.dto.req.message.android.ThirdNotification; +import com.getui.push.v2.sdk.dto.req.message.android.Ups; +import com.getui.push.v2.sdk.dto.req.message.ios.Alert; +import com.getui.push.v2.sdk.dto.req.message.ios.Aps; +import com.getui.push.v2.sdk.dto.req.message.ios.IosDTO; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author: 谢绍许 + * @date: 2024-07-06 + * @version: 1.0 + */ +@Slf4j +@Component +@RequiredArgsConstructor +public class UniPushService { + + private final PushApi pushApi; + + public void pushByCid(NotifySession session, String body){ + //根据cid进行单推 + PushDTO pushDTO = new PushDTO(); + // 设置推送参数,requestid需要每次变化唯一 + pushDTO.setRequestId(System.currentTimeMillis()+""); + Settings settings = new Settings(); + pushDTO.setSettings(settings); + //消息有效期,走厂商消息必须设置该值 + settings.setTtl(3600000); + //在线走个推通道时推送的消息体 + PushMessage pushMessage = new PushMessage(); + pushDTO.setPushMessage(pushMessage); + //此格式的透传消息由 unipush 做了特殊处理,会自动展示通知栏。开发者也可自定义其它格式,在客户端自己处理。 + GTNotification gtNotification = new GTNotification(); + gtNotification.setTitle(session.getTitle()); + gtNotification.setBody(body); + gtNotification.setClickType("startapp"); + gtNotification.setNotifyId(session.getNotifyId().toString()); + gtNotification.setLogoUrl(session.getLogo()); + gtNotification.setBadgeAddNum("1"); + pushMessage.setNotification(gtNotification); + // 设置接收人信息 + Audience audience = new Audience(); + pushDTO.setAudience(audience); + audience.addCid(session.getCid()); + //设置离线推送时的消息体 + PushChannel pushChannel = new PushChannel(); + //安卓离线厂商通道推送的消息体 + AndroidDTO androidDTO = new AndroidDTO(); + Ups ups = new Ups(); + ThirdNotification thirdNotification = new ThirdNotification(); + ups.setNotification(thirdNotification); + ups.setOptions(buildOptions(session.getLogo())); + thirdNotification.setTitle(session.getTitle()); + thirdNotification.setBody(body); + thirdNotification.setNotifyId(session.getNotifyId().toString()); + // 打开首页 + thirdNotification.setClickType("startapp"); + androidDTO.setUps(ups); + pushChannel.setAndroid(androidDTO); + // ios离线apn通道推送的消息体 + Alert alert = new Alert(); + alert.setTitle(session.getTitle()); + alert.setBody(body); + Aps aps = new Aps(); + // 0:普通通知消息 1:静默推送(无通知栏消息),静默推送时不需要填写其他参数。苹果建议1小时最多推送3条静默消息 + aps.setContentAvailable(0); + // default: 系统铃声 不填:无声 + aps.setSound("default"); + aps.setAlert(alert); + + IosDTO iosDTO = new IosDTO(); + iosDTO.setAps(aps); + iosDTO.setType("notify"); + pushChannel.setIos(iosDTO); + pushDTO.setPushChannel(pushChannel); + // 进行cid单推 + ApiResult>> apiResult = pushApi.pushToSingleByCid(pushDTO); + if (apiResult.isSuccess()) { + log.info("推送成功,{}",apiResult.getData()); + } else { + log.info("推送失败,code:{},msg:{}",apiResult.getCode(),apiResult.getMsg()); + } + } + + + private Map> buildOptions(String logo){ + Map> options = new HashMap<>(); + // 小米 + Map xm = new HashMap<>(); + xm.put("/extra.notification_style_type",1); + xm.put("/extra.notification_large_icon_uri",logo); + options.put("XM",xm); + // 华为 + Map hw = new HashMap<>(); + hw.put("/message/android/notification/image",logo); + hw.put("/message/android/notification/style",1); + options.put("HW",hw); + // 荣耀 + Map ho = new HashMap<>(); + hw.put("/android/notification/badge/addNum",1); + hw.put("/android/notification/icon",logo); + options.put("HW",hw); + return options; + } +} diff --git a/im-platform/src/main/java/com/bx/implatform/session/NotifySession.java b/im-platform/src/main/java/com/bx/implatform/session/NotifySession.java new file mode 100644 index 0000000..1ab253c --- /dev/null +++ b/im-platform/src/main/java/com/bx/implatform/session/NotifySession.java @@ -0,0 +1,43 @@ +package com.bx.implatform.session; + +import lombok.Data; + +/** + * 离线通知session + * @author: blue + * @date: 2024-07-06 + * @version: 1.0 + */ +@Data +public class NotifySession { + /** + * 接收方客户端id + */ + private String cid; + + /** + * 通知id + */ + private Integer notifyId; + + /** + * 发送方用户名 + */ + private String sendNickName; + + /** + * 标题 + */ + private String title; + + /** + * 显示图标 + */ + private String logo; + + /** + * 消息数量 + */ + private Integer count; + +} diff --git a/im-platform/src/main/resources/application.yml b/im-platform/src/main/resources/application.yml index ae5abb0..62ce8d6 100644 --- a/im-platform/src/main/resources/application.yml +++ b/im-platform/src/main/resources/application.yml @@ -21,6 +21,16 @@ mybatis-plus: map-underscore-to-camel-case: true #开启自动驼峰命名规则 log-impl: org.apache.ibatis.logging.stdout.StdOutImpl +notify: + enable: true + max: + private: -1 # 私聊单个会话最大通知数量,-1表示不显示 + group: 10 # 群聊单个会话最大通知数量,-1表示不显示 + uniPush: + appId: nyK71XQYUy9s7Vlzoutlp1 + appKey: XtG6NkUSL98evtpLSE0jYA + masterSecret: MxApXxsx057jcPCeC0cXk6 + jwt: accessToken: expireIn: 1800 #半个小时 diff --git a/im-uniapp/App.vue b/im-uniapp/App.vue index 98a8802..7984fb7 100644 --- a/im-uniapp/App.vue +++ b/im-uniapp/App.vue @@ -21,6 +21,7 @@ store.dispatch("load").then(() => { // 初始化websocket this.initWebSocket(); + this.initUniPush(); }).catch((e) => { console.log(e); this.exit(); @@ -330,6 +331,21 @@ url: '/user/self', method: 'GET' }) + }, + initUniPush(){ + // #ifdef APP-PLUS + plus.push.setAutoNotification(true); + const clientInfo = plus.push.getClientInfo(); + console.log("clientInfo",clientInfo); + plus.push.addEventListener('click', (message)=>{ + const messages = plus.push.getAllMessage(); + console.log("messages",messages) + console.log("click",message) + }); + plus.push.addEventListener('receive', (message)=>{ + console.log("receive",message) + }); + // #endif } }, onLaunch() { @@ -351,6 +367,7 @@ }) // #endif } + } } diff --git a/im-uniapp/manifest.json b/im-uniapp/manifest.json index d69c7ad..2c30905 100644 --- a/im-uniapp/manifest.json +++ b/im-uniapp/manifest.json @@ -20,7 +20,8 @@ "modules" : { "Camera" : {}, "Record" : {}, - "Bluetooth" : {} + "Bluetooth" : {}, + "Push" : {} }, /* 应用发布信息 */ "distribute" : { @@ -59,7 +60,16 @@ /* SDK配置 */ "sdkConfigs" : { "ad" : {}, - "speech" : {} + "speech" : {}, + "push" : { + "unipush" : { + "icons" : { + "small" : { + "ldpi" : "C:/Users/82565/Desktop/盒子/logo.png" + } + } + } + } }, "icons" : { "android" : { diff --git a/im-uniapp/pages/login/login.vue b/im-uniapp/pages/login/login.vue index f8cb97a..1e91a81 100644 --- a/im-uniapp/pages/login/login.vue +++ b/im-uniapp/pages/login/login.vue @@ -23,7 +23,8 @@ loginForm: { terminal: 1, // APP终端 userName: '', - password: '' + password: '', + cid: '' }, rules: { userName: { @@ -43,6 +44,11 @@ }, methods: { submit() { + // APP需要上报cid,用于离线推送 + // #ifdef APP-PLUS + const clientInfo = plus.push.getClientInfo(); + this.loginForm.cid = clientInfo.clientid; + // #endif this.$http({ url: '/login', data: this.loginForm,