18339543638 1 год назад
Родитель
Сommit
74a668c3af

+ 7 - 0
nb-service/app-assistant/pom.xml

@@ -13,6 +13,13 @@
 
 
     <dependencies>
+        <dependency>
+            <groupId>com.turo</groupId>
+            <artifactId>pushy</artifactId>
+            <version>0.13.10</version>
+        </dependency>
+
+
         <dependency>
             <groupId>com.tuoren</groupId>
             <artifactId>nb-im</artifactId>

+ 43 - 0
nb-service/app-assistant/src/main/java/com/nb/app/assistant/controller/AppIphoneController.java

@@ -0,0 +1,43 @@
+package com.nb.app.assistant.controller;
+
+import com.nb.app.assistant.dto.IphoneDeviceDTO;
+import com.nb.app.assistant.service.LocalAppIphoneService;
+import com.nb.app.doctor.api.feign.IAppDoctorUserClient;
+import com.nb.core.result.R;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * @author lifang
+ * @version 1.0.0
+ * @ClassName PatientMonitorController.java
+ * @Description
+ * @createTime 2022年08月11日 15:40:00
+ */
+@RestController
+@AllArgsConstructor
+@RequestMapping("/app/iphone")
+@Api(tags = "苹果设备离线消息推送")
+@Slf4j
+public class AppIphoneController {
+    private final LocalAppIphoneService appIphoneService;
+
+    @PostMapping("/deviceToken/add")
+    @ApiOperation("新增推送设备token")
+    public R<Boolean> add(@RequestBody@Validated IphoneDeviceDTO source){
+        appIphoneService.addDeviceToken(source);
+        return R.success(true);
+    }
+
+    @PostMapping("/deviceToken/remove")
+    @ApiOperation("删除推送设备token")
+    public R<Boolean> lookDoctor(@RequestBody@Validated IphoneDeviceDTO source){
+        appIphoneService.removeDeviceToken(source);
+        return R.success(true);
+    }
+}

+ 23 - 0
nb-service/app-assistant/src/main/java/com/nb/app/assistant/dto/IphoneDeviceDTO.java

@@ -0,0 +1,23 @@
+package com.nb.app.assistant.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+
+/**
+ * @ClassName : IphoneDeviceDTO
+ * @Description :
+ * @Author : LF
+ * @Date: 2024年09月10日
+ */
+@Data
+public class IphoneDeviceDTO {
+    @ApiModelProperty(value = "医院id",required = true)
+    @NotBlank(message = "医院id不能为空")
+    private String tenantId;
+
+    @ApiModelProperty(value = "deviceToken",required = true)
+    @NotBlank(message = "deviceToken不能为空")
+    private String deviceToken;
+}

+ 31 - 0
nb-service/app-assistant/src/main/java/com/nb/app/assistant/service/LocalAppIphoneService.java

@@ -0,0 +1,31 @@
+package com.nb.app.assistant.service;
+
+import com.nb.app.assistant.dto.IphoneDeviceDTO;
+import lombok.AllArgsConstructor;
+import org.redisson.api.RSet;
+import org.redisson.api.RedissonClient;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.PostConstruct;
+
+/**
+ * @ClassName : LocalAppIphoneService
+ * @Description :
+ * @Author : LF
+ * @Date: 2024年09月10日
+ */
+@Service
+@AllArgsConstructor
+public class LocalAppIphoneService {
+    private final RedissonClient redissonClient;
+
+    public void addDeviceToken(IphoneDeviceDTO source){
+        RSet<String> tenantSet = redissonClient.getSet(source.getTenantId());
+        tenantSet.add(source.getDeviceToken());
+    }
+
+    public void removeDeviceToken(IphoneDeviceDTO source){
+        RSet<String> tenantSet = redissonClient.getSet(source.getTenantId());
+        tenantSet.remove(source.getDeviceToken());
+    }
+}

+ 100 - 0
nb-service/app-assistant/src/main/java/com/nb/app/assistant/utils/ApnsUtils.java

