You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android应用无法接收OneSignal推送,控制台显示从未订阅

OneSignal + Firebase推送集成问题:授权后控制台仍显示「从未订阅」

我在Android应用中集成了OneSignal与Firebase推送服务,已完成下述配置:

  • 实现了MainActivity中的身份与权限处理、BiratBazarApp初始化逻辑、OneSignalManager单例管理类、BiratBazarNotificationService通知扩展类;
  • 配置了完整的ProGuard规则、AndroidManifest权限与OneSignal相关元数据;
  • build.gradle中引入了对应版本的Firebase BOM和OneSignal依赖;
  • Firebase已启用Cloud Messaging,OneSignal已关联Firebase配置。

但点击通知权限授权弹窗的「允许」按钮后,OneSignal控制台始终显示「从未订阅」,无法接收推送通知,请求协助排查问题原因。


相关代码与配置

MainActivity.java

// ─────────────────────────────────────────────
// OneSignal Identity + Permission Handling
// ─────────────────────────────────────────────

private IUserStateObserver identityObserver = null;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    SharedPreferences prefs = getSharedPreferences("biratbazar_prefs", Context.MODE_PRIVATE);
    boolean isLoggedIn = prefs.getBoolean("is_logged_in", false);
    String savedUserId = prefs.getString("user_id", null);

    // Observe user identity state
    identityObserver = state -> {
        String currentExternalId = state.getCurrent().getExternalId();
        String currentOnesignalId = state.getCurrent().getOnesignalId();

        Log.d("OneSignal", "User State Change: ExternalID=" 
                + currentExternalId + ", OneSignalID=" + currentOnesignalId);

        boolean isIdentified = isLoggedIn
                ? (currentExternalId != null && currentExternalId.equals(savedUserId))
                : (currentOnesignalId != null);

        if (isIdentified && identityObserver != null) {
            Log.d("OneSignal", "Identity confirmed. Requesting permission...");

            IUserStateObserver toRemove = identityObserver;
            identityObserver = null;
            OneSignal.getUser().removeObserver(toRemove);

            runOnUiThread(this::requestOneSignalPermission);
        }
    };

    OneSignal.getUser().addObserver(identityObserver);

    // Debug: subscription state
    OneSignal.getUser().getPushSubscription().addObserver(state -> {
        boolean hasToken = state.getCurrent().getToken() != null
                && !state.getCurrent().getToken().isEmpty();

        Log.d("OneSignal", "Subscription Changed: ID="
                + state.getCurrent().getId()
                + ", OptedIn=" + state.getCurrent().getOptedIn()
                + ", HasToken=" + hasToken);
    });

    // Login with external ID if available
    if (isLoggedIn && savedUserId != null) {
        OneSignalManager.getInstance().login(savedUserId);
    }
}

// ─────────────────────────────────────────────
// Request Permission
// ─────────────────────────────────────────────

private void requestOneSignalPermission() {
    OneSignal.getNotifications().requestPermission(true, Continue.with(result -> {
        if (result.isSuccess() && Boolean.TRUE.equals(result.getData())) {
            Log.d("OneSignal", "Permission granted → opting in");
            OneSignal.getUser().getPushSubscription().optIn();
        } else {
            Log.d("OneSignal", "Permission not granted or failed: " + result);
        }
    }));
}

// ─────────────────────────────────────────────
// Ensure opt-in on resume
// ─────────────────────────────────────────────

@Override
protected void onResume() {
    super.onResume();

    if (OneSignal.getNotifications().getPermission()) {
        OneSignal.getUser().getPushSubscription().optIn();
    }
}

BiratBazarApp.java

package com.officersiam.biratbazar;

import android.app.Application;
import android.util.Log;
import com.google.firebase.FirebaseApp;
import com.onesignal.Continue;
import com.onesignal.OneSignal;
import com.onesignal.debug.LogLevel;

public class BiratBazarApp extends Application {

    private static final String ONESIGNAL_APP_ID = "58eeb5a7-3adf-4d9d-8915-f45c6a542284";

