PushService.py 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819
  1. # -*- coding: utf-8 -*-
  2. """
  3. @Time : 2022/5/19 11:43
  4. @Auth : Locky
  5. @File :PushService.py
  6. @IDE :PyCharm
  7. """
  8. import hashlib
  9. import json
  10. import logging
  11. import os
  12. import time
  13. import apns2
  14. import firebase_admin
  15. import jpush
  16. import requests
  17. from firebase_admin import messaging
  18. from pyfcm import FCMNotification
  19. from AnsjerPush.config import APP_BUNDLE_DICT, APNS_MODE, BASE_DIR, APNS_CONFIG, FCM_CONFIG, JPUSH_CONFIG, XMPUSH_CONFIG \
  20. , VIVOPUSH_CONFIG, OPPOPUSH_CONFIG, MEIZUPUSH_CONFIG, CONFIG_INFO, HONORPUSH_CONFIG, DATA_PUSH_EVENT_TYPE_LIST, \
  21. CONFIG_TEST
  22. from AnsjerPush.packages import apns2
  23. import jwt
  24. import httpx
  25. from Model.models import UidPushModel
  26. from Object.RedisObject import RedisObject
  27. from Object.S3Email import S3Email
  28. from Object.enums.ConstantEnum import ConstantEnum
  29. from Object.enums.EventTypeEnum import EventTypeEnumObj
  30. from Service.CommonService import CommonService
  31. from Service.VivoPushService.push_admin.APIMessage import PushMessage
  32. from Service.VivoPushService.push_admin.APISender import APISender
  33. from AnsjerPush.config import LOGGER
  34. TIME_LOGGER = logging.getLogger('time')
  35. class PushObject:
  36. # 推送对象
  37. @staticmethod
  38. def get_msg_title(nickname):
  39. """
  40. 获取推送消息标题
  41. @param nickname: 设备名
  42. @return: msg_title
  43. """
  44. return nickname
  45. @staticmethod
  46. def get_gateway_msg_text(n_time, tz, lang, alarm):
  47. """
  48. 获取网关推送消息内容
  49. @param n_time: 当前时间
  50. @param tz: 时区
  51. @param lang: 语言
  52. @param alarm: 警报
  53. @return: msg_text
  54. """
  55. n_date = CommonService.get_now_time_str(n_time=n_time, tz=tz, lang=lang)
  56. if lang == 'cn':
  57. msg_text = '{} 日期:{}'.format(alarm, n_date)
  58. else:
  59. msg_text = '{} date:{}'.format(alarm, n_date)
  60. return msg_text
  61. @staticmethod
  62. def get_ai_msg_text(channel, n_time, lang, tz, label):
  63. """
  64. 获取AI推送内容
  65. @param channel: 通道
  66. @param n_time: 当前时间
  67. @param lang: 语言
  68. @param tz: 时区
  69. @param label: 识别到的标签
  70. @return: ai_msg_text
  71. """
  72. n_date = CommonService.get_now_time_str(n_time=n_time, tz=tz, lang=lang)
  73. if lang == 'cn':
  74. msg = '摄像头AI识别到了{}'.format(label)
  75. ai_msg_text = '{msg} 通道:{channel} 日期:{date}'.format(msg=msg, channel=channel, date=n_date)
  76. else:
  77. msg = 'Camera AI recognizes {}'.format(label)
  78. ai_msg_text = '{msg} channel:{channel} date:{date}'.format(msg=msg, channel=channel, date=n_date)
  79. return ai_msg_text
  80. @staticmethod
  81. def get_low_power_msg_text(channel, n_time, lang, tz, electricity, is_sys=0):
  82. """
  83. 获取低电量推送内容
  84. @param channel: 通道
  85. @param n_time: 当前时间
  86. @param lang: 语言
  87. @param tz: 时区
  88. @param electricity: 电量
  89. @param is_sys: 是否为系统消息
  90. @return: low_power_msg_text
  91. """
  92. n_date = CommonService.get_now_time_str(n_time=n_time, tz=tz, lang=lang)
  93. if lang == 'cn':
  94. alarm = '剩余电量 ' + electricity
  95. if is_sys:
  96. low_power_msg_text = '{} 通道:{}'.format(alarm, channel)
  97. else:
  98. low_power_msg_text = '{} 通道:{} 日期:{}'.format(alarm, channel, n_date)
  99. else:
  100. alarm = 'Battery remaining ' + electricity
  101. if is_sys:
  102. low_power_msg_text = '{} channel:{}'.format(alarm, channel)
  103. else:
  104. low_power_msg_text = '{} channel:{} date:{}'.format(alarm, channel, n_date)
  105. return low_power_msg_text
  106. @staticmethod
  107. def ios_apns_push(nickname, app_bundle_id, token_val, n_time, event_type, msg_title, msg_text,
  108. uid='', channel='1', launch_image=None):
  109. """
  110. ios apns 推送
  111. @param nickname: 设备昵称
  112. @param app_bundle_id: app包id
  113. @param token_val: 推送token
  114. @param n_time: 当前时间
  115. @param event_type: 事件类型
  116. @param msg_title: 推送标题
  117. @param msg_text: 推送内容
  118. @param uid: uid
  119. @param channel: 通道
  120. @param launch_image: 推送图片链接
  121. @return: bool
  122. """
  123. pem_path = os.path.join(BASE_DIR, APNS_CONFIG[app_bundle_id]['pem_path'])
  124. LOGGER.info('IOS推送: uid:{}, app_bundle_id:{}, pem_path:{}, msg_text:'.format(
  125. uid, app_bundle_id, pem_path, msg_text))
  126. try:
  127. apns_url = "https://api.sandbox.push.apple.com" if CONFIG_INFO == CONFIG_TEST else "https://api.push.apple.com"
  128. url = f"{apns_url}/3/device/{token_val}"
  129. jump_type = CommonService.get_jump_type(event_type)
  130. push_data = {
  131. 'alert': msg_text, 'msg': '', 'sound': '',
  132. 'zpush': '1', 'uid': uid, 'channel': channel,
  133. 'received_at': n_time, 'event_time': n_time, 'event_type': event_type,
  134. 'nickname': nickname, 'image_url': launch_image, 'jump_type': jump_type
  135. }
  136. sound = 'call_phone.mp3' if event_type in DATA_PUSH_EVENT_TYPE_LIST else 'default'
  137. body = {
  138. "aps": {
  139. "alert": {
  140. "title": msg_title,
  141. "body": msg_text,
  142. "launch-image": launch_image
  143. },
  144. "sound": sound,
  145. "category": "myCategory",
  146. "mutable-content": 1
  147. },
  148. "custom": push_data
  149. }
  150. headers = {
  151. "apns-topic": app_bundle_id,
  152. "apns-push-type": "alert"
  153. }
  154. with httpx.Client(http2=True,timeout=10,cert=pem_path,) as client:
  155. res = client.post(url, headers=headers, json=body)
  156. if res.status_code == 200:
  157. LOGGER.info(f"{uid} iOS 推送成功, token:{token_val}")
  158. return True
  159. else:
  160. LOGGER.error(f"{uid} iOS 推送失败,状态码: {res.status_code}, 原因: {res.text}")
  161. return False
  162. except Exception as e:
  163. LOGGER.error(f"{uid} iOS 推送异常: {repr(e)}, 行数: {e.__traceback__.tb_lineno}")
  164. return False
  165. @staticmethod
  166. def ios_p8_push(nickname, app_bundle_id, token_val, n_time, event_type, msg_title, msg_text,
  167. uid='', channel='1', launch_image=None):
  168. """
  169. iOS推送 (P8证书模式)
  170. @param nickname: 设备昵称
  171. @param app_bundle_id: app包id
  172. @param token_val: 推送 token
  173. @param n_time: 当前时间
  174. @param event_type: 事件类型
  175. @param msg_title: 推送标题
  176. @param msg_text: 推送内容
  177. @param uid:uid
  178. @param channel: 通道
  179. @param launch_image: 推送图片链接
  180. @return: bool
  181. """
  182. if app_bundle_id not in ConstantEnum.IOS_P8_CONFIG.value:
  183. return PushObject.ios_apns_push(
  184. nickname=nickname,
  185. app_bundle_id=app_bundle_id,
  186. token_val=token_val,
  187. n_time=n_time,
  188. event_type=event_type,
  189. msg_title=msg_title,
  190. msg_text=msg_text,
  191. uid=uid,
  192. channel=channel,
  193. launch_image=launch_image
  194. )
  195. else:
  196. LOGGER.info("进入 ios_p8_push 方法,准备开始推送")
  197. try:
  198. team_id = ConstantEnum.IOS_P8_CONFIG.value[app_bundle_id]['team_id']
  199. key_id = ConstantEnum.IOS_P8_CONFIG.value[app_bundle_id]['key_id']
  200. p8_path = os.path.join(BASE_DIR, ConstantEnum.IOS_P8_CONFIG.value[app_bundle_id]['pem_path'])
  201. with open(p8_path, "r") as f:
  202. private_key = f.read()
  203. now = int(time.time())
  204. token = jwt.encode(
  205. {"iss": team_id, "iat": now},
  206. private_key,
  207. algorithm="ES256",
  208. headers={"kid": key_id}
  209. )
  210. if isinstance(token, bytes):
  211. token = token.decode("utf-8")
  212. apns_url = "https://api.sandbox.push.apple.com" if CONFIG_INFO == CONFIG_TEST else "https://api.push.apple.com"
  213. url = f"{apns_url}/3/device/{token_val}"
  214. jump_type = CommonService.get_jump_type(event_type)
  215. push_data = {
  216. 'alert': msg_text, 'msg': '', 'sound': '',
  217. 'zpush': '1', 'uid': uid, 'channel': channel,
  218. 'received_at': n_time, 'event_time': n_time, 'event_type': event_type,
  219. 'nickname': nickname, 'image_url': launch_image, 'jump_type': jump_type
  220. }
  221. sound = 'call_phone.mp3' if event_type in DATA_PUSH_EVENT_TYPE_LIST else 'default'
  222. body = {
  223. "aps": {
  224. "alert": {
  225. "title": msg_title,
  226. "body": msg_text,
  227. "launch-image": launch_image
  228. },
  229. "sound": sound,
  230. "category": "myCategory",
  231. "mutable-content": 1
  232. },
  233. "custom": push_data
  234. }
  235. headers = {
  236. "authorization": f"bearer {token}",
  237. "apns-topic": app_bundle_id,
  238. "apns-push-type": "alert"
  239. }
  240. with httpx.Client(http2=True, timeout=10,) as client:
  241. res = client.post(url, headers=headers, json=body)
  242. if res.status_code == 200:
  243. LOGGER.info(f"{uid} iOS p8 推送成功, token:{token_val}")
  244. return True
  245. else:
  246. LOGGER.error(f"{uid} iOS p8 推送失败,状态码: {res.status_code}, 原因: {res.text}")
  247. return False
  248. except Exception as e:
  249. LOGGER.error(f"{uid} iOS p8 推送异常: {repr(e)}, 行数: {e.__traceback__.tb_lineno}")
  250. return False
  251. @staticmethod
  252. def android_fcm_push(nickname, app_bundle_id, token_val, n_time, event_type, msg_title, msg_text,
  253. uid='', channel='1', image=''):
  254. """
  255. android fcm 推送
  256. @param nickname: 设备昵称
  257. @param app_bundle_id: app包id
  258. @param token_val: 推送token
  259. @param n_time: 当前时间
  260. @param event_type: 事件类型
  261. @param msg_title: 推送标题
  262. @param msg_text: 推送内容
  263. @param uid: uid
  264. @param channel: 通道
  265. @param image: 推送图片链接
  266. @return: bool
  267. """
  268. try:
  269. serverKey = FCM_CONFIG[app_bundle_id]
  270. push_service = FCMNotification(api_key=serverKey)
  271. push_data = {'alert': msg_text, 'msg': '', 'sound': 'sound.aif', 'zpush': '1', 'image': image,
  272. 'received_at': n_time, 'event_time': n_time, 'event_type': event_type, 'nickname': nickname,
  273. 'uid': uid, 'channel': channel
  274. }
  275. if event_type in DATA_PUSH_EVENT_TYPE_LIST:
  276. push_data['priority'] = 'high'
  277. push_data['content_available'] = True
  278. push_data['direct_boot_ok'] = True
  279. result = push_service.notify_single_device(registration_id=token_val, message_title=msg_title,
  280. message_body=msg_text, data_message=push_data,
  281. click_action='android.intent.action.VIEW',
  282. extra_kwargs={'default_sound': True,
  283. 'default_vibrate_timings': True,
  284. 'default_light_settings': True,
  285. },
  286. )
  287. TIME_LOGGER.info('uid:{}fcm推送结果:{}'.format(uid, result))
  288. return True
  289. except Exception as e:
  290. TIME_LOGGER.error('uid:{}fcm推送异常:{}'.format(uid, repr(e)))
  291. return False
  292. @staticmethod
  293. def android_fcm_push_v1(nickname, app_bundle_id, token_val, n_time, event_type, msg_title, msg_text,
  294. uid='', channel='1', image=''):
  295. """
  296. android fcm 推送
  297. @param nickname: 设备昵称
  298. @param app_bundle_id: app包id
  299. @param token_val: 推送token
  300. @param n_time: 当前时间
  301. @param event_type: 事件类型
  302. @param msg_title: 推送标题
  303. @param msg_text: 推送内容
  304. @param uid: uid
  305. @param channel: 通道
  306. @param image: 推送图片链接
  307. @return: bool
  308. """
  309. try:
  310. event_type = str(event_type)
  311. n_time = str(n_time)
  312. # 跳转类型
  313. jump_type = str(CommonService.get_jump_type(event_type))
  314. # 推送数据类型必须为字符串,否则抛ValueError('Message.data must not contain non-string values.')异常
  315. push_data = {'alert': msg_text, 'msg': '', 'sound': 'sound.aif', 'zpush': '1',
  316. 'received_at': n_time, 'event_time': n_time, 'event_type': event_type, 'nickname': nickname,
  317. 'uid': uid, 'channel': channel, 'jump_type': jump_type
  318. }
  319. if event_type in DATA_PUSH_EVENT_TYPE_LIST:
  320. push_data['priority'] = 'high'
  321. push_data['content_available'] = True
  322. push_data['direct_boot_ok'] = True
  323. message = messaging.Message(
  324. notification=messaging.Notification(
  325. title=msg_title,
  326. body=msg_text,
  327. image=image
  328. ),
  329. data=push_data,
  330. token=token_val,
  331. )
  332. # Send a message to the device corresponding to the provided
  333. # registration token.
  334. result = messaging.send(message)
  335. LOGGER.info('uid:{}fcm推送结果:{}'.format(uid, result))
  336. return True
  337. except Exception as e:
  338. LOGGER.info('uid:{}fcm推送异常:{}'.format(uid, repr(e)))
  339. return False
  340. @staticmethod
  341. def android_jpush(nickname, app_bundle_id, token_val, n_time, event_type, msg_title, msg_text, channel=1):
  342. """
  343. android 极光 推送
  344. @param nickname: 设备昵称
  345. @param app_bundle_id: app包id
  346. @param token_val: 推送token
  347. @param n_time: 当前时间
  348. @param event_type: 事件类型
  349. @param msg_title: 推送标题
  350. @param msg_text: 推送内容
  351. @param channel: 设备通道
  352. @return: bool
  353. """
  354. try:
  355. # app_key = JPUSH_CONFIG[app_bundle_id]['Key']
  356. # master_secret = JPUSH_CONFIG[app_bundle_id]['Secret']
  357. # # 换成各自的app_key和master_secret
  358. # _jpush = jpush.JPush(app_key, master_secret)
  359. # push = _jpush.create_push()
  360. # push.audience = jpush.registration_id(token_val)
  361. # if event_type in DATA_PUSH_EVENT_TYPE_LIST:
  362. # channel_id = '111934'
  363. # else:
  364. # channel_id = '1'
  365. # push_data = {'alert': msg_text, 'msg': '', 'sound': 'sound.aif', 'zpush': '1', 'uid': nickname,
  366. # 'received_at': n_time, 'event_time': n_time, 'event_type': event_type, 'nickname': nickname,
  367. # 'channel': channel
  368. # }
  369. # android = jpush.android(title=msg_title, big_text=msg_text, alert=msg_text, extras=push_data,
  370. # priority=1, style=1, alert_type=7, channel_id=channel_id
  371. # )
  372. # push.notification = jpush.notification(android=android)
  373. # push.platform = jpush.all_
  374. # res = push.send()
  375. # assert res.status_code == 200
  376. return True
  377. except Exception as e:
  378. LOGGER.info('极光推送异常:{}'.format(repr(e)))
  379. return False
  380. @staticmethod
  381. def jpush(nickname, app_bundle_id, token_val, n_time, event_type, msg_title, msg_text, channel=1):
  382. """
  383. android 极光 推送
  384. @param nickname: 设备昵称
  385. @param app_bundle_id: app包id
  386. @param token_val: 推送token
  387. @param n_time: 当前时间
  388. @param event_type: 事件类型
  389. @param msg_title: 推送标题
  390. @param msg_text: 推送内容
  391. @param channel: 设备通道
  392. @return: bool
  393. """
  394. try:
  395. app_key = JPUSH_CONFIG[app_bundle_id]['Key']
  396. master_secret = JPUSH_CONFIG[app_bundle_id]['Secret']
  397. # 换成各自的app_key和master_secret
  398. _jpush = jpush.JPush(app_key, master_secret)
  399. push = _jpush.create_push()
  400. push.audience = jpush.registration_id(token_val)
  401. if event_type in DATA_PUSH_EVENT_TYPE_LIST:
  402. channel_id = '111934'
  403. else:
  404. channel_id = '1'
  405. # 跳转类型
  406. jump_type = CommonService.get_jump_type(event_type)
  407. push_data = {'alert': msg_text, 'msg': '', 'sound': 'sound.aif', 'zpush': '1', 'uid': nickname,
  408. 'received_at': n_time, 'event_time': n_time, 'event_type': event_type, 'nickname': nickname,
  409. 'channel': channel, 'jump_type': jump_type
  410. }
  411. android = jpush.android(title=msg_title, big_text=msg_text, alert=msg_text, extras=push_data,
  412. priority=1, style=1, alert_type=7, channel_id=channel_id
  413. )
  414. push.notification = jpush.notification(android=android)
  415. push.platform = jpush.all_
  416. res = push.send()
  417. assert res.status_code == 200
  418. LOGGER.info('极光推送响应:{}, 参数:{}, 令牌:{}'.format(res, push_data, token_val))
  419. return True
  420. except Exception as e:
  421. LOGGER.info('极光推送异常:{}'.format(repr(e)))
  422. return False
  423. @staticmethod
  424. def android_xmpush(channel_id, nickname, app_bundle_id, token_val, n_time, event_type, msg_title, msg_text,
  425. uid='', channel='1', image=''):
  426. """
  427. android 小米 推送
  428. @param channel_id: 通知通道
  429. @param nickname: 设备昵称
  430. @param app_bundle_id: app包id
  431. @param token_val: 推送token
  432. @param n_time: 当前时间
  433. @param event_type: 事件类型
  434. @param msg_title: 推送标题
  435. @param msg_text: 推送内容
  436. @param uid: uid
  437. @param channel: 通道
  438. @param image: 推送图片链接
  439. @return: bool
  440. """
  441. try:
  442. url = 'https://api.xmpush.xiaomi.com/v3/message/regid'
  443. app_secret = XMPUSH_CONFIG[app_bundle_id]
  444. # 跳转类型
  445. jump_type = CommonService.get_jump_type(event_type)
  446. data = {
  447. 'title': msg_title,
  448. 'description': msg_text,
  449. 'payload': 'payload',
  450. 'restricted_package_name': app_bundle_id,
  451. 'registration_id': token_val,
  452. 'extra.channel_id': channel_id,
  453. 'extra.alert': msg_text,
  454. 'extra.msg': '',
  455. 'extra.sound': 'sound.aif',
  456. 'extra.zpush': '1',
  457. 'extra.received_at': n_time,
  458. 'extra.event_time': n_time,
  459. 'extra.event_type': event_type,
  460. 'extra.nickname': nickname,
  461. 'extra.uid': uid,
  462. 'extra.channel': channel,
  463. 'extra.jump_type': jump_type
  464. }
  465. # if image:
  466. # data['extra.notification_style_type'] = 2
  467. # data['extra.notification_bigPic_uri'] = image
  468. headers = {
  469. 'Authorization': 'key={}'.format(app_secret)
  470. }
  471. response = requests.post(url, data=data, headers=headers)
  472. LOGGER.info("小米推送返回值:{}".format(response.json()))
  473. assert response.status_code == 200
  474. return True
  475. except Exception as e:
  476. LOGGER.info("小米推送异常:{}".format(repr(e)))
  477. return False
  478. @staticmethod
  479. def android_vivopush(token_val, n_time, event_type, msg_title, msg_text, app_bundle_id='', uid='', channel='1',
  480. image='', nickname='', appBundleId='', jg_token_val=''):
  481. """
  482. vivo 推送(不支持图片)
  483. @param app_bundle_id: app包名
  484. @param appBundleId: app包名
  485. @param token_val: 推送token
  486. @param jg_token_val: 极光推送token
  487. @param event_type: 事件类型
  488. @param msg_title: 推送标题
  489. @param msg_text: 推送内容
  490. @param n_time: 当前时间
  491. @param nickname: 设备昵称
  492. @param uid: uid
  493. @param image: 推送图片链接
  494. @param channel: 通道
  495. @return: bool
  496. """
  497. try:
  498. app_bundle_id = app_bundle_id if app_bundle_id != '' else appBundleId
  499. # 获取redis里面的authToken
  500. if msg_title == '':
  501. msg_title = APP_BUNDLE_DICT[app_bundle_id]
  502. app_id = VIVOPUSH_CONFIG[app_bundle_id]['ID']
  503. app_key = VIVOPUSH_CONFIG[app_bundle_id]['Key']
  504. app_secret = VIVOPUSH_CONFIG[app_bundle_id]['Secret']
  505. sender = APISender(app_secret)
  506. rec = sender.get_token(app_id, app_key)
  507. # 鉴权接口调用获得authToken
  508. sender_send = APISender(app_secret)
  509. sender_send.set_token(rec['authToken'])
  510. # 跳转类型
  511. jump_type = CommonService.get_jump_type(event_type)
  512. push_data = {'alert': msg_text, 'msg': '', 'sound': 'sound.aif', 'zpush': '1', 'image': image,
  513. 'received_at': n_time, 'event_time': n_time, 'event_type': event_type, 'nickname': nickname,
  514. 'uid': uid, 'channel': channel, 'jump_type': jump_type
  515. }
  516. # 获取唯一标识符
  517. uid_push_qs = UidPushModel.objects.filter(token_val=token_val).values('m_code')
  518. m_code = uid_push_qs[0]['m_code'] if uid_push_qs[0]['m_code'] else ''
  519. # 推送 push_mode: 推送模式 (0:正式推送;1:测试推送,默认为0)
  520. # 推送 event_type: 消息类型 (0:运营类消息,1:系统类消息。默认为 0)
  521. # 推送 skip_type: 跳转类型(1:打开 APP 首页 2:打开链接 3:自定义 4:打开 app 内指定页面)
  522. activity = 'vpushscheme://com.vivo.pushvideo/detail'
  523. message = PushMessage() \
  524. .reg_id(token_val) \
  525. .title(msg_title) \
  526. .content(msg_text) \
  527. .push_mode(0) \
  528. .notify_type(3) \
  529. .skip_type(4) \
  530. .skip_content(activity) \
  531. .request_id(m_code) \
  532. .classification(1) \
  533. .client_custom_map(**push_data) \
  534. .message_dict()
  535. rec = sender_send.send(message)
  536. LOGGER.info('vivo推送结果:{}, 设备uid:{}'.format(rec, uid))
  537. if rec['result'] == 0 and event_type in DATA_PUSH_EVENT_TYPE_LIST:
  538. PushObject.jpush_transparent_transmission(msg_title, msg_text, app_bundle_id, jg_token_val, push_data)
  539. return True
  540. except Exception as e:
  541. LOGGER.error('vivo推送异常,uid:{},error_line:{},error_msg:{}'.
  542. format(uid, e.__traceback__.tb_lineno, repr(e)))
  543. return False
  544. @staticmethod
  545. def android_oppopush(channel_id, nickname, app_bundle_id, token_val, n_time, event_type, msg_title, msg_text,
  546. uid='', channel='1', image='', jg_token_val=''):
  547. """
  548. android oppo 推送
  549. @param channel_id: 通知通道id
  550. @param nickname: 设备昵称
  551. @param app_bundle_id: app包id
  552. @param token_val: 推送token
  553. @param jg_token_val: 推送token
  554. @param n_time: 当前时间
  555. @param event_type: 事件类型
  556. @param msg_title: 推送标题
  557. @param msg_text: 推送内容
  558. @param uid: uid
  559. @param channel: 通道
  560. @param image: 推送图片链接
  561. @return: bool
  562. """
  563. try:
  564. """
  565. android 国内oppo APP消息提醒推送
  566. """
  567. app_key = OPPOPUSH_CONFIG[app_bundle_id]['Key']
  568. master_secret = OPPOPUSH_CONFIG[app_bundle_id]['Secret']
  569. url = 'https://api.push.oppomobile.com/'
  570. now_time = str(round(time.time() * 1000))
  571. # 1、实例化一个sha256对象
  572. sha256 = hashlib.sha256()
  573. # 2、调用update方法进行加密
  574. sha256.update((app_key + now_time + master_secret).encode('utf-8'))
  575. # 3、调用hexdigest方法,获取加密结果
  576. sign = sha256.hexdigest()
  577. # 获取auth_token
  578. get_token_url = url + 'server/v1/auth'
  579. post_data = {
  580. 'app_key': app_key,
  581. 'sign': sign,
  582. 'timestamp': now_time
  583. }
  584. headers = {'Content-Type': 'application/x-www-form-urlencoded'}
  585. response = requests.post(get_token_url, data=post_data, headers=headers)
  586. result = response.json()
  587. # 发送推送
  588. push_url = url + 'server/v1/message/notification/unicast'
  589. extra_data = {'alert': msg_text, 'msg': '', 'sound': 'sound.aif', 'zpush': '1',
  590. 'received_at': n_time, 'event_time': n_time, 'event_type': event_type, 'nickname': nickname,
  591. 'uid': uid, 'channel': channel
  592. }
  593. message = {
  594. "target_type": 2,
  595. "target_value": token_val,
  596. "notification": {
  597. "title": msg_title,
  598. "content": msg_text,
  599. 'channel_id': channel_id,
  600. 'action_parameters': extra_data,
  601. 'click_action_type': 1,
  602. 'click_action_activity': OPPOPUSH_CONFIG[app_bundle_id]['click_action_activity']
  603. }
  604. }
  605. push_data = {
  606. 'auth_token': result['data']['auth_token'],
  607. 'message': json.dumps(message)
  608. }
  609. response = requests.post(push_url, data=push_data, headers=headers)
  610. LOGGER.info("oppo推送返回值:{}".format(response.json()))
  611. if response.status_code == 200 and event_type in DATA_PUSH_EVENT_TYPE_LIST:
  612. PushObject.jpush_transparent_transmission(msg_title, msg_text, app_bundle_id, jg_token_val, extra_data)
  613. return True
  614. except Exception as e:
  615. LOGGER.info("oppo推送异常:{}".format(repr(e)))
  616. return False
  617. @staticmethod
  618. def android_meizupush(token_val, n_time, event_type, msg_title, msg_text, uid='', channel='1',
  619. app_bundle_id='', appBundleId='', nickname='', image=''):
  620. """
  621. android 魅族推送(不支持图片)
  622. @param app_bundle_id: app包名
  623. @param appBundleId: app包名
  624. @param token_val: 推送token
  625. @param event_type: 消息类型 (0:运营类消息,1:系统类消息。默认为 0)
  626. @param msg_title: 推送标题
  627. @param msg_text: 推送内容
  628. @param n_time: 当前时间
  629. @param nickname: 设备昵称
  630. @param uid: uid
  631. @param image: 推送图片链接
  632. @param channel: 通道
  633. @return: bool
  634. """
  635. try:
  636. # 获取包和AppSecret
  637. app_bundle_id = app_bundle_id if app_bundle_id != '' else appBundleId
  638. appId = MEIZUPUSH_CONFIG[app_bundle_id]['ID']
  639. appSecret = MEIZUPUSH_CONFIG[app_bundle_id]['AppSecret']
  640. url = 'https://server-api-push.meizu.com/garcia/api/server/push/varnished/pushByPushId'
  641. # 跳转类型
  642. jump_type = CommonService.get_jump_type(event_type)
  643. extra_data = {'alert': msg_text, 'msg': '', 'sound': 'sound.aif', 'zpush': '1',
  644. 'received_at': n_time, 'event_time': n_time, 'event_type': event_type, 'nickname': nickname,
  645. 'uid': uid, 'channel': channel, 'jump_type': jump_type
  646. }
  647. # 转换为json格式
  648. extra_data = json.dumps(extra_data)
  649. if msg_title == '':
  650. msg_title = APP_BUNDLE_DICT[app_bundle_id]
  651. # 拼接发送内容
  652. activity = MEIZUPUSH_CONFIG[app_bundle_id]['click_action_activity']
  653. # clickType点击动作, 0打开应用, 1打开应用页面, 2打开url页面, 3应用客户端自定义
  654. messageJson = '{"clickTypeInfo": {"activity": "%s",' \
  655. '"clickType": 1, "parameters": %s },"extra": {},' % (activity, extra_data)
  656. noticeBarInfo = ('"noticeBarInfo": {"title": "%s", "content": "%s"},' % (msg_title, msg_text))
  657. noticeExpandInfo = '"noticeExpandInfo": {"noticeExpandType": 0}, "pushTimeInfo": {"validTime": 24}}'
  658. messageJson += noticeBarInfo
  659. messageJson += noticeExpandInfo
  660. data_meizu = {
  661. 'appId': appId,
  662. 'pushIds': token_val,
  663. 'messageJson': messageJson
  664. }
  665. # 魅族MD5加密,生成密钥
  666. sign = CommonService.getMD5Sign(data=data_meizu, key=appSecret)
  667. data = {
  668. 'appId': appId,
  669. 'messageJson': messageJson,
  670. 'sign': sign,
  671. 'pushIds': token_val,
  672. }
  673. # 进行推送
  674. response = requests.post(url, data=data)
  675. LOGGER.info("魅族推送结果:{}".format(response.json()))
  676. return True
  677. except Exception as e:
  678. LOGGER.info("魅族推送异常:{}".format(repr(e)))
  679. return False
  680. @staticmethod
  681. def android_honorpush(token_val, n_time, event_type, msg_title, msg_text,
  682. uid='', channel='1', image='', app_bundle_id='', appBundleId='', channel_id='', nickname=''):
  683. """
  684. android honor 推送
  685. @param channel_id: 通知通道id
  686. @param nickname: 设备昵称
  687. @param app_bundle_id: app包id
  688. @param appBundleId: app包id
  689. @param token_val: 推送token
  690. @param n_time: 当前时间
  691. @param event_type: 事件类型
  692. @param msg_title: 推送标题
  693. @param msg_text: 推送内容
  694. @param uid: uid
  695. @param channel: 通道
  696. @param image: 推送图片链接
  697. @return: bool
  698. """
  699. app_bundle_id = appBundleId if appBundleId else app_bundle_id
  700. try:
  701. client_id = HONORPUSH_CONFIG[app_bundle_id]['client_id']
  702. client_secret = HONORPUSH_CONFIG[app_bundle_id]['client_secret']
  703. app_id = HONORPUSH_CONFIG[app_bundle_id]['app_id']
  704. get_access_token_url = 'https://iam.developer.hihonor.com/auth/token'
  705. post_data = {
  706. 'grant_type': 'client_credentials',
  707. 'client_id': client_id,
  708. 'client_secret': client_secret
  709. }
  710. headers = {'Content-Type': 'application/x-www-form-urlencoded'}
  711. access_token_response = requests.post(get_access_token_url, data=post_data, headers=headers)
  712. access_result = access_token_response.json()
  713. authorization_token = 'Bearer ' + access_result['access_token']
  714. # 发送推送
  715. push_url = 'https://push-api.cloud.hihonor.com/api/v1/{}/sendMessage'.format(app_id)
  716. headers = {'Content-Type': 'application/json', 'Authorization': authorization_token,
  717. 'timestamp': str(int(time.time()) * 1000)}
  718. # 跳转类型
  719. jump_type = CommonService.get_jump_type(event_type)
  720. extra_data = {'alert': msg_text, 'msg': '', 'sound': 'sound.aif', 'zpush': '1',
  721. 'received_at': n_time, 'event_time': n_time, 'event_type': str(event_type),
  722. 'nickname': nickname, 'uid': uid, 'channel': channel, 'title': msg_title, 'body': msg_text,
  723. 'jump_type': jump_type
  724. }
  725. # 通知推送
  726. push_data = {
  727. "android": {
  728. "notification": {
  729. "body": msg_text,
  730. "title": msg_title,
  731. "importance": "NORMAL",
  732. "clickAction": {
  733. "type": 3,
  734. }
  735. },
  736. "targetUserType": 0,
  737. "data": json.dumps(extra_data)
  738. },
  739. "token": [token_val]
  740. }
  741. LOGGER.info("uid:{},时间:{},荣耀推送发送内容:{}".format(uid, n_time, push_data))
  742. response = requests.post(push_url, json=push_data, headers=headers)
  743. LOGGER.info("uid:{},时间:{},荣耀推送通知返回值:{}".format(uid, n_time, response.json()))
  744. # 一键通话透传推送
  745. if int(event_type) in DATA_PUSH_EVENT_TYPE_LIST:
  746. push_data = {
  747. "data": json.dumps(extra_data),
  748. "token": [token_val]
  749. }
  750. response = requests.post(push_url, json=push_data, headers=headers)
  751. LOGGER.info("uid:{},时间:{},荣耀透传推送返回值:{}".format(uid, n_time, response.json()))
  752. return True
  753. except Exception as e:
  754. LOGGER.info("荣耀推送异常:error_line:{},error_msg:{}".format(e.__traceback__.tb_lineno, repr(e)))
  755. return False
  756. @staticmethod
  757. def jpush_transparent_transmission(msg_title, msg_text, app_bundle_id, token_val, extra_data):
  758. """
  759. android 极光透传
  760. @param msg_title: 推送标题
  761. @param msg_text: 推送内容
  762. @param token_val: 推送token
  763. @param app_bundle_id: app包id
  764. @param extra_data: 额外数据
  765. @return: None
  766. """
  767. try:
  768. app_key = JPUSH_CONFIG[app_bundle_id]['Key']
  769. master_secret = JPUSH_CONFIG[app_bundle_id]['Secret']
  770. # 换成各自的app_key和master_secret
  771. _jpush = jpush.JPush(app_key, master_secret)
  772. push = _jpush.create_push()
  773. push.audience = jpush.registration_id(token_val)
  774. push.message = jpush.message(msg_content=msg_text, title=msg_title, extras=extra_data)
  775. push.platform = jpush.all_
  776. res = push.send()
  777. LOGGER.info('极光透传,结果:{},参数:{}'.format(res, extra_data))
  778. except Exception as e:
  779. LOGGER.info('jpush_transparent_transmission极光透传异常:errLine:{}, errMsg:{}, 参数:{}'.format(
  780. e.__traceback__.tb_lineno, repr(e), extra_data))