Переглянути джерело

修改ios推送支持p8证书

zhuojiaxuan 2 тижнів тому
батько
коміт
121b881e67

+ 1 - 1
Controller/ComboCron/ComboCronPushController.py

@@ -259,7 +259,7 @@ class ComboCronPushView(View):
         try:
             # ios apns
             if push_type == 0:
-                PushObject.ios_apns_push(**kwargs)
+                PushObject.ios_p8_push(**kwargs)
             # android gcm
             elif push_type == 1:
                 PushObject.android_fcm_push_v1(**kwargs)

+ 1 - 1
Controller/PowerWarningController.py

@@ -88,7 +88,7 @@ class PowerWarningView(View):
                 try:
                     # 推送消息
                     if push_type == 0:  # ios apns
-                        PushObject.ios_apns_push(**kwargs)
+                        PushObject.ios_p8_push(**kwargs)
                     elif push_type == 1:  # android gcm
                         PushObject.android_fcm_push_v1(**kwargs)
                     elif push_type == 2:  # android jpush

+ 1 - 1
Controller/TransparentTransmissionPushController.py

@@ -109,7 +109,7 @@ class TransparentTransmissionPushView(View):
                 }
                 LOGGER.info('进入登出推送线程,参数:{}'.format(kwargs))
                 if push_item['push_type'] == 0:  # 苹果
-                    PushObject.ios_apns_push(**kwargs)
+                    PushObject.ios_p8_push(**kwargs)
                 elif push_item['push_type'] == 1:  # 谷歌
                     PushObject.android_fcm_push_v1(**kwargs)
                 elif push_item['push_type'] == 2:  # 极光

+ 1 - 1
Controller/gatewayController.py

@@ -446,7 +446,7 @@ class GatewayView(View):
         @return: None
         """
         if push_type == 0:  # ios apns
-            PushObject.ios_apns_push(**kwargs)
+            PushObject.ios_p8_push(**kwargs)
         elif push_type == 1:  # android gcm
             PushObject.android_fcm_push_v1(**kwargs)
         elif push_type == 2:  # android 极光推送

+ 1 - 1
Object/SageMakerAiObject.py

@@ -255,7 +255,7 @@ class SageMakerAiObject:
         uid = kwargs['uid']
         try:
             if push_type == 0:  # ios apns
-                PushObject.ios_apns_push(**kwargs)
+                PushObject.ios_p8_push(**kwargs)
             elif push_type == 1:  # android gcm
                 PushObject.android_fcm_push_v1(**kwargs)
             elif push_type == 2:  # android jpush

+ 8 - 0
Object/enums/ConstantEnum.py

@@ -16,3 +16,11 @@ class ConstantEnum(Enum):
     ZOSI_CN_APP_BUNDLE_ID_IOS = 'com.ansjer.customizede'
     LOOCAM_APP_BUNDLE_ID_IOS = 'com.ansjer.loocamccloud'
     VSEES_APP_BUNDLE_ID_IOS = 'com.cloudlife.commissionf'
+
+    IOS_P8_CONFIG = {
+        'com.ansjer.loocamccloud': {
+            'pem_path': 'static/ios_p8/com.ansjer.loocamccloud.p8',
+            'team_id': 'JCHT67XT68',
+            'key_id': '3VMT4HX58K',
+        },
+    }

+ 1 - 1
Service/CustomizedPushService.py

@@ -177,7 +177,7 @@ class CustomizedPushObject:
             # ios
             if push_type == 0:
                 push_kwargs['launch_image'] = icon_link
-                return PushObject.ios_apns_push(**push_kwargs)
+                return PushObject.ios_p8_push(**push_kwargs)
             # gcm
             elif push_type == 1:
                 if icon_link is None:

+ 2 - 2
Service/DevicePushService.py

@@ -501,7 +501,7 @@ class DevicePushService:
                     }
 
                     if push_type == 0:  # ios apns
-                        push_result = PushObject.ios_apns_push(**kwargs)
+                        push_result = PushObject.ios_p8_push(**kwargs)
                     elif push_type == 1:  # android gcm
                         push_result = PushObject.android_fcm_push_v1(**kwargs)
                     elif push_type == 2:  # android jpush
@@ -995,7 +995,7 @@ class DevicePushService:
                     'get_object', Params={'Bucket': bucket, 'Key': key}, ExpiresIn=3600)
             push_result = False
             if push_type == 0:
-                push_result = PushObject.ios_apns_push(
+                push_result = PushObject.ios_p8_push(
                     uid, appBundleId, token_val, n_time, event_type, msg_title, msg_text, uid, channel, image_url)
             elif push_type == 1:
                 push_result = PushObject.android_fcm_push_v1(

+ 146 - 17
Service/PushService.py

@@ -19,10 +19,16 @@ from firebase_admin import messaging
 from pyfcm import FCMNotification
 
 from AnsjerPush.config import APP_BUNDLE_DICT, APNS_MODE, BASE_DIR, APNS_CONFIG, FCM_CONFIG, JPUSH_CONFIG, XMPUSH_CONFIG \
-    , VIVOPUSH_CONFIG, OPPOPUSH_CONFIG, MEIZUPUSH_CONFIG, CONFIG_INFO, HONORPUSH_CONFIG, DATA_PUSH_EVENT_TYPE_LIST
+    , VIVOPUSH_CONFIG, OPPOPUSH_CONFIG, MEIZUPUSH_CONFIG, CONFIG_INFO, HONORPUSH_CONFIG, DATA_PUSH_EVENT_TYPE_LIST, \
+    CONFIG_TEST
+from AnsjerPush.packages import apns2
+import jwt
+import httpx
+
 from Model.models import UidPushModel
 from Object.RedisObject import RedisObject
 from Object.S3Email import S3Email
+from Object.enums.ConstantEnum import ConstantEnum
 from Object.enums.EventTypeEnum import EventTypeEnumObj
 from Service.CommonService import CommonService
 from Service.VivoPushService.push_admin.APIMessage import PushMessage
@@ -127,27 +133,150 @@ class PushObject:
         LOGGER.info('IOS推送: uid:{}, app_bundle_id:{}, pem_path:{}, msg_text:'.format(
             uid, app_bundle_id, pem_path, msg_text))
         try:
-            cli = apns2.APNSClient(mode=APNS_MODE, client_cert=pem_path)
-            alert = apns2.PayloadAlert(title=msg_title, body=msg_text, launch_image=launch_image)
-            # 跳转类型,1:推送消息,2:系统消息,3:音视频通话消息
+            apns_url = "https://api.sandbox.push.apple.com" if CONFIG_INFO == CONFIG_TEST else "https://api.push.apple.com"
+            url = f"{apns_url}/3/device/{token_val}"
+
             jump_type = CommonService.get_jump_type(event_type)
-            push_data = {'alert': msg_text, 'msg': '', 'sound': '', 'zpush': '1', 'uid': uid, 'channel': channel,
-                         'received_at': n_time, 'event_time': n_time, 'event_type': event_type, 'nickname': nickname,
-                         'image_url': launch_image, 'jump_type': jump_type
-                         }
+            push_data = {
+                'alert': msg_text, 'msg': '', 'sound': '',
+                'zpush': '1', 'uid': uid, 'channel': channel,
+                'received_at': n_time, 'event_time': n_time, 'event_type': event_type,
+                'nickname': nickname, 'image_url': launch_image, 'jump_type': jump_type
+            }
             sound = 'call_phone.mp3' if event_type in DATA_PUSH_EVENT_TYPE_LIST else 'default'
-            payload = apns2.Payload(alert=alert, custom=push_data, sound=sound, category='myCategory',
-                                    mutable_content=True)
-            n = apns2.Notification(payload=payload, priority=apns2.PRIORITY_LOW)
-            res = cli.push(n=n, device_token=token_val, topic=app_bundle_id)
-            LOGGER.info('IOS推送响应状态码{},token:{},uid:{},params:{}'
-                        .format(res.status_code, token_val, uid, json.dumps(push_data)))
-            assert res.status_code == 200 or res.status_code == 410
-            return True
+
+            body = {
+                "aps": {
+                    "alert": {
+                        "title": msg_title,
+                        "body": msg_text,
+                        "launch-image": launch_image
+                    },
+                    "sound": sound,
+                    "category": "myCategory",
+                    "mutable-content": 1
+                },
+                "custom": push_data
+            }
+
+            headers = {
+                "apns-topic": app_bundle_id,
+                "apns-push-type": "alert"
+            }
+
+            with httpx.Client(http2=True,timeout=10,cert=pem_path,) as client:
+                res = client.post(url, headers=headers, json=body)
+
+            if res.status_code == 200:
+                LOGGER.info(f"{uid} iOS 推送成功, token:{token_val}")
+                return True
+            else:
+                LOGGER.error(f"{uid} iOS 推送失败,状态码: {res.status_code}, 原因: {res.text}")
+                return False
+
         except Exception as e:
-            LOGGER.info('IOS推送异常: {}, 证书路径: {}'.format(repr(e), pem_path))
+            LOGGER.error(f"{uid} iOS 推送异常: {repr(e)}, 行数: {e.__traceback__.tb_lineno}")
             return False
 
+    @staticmethod
+    def ios_p8_push(nickname, app_bundle_id, token_val, n_time, event_type, msg_title, msg_text,
+                    uid='', channel='1', launch_image=None):
+        """
+        iOS推送 (P8证书模式)
+        @param nickname: 设备昵称
+        @param app_bundle_id: app包id
+        @param token_val: 推送 token
+        @param n_time: 当前时间
+        @param event_type: 事件类型
+        @param msg_title: 推送标题
+        @param msg_text: 推送内容
+        @param uid:uid
+        @param channel: 通道
+        @param launch_image: 推送图片链接
+        @return: bool
+        """
+        if app_bundle_id not in ConstantEnum.IOS_P8_CONFIG.value:
+            return PushObject.ios_apns_push(
+                nickname=nickname,
+                app_bundle_id=app_bundle_id,
+                token_val=token_val,
+                n_time=n_time,
+                event_type=event_type,
+                msg_title=msg_title,
+                msg_text=msg_text,
+                uid=uid,
+                channel=channel,
+                launch_image=launch_image
+            )
+        else:
+            LOGGER.info("进入 ios_p8_push 方法,准备开始推送")
+
+            try:
+                team_id = ConstantEnum.IOS_P8_CONFIG.value[app_bundle_id]['team_id']
+                key_id = ConstantEnum.IOS_P8_CONFIG.value[app_bundle_id]['key_id']
+                p8_path = os.path.join(BASE_DIR, ConstantEnum.IOS_P8_CONFIG.value[app_bundle_id]['pem_path'])
+
+
+                with open(p8_path, "r") as f:
+                    private_key = f.read()
+                now = int(time.time())
+
+                token = jwt.encode(
+                    {"iss": team_id, "iat": now},
+                    private_key,
+                    algorithm="ES256",
+                    headers={"kid": key_id}
+                )
+                if isinstance(token, bytes):
+                    token = token.decode("utf-8")
+
+                apns_url = "https://api.sandbox.push.apple.com" if CONFIG_INFO == CONFIG_TEST else "https://api.push.apple.com"
+                url = f"{apns_url}/3/device/{token_val}"
+
+
+                jump_type = CommonService.get_jump_type(event_type)
+                push_data = {
+                    'alert': msg_text, 'msg': '', 'sound': '',
+                    'zpush': '1', 'uid': uid, 'channel': channel,
+                    'received_at': n_time, 'event_time': n_time, 'event_type': event_type,
+                    'nickname': nickname, 'image_url': launch_image, 'jump_type': jump_type
+                }
+                sound = 'call_phone.mp3' if event_type in DATA_PUSH_EVENT_TYPE_LIST else 'default'
+
+                body = {
+                    "aps": {
+                        "alert": {
+                            "title": msg_title,
+                            "body": msg_text,
+                            "launch-image": launch_image
+                        },
+                        "sound": sound,
+                        "category": "myCategory",
+                        "mutable-content": 1
+                    },
+                    "custom": push_data
+                }
+
+                headers = {
+                    "authorization": f"bearer {token}",
+                    "apns-topic": app_bundle_id,
+                    "apns-push-type": "alert"
+                }
+
+                with httpx.Client(http2=True, timeout=10,) as client:
+                    res = client.post(url, headers=headers, json=body)
+
+                if res.status_code == 200:
+                    LOGGER.info(f"{uid} iOS p8 推送成功, token:{token_val}")
+                    return True
+                else:
+                    LOGGER.error(f"{uid} iOS p8 推送失败,状态码: {res.status_code}, 原因: {res.text}")
+                    return False
+
+            except Exception as e:
+                LOGGER.error(f"{uid} iOS p8 推送异常: {repr(e)}, 行数: {e.__traceback__.tb_lineno}")
+                return False
+
     @staticmethod
     def android_fcm_push(nickname, app_bundle_id, token_val, n_time, event_type, msg_title, msg_text,
                          uid='', channel='1', image=''):

+ 2 - 1
requirements.txt

@@ -38,11 +38,12 @@ greenlet==3.0.3
 grpcio==1.63.0
 grpcio-status==1.62.2
 gunicorn==22.0.0
-h2==2.6.2
+h2==4.3.0
 hpack==3.0.0
 httplib2==0.22.0
 hyper==0.7.0
 hyperframe==3.2.0
+httpx==0.28.1
 idna==3.7
 image==1.5.33
 importlib_resources==6.4.0