From afebf6404cc104d9fec563819a9bf46aa5651f50 Mon Sep 17 00:00:00 2001 From: rjb <263303411@qq.com> Date: Wed, 31 Dec 2025 10:42:38 +0800 Subject: [PATCH] =?UTF-8?q?=E7=BB=95=E5=BC=80=E5=B9=B3=E5=8F=B0=E5=BC=BA?= =?UTF-8?q?=E6=8F=90=E9=86=92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Android通知渠道配置示例代码.java | 262 ++++++++++++++++++ Android高优先级通知渠道配置指南.md | 414 +++++++++++++++++++++++++++++ OPPO推送强提醒替代方案.md | 90 +++++++ push.log | 2 + test_communication_service_push.sh | 115 ++++++++ test_new_channel_push.sh | 132 +++++++++ test_strong_reminder_push.sh | 81 ++++++ 通讯与服务类消息权限申请说明.md | 80 ++++++ 通讯与服务类消息配置说明.md | 66 +++++ 9 files changed, 1242 insertions(+) create mode 100644 Android通知渠道配置示例代码.java create mode 100644 Android高优先级通知渠道配置指南.md create mode 100644 OPPO推送强提醒替代方案.md create mode 100755 test_communication_service_push.sh create mode 100755 test_new_channel_push.sh create mode 100755 test_strong_reminder_push.sh create mode 100644 通讯与服务类消息权限申请说明.md create mode 100644 通讯与服务类消息配置说明.md diff --git a/Android通知渠道配置示例代码.java b/Android通知渠道配置示例代码.java new file mode 100644 index 0000000..2c05bd6 --- /dev/null +++ b/Android通知渠道配置示例代码.java @@ -0,0 +1,262 @@ +/** + * Android 高优先级通知渠道配置 - 完整示例代码 + * 包名: com.xunpaisoft.social + */ + +// ============================================ +// 1. Application.java - 创建通知渠道 +// ============================================ +package com.xunpaisoft.social; + +import android.app.Application; +import android.app.NotificationChannel; +import android.app.NotificationManager; +import android.content.Context; +import android.media.AudioAttributes; +import android.os.Build; + +public class MyApplication extends Application { + + public static final String CHANNEL_ID_IMPORTANT = "important_messages"; + public static final String CHANNEL_NAME_IMPORTANT = "重要消息"; + + @Override + public void onCreate() { + super.onCreate(); + createNotificationChannels(); + } + + private void createNotificationChannels() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + NotificationManager notificationManager = + (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); + + // 检查渠道是否已存在 + if (notificationManager.getNotificationChannel(CHANNEL_ID_IMPORTANT) == null) { + NotificationChannel importantChannel = new NotificationChannel( + CHANNEL_ID_IMPORTANT, + CHANNEL_NAME_IMPORTANT, + NotificationManager.IMPORTANCE_HIGH // 高优先级 + ); + + // 设置渠道描述 + importantChannel.setDescription("重要消息通知,包括即时聊天、语音通话等"); + + // 启用指示灯 + importantChannel.enableLights(true); + importantChannel.setLightColor(android.graphics.Color.BLUE); + + // 启用振动 + importantChannel.enableVibration(true); + // 设置振动模式:等待0ms,振动1000ms,暂停500ms,再振动1000ms + importantChannel.setVibrationPattern(new long[]{0, 1000, 500, 1000}); + + // 设置通知声音(使用系统默认通知声音) + importantChannel.setSound( + android.provider.Settings.System.DEFAULT_NOTIFICATION_URI, + new AudioAttributes.Builder() + .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION) + .setUsage(AudioAttributes.USAGE_NOTIFICATION) + .build() + ); + + // 在锁屏上显示 + importantChannel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC); + + // 创建渠道 + notificationManager.createNotificationChannel(importantChannel); + } + } + } +} + +// ============================================ +// 2. PushNotificationHelper.java - 显示通知 +// ============================================ +package com.xunpaisoft.social; + +import android.app.Notification; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.content.Context; +import android.content.Intent; +import android.graphics.BitmapFactory; +import android.os.Build; + +public class PushNotificationHelper { + + private static final String CHANNEL_ID = MyApplication.CHANNEL_ID_IMPORTANT; + + /** + * 显示推送通知 + * @param context 上下文 + * @param title 通知标题 + * @param content 通知内容 + */ + public static void showNotification(Context context, String title, String content) { + NotificationManager notificationManager = + (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); + + // 创建点击意图 + Intent intent = new Intent(context, MainActivity.class); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); + + PendingIntent pendingIntent = PendingIntent.getActivity( + context, + 0, + intent, + PendingIntent.FLAG_UPDATE_CURRENT | + (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ? PendingIntent.FLAG_IMMUTABLE : 0) + ); + + // 构建通知 + Notification.Builder builder; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + // Android 8.0 及以上使用渠道 + builder = new Notification.Builder(context, CHANNEL_ID); + } else { + // Android 8.0 以下 + builder = new Notification.Builder(context); + builder.setPriority(Notification.PRIORITY_HIGH); // 高优先级 + } + + builder.setContentTitle(title) + .setContentText(content) + .setSmallIcon(R.drawable.ic_notification) // 小图标(必须) + .setLargeIcon(BitmapFactory.decodeResource( + context.getResources(), + R.drawable.ic_launcher + )) // 大图标(可选) + .setContentIntent(pendingIntent) + .setAutoCancel(true) // 点击后自动取消 + .setDefaults(Notification.DEFAULT_ALL) // 使用默认声音、振动、灯光 + .setWhen(System.currentTimeMillis()) + .setShowWhen(true); + + // 设置通知样式(可选,显示更多内容) + Notification.BigTextStyle bigTextStyle = new Notification.BigTextStyle(); + bigTextStyle.bigText(content); + builder.setStyle(bigTextStyle); + + // 显示通知 + int notificationId = (int) System.currentTimeMillis(); + notificationManager.notify(notificationId, builder.build()); + } +} + +// ============================================ +// 3. OppoPushMessageService.java - OPPO推送处理 +// ============================================ +package com.xunpaisoft.social; + +import android.content.Context; +import com.heytap.msp.push.mode.DataMessage; +import com.heytap.msp.push.service.DataMessageCallbackService; + +public class OppoPushMessageService extends DataMessageCallbackService { + + @Override + public void processMessage(Context context, DataMessage dataMessage) { + super.processMessage(context, dataMessage); + + // 获取推送消息内容 + String title = dataMessage.getTitle(); + String content = dataMessage.getContent(); + + // 使用高优先级通知渠道显示通知 + PushNotificationHelper.showNotification(context, title, content); + } +} + +// ============================================ +// 4. MainActivity.java - 权限申请(Android 13+) +// ============================================ +package com.xunpaisoft.social; + +import android.Manifest; +import android.content.pm.PackageManager; +import android.os.Build; +import android.os.Bundle; +import androidx.appcompat.app.AppCompatActivity; +import androidx.core.app.ActivityCompat; +import androidx.core.content.ContextCompat; + +public class MainActivity extends AppCompatActivity { + + private static final int REQUEST_NOTIFICATION_PERMISSION = 1001; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + // Android 13+ (API 33+) 需要动态申请通知权限 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + if (ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) + != PackageManager.PERMISSION_GRANTED) { + ActivityCompat.requestPermissions( + this, + new String[]{Manifest.permission.POST_NOTIFICATIONS}, + REQUEST_NOTIFICATION_PERMISSION + ); + } + } + } + + @Override + public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + if (requestCode == REQUEST_NOTIFICATION_PERMISSION) { + if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + // 权限已授予,可以显示通知 + } + } + } +} + +// ============================================ +// 5. AndroidManifest.xml 配置 +// ============================================ +/* + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +*/ + diff --git a/Android高优先级通知渠道配置指南.md b/Android高优先级通知渠道配置指南.md new file mode 100644 index 0000000..9c97afc --- /dev/null +++ b/Android高优先级通知渠道配置指南.md @@ -0,0 +1,414 @@ +# Android 高优先级通知渠道配置指南 + +## 概述 + +在 Android 应用中配置高优先级通知渠道,可以实现强提醒效果,包括: +- ✓ 灭屏状态下的声音和振动提醒 +- ✓ 锁屏界面显示通知 +- ✓ 通知栏显示消息 +- ✓ 绕过免打扰模式(部分情况下) + +## 实现步骤 + +### 1. 创建高优先级通知渠道 + +在应用启动时(Application 或 MainActivity 的 onCreate 中)创建通知渠道: + +```java +import android.app.Application; +import android.app.NotificationChannel; +import android.app.NotificationManager; +import android.content.Context; +import android.media.AudioAttributes; +import android.net.Uri; +import android.os.Build; + +public class MyApplication extends Application { + + public static final String CHANNEL_ID_IMPORTANT = "important_messages"; + public static final String CHANNEL_NAME_IMPORTANT = "重要消息"; + + @Override + public void onCreate() { + super.onCreate(); + createNotificationChannels(); + } + + private void createNotificationChannels() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + NotificationManager notificationManager = + (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); + + // 创建高优先级通知渠道 + NotificationChannel importantChannel = new NotificationChannel( + CHANNEL_ID_IMPORTANT, + CHANNEL_NAME_IMPORTANT, + NotificationManager.IMPORTANCE_HIGH // 高优先级 + ); + + // 设置渠道描述 + importantChannel.setDescription("重要消息通知,包括即时聊天、语音通话等"); + + // 启用指示灯 + importantChannel.enableLights(true); + importantChannel.setLightColor(android.graphics.Color.BLUE); + + // 启用振动 + importantChannel.enableVibration(true); + // 设置振动模式:等待0ms,振动1000ms,暂停500ms,再振动1000ms + importantChannel.setVibrationPattern(new long[]{0, 1000, 500, 1000}); + + // 设置通知声音(使用系统默认通知声音) + importantChannel.setSound( + android.provider.Settings.System.DEFAULT_NOTIFICATION_URI, + new AudioAttributes.Builder() + .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION) + .setUsage(AudioAttributes.USAGE_NOTIFICATION) + .build() + ); + + // 设置绕过免打扰模式(需要用户授权) + // importantChannel.setBypassDnd(true); + + // 在锁屏上显示 + importantChannel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC); + + // 创建渠道 + notificationManager.createNotificationChannel(importantChannel); + } + } +} +``` + +### 2. 在 AndroidManifest.xml 中注册 Application + +```xml + + ... + +``` + +### 3. 处理 OPPO 推送消息时使用该渠道 + +当收到 OPPO 推送消息时,在显示通知时指定使用该渠道: + +```java +import android.app.Notification; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.content.Context; +import android.content.Intent; +import android.graphics.BitmapFactory; +import android.os.Build; + +public class PushMessageHandler { + + private Context context; + private NotificationManager notificationManager; + + public PushMessageHandler(Context context) { + this.context = context; + this.notificationManager = + (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); + } + + /** + * 显示推送通知 + * @param title 通知标题 + * @param content 通知内容 + * @param data 推送数据(可选) + */ + public void showNotification(String title, String content, Map data) { + // 创建点击意图 + Intent intent = new Intent(context, MainActivity.class); + if (data != null) { + for (Map.Entry entry : data.entrySet()) { + intent.putExtra(entry.getKey(), entry.getValue()); + } + } + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); + + PendingIntent pendingIntent = PendingIntent.getActivity( + context, + 0, + intent, + PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE + ); + + // 构建通知 + Notification.Builder builder; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + // Android 8.0 及以上使用渠道 + builder = new Notification.Builder(context, MyApplication.CHANNEL_ID_IMPORTANT); + } else { + // Android 8.0 以下 + builder = new Notification.Builder(context); + } + + builder.setContentTitle(title) + .setContentText(content) + .setSmallIcon(R.drawable.ic_notification) // 小图标 + .setLargeIcon(BitmapFactory.decodeResource( + context.getResources(), + R.drawable.ic_launcher + )) // 大图标 + .setContentIntent(pendingIntent) + .setAutoCancel(true) // 点击后自动取消 + .setPriority(Notification.PRIORITY_HIGH) // 高优先级(Android 7.1及以下) + .setDefaults(Notification.DEFAULT_ALL) // 使用默认声音、振动、灯光 + .setWhen(System.currentTimeMillis()) + .setShowWhen(true); + + // 设置通知样式(可选) + Notification.BigTextStyle bigTextStyle = new Notification.BigTextStyle(); + bigTextStyle.bigText(content); + builder.setStyle(bigTextStyle); + + // 显示通知 + int notificationId = (int) System.currentTimeMillis(); + notificationManager.notify(notificationId, builder.build()); + } +} +``` + +### 4. 在 OPPO 推送接收处理中使用 + +```java +import com.heytap.msp.push.mode.DataMessage; +import com.heytap.msp.push.service.DataMessageCallbackService; + +public class OppoPushMessageService extends DataMessageCallbackService { + + @Override + public void processMessage(Context context, DataMessage dataMessage) { + super.processMessage(context, dataMessage); + + // 获取推送消息内容 + String title = dataMessage.getTitle(); + String content = dataMessage.getContent(); + Map extra = dataMessage.getExtra(); + + // 使用高优先级通知渠道显示通知 + PushMessageHandler handler = new PushMessageHandler(context); + handler.showNotification(title, content, extra); + } +} +``` + +### 5. 在 AndroidManifest.xml 中注册推送服务 + +```xml + + ... + + + + + + + + + ... + +``` + +## 完整示例代码 + +### Application.java + +```java +package com.xunpaisoft.social; + +import android.app.Application; +import android.app.NotificationChannel; +import android.app.NotificationManager; +import android.content.Context; +import android.media.AudioAttributes; +import android.os.Build; + +public class MyApplication extends Application { + + public static final String CHANNEL_ID_IMPORTANT = "important_messages"; + public static final String CHANNEL_NAME_IMPORTANT = "重要消息"; + + @Override + public void onCreate() { + super.onCreate(); + createNotificationChannels(); + } + + private void createNotificationChannels() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + NotificationManager notificationManager = + (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); + + // 检查渠道是否已存在 + if (notificationManager.getNotificationChannel(CHANNEL_ID_IMPORTANT) == null) { + NotificationChannel importantChannel = new NotificationChannel( + CHANNEL_ID_IMPORTANT, + CHANNEL_NAME_IMPORTANT, + NotificationManager.IMPORTANCE_HIGH + ); + + importantChannel.setDescription("重要消息通知"); + importantChannel.enableLights(true); + importantChannel.enableVibration(true); + importantChannel.setVibrationPattern(new long[]{0, 1000, 500, 1000}); + importantChannel.setSound( + android.provider.Settings.System.DEFAULT_NOTIFICATION_URI, + new AudioAttributes.Builder() + .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION) + .setUsage(AudioAttributes.USAGE_NOTIFICATION) + .build() + ); + + notificationManager.createNotificationChannel(importantChannel); + } + } + } +} +``` + +### PushNotificationHelper.java + +```java +package com.xunpaisoft.social; + +import android.app.Notification; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.content.Context; +import android.content.Intent; +import android.os.Build; + +public class PushNotificationHelper { + + private static final String CHANNEL_ID = MyApplication.CHANNEL_ID_IMPORTANT; + + public static void showNotification(Context context, String title, String content) { + NotificationManager notificationManager = + (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); + + Intent intent = new Intent(context, MainActivity.class); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); + + PendingIntent pendingIntent = PendingIntent.getActivity( + context, + 0, + intent, + PendingIntent.FLAG_UPDATE_CURRENT | + (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ? PendingIntent.FLAG_IMMUTABLE : 0) + ); + + Notification.Builder builder; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + builder = new Notification.Builder(context, CHANNEL_ID); + } else { + builder = new Notification.Builder(context); + builder.setPriority(Notification.PRIORITY_HIGH); + } + + builder.setContentTitle(title) + .setContentText(content) + .setSmallIcon(R.drawable.ic_notification) + .setContentIntent(pendingIntent) + .setAutoCancel(true) + .setDefaults(Notification.DEFAULT_ALL); + + int notificationId = (int) System.currentTimeMillis(); + notificationManager.notify(notificationId, builder.build()); + } +} +``` + +## 权限配置 + +在 `AndroidManifest.xml` 中添加必要权限: + +```xml + + + + + + + + + + + + ... + + +``` + +## Android 13+ (API 33+) 权限处理 + +Android 13 及以上版本需要动态申请通知权限: + +```java +import android.Manifest; +import android.content.pm.PackageManager; +import androidx.core.app.ActivityCompat; +import androidx.core.content.ContextCompat; + +public class MainActivity extends AppCompatActivity { + + private static final int REQUEST_NOTIFICATION_PERMISSION = 1001; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + // Android 13+ 需要动态申请通知权限 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + if (ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) + != PackageManager.PERMISSION_GRANTED) { + ActivityCompat.requestPermissions( + this, + new String[]{Manifest.permission.POST_NOTIFICATIONS}, + REQUEST_NOTIFICATION_PERMISSION + ); + } + } + } + + @Override + public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + if (requestCode == REQUEST_NOTIFICATION_PERMISSION) { + if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + // 权限已授予 + } + } + } +} +``` + +## 测试验证 + +1. **安装应用**:在 OPPO 手机上安装配置好的应用 +2. **发送推送**:使用之前的测试脚本发送推送消息 +3. **验证效果**: + - ✓ 灭屏状态下应该有声音和振动 + - ✓ 锁屏界面应该显示通知 + - ✓ 通知栏应该显示消息 + - ✓ 通知应该使用"重要消息"渠道 + +## 注意事项 + +1. **渠道创建时机**:通知渠道应该在应用启动时创建,且只需创建一次 +2. **渠道优先级**:`IMPORTANCE_HIGH` 表示高优先级,会显示在通知栏顶部并发出声音 +3. **用户设置**:用户可以在系统设置中修改渠道的提醒方式,但高优先级渠道默认会启用声音和振动 +4. **兼容性**:Android 8.0 (API 26) 及以上版本才支持通知渠道,低版本会自动使用传统通知方式 + +## 与 OPPO 推送集成 + +当收到 OPPO 推送消息时,在消息处理回调中使用配置好的通知渠道显示通知即可。这样即使不使用通讯与服务类消息权限,也能实现强提醒效果。 + diff --git a/OPPO推送强提醒替代方案.md b/OPPO推送强提醒替代方案.md new file mode 100644 index 0000000..e00f7f7 --- /dev/null +++ b/OPPO推送强提醒替代方案.md @@ -0,0 +1,90 @@ +# OPPO推送 - 强提醒替代方案 + +## 问题 + +无法找到"通讯与服务类消息"权限申请入口,但需要实现强提醒功能。 + +## 替代方案 + +### 方案1: 使用 notify_level 参数(如果支持) + +即使不使用 `previte_message` 频道,也可以尝试设置 `notify_level` 参数: + +```json +{ + "notification": { + "notify_level": 2, // 2: 通知栏、锁屏、铃声、振动 + "offLine": true, + "offLineTtl": 86400 + } +} +``` + +### 方案2: 在应用端配置通知渠道 + +在 Android 应用中创建高优先级通知渠道: + +```java +// Android 代码示例 +if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + NotificationChannel channel = new NotificationChannel( + "high_priority_channel", + "重要消息", + NotificationManager.IMPORTANCE_HIGH + ); + channel.setDescription("重要消息通知"); + channel.enableLights(true); + channel.enableVibration(true); + channel.setVibrationPattern(new long[]{0, 1000, 500, 1000}); + channel.setSound(Uri.parse("android.resource://" + getPackageName() + "/" + R.raw.notification_sound), + new AudioAttributes.Builder() + .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION) + .setUsage(AudioAttributes.USAGE_NOTIFICATION) + .build()); + + NotificationManager notificationManager = getSystemService(NotificationManager.class); + notificationManager.createNotificationChannel(channel); +} +``` + +### 方案3: 联系 OPPO 客服 + +如果确实需要通讯与服务类消息权限,可以: +1. 在 OPPO 开放平台找到"咨询"或"客服"入口 +2. 说明需要申请通讯与服务类消息权限 +3. 提供应用信息和使用场景 + +### 方案4: 使用 HTTP API 测试其他参数组合 + +尝试不使用 `channel_id`,但设置其他强提醒参数: + +```json +{ + "notification": { + "title": "知你", + "content": "我是api", + "notify_level": 2, + "category": "IM", + "offLine": true, + "offLineTtl": 86400, + "showTimeType": 0, + "networkType": 0 + } +} +``` + +## 测试脚本 + +已创建测试脚本,可以尝试不同的参数组合: + +```bash +cd /home/renjianbo/push/push_server +./test_communication_service_push.sh OPPO_CN_95ac9afc103d70bb26441ec0cbb06b97 +``` + +## 建议 + +1. **优先尝试方案2**:在应用端配置高优先级通知渠道,这是最可靠的方案 +2. **联系客服**:如果必须使用通讯与服务类消息,联系 OPPO 客服咨询申请流程 +3. **查看文档**:在 OPPO 开放平台的"文档"中查找相关说明 + diff --git a/push.log b/push.log index 730f310..602d7e4 100644 --- a/push.log +++ b/push.log @@ -129,3 +129,5 @@ Caused by: java.security.InvalidKeyException: IOException : null 2025-12-31 10:07:07.002 INFO 24833 --- [pool-2-thread-2] c.w.push.android.oppo.OppoPush : Server response: MessageId: 32150237-1-1-6954854a35f9ec01757142d9 ErrorCode: ReturnCode{code=0, message='Success'} Reason: OK 2025-12-31 10:07:55.122 INFO 24833 --- [nio-8080-exec-8] c.w.push.android.AndroidPushServiceImpl : Android push {"sender":"api_user","senderName":"知你","convType":0,"target":"test_target","targetName":"测试目标","line":0,"cntType":1,"serverTime":1767146875000,"pushMessageType":0,"pushType":5,"pushContent":"我是api","unReceivedMsg":1,"mentionedType":0,"packageName":"com.xunpaisoft.social","deviceToken":"OPPO_CN_95ac9afc103d70bb26441ec0cbb06b97","isHiddenDetail":false,"language":"zh","messageId":1767146875,"callStartUid":0,"republish":false,"existBadgeNumber":0} 2025-12-31 10:07:55.249 INFO 24833 --- [pool-2-thread-2] c.w.push.android.oppo.OppoPush : Server response: MessageId: 32150237-1-1-6954857b816b510175dc87a7 ErrorCode: ReturnCode{code=0, message='Success'} Reason: OK +2025-12-31 10:13:08.533 INFO 24833 --- [nio-8080-exec-9] c.w.push.android.AndroidPushServiceImpl : Android push {"sender":"api_user","senderName":"知你","convType":0,"target":"test_target","targetName":"测试目标","line":0,"cntType":1,"serverTime":1767147188000,"pushMessageType":0,"pushType":5,"pushContent":"我是api","unReceivedMsg":1,"mentionedType":0,"packageName":"com.xunpaisoft.social","deviceToken":"OPPO_CN_95ac9afc103d70bb26441ec0cbb06b97","isHiddenDetail":false,"language":"zh","messageId":1767147188,"callStartUid":0,"republish":false,"existBadgeNumber":0} +2025-12-31 10:13:08.639 INFO 24833 --- [pool-2-thread-2] c.w.push.android.oppo.OppoPush : Server response: MessageId: 32150237-1-1-695486b415eb8d017545d1f9 ErrorCode: ReturnCode{code=0, message='Success'} Reason: OK diff --git a/test_communication_service_push.sh b/test_communication_service_push.sh new file mode 100755 index 0000000..3bfa536 --- /dev/null +++ b/test_communication_service_push.sh @@ -0,0 +1,115 @@ +#!/bin/bash + +# OPPO推送 - 通讯与服务类消息测试脚本 +# 此脚本使用 HTTP API 直接发送通讯与服务类消息,实现强提醒功能 + +if [ -z "$1" ]; then + echo "使用方法: $0 " + echo "device_token: OPPO设备的registration_id" + echo "" + echo "示例: $0 OPPO_CN_95ac9afc103d70bb26441ec0cbb06b97" + exit 1 +fi + +DEVICE_TOKEN=$1 + +# OPPO推送配置 +APP_KEY="bb0819c889ae40cd8bde5a8ad4e670fe" +APP_SERVER_SECRET="2d8b4e922d60453d987f0d09de6eb4a6" +API_URL="https://api.push.oppomobile.com" + +echo "==========================================" +echo "OPPO推送 - 通讯与服务类消息测试" +echo "==========================================" +echo "设备Token: $DEVICE_TOKEN" +echo "" + +# 1. 获取 auth_token +echo "步骤1: 获取 auth_token..." +TIMESTAMP=$(date +%s)000 + +# 生成签名: SHA256(app_key + timestamp + master_secret) +SIGN_STRING="${APP_KEY}${TIMESTAMP}${APP_SERVER_SECRET}" +SIGN=$(echo -n "$SIGN_STRING" | sha256sum | awk '{print $1}') + +echo "Timestamp: $TIMESTAMP" +echo "Sign: $SIGN" +echo "" + +# 获取 token +AUTH_RESPONSE=$(curl -s -X POST "${API_URL}/server/v1/auth" \ + -H "Content-Type: application/x-www-form-urlencoded" \ + -d "app_key=${APP_KEY}×tamp=${TIMESTAMP}&sign=${SIGN}") + +echo "Auth响应: $AUTH_RESPONSE" +echo "" + +# 解析 token +AUTH_TOKEN=$(echo "$AUTH_RESPONSE" | grep -o '"auth_token":"[^"]*' | cut -d'"' -f4) + +if [ -z "$AUTH_TOKEN" ]; then + echo "错误: 无法获取 auth_token" + echo "响应: $AUTH_RESPONSE" + exit 1 +fi + +echo "✓ 获取 auth_token 成功: ${AUTH_TOKEN:0:20}..." +echo "" + +# 2. 发送通讯与服务类消息 +echo "步骤2: 发送通讯与服务类消息..." +echo "" + +# 构建消息体(包含通讯与服务类消息参数) +MESSAGE_JSON=$(cat </dev/null || echo "$MESSAGE_JSON" +echo "" + +# 发送推送 +PUSH_RESPONSE=$(curl -s -X POST "${API_URL}/server/v1/message/notification/unicast" \ + -H "Content-Type: application/x-www-form-urlencoded" \ + -d "message=$(echo "$MESSAGE_JSON" | python -c "import sys, json, urllib.parse; print(urllib.parse.quote(json.dumps(json.load(sys.stdin))))" 2>/dev/null || echo "$MESSAGE_JSON")&auth_token=${AUTH_TOKEN}") + +echo "推送响应:" +echo "$PUSH_RESPONSE" | python -m json.tool 2>/dev/null || echo "$PUSH_RESPONSE" +echo "" + +# 检查结果 +if echo "$PUSH_RESPONSE" | grep -q '"code":0'; then + echo "✓ 推送成功!" + echo "" + echo "请检查OPPO手机:" + echo "1. 灭屏状态下应该有声音和振动提醒" + echo "2. 锁屏界面应该显示通知" + echo "3. 通知栏应该显示消息" + echo "4. 消息应该被分类为'通讯与服务'类型" +else + echo "✗ 推送失败" + echo "响应: $PUSH_RESPONSE" +fi + +echo "" +echo "==========================================" + diff --git a/test_new_channel_push.sh b/test_new_channel_push.sh new file mode 100755 index 0000000..c6ba173 --- /dev/null +++ b/test_new_channel_push.sh @@ -0,0 +1,132 @@ +#!/bin/bash + +# OPPO推送 - 使用新通道方式测试(通过category标记) +# 根据OPPO平台说明:如果标记category使用新通道能力,用户的通知二级开关默认开启 + +if [ -z "$1" ]; then + echo "使用方法: $0 " + exit 1 +fi + +DEVICE_TOKEN=$1 + +# OPPO推送配置 +APP_KEY="bb0819c889ae40cd8bde5a8ad4e670fe" +APP_SERVER_SECRET="2d8b4e922d60453d987f0d09de6eb4a6" +API_URL="https://api.push.oppomobile.com" + +echo "==========================================" +echo "OPPO推送 - 新通道方式测试(使用category标记)" +echo "==========================================" + +# 1. 获取 auth_token +TIMESTAMP=$(date +%s)000 +SIGN_STRING="${APP_KEY}${TIMESTAMP}${APP_SERVER_SECRET}" +SIGN=$(echo -n "$SIGN_STRING" | sha256sum | awk '{print $1}') + +AUTH_RESPONSE=$(curl -s -X POST "${API_URL}/server/v1/auth" \ + -H "Content-Type: application/x-www-form-urlencoded" \ + -d "app_key=${APP_KEY}×tamp=${TIMESTAMP}&sign=${SIGN}") + +AUTH_TOKEN=$(echo "$AUTH_RESPONSE" | grep -o '"auth_token":"[^"]*' | cut -d'"' -f4) + +if [ -z "$AUTH_TOKEN" ]; then + echo "错误: 无法获取 auth_token" + exit 1 +fi + +echo "✓ 获取 auth_token 成功" +echo "" + +# 2. 尝试方式1: 使用category标记,不指定channel_id(让系统自动使用新通道) +echo "方式1: 使用category=IM,不指定channel_id..." +MESSAGE_JSON1=$(cat </dev/null || echo "$MESSAGE_JSON1")&auth_token=${AUTH_TOKEN}") + +echo "响应1:" +echo "$PUSH_RESPONSE1" | python -m json.tool 2>/dev/null || echo "$PUSH_RESPONSE1" +echo "" + +# 3. 尝试方式2: 使用已存在的通道ID +echo "方式2: 使用已存在的通道ID (previte_message)..." +MESSAGE_JSON2=$(cat </dev/null || echo "$MESSAGE_JSON2")&auth_token=${AUTH_TOKEN}") + +echo "响应2:" +echo "$PUSH_RESPONSE2" | python -m json.tool 2>/dev/null || echo "$PUSH_RESPONSE2" +echo "" + +# 4. 尝试方式3: 使用其他已存在的通道ID +echo "方式3: 使用其他通道ID (oppo_push_im)..." +MESSAGE_JSON3=$(cat </dev/null || echo "$MESSAGE_JSON3")&auth_token=${AUTH_TOKEN}") + +echo "响应3:" +echo "$PUSH_RESPONSE3" | python -m json.tool 2>/dev/null || echo "$PUSH_RESPONSE3" +echo "" + +echo "==========================================" +echo "测试完成!请检查哪个方式成功,并在手机上验证提醒效果。" +echo "==========================================" + diff --git a/test_strong_reminder_push.sh b/test_strong_reminder_push.sh new file mode 100755 index 0000000..aa19113 --- /dev/null +++ b/test_strong_reminder_push.sh @@ -0,0 +1,81 @@ +#!/bin/bash + +# OPPO推送 - 强提醒测试脚本(不使用通讯与服务类消息权限) +# 尝试通过其他参数实现强提醒效果 + +if [ -z "$1" ]; then + echo "使用方法: $0 " + exit 1 +fi + +DEVICE_TOKEN=$1 + +# OPPO推送配置 +APP_KEY="bb0819c889ae40cd8bde5a8ad4e670fe" +APP_SERVER_SECRET="2d8b4e922d60453d987f0d09de6eb4a6" +API_URL="https://api.push.oppomobile.com" + +echo "==========================================" +echo "OPPO推送 - 强提醒测试(不使用通讯与服务权限)" +echo "==========================================" + +# 1. 获取 auth_token +TIMESTAMP=$(date +%s)000 +SIGN_STRING="${APP_KEY}${TIMESTAMP}${APP_SERVER_SECRET}" +SIGN=$(echo -n "$SIGN_STRING" | sha256sum | awk '{print $1}') + +AUTH_RESPONSE=$(curl -s -X POST "${API_URL}/server/v1/auth" \ + -H "Content-Type: application/x-www-form-urlencoded" \ + -d "app_key=${APP_KEY}×tamp=${TIMESTAMP}&sign=${SIGN}") + +AUTH_TOKEN=$(echo "$AUTH_RESPONSE" | grep -o '"auth_token":"[^"]*' | cut -d'"' -f4) + +if [ -z "$AUTH_TOKEN" ]; then + echo "错误: 无法获取 auth_token" + exit 1 +fi + +echo "✓ 获取 auth_token 成功" +echo "" + +# 2. 发送消息(尝试使用 notify_level 等参数,但不使用 channel_id) +MESSAGE_JSON=$(cat </dev/null || echo "$MESSAGE_JSON")&auth_token=${AUTH_TOKEN}") + +echo "响应:" +echo "$PUSH_RESPONSE" | python -m json.tool 2>/dev/null || echo "$PUSH_RESPONSE" + +if echo "$PUSH_RESPONSE" | grep -q '"code":0'; then + echo "" + echo "✓ 推送成功!" + echo "注意:如果仍然没有强提醒,建议在应用端配置高优先级通知渠道" +else + echo "" + echo "✗ 推送失败" +fi + +echo "" +echo "==========================================" + diff --git a/通讯与服务类消息权限申请说明.md b/通讯与服务类消息权限申请说明.md new file mode 100644 index 0000000..ede3d9d --- /dev/null +++ b/通讯与服务类消息权限申请说明.md @@ -0,0 +1,80 @@ +# OPPO推送 - 通讯与服务类消息权限申请说明 + +## 问题 + +发送通讯与服务类消息时,返回错误: +``` +{"code":67,"message":"private classify channel need permission"} +``` + +## 原因 + +使用 `previte_message` 频道(通讯与服务类消息)需要在 OPPO 开放平台申请特殊权限。 + +## 解决方案 + +### 步骤1: 登录 OPPO 开放平台 + +访问:https://open.oppomobile.com + +### 步骤2: 进入应用管理 + +1. 登录后,进入"应用管理" +2. 找到您的应用(包名: com.xunpaisoft.social) +3. 进入应用详情页面 + +### 步骤3: 申请通讯与服务类消息权限 + +1. 在应用详情页面,找到"推送服务"或"消息推送"相关设置 +2. 查找"通讯与服务类消息"或"私信类消息"权限申请入口 +3. 提交权限申请,填写相关信息: + - 应用用途说明 + - 使用场景说明 + - 为什么需要通讯与服务类消息权限 + +### 步骤4: 等待审核 + +- 通常审核时间为 1-3 个工作日 +- 审核通过后,即可使用 `previte_message` 频道发送通讯与服务类消息 + +## 申请权限后 + +权限申请通过后,可以使用以下参数发送通讯与服务类消息: + +```json +{ + "notification": { + "channel_id": "previte_message", + "channel_name": "消息推送", + "category": "IM", + "notify_level": 2 + } +} +``` + +这些参数将实现: +- ✓ 离线消息强提醒 +- ✓ 通知栏、锁屏、铃声、振动 +- ✓ 灭屏状态下的声音和振动提醒 + +## 临时方案 + +如果暂时无法申请权限,可以: +1. 使用普通推送消息(当前方式) +2. 在应用端配置通知渠道,实现部分强提醒效果 +3. 等待权限申请通过后再使用通讯与服务类消息 + +## 测试脚本 + +权限申请通过后,可以使用以下脚本测试: + +```bash +cd /home/renjianbo/push/push_server +./test_communication_service_push.sh OPPO_CN_95ac9afc103d70bb26441ec0cbb06b97 +``` + +## 相关文档 + +- OPPO推送服务文档:https://open.oppomobile.com/documentation/page/info?id=13189 +- OPPO开放平台:https://open.oppomobile.com + diff --git a/通讯与服务类消息配置说明.md b/通讯与服务类消息配置说明.md new file mode 100644 index 0000000..d196dfa --- /dev/null +++ b/通讯与服务类消息配置说明.md @@ -0,0 +1,66 @@ +# OPPO推送 - 通讯与服务类消息配置说明 + +## 问题描述 + +当前推送的消息是"内容与运营"类型,只有声音提醒,灭屏时没有强提醒。 +需要发送"通讯与服务"类型的消息,实现: +- 离线消息强提醒 +- 通知栏、锁屏、铃声、振动 + +## 解决方案 + +OPPO SDK 的 `Notification` 类不支持设置通讯与服务类消息的关键参数,需要使用 HTTP API 直接发送。 + +## 需要设置的参数 + +1. **channel_id**: `"previte_message"` - 通讯与服务频道ID(必须) +2. **channel_name**: `"消息推送"` - 频道名称(必须) +3. **category**: `"IM"` - 消息类别,IM表示即时聊天、音频、视频通话(必须) +4. **notify_level**: `2` - 通知级别,2表示通知栏、锁屏、铃声、振动(必须) + +## 实现方式 + +由于 `push_server-master` 项目使用的是 OPPO SDK,而 SDK 的 `Notification` 类不支持这些参数,需要: + +### 方案1: 修改为使用 HTTP API(推荐) + +修改 `OppoPush.java`,添加使用 HTTP API 发送通讯与服务类消息的方法。 + +### 方案2: 通过 API 直接调用(临时方案) + +不修改代码,直接通过 HTTP API 发送通讯与服务类消息。 + +## 直接使用 HTTP API 发送的示例 + +```bash +# 1. 先获取 auth_token +curl -X POST "https://api.push.oppomobile.com/server/v1/auth" \ + -H "Content-Type: application/x-www-form-urlencoded" \ + -d "app_key=bb0819c889ae40cd8bde5a8ad4e670fe×tamp=$(date +%s)000&sign=生成的签名" + +# 2. 使用 auth_token 发送通讯与服务类消息 +curl -X POST "https://api.push.oppomobile.com/server/v1/message/notification/unicast" \ + -H "Content-Type: application/x-www-form-urlencoded" \ + -d "message={\"target_type\":1,\"target_value\":\"OPPO_CN_95ac9afc103d70bb26441ec0cbb06b97\",\"notification\":{\"title\":\"知你\",\"content\":\"我是api\",\"channel_id\":\"previte_message\",\"channel_name\":\"消息推送\",\"category\":\"IM\",\"notify_level\":2,\"offLine\":true,\"offLineTtl\":86400,\"showTimeType\":0,\"networkType\":0}}&auth_token=你的auth_token" +``` + +## 注意事项 + +1. **频道ID必须正确**: `channel_id` 必须设置为 `"previte_message"`,这是 OPPO 系统识别的通讯与服务类消息标识 +2. **频道名称**: `channel_name` 必须设置为 `"消息推送"` +3. **通知级别**: `notify_level` 设置为 `2` 才能实现通知栏、锁屏、铃声、振动的强提醒 +4. **类别**: `category` 设置为 `"IM"` 表示即时聊天、音频、视频通话类消息 +5. **离线消息**: `offLine` 设置为 `true`,`offLineTtl` 建议设置为 `86400`(24小时) + +## 验证方法 + +发送通讯与服务类消息后,应该: +1. ✓ 在灭屏状态下有声音和振动提醒 +2. ✓ 在锁屏界面显示通知 +3. ✓ 在通知栏显示消息 +4. ✓ 消息被分类为"通讯与服务"类型 + +## 下一步 + +需要修改 `push_server-master/src/main/java/cn/wildfirechat/push/android/oppo/OppoPush.java`,添加使用 HTTP API 发送通讯与服务类消息的功能。 +