@@ -0,0 +1,100 @@
+package com.nb.app.assistant.utils;
+
+import cn.hutool.core.io.FileUtil;
+import com.turo.pushy.apns.*;
+import com.turo.pushy.apns.auth.ApnsSigningKey;
+import com.turo.pushy.apns.util.SimpleApnsPushNotification;
+import com.turo.pushy.apns.util.concurrent.PushNotificationFuture;
+import io.netty.channel.EventLoopGroup;
+import io.netty.channel.nio.NioEventLoopGroup;
+import lombok.extern.slf4j.Slf4j;
+
+import java.io.File;
+import java.util.Date;
+import java.util.UUID;
+
+import static com.turo.pushy.apns.PushType.*;
+import static com.turo.pushy.apns.PushType.ALERT;
+
+
+@Slf4j
+public class ApnsUtils {
+    private static ApnsClient apnsClient = null;
+    public static void sendMsg(String deviceToken,String msgContent) throws Exception {
+        //IOS等终端设备注册后返回的DeviceToken
+        /**
+         * Use the voip push type for notifications that provide information about an incoming Voice-over-IP (VoIP)
+         * call. For more information, see Responding to VoIP Notifications from PushKit.
+         * If you set this push type, the apns-topic header field must use your app’s bundle ID with .voip
+         * appended to the end. If you’re using certificate-based authentication,
+         * you must also register the certificate for VoIP services.
+         * The topic is then part of the 1.2.840.113635.100.6.3.4 or 1.2.840.113635.100.6.3.6 extension.
+         */
+        //这是你的主题,大多数情况是bundleId,voip需要在bundleId加上.voip。对应文档中的apns-topic
+        //此处可以参考https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/sending_notification_requests_to_apns?language=objc
+
+        String topic = "tuoren.PumpIOS";
+        String payload = "{  \n" +
+                "   \"aps\":{  \n" +
+                "      \"alert\":{  \n" +
+                "         \"title\":\"驼人镇痛泵报警\",\n" +
+                "         \"subtitle\":\"75415123E11248\",\n" +
+                "         \"body\":\"故障报警\"\n" +
+                "      },\n" +
+                "      \"badge\":1, \n" +
+                "      \"sound\":\"default\", \n" +
+                "   }\n" +
+                "}\n" ;
+        //有效时间
+        Date invalidationTime= new Date(System.currentTimeMillis() + 60 * 60 * 1000L );
+        //发送策略 apns-priority 10为立即 5为省电
+        DeliveryPriority priority= DeliveryPriority.IMMEDIATE;
+        //推送方式,主要有alert,background,voip,complication,fileprovider,mdm
+        PushType pushType = ALERT;
+        //推送的合并ID,相同的 apns-collapse-id会在App中合并
+        String collapseId= UUID.randomUUID().toString();
+        //apnsId 唯一标示,如果不传,APNs会给我们生成一个
+        UUID apnsId = UUID.randomUUID();
+        //构造一个APNs的推送消息实体
+
+        SimpleApnsPushNotification msg = new SimpleApnsPushNotification(deviceToken,topic,payload,invalidationTime,priority,pushType,collapseId,apnsId);
+        //开始推送
+        PushNotificationFuture<SimpleApnsPushNotification, PushNotificationResponse<SimpleApnsPushNotification>> future = getAPNSConnect().sendNotification(msg);
+        PushNotificationResponse<SimpleApnsPushNotification> response = future.get();
+        System.out.println(response.getRejectionReason());
+        //如果返回的消息中success为true那么成功,否则失败!
+        //如果失败不必惊慌,rejectionReason字段中会有失败的原因。对应官网找到原因即可
+        //https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/handling_notification_responses_from_apns?language=objc
+
+        System.out.println("------------->"+response);
+
+
+    }
+
+    public static ApnsClient getAPNSConnect() {
+
+        if (apnsClient == null) {
+            try {
+                //四个线程
+                File file = FileUtil.file("AuthKey_X4S8H58U59.p8");
+
+                EventLoopGroup eventLoopGroup = new NioEventLoopGroup(4);
+                apnsClient = new ApnsClientBuilder()
+                        .setApnsServer(ApnsClientBuilder.DEVELOPMENT_APNS_HOST)
+                        .setSigningKey(ApnsSigningKey.loadFromPkcs8File(file,
+                                "JRWKVG95GL", "X4S8H58U59"))
+                        .setConcurrentConnections(4)
+                        .setEventLoopGroup(eventLoopGroup)
+                        .build();
+            } catch (Exception e) {
+                log.error("ios get pushy apns client failed!");
+                e.printStackTrace();
+            }
+        }
+        return apnsClient;
+    }
+
+    public static void main(String[] args) throws Exception {
+        sendMsg("ad8b799839398e10d78c55041dbbe6483563cf75428e2ebe21162a75f83598b2","");
+    }
+}

+ 6 - 0
nb-service/app-assistant/src/main/resources/AuthKey_X4S8H58U59.p8

@@ -0,0 +1,6 @@
+-----BEGIN PRIVATE KEY-----
+MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQggByASbQqV4ZeT1rv
+iD9BNFoohsQu+utRJH7H5CubZ/KgCgYIKoZIzj0DAQehRANCAATdP1vc9R17F7pi
+n69ZptaYmsPtKAyDSbquDxJKfT19cxEfQZhNiWnGLxTXq+zdURFBi5T2P+b/qebb
+8hWEojJY
+-----END PRIVATE KEY-----