diff --git a/OPPO_PUSH_README.md b/OPPO_PUSH_README.md new file mode 100644 index 0000000..4b4625c --- /dev/null +++ b/OPPO_PUSH_README.md @@ -0,0 +1,121 @@ +# OPPO推送服务配置说明 + +## 配置信息 + +已配置的OPPO推送参数: +- **包名**: com.xunpaisoft.social +- **AppId**: 32150237 +- **AppKey**: bb0819c889ae40cd8bde5a8ad4e670fe +- **AppSecret**: 9b5a0e6d560e406dbb70fbb4e0e38098 +- **AppServerSecret**: 2d8b4e922d60453d987f0d09de6eb4a6 + +配置文件位置: `config/oppo.properties` + +## 启动服务 + +### 1. 编译项目 + +```bash +cd /home/renjianbo/push/push_server +mvn clean package +``` + +### 2. 运行服务 + +编译成功后,在 `target` 目录找到 `push-xxxx.jar`,然后执行: + +```bash +# 确保 config 目录在 jar 包同级目录 +java -jar target/push-*.jar +``` + +或者后台运行: + +```bash +nohup java -jar target/push-*.jar > push.log 2>&1 & +``` + +服务启动后,默认监听端口:**8085** + +## 测试推送 + +### 方法1: 使用测试脚本 + +```bash +cd /home/renjianbo/push/push_server +./test_oppo_push.sh +``` + +其中 `device_token` 是 OPPO 手机的 registration_id,需要从 OPPO 手机应用中获取。 + +### 方法2: 使用 curl 命令 + +```bash +curl -X POST http://localhost:8085/android/push \ + -H "Content-Type: application/json;charset=UTF-8" \ + -d '{ + "pushType": 5, + "pushMessageType": 0, + "packageName": "com.xunpaisoft.social", + "deviceToken": "YOUR_DEVICE_TOKEN", + "pushContent": "这是一条测试推送消息", + "sender": "test_user", + "senderName": "测试用户", + "target": "test_target", + "targetName": "测试目标", + "convType": 0, + "line": 0, + "cntType": 1, + "serverTime": 1234567890000, + "unReceivedMsg": 1, + "mentionedType": 0, + "isHiddenDetail": false, + "language": "zh", + "messageId": 1234567890, + "republish": false, + "existBadgeNumber": 0 + }' +``` + +**注意**: 将 `YOUR_DEVICE_TOKEN` 替换为实际的 OPPO 设备 registration_id。 + +## 获取 Device Token + +OPPO 手机的 registration_id(device_token)需要从以下方式获取: + +1. **从 OPPO 手机应用中获取**: 应用启动后,OPPO Push SDK 会返回 registration_id +2. **查看应用日志**: 在应用日志中查找 registration_id +3. **从 OPPO 推送平台获取**: 登录 OPPO 开放平台,在推送统计中可以看到设备的 registration_id + +## 验证推送 + +1. 确保 OPPO 手机已安装应用(包名: com.xunpaisoft.social) +2. 确保应用已获取推送权限 +3. 确保手机网络正常 +4. 发送测试推送后,检查手机是否收到通知 +5. 查看服务器日志: `tail -f push.log` 或查看控制台输出 + +## 常见问题 + +1. **推送失败**: + - 检查 device_token 是否正确 + - 检查包名是否匹配(com.xunpaisoft.social) + - 检查服务器日志中的错误信息 + +2. **服务启动失败**: + - 检查端口 8085 是否被占用 + - 检查 config 目录是否存在且配置文件正确 + +3. **配置不生效**: + - 确保 config 目录在 jar 包同级目录 + - 检查配置文件格式是否正确 + +## 日志查看 + +服务日志文件: `push.log` + +查看实时日志: +```bash +tail -f push.log +``` + diff --git a/config/application.properties b/config/application.properties index a30a91f..a3ac65c 100644 --- a/config/application.properties +++ b/config/application.properties @@ -1 +1 @@ -server.port=8085 \ No newline at end of file +server.port=8080 \ No newline at end of file diff --git a/config/oppo.properties b/config/oppo.properties index fffdcd1..9972b85 100644 --- a/config/oppo.properties +++ b/config/oppo.properties @@ -1,2 +1,6 @@ -oppo.AppKey=16c6afe503b24259928e082ef01a6bf2 -oppo.AppSecret=2114e4067de4424fbfc0638e311ce88c \ No newline at end of file +# OPPO推送服务配置 +# 包名: com.xunpaisoft.social +# AppId: 32150237 +oppo.AppKey=bb0819c889ae40cd8bde5a8ad4e670fe +oppo.AppSecret=9b5a0e6d560e406dbb70fbb4e0e38098 +oppo.AppServerSecret=2d8b4e922d60453d987f0d09de6eb4a6 \ No newline at end of file diff --git a/push.log b/push.log new file mode 100644 index 0000000..1e5c33b --- /dev/null +++ b/push.log @@ -0,0 +1,123 @@ +SLF4J: Class path contains multiple SLF4J bindings. +SLF4J: Found binding in [jar:file:/home/renjianbo/push/push_server-master/target/push-0.1.2.jar!/BOOT-INF/lib/logback-classic-1.2.3.jar!/org/slf4j/impl/StaticLoggerBinder.class] +SLF4J: Found binding in [jar:file:/home/renjianbo/push/push_server-master/target/push-0.1.2.jar!/BOOT-INF/lib/log4j-slf4j-impl-2.17.1.jar!/org/slf4j/impl/StaticLoggerBinder.class] +SLF4J: Found binding in [jar:file:/home/renjianbo/push/push_server-master/target/push-0.1.2.jar!/BOOT-INF/lib/slf4j-log4j12-1.7.5.jar!/org/slf4j/impl/StaticLoggerBinder.class] +SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation. +SLF4J: Actual binding is of type [ch.qos.logback.classic.util.ContextSelectorStaticBinder] + + . ____ _ __ _ _ + /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ +( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ + \\/ ___)| |_)| | | | | || (_| | ) ) ) ) + ' |____| .__|_| |_|_| |_\__, | / / / / + =========|_|==============|___/=/_/_/_/ + :: Spring Boot :: (v2.0.6.RELEASE) + +2025-12-31 09:59:06.314 INFO 24833 --- [ main] cn.wildfirechat.push.PushApplication : Starting PushApplication v0.1.2 on VM-4-13-centos with PID 24833 (/home/renjianbo/push/push_server-master/target/push-0.1.2.jar started by renjianbo in /home/renjianbo/push/push_server) +2025-12-31 09:59:06.321 INFO 24833 --- [ main] cn.wildfirechat.push.PushApplication : No active profile set, falling back to default profiles: default +2025-12-31 09:59:06.433 INFO 24833 --- [ main] ConfigServletWebServerApplicationContext : Refreshing org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@2a3046da: startup date [Wed Dec 31 09:59:06 CST 2025]; root of context hierarchy +2025-12-31 09:59:09.464 INFO 24833 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http) +2025-12-31 09:59:09.508 INFO 24833 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat] +2025-12-31 09:59:09.508 INFO 24833 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/8.5.34 +2025-12-31 09:59:09.574 INFO 24833 --- [ost-startStop-1] o.a.catalina.core.AprLifecycleListener : The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: [/usr/java/packages/lib/amd64:/usr/lib64:/lib64:/lib:/usr/lib] +2025-12-31 09:59:09.729 INFO 24833 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext +2025-12-31 09:59:09.729 INFO 24833 --- [ost-startStop-1] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 3300 ms +2025-12-31 09:59:09.836 INFO 24833 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean : Servlet dispatcherServlet mapped to [/] +2025-12-31 09:59:09.841 INFO 24833 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'characterEncodingFilter' to: [/*] +2025-12-31 09:59:09.841 INFO 24833 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'hiddenHttpMethodFilter' to: [/*] +2025-12-31 09:59:09.841 INFO 24833 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'httpPutFormContentFilter' to: [/*] +2025-12-31 09:59:09.841 INFO 24833 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'requestContextFilter' to: [/*] +2025-12-31 09:59:10.031 INFO 24833 --- [ main] c.w.push.android.oppo.OppoPush : OppoPush init start, appKey: bb0819c889ae40cd8bde5a8ad4e670fe, appSecret: 9b5a0e6d56..., appServerSecret: 2d8b4e922d... +2025-12-31 09:59:10.917 INFO 24833 --- [ main] c.w.push.android.oppo.OppoPush : OppoPush init success, using secret: appServerSecret +2025-12-31 09:59:11.313 ERROR 24833 --- [ main] cn.wildfirechat.push.ios.ApnsServer : ApnsServer init failed +java.security.InvalidKeyException: java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: IOException : null + at com.turo.pushy.apns.auth.ApnsSigningKey.loadFromInputStream(ApnsSigningKey.java:165) + at com.turo.pushy.apns.auth.ApnsSigningKey.loadFromPkcs8File(ApnsSigningKey.java:107) + at cn.wildfirechat.push.ios.ApnsServer.init(ApnsServer.java:60) + at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) + at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.lang.reflect.Method.invoke(Method.java:498) + at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement.invoke(InitDestroyAnnotationBeanPostProcessor.java:366) + at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata.invokeInitMethods(InitDestroyAnnotationBeanPostProcessor.java:309) + at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:136) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:416) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1686) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:573) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:495) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:317) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:315) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:251) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1135) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1062) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:581) + at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:90) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:370) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:572) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:495) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:317) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:315) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:251) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1135) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1062) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:581) + at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:90) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:370) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:572) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:495) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:317) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:315) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:759) + at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:867) + at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:548) + at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:140) + at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:754) + at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:386) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:307) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1242) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1230) + at cn.wildfirechat.push.PushApplication.main(PushApplication.java:9) + at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) + at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.lang.reflect.Method.invoke(Method.java:498) + at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:48) + at org.springframework.boot.loader.Launcher.launch(Launcher.java:87) + at org.springframework.boot.loader.Launcher.launch(Launcher.java:50) + at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:51) +Caused by: java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: IOException : null + at sun.security.ec.ECKeyFactory.engineGeneratePrivate(ECKeyFactory.java:169) + at java.security.KeyFactory.generatePrivate(KeyFactory.java:372) + at com.turo.pushy.apns.auth.ApnsSigningKey.loadFromInputStream(ApnsSigningKey.java:163) + ... 61 more +Caused by: java.security.InvalidKeyException: IOException : null + at sun.security.pkcs.PKCS8Key.decode(PKCS8Key.java:351) + at sun.security.pkcs.PKCS8Key.decode(PKCS8Key.java:356) + at sun.security.ec.ECPrivateKeyImpl.(ECPrivateKeyImpl.java:81) + at sun.security.ec.ECKeyFactory.implGeneratePrivate(ECKeyFactory.java:237) + at sun.security.ec.ECKeyFactory.engineGeneratePrivate(ECKeyFactory.java:165) + ... 63 more +2025-12-31 09:59:11.489 INFO 24833 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler] +2025-12-31 09:59:11.858 INFO 24833 --- [ main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@2a3046da: startup date [Wed Dec 31 09:59:06 CST 2025]; root of context hierarchy +2025-12-31 09:59:12.017 INFO 24833 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/android/push],methods=[POST],produces=[application/json;charset=UTF-8]}" onto public java.lang.Object cn.wildfirechat.push.PushController.androidPush(cn.wildfirechat.push.PushMessage) +2025-12-31 09:59:12.019 INFO 24833 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/ios/push],methods=[POST],produces=[application/json;charset=UTF-8]}" onto public java.lang.Object cn.wildfirechat.push.PushController.iOSPush(cn.wildfirechat.push.PushMessage) +2025-12-31 09:59:12.019 INFO 24833 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/harmony/push],methods=[POST],produces=[application/json;charset=UTF-8]}" onto public java.lang.Object cn.wildfirechat.push.PushController.hmPush(cn.wildfirechat.push.PushMessage) +2025-12-31 09:59:12.024 INFO 24833 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse) +2025-12-31 09:59:12.024 INFO 24833 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity> org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.error(javax.servlet.http.HttpServletRequest) +2025-12-31 09:59:12.103 INFO 24833 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler] +2025-12-31 09:59:12.104 INFO 24833 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler] +2025-12-31 09:59:12.605 INFO 24833 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup +2025-12-31 09:59:12.669 INFO 24833 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path '' +2025-12-31 09:59:12.677 INFO 24833 --- [ main] cn.wildfirechat.push.PushApplication : Started PushApplication in 7.306 seconds (JVM running for 8.144) +2025-12-31 09:59:22.368 INFO 24833 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : FrameworkServlet 'dispatcherServlet': initialization started +2025-12-31 09:59:22.389 INFO 24833 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : FrameworkServlet 'dispatcherServlet': initialization completed in 21 ms +2025-12-31 09:59:22.520 INFO 24833 --- [nio-8080-exec-1] c.w.push.android.AndroidPushServiceImpl : Android push {"sender":"test_user","senderName":"测试用户","convType":0,"target":"test_target","targetName":"测试目标","line":0,"cntType":1,"serverTime":1767146362000,"pushMessageType":0,"pushType":5,"pushContent":"这是一条测试推送消息 - 2025-12-31 09:59:22","unReceivedMsg":1,"mentionedType":0,"packageName":"com.xunpaisoft.social","deviceToken":"OPPO_CN_95ac9afc103d70bb26441ec0cbb06b97","isHiddenDetail":false,"language":"zh","messageId":1767146362,"callStartUid":0,"republish":false,"existBadgeNumber":0} +2025-12-31 09:59:22.626 INFO 24833 --- [pool-2-thread-1] c.w.push.android.oppo.OppoPush : Server response: MessageId: 32150237-1-1-6954837a1acc0c0174ca3d27 ErrorCode: ReturnCode{code=0, message='Success'} Reason: OK diff --git a/src/main/java/cn/wildfirechat/push/android/oppo/OppoConfig.java b/src/main/java/cn/wildfirechat/push/android/oppo/OppoConfig.java index 0a68473..bb51740 100644 --- a/src/main/java/cn/wildfirechat/push/android/oppo/OppoConfig.java +++ b/src/main/java/cn/wildfirechat/push/android/oppo/OppoConfig.java @@ -10,6 +10,7 @@ import org.springframework.context.annotation.PropertySource; public class OppoConfig { private String appSecret; private String appKey; + private String appServerSecret; public String getAppSecret() { return appSecret; @@ -26,4 +27,12 @@ public class OppoConfig { public void setAppKey(String appKey) { this.appKey = appKey; } + + public String getAppServerSecret() { + return appServerSecret; + } + + public void setAppServerSecret(String appServerSecret) { + this.appServerSecret = appServerSecret; + } } diff --git a/src/main/java/cn/wildfirechat/push/android/oppo/OppoPush.java b/src/main/java/cn/wildfirechat/push/android/oppo/OppoPush.java index 51b233f..d2739a8 100644 --- a/src/main/java/cn/wildfirechat/push/android/oppo/OppoPush.java +++ b/src/main/java/cn/wildfirechat/push/android/oppo/OppoPush.java @@ -28,9 +28,14 @@ public class OppoPush { @PostConstruct private void init() { try { - mSender = new Sender(mConfig.getAppKey(), mConfig.getAppSecret()); + // 根据 OPPO SDK 文档,Sender 的第二个参数应该是 masterSecret(appServerSecret) + // 如果配置了 appServerSecret,优先使用它;否则使用 appSecret + String secret = mConfig.getAppServerSecret() != null ? mConfig.getAppServerSecret() : mConfig.getAppSecret(); + mSender = new Sender(mConfig.getAppKey(), secret); + LOG.info("OppoPush initialized successfully with appKey: {}, using appServerSecret: {}", + mConfig.getAppKey(), mConfig.getAppServerSecret() != null); } catch (Exception e) { - LOG.error("OppoPush init failed"); + LOG.error("OppoPush init failed", e); e.printStackTrace(); } } diff --git a/test_oppo_push.sh b/test_oppo_push.sh new file mode 100755 index 0000000..82cb112 --- /dev/null +++ b/test_oppo_push.sh @@ -0,0 +1,58 @@ +#!/bin/bash + +# OPPO推送测试脚本 +# 使用方法: ./test_oppo_push.sh +# device_token: OPPO手机的registration_id,需要从OPPO手机应用中获取 + +if [ -z "$1" ]; then + echo "使用方法: $0 " + echo "device_token: OPPO手机的registration_id" + echo "" + echo "示例: $0 1234567890abcdef" + exit 1 +fi + +DEVICE_TOKEN=$1 +SERVER_URL="http://localhost:8080/android/push" + +echo "正在测试OPPO推送..." +echo "设备Token: $DEVICE_TOKEN" +echo "服务器地址: $SERVER_URL" +echo "" + +# 构建推送消息JSON +# pushType=5 表示 OPPO 推送类型 +# packageName 需要与配置的包名一致: com.xunpaisoft.social +curl -X POST "$SERVER_URL" \ + -H "Content-Type: application/json;charset=UTF-8" \ + -d "{ + \"pushType\": 5, + \"pushMessageType\": 0, + \"packageName\": \"com.xunpaisoft.social\", + \"deviceToken\": \"$DEVICE_TOKEN\", + \"pushContent\": \"这是一条测试推送消息\", + \"sender\": \"test_user\", + \"senderName\": \"测试用户\", + \"target\": \"test_target\", + \"targetName\": \"测试目标\", + \"convType\": 0, + \"line\": 0, + \"cntType\": 1, + \"serverTime\": $(date +%s)000, + \"unReceivedMsg\": 1, + \"mentionedType\": 0, + \"isHiddenDetail\": false, + \"language\": \"zh\", + \"messageId\": $(date +%s), + \"republish\": false, + \"existBadgeNumber\": 0 + }" + +echo "" +echo "" +echo "测试完成!请检查OPPO手机是否收到推送消息。" +echo "如果推送失败,请检查:" +echo "1. 服务器是否已启动 (端口 8080)" +echo "2. device_token 是否正确(需要从OPPO手机应用中获取)" +echo "3. 查看服务器日志: tail -f push.log" + diff --git a/test_push_8080.sh b/test_push_8080.sh new file mode 100755 index 0000000..e8415d8 --- /dev/null +++ b/test_push_8080.sh @@ -0,0 +1,95 @@ +#!/bin/bash + +# OPPO推送测试脚本 (使用8080端口) +# 使用方法: ./test_push_8080.sh +# device_token: OPPO手机的registration_id,需要从OPPO手机应用中获取 + +if [ -z "$1" ]; then + echo "==========================================" + echo "OPPO推送测试脚本 (端口: 8080)" + echo "==========================================" + echo "" + echo "使用方法: $0 " + echo "" + echo "device_token: OPPO手机的registration_id" + echo " (需要从OPPO手机应用中获取)" + echo "" + echo "示例: $0 1234567890abcdef1234567890abcdef" + echo "" + echo "如果没有device_token,请:" + echo "1. 在OPPO手机上安装应用 (包名: com.xunpaisoft.social)" + echo "2. 启动应用并查看日志获取registration_id" + echo "3. 或者从OPPO推送平台查看设备列表" + exit 1 +fi + +DEVICE_TOKEN=$1 +SERVER_URL="http://localhost:8080/android/push" + +echo "==========================================" +echo "正在测试OPPO推送..." +echo "==========================================" +echo "设备Token: $DEVICE_TOKEN" +echo "服务器地址: $SERVER_URL" +echo "包名: com.xunpaisoft.social" +echo "" + +# 构建推送消息JSON +# pushType=5 表示 OPPO 推送类型 +TIMESTAMP=$(date +%s) +MESSAGE_ID=$TIMESTAMP + +RESPONSE=$(curl -s -w "\nHTTP_CODE:%{http_code}" -X POST "$SERVER_URL" \ + -H "Content-Type: application/json;charset=UTF-8" \ + -d "{ + \"pushType\": 5, + \"pushMessageType\": 0, + \"packageName\": \"com.xunpaisoft.social\", + \"deviceToken\": \"$DEVICE_TOKEN\", + \"pushContent\": \"这是一条测试推送消息 - $(date '+%Y-%m-%d %H:%M:%S')\", + \"sender\": \"test_user\", + \"senderName\": \"测试用户\", + \"target\": \"test_target\", + \"targetName\": \"测试目标\", + \"convType\": 0, + \"line\": 0, + \"cntType\": 1, + \"serverTime\": ${TIMESTAMP}000, + \"unReceivedMsg\": 1, + \"mentionedType\": 0, + \"isHiddenDetail\": false, + \"language\": \"zh\", + \"messageId\": $MESSAGE_ID, + \"republish\": false, + \"existBadgeNumber\": 0 + }") + +HTTP_CODE=$(echo "$RESPONSE" | grep "HTTP_CODE:" | cut -d: -f2) +BODY=$(echo "$RESPONSE" | sed '/HTTP_CODE:/d') + +echo "----------------------------------------" +echo "服务器响应:" +echo "----------------------------------------" +echo "$BODY" | python -m json.tool 2>/dev/null || echo "$BODY" +echo "" +echo "HTTP状态码: $HTTP_CODE" +echo "" + +if [ "$HTTP_CODE" = "200" ]; then + echo "✓ 推送请求已发送成功!" + echo "" + echo "请检查:" + echo "1. OPPO手机是否收到推送通知" + echo "2. 查看服务器日志了解详细推送结果" +else + echo "✗ 推送请求失败 (HTTP $HTTP_CODE)" + echo "" + echo "请检查:" + echo "1. 服务器是否正常运行在8080端口" + echo "2. device_token 是否正确" + echo "3. 查看服务器日志: tail -f push.log 或查看控制台输出" +fi + +echo "" +echo "==========================================" +