You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

React Native安卓应用图标通知角标计数器实现失败求助:求可行方案或代码纠错

解决React Native Android应用图标角标计数器问题

首先,你的原生Java模块没生效的核心原因很明确:Android没有统一的系统级应用图标角标API,不同厂商(小米、华为、OPPO、vivo等)有各自的实现逻辑。而且你当前的代码只是创建了一个带数字的Notification对象,既没有发送这个通知,也没有针对厂商做适配——setNumber()只是设置通知本身的数字,不会直接显示在应用图标上。

一、修复你的原生模块代码

下面是针对主流Android厂商适配后的完整代码,覆盖小米、华为、OPPO、vivo以及原生Android的处理逻辑:

1. 更新BadgesModule.java

package com.yourpackage.name; // 替换成你的项目实际包名
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.content.Context;
import android.os.Build;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import androidx.core.app.NotificationCompat;

public class BadgesModule extends ReactContextBaseJavaModule {
    private final ReactApplicationContext context;
    private static final String NOTIFICATION_CHANNEL_ID = "badge_channel";
    private static final String NOTIFICATION_CHANNEL_NAME = "Badge Channel";

    public BadgesModule(ReactApplicationContext context) {
        super(context);
        this.context = context;
        createNotificationChannel();
    }

    @Override
    public String getName() {
        return "Badges";
    }

    // 创建Android 8.0+必须的通知渠道
    private void createNotificationChannel() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel(
                    NOTIFICATION_CHANNEL_ID,
                    NOTIFICATION_CHANNEL_NAME,
                    NotificationManager.IMPORTANCE_LOW
            );
            NotificationManager notificationManager = context.getSystemService(NotificationManager.class);
            if (notificationManager != null) {
                notificationManager.createNotificationChannel(channel);
            }
        }
    }

    @ReactMethod
    public void setNotificationBadge(int count) {
        NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
        
        // 1. 适配小米设备
        try {
            Class<?> miuiNotificationClass = Class.forName("android.app.MiuiNotification");
            Object miuiNotification = miuiNotificationClass.newInstance();
            java.lang.reflect.Field field = miuiNotification.getClass().getDeclaredField("messageCount");
            field.setAccessible(true);
            field.set(miuiNotification, count);
            
            NotificationCompat.Builder builder = new NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID);
            Notification notification = builder.build();
            field = notification.getClass().getField("extraNotification");
            field.set(notification, miuiNotification);
            
            if (count > 0) {
                notificationManager.notify(1, notification);
            } else {
                notificationManager.cancel(1);
            }
            return;
        } catch (Exception e) {
            // 非小米设备,继续处理其他厂商
        }

        // 2. 适配华为设备
        try {
            String packageName = context.getPackageName();
            android.os.Bundle bundle = new android.os.Bundle();
            bundle.putString("package", packageName);
            bundle.putString("class", context.getPackageManager().getLaunchIntentForPackage(packageName).getComponent().getClassName());
            bundle.putInt("badgenumber", count);
            context.getContentResolver().call(
                    android.net.Uri.parse("content://com.huawei.android.launcher.settings/badge/"),
                    "change_badge",
                    null,
                    bundle
            );
            return;
        } catch (Exception e) {
            // 非华为设备,继续处理
        }

        // 3. 适配OPPO设备
        try {
            String packageName = context.getPackageName();
            android.os.Bundle bundle = new android.os.Bundle();
            bundle.putInt("app_badge_count", count);
            context.getContentResolver().call(
                    android.net.Uri.parse("content://com.android.badge/badge"),
                    "setBadge",
                    packageName,
                    bundle
            );
            return;
        } catch (Exception e) {
            // 非OPPO设备,继续处理
        }

        // 4. 适配vivo设备
        try {
            Class<?> vivoBadgeClass = Class.forName("com.vivo.notification.sdk.StatusBarNotificationUtils");
            java.lang.reflect.Method method = vivoBadgeClass.getMethod("setBadgeNumber", Context.class, int.class);
            method.invoke(null, context, count);
            return;
        } catch (Exception e) {
            // 非vivo设备,继续处理
        }

        // 5. 原生Android适配(仅部分原生系统支持,如Android 13+)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
            if (count > 0) {
                Notification notification = new NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID)
                        .setSmallIcon(R.mipmap.ic_launcher) // 替换成你的应用小图标
                        .setNumber(count)
                        .build();
                notificationManager.notify(1, notification);
            } else {
                notificationManager.cancel(1);
            }
        }
    }
}

2. 确保BadgesPackage.java的包名正确

package com.yourpackage.name; // 替换成你的项目实际包名
import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;
import java.util.Collections;
import java.util.List;
import java.util.ArrayList;

public class BadgesPackage implements ReactPackage {
    @Override
    public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
        return Collections.emptyList();
    }

    @Override
    public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
        List<NativeModule> modules = new ArrayList<>();
        modules.add(new BadgesModule(reactContext));
        return modules;
    }
}

3. 关键注意事项

  • 替换代码中的com.yourpackage.name为你项目的实际包名
  • 确保R.mipmap.ic_launcher是你应用的小图标路径(路径不同请自行调整)
  • 部分厂商要求应用拥有通知权限才能修改角标,建议在JS端先请求通知权限

二、更省心的替代方案:使用成熟第三方库

如果不想自己维护原生适配代码,推荐使用专门处理角标的第三方库,比如:

react-native-badge-control

这个库已经封装了主流Android厂商的适配逻辑,使用极简:

  1. 安装依赖:
npm install react-native-badge-control --save
  1. 自动配置(少数版本可能需要手动链接)
  2. JS端调用:
import BadgeControl from 'react-native-badge-control';

// 设置角标数字
BadgeControl.setBadgeCount(2);

// 清除角标
BadgeControl.clearBadge();

react-native-push-notification

如果你已经用这个库处理推送,它也支持Android角标设置,只需在配置中启用相关选项,然后调用:

import PushNotification from 'react-native-push-notification';

PushNotification.setApplicationIconBadgeNumber(2);

三、优化JS端调用逻辑

建议在调用时区分平台,确保iOS和Android逻辑分离:

import { NativeModules, Platform } from 'react-native';
import PushNotification from 'react-native-push-notification';

const BadgeModule = NativeModules.Badges;

export const useBadgeNumbers = (count) => {
    if (Platform.OS === 'ios') {
        // iOS沿用你原来的实现
        PushNotification.setApplicationIconBadgeNumber(count);
    } else {
        BadgeModule?.setNotificationBadge(count);
    }
};

内容的提问来源于stack exchange,提问作者vasilek_

火山引擎 最新活动