    @Override
    public void onCreate() {
        super.onCreate();

        // 1. Initialize Firebase first
        try {
            FirebaseApp.initializeApp(this);
        } catch (Exception e) {
            Log.e("Firebase", "Firebase init error", e);
        }

        // 2. Initialize OneSignal
        OneSignalManager.getInstance().initialize(this, ONESIGNAL_APP_ID);
    }
}

OneSignalManager.java

package com.officersiam.biratbazar;

import android.content.Context;
import android.util.Log;
import com.onesignal.OneSignal;
import com.onesignal.debug.LogLevel;
import com.onesignal.user.subscriptions.IPushSubscriptionObserver;
import com.onesignal.user.subscriptions.PushSubscriptionChangedState;
import com.onesignal.inAppMessages.IInAppMessageLifecycleListener;
import com.onesignal.inAppMessages.IInAppMessageWillDismissEvent;
import com.onesignal.inAppMessages.IInAppMessageDidDismissEvent;
import com.onesignal.inAppMessages.IInAppMessageWillDisplayEvent;
import com.onesignal.inAppMessages.IInAppMessageDidDisplayEvent;
import java.util.concurrent.Executors;
import androidx.annotation.NonNull;

public class OneSignalManager {
    private static OneSignalManager instance;
    private boolean isInitialized = false;

    private OneSignalManager() {}

    public static synchronized OneSignalManager getInstance() {
        if (instance == null) {
            instance = new OneSignalManager();
        }
        return instance;
    }

    public void initialize(Context context, String appId) {
        if (isInitialized) return;

        // Set log level for debugging
        OneSignal.getDebug().setLogLevel(LogLevel.VERBOSE);

        // Initialize OneSignal
        OneSignal.initWithContext(context, appId);
        isInitialized = true;
        Log.d("OneSignalManager", "OneSignal initialized with App ID: " + appId);
    }

    public void login(String externalId) {
        Executors.newSingleThreadExecutor().execute(() -> OneSignal.login(externalId));
    }

    public void logout() {
        Executors.newSingleThreadExecutor().execute(() -> OneSignal.logout());
    }

    public void addPushSubscriptionObserver(IPushSubscriptionObserver observer) {
        OneSignal.getUser().getPushSubscription().addObserver(observer);
    }

    public void addTrigger(String key, String value) {
        Executors.newSingleThreadExecutor().execute(() -> OneSignal.getInAppMessages().addTrigger(key, value));
    }

    public void addIAMLifecycleListener(IInAppMessageLifecycleListener listener) {
        OneSignal.getInAppMessages().addLifecycleListener(listener);
    }

    public void removeIAMLifecycleListener(IInAppMessageLifecycleListener listener) {
        OneSignal.getInAppMessages().removeLifecycleListener(listener);
    }
}

BiratBazarNotificationService.java

package com.officersiam.biratbazar.notification;

import com.onesignal.notifications.INotificationReceivedEvent;
import com.onesignal.notifications.INotificationServiceExtension;

/**
 * Declared in AndroidManifest with:
 *   <action android:name="com.onesignal.NotificationServiceExtension"/>
 *
 * Allows us to intercept / modify notifications before they are displayed.
 */
public class BiratBazarNotificationService implements INotificationServiceExtension {

    @Override
    public void onNotificationReceived(INotificationReceivedEvent event) {
        // Display all notifications as-is.
        // To suppress a notification call event.preventDefault() without display().
        event.getNotification().display();
    }
}

ProGuard规则(proguard-rules.pro)

# ============================================================
#  BiratBazar — ProGuard Rules
# ============================================================

# ── App classes ─────────────────────────────────────────────
-keep class com.officersiam.biratbazar.** { *; }

# ── OneSignal ───────────────────────────────────────────────
-keep class com.onesignal.** { *; }
-keepclassmembers class com.onesignal.** {
    public <init>(...);
}
-keep class com.onesignal.OSRemoteNotificationReceivedHandler { *; }
-dontwarn com.onesignal.**

# ── Firebase / FCM ──────────────────────────────────────────
-keep class com.google.firebase.** { *; }
-keepclassmembers class com.google.firebase.** {
    public <init>(...);
}
-keep class com.google.android.gms.** { *; }
-dontwarn com.google.firebase.**
-dontwarn com.google.android.gms.**

# ── AndroidX WorkManager (OneSignal background jobs) ────────
-keep class androidx.work.** { *; }
-keepclassmembers class androidx.work.** {
    public <init>(...);
}
-dontwarn androidx.work.**

# ── WebView JavaScript Interface ────────────────────────────
-keepclassmembers class * {
    @android.webkit.JavascriptInterface <methods>;
}

# ── ViewBinding ─────────────────────────────────────────────
-keep class * implements androidx.viewbinding.ViewBinding {
    public static * inflate(...);
    public static * bind(android.view.View);
}

# ── Material / BottomSheet ──────────────────────────────────
-keep class com.google.android.material.** { *; }
-dontwarn com.google.android.material.**

# ── Lottie ──────────────────────────────────────────────────
-keep class com.airbnb.lottie.** { *; }
-dontwarn com.airbnb.lottie.**

# ── General Android safety nets ─────────────────────────────
# Preserve all native method names
-keepclasseswithmembernames class * {
    native <methods>;
}

# Preserve custom View constructors (used by XML inflation)
-keepclasseswithmembers class * {
    public <init>(android.content.Context, android.util.AttributeSet);
    public <init>(android.content.Context, android.util.AttributeSet, int);
}

# Keep Parcelable implementations
-keepclassmembers class * implements android.os.Parcelable {
    public static final android.os.Parcelable$Creator *;
}

# Keep Serializable implementations
-keepclassmembers class * implements java.io.Serializable {
    static final long serialVersionUID;
    private static final java.io.ObjectStreamField[] serialPersistentFields;
    private void writeObject(java.io.ObjectOutputStream);
    private void readObject(java.io.ObjectInputStream);
    java.lang.Object writeReplace();
    java.lang.Object readResolve();
}

# Keep R class fields (referenced by name in some libs)
-keepclassmembers class **.R$* {
    public static <fields>;
}

# Keep enums
-keepclassmembers enum * {
    public static **[] values();
    public static ** valueOf(java.lang.String);
}

# ── Debugging (remove/disable in production if preferred) ───
-keepattributes SourceFile,LineNumberTable
-renamesourcefileattribute SourceFile

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
    <uses-permission android:name="android.permission.VIBRATE" />
    <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />

    <application
        android:name=".BiratBazarApp"
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/Theme.BiratBazar"
        android:networkSecurityConfig="@xml/network_security_config"
        android:usesCleartextTraffic="true"
        tools:targetApi="31">

        <!-- OneSignal configuration -->
        <meta-data android:name="onesignal_app_id" android:value="58eeb5a7-3adf-4d9d-8915-f45c6a542284" />
        <meta-data
            android:name="com.onesignal.NotificationServiceExtension"
            android:value="com.officersiam.biratbazar.notification.BiratBazarNotificationService" />

        <!-- Honor/EMUI FCM workaround -->
        <meta-data
            android:name="com.google.firebase.messaging.default_notification_channel_id"
            android:value="@string/default_notification_channel_id" />

    </application>

</manifest>

build.gradle(app模块)

plugins {
    id 'com.android.application'
    id 'com.google.gms.google-services'
}

dependencies {

    // Firebase
    implementation platform('com.google.firebase:firebase-bom:34.12.0')
    implementation 'com.google.firebase:firebase-messaging'
    implementation 'com.google.firebase:firebase-analytics'

    // OneSignal
    implementation 'com.onesignal:OneSignal:[5.6.1, 5.9.99]'
}

build.gradle(项目根目录)

plugins {
    id 'com.android.application' version '8.2.2' apply false
    id 'com.android.library' version '8.2.2' apply false
    id 'com.google.gms.google-services' version '4.4.4' apply false
}

配置状态截图

  • Firebase SDK配置:
    Firebase SDK配置

  • OneSignal关联Firebase配置:
    OneSignal关联Firebase配置

  • Firebase Cloud Messaging启用状态:
    Firebase Cloud Messaging启用状态

  • OneSignal控制台订阅状态:
    OneSignal控制台显示「从未订阅」


内容的提问来源于stack exchange,提问作者Siam Al Mahmud

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.01 20:42:26