OneSignal / OneSignal-Flutter-SDK

OneSignal is a free push notification service for mobile apps. This plugin makes it easy to integrate your flutter app with OneSignal
https://www.onesignal.com
Other
606 stars 204 forks source link

[Bug]: After upgrading to >5.0.0, all subscription Ids are now empty strings or null for iOS devices. #890

Open temcewen opened 1 month ago

temcewen commented 1 month ago

What happened?

The latest versions of the SDK have completely broken notifications for our app. All subscription ids are now empty strings, and there are no notifications being received by new devices. We upgraded from 5.0.0 to several different versions including 5.1.2 and 5.2.0, none of them have worked.

We had this working before the upgrade, after the upgrade, it's completely broken.

We've tried waiting over 5 minutes in case it needed time to make the calls and get the ID, but it just doesn't ever set it to anything other than an empty string.

Screenshot 2024-05-16 at 9 44 01 PM

Steps to reproduce?

Install the new SDKs.
Use an iOS device (doesn't work for any of them).
Try using OneSignal and follow all the instructions in the dev docs exactly.
The subscription id will be an empty string.

What did you expect to happen?

I expected the subscription id to have a UUID.

OneSignal Flutter SDK version

5.2.0

Which platform(s) are affected?

Relevant log output

flutter: The Dart VM service is listening on http://127.0.0.1:62815/Yaka3go9wf4=/
FATAL: OneSignal AppId: (null) - AppId is null or format is invalid, stopping initialization.
Example usage: 'b2f7f966-d8cc-11e4-bed1-df8f05be55ba'
fopen failed for data file: errno = 2 (No such file or directory)
Errors found! Invalidating cache...
fopen failed for data file: errno = 2 (No such file or directory)
Errors found! Invalidating cache...
VERBOSE: startLocationSharedWithFlag called with status: 0
VERBOSE: startLocationSharedWithFlag set false, clearing last location!
VERBOSE: oneSignalDidRegisterForRemoteNotifications:deviceToken:
INFO: Device Registered with Apple: bba61b947a90c1588faa83ca8b106656dea2537f7b55e1acb719dc7c806c57ff
VERBOSE: getNotificationTypes:mSubscriptionStatus: -1
VERBOSE: OSOperationRepo enqueueDelta: <OSDelta OS_UPDATE_SUBSCRIPTION_DELTA with property: address value: Optional("bba61b947a90c1588faa83ca8b106656dea2537f7b55e1acb719dc7c806c57ff")>
VERBOSE: firePushSubscriptionChanged from {
    id = "";
    optedIn = 0;
    token = "";
} to {
    id = "";
    optedIn = 0;
    token = bba61b947a90c1588faa83ca8b106656dea2537f7b55e1acb719dc7c806c57ff;
}
VERBOSE: OSOperationRepo enqueueDelta: <OSDelta OS_UPDATE_SUBSCRIPTION_DELTA with property: notificationTypes value: -18>
VERBOSE: OneSignal.startNewSessionInternal
DEBUG: Outcomes cleared for current session
DEBUG: OneSignal SessionManager restartSessionIfNeeded with entryAction:: 2 channelTrackers: (
)
DEBUG: OneSignal SessionManager sendSessionEndingWithInfluences with influences: (
)
VERBOSE: getNotificationTypes:mSubscriptionStatus: -1
VERBOSE: OneSignalUserManagerImpl starting new session
VERBOSE: OSUserExecutor.executePendingRequests called with queue [<OSRequestCreateUser with externalId: nil>]
WARNING: OneSignalUserManagerImpl.startNewSession() is unable to fetch user with External ID nil due to null OneSignal ID
VERBOSE: ForegroundLifecycleListener added successfully
VERBOSE: application/scene willResignActive
VERBOSE: OSMessagingController onPushSubscriptionDidChange: changed to nil subscription id
VERBOSE: application/scene didBecomeActive
DEBUG: Application Foregrounded started
DEBUG: cancelFocusCall of {
}
DEBUG: shouldStartNewSession:timeSinceLastClosed: 1715918803.293014
DEBUG: shouldStartNewSession:timeSinceInitialization: 0.438216
VERBOSE: getNotificationTypes:mSubscriptionStatus: -1
DEBUG: OneSignal SessionManager attemptSessionUpgrade with entryAction: 1
DEBUG: OneSignal SessionManager attemptSessionUpgrade try UNATTRIBUTED to INDIRECT upgrade
DEBUG: OSChannelTracker for: notification_id lastChannelObjectReceived: (null)
DEBUG: OSChannelTracker for: iam_id lastChannelObjectReceived: (null)
DEBUG: Trackers after update attempt: (
    "OSChannelTracker tag: notification_id influenceType: UNATTRIBUTED indirectIds: (null) directIds: (null)",
    "OSChannelTracker tag: iam_id influenceType: UNATTRIBUTED indirectIds: (null) directIds: (null)"
)
DEBUG: OneSignal SessionManager sendSessionEndingWithInfluences with influences: (
)
VERBOSE: network response (OSRequestGetIosParams) with URL https://api.onesignal.com/apps/5a17626a-ab83-4c30-b9c2-38a454fb14a1/ios_params.js: {
    httpStatusCode = 200;
    outcomes =     {
        direct =         {
            enabled = 0;
        };
        indirect =         {
            enabled = 0;
            "notification_attribution" =             {
                limit = 10;
                "minutes_since_displayed" = 60;
            };
        };
        unattributed =         {
            enabled = 0;
        };
    };
    "receive_receipts_enable" = 0;
    "require_email_auth" = 1;
    "require_user_id_auth" = 1;
    "uses_provisional_auth" = 0;
}
VERBOSE: network response (OneSignalUser.OSRequestCreateUser) with URL https://api.onesignal.com/apps/5a17626a-ab83-4c30-b9c2-38a454fb14a1/users: {
    errors =     (
                {
            code = "auth-1";
            title = "This operation requires 'Authorization' in the HTTP header";
        }
    );
    httpStatusCode = 401;
}
ERROR: OSUserExecutor create user request failed with error: Optional(Error Domain=OneSignalError Code=401 "(null)" UserInfo={returned={
    errors =     (
                {
            code = "auth-1";
            title = "This operation requires 'Authorization' in the HTTP header";
        }
    );
    httpStatusCode = 401;
}})
DEBUG: OSOperationRepo not flushing queue due to being paused
VERBOSE: Notification click listener added successfully
VERBOSE: requestPermission Called
VERBOSE: Firing registerForRemoteNotifications
VERBOSE: oneSignalDidRegisterForRemoteNotifications:deviceToken:
INFO: Device Registered with Apple: bba61b947a90c1588faa83ca8b106656dea2537f7b55e1acb719dc7c806c57ff
VERBOSE: application/scene willResignActive
DEBUG: Application Backgrounded started
DEBUG: TimeProcessor <OSUnattributedFocusTimeProcessor: 0x300a24720> for session attributed 0
DEBUG: sendOnFocusCall unattributed with totalTimeActive 6.259518
DEBUG: OSBaseFocusTimeProcessor hasMinSyncTime getMinSessionTime: 60 activeTime: 6.259518
DEBUG: unattributed influence saveUnsentActiveTime 6.259518
DEBUG: OSOperationRepo not flushing queue due to being paused
DEBUG: OSOperationRepo not flushing queue due to being paused
VERBOSE: updateNotificationTypes called: 15
VERBOSE: Firing registerForRemoteNotifications
VERBOSE: startedRegister: 1
VERBOSE: getNotificationTypes:mSubscriptionStatus: -1
VERBOSE: firePushSubscriptionChanged from {
    id = "";
    optedIn = 0;
    token = bba61b947a90c1588faa83ca8b106656dea2537f7b55e1acb719dc7c806c57ff;
} to {
    id = "";
    optedIn = 1;
    token = bba61b947a90c1588faa83ca8b106656dea2537f7b55e1acb719dc7c806c57ff;
}
VERBOSE: OSMessagingController onPushSubscriptionDidChange: changed to nil subscription id
VERBOSE: oneSignalDidRegisterForRemoteNotifications:deviceToken:
INFO: Device Registered with Apple: bba61b947a90c1588faa83ca8b106656dea2537f7b55e1acb719dc7c806c57ff
flutter: OneSignal subscription changed.
VERBOSE: OSOperationRepo enqueueDelta: <OSDelta OS_UPDATE_SUBSCRIPTION_DELTA with property: enabled value: true>
VERBOSE: OSOperationRepo enqueueDelta: <OSDelta OS_UPDATE_SUBSCRIPTION_DELTA with property: notificationTypes value: 31>
VERBOSE: application/scene didBecomeActive
DEBUG: Application Foregrounded started
DEBUG: cancelFocusCall of {
    "NOT_ATTRIBUTED" = "<OSUnattributedFocusTimeProcessor: 0x300a24720>";
}
DEBUG: shouldStartNewSession:timeSinceLastClosed: 6.965471
DEBUG: shouldStartNewSession:timeSinceInitialization: 13.368212
VERBOSE: getNotificationTypes:mSubscriptionStatus: -1
DEBUG: OneSignal SessionManager attemptSessionUpgrade with entryAction: 1
DEBUG: OneSignal SessionManager attemptSessionUpgrade try UNATTRIBUTED to INDIRECT upgrade
DEBUG: OSChannelTracker for: notification_id lastChannelObjectReceived: (null)
DEBUG: OSChannelTracker for: iam_id lastChannelObjectReceived: (null)
DEBUG: Trackers after update attempt: (
    "OSChannelTracker tag: notification_id influenceType: UNATTRIBUTED indirectIds: (null) directIds: (null)",
    "OSChannelTracker tag: iam_id influenceType: UNATTRIBUTED indirectIds: (null) directIds: (null)"
)
DEBUG: OneSignal SessionManager sendSessionEndingWithInfluences with influences: (
)
DEBUG: OSOperationRepo not flushing queue due to being paused

Code of Conduct

temcewen commented 1 month ago

I am also getting these warnings when running pod install:

[!] CocoaPods did not set the base configuration of your project because your project already has a custom config set. In order for CocoaPods integration to work at all, please either set the base configurations of the target Runner to Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig or include the Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig in your build configuration (Flutter/Release.xcconfig).

[!] The OneSignalNotificationServiceExtension [Debug] target overrides the CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER build setting defined in `Pods/Target Support Files/Pods-OneSignalNotificationServiceExtension/Pods-OneSignalNotificationServiceExtension.debug.xcconfig'. This can lead to problems with the CocoaPods installation

[!] The OneSignalNotificationServiceExtension [Release] target overrides the CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER build setting defined in `Pods/Target Support Files/Pods-OneSignalNotificationServiceExtension/Pods-OneSignalNotificationServiceExtension.release.xcconfig'. This can lead to problems with the CocoaPods installation

[!] The OneSignalNotificationServiceExtension [Profile] target overrides the CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER build setting defined in `Pods/Target Support Files/Pods-OneSignalNotificationServiceExtension/Pods-OneSignalNotificationServiceExtension.profile.xcconfig'. This can lead to problems with the CocoaPods installation

temcewen commented 1 month ago

Also, I can see the logs say the App Id is null, but that makes no sense because we only call OneSignal.initialize(APP_ID) one time and we're passing it the correct app id. This log also happens before the app even starts it would seem.

temcewen commented 1 month ago

@emawby @jennantilla @nan-li

Sorry for the @ mentions, just trying to get visibility on this as it's preventing us from releasing any new versions of our app. This is a really critical issue for us as of now.

GregoryLEDEE commented 1 month ago

Has same issue here. Was on 5.1.3 version and worked perfectly until 5/17/24.

The issue seems to affect only Android devices (even with the new version 5.2.0) iOS still receiving notifications

temcewen commented 1 month ago

@GregoryLEDEE We're having issues with iOS devices, but only new subscriptions. Devices where the app was installed prior to 5/10/2024 are still able to receive notifications. Have you tested new installs / new subscriptions for iOS devices?

GregoryLEDEE commented 1 month ago

@temcewen Just tested with an iPhone 13 Pro Max simulator and worked perfectly (with new subscription creation)

GregoryLEDEE commented 1 month ago

@temcewen found the solution ! I don't know how you call and use OneSignal init but here is our case :

Before their update, this code worked perfectly (not anymore)

Future<void> registerForPushNotifications() async {
  if (kIsWeb) return;
  try {
    OneSignal.initialize("APP_ID");
    await OneSignal.Notifications.requestPermission(true);
    playerID = OneSignal.User.pushSubscription.id;
  } on Exception catch (e) {
    print(e);
  }
}

Don't know why (maybe they changed the initialize function, but if I had a little delay after initialize, it works again:

Future<void> registerForPushNotifications() async {
  if (kIsWeb) return;
  try {
    OneSignal.initialize("APP_ID");
    await Future.delayed(Duration(milliseconds: 100));
    await OneSignal.Notifications.requestPermission(true);
    playerID = OneSignal.User.pushSubscription.id;
  } on Exception catch (e) {
    print(e);
  }
}

The initialize function is like:

  static void initialize(String appId) {
    _channel.invokeMethod('OneSignal#initialize', {'appId': appId});
    InAppMessages.lifecycleInit();
    User.lifecycleInit();
    User.pushSubscription.lifecycleInit();
    Notifications.lifecycleInit();
  }

And all lifecycleInit calls are async functions, so in my opinion, they should modify the initialize function to be:

  static Future<void> initialize(String appId) async {
    _channel.invokeMethod('OneSignal#initialize', {'appId': appId});
    await InAppMessages.lifecycleInit();
    await User.lifecycleInit();
    await User.pushSubscription.lifecycleInit();
    await Notifications.lifecycleInit();
  }
temcewen commented 1 month ago

@GregoryLEDEE I tried that solution and it didn't work for me. The OneSignal subscription id is still showing up as an empty string unfortunately. I think we're going to transition to using FCM directly instead of OneSignal. Thanks for trying to help though!

nan-li commented 1 month ago

Hi @temcewen, thanks for reaching out,

Looking at your logs, I see these statements that are the root cause:

VERBOSE: network response (OneSignalUser.OSRequestCreateUser) with URL https://api.onesignal.com/apps/5a17626a-ab83-4c30-b9c2-38a454fb14a1/users: {
    errors =     (
                {
            code = "auth-1";
            title = "This operation requires 'Authorization' in the HTTP header";
        }
    );
    httpStatusCode = 401;
}

You have Identity Verification turned on for your app in the dashboard, but the v5.x.x of the OneSignal SDKs do not currently support Identity Verification.

nan-li commented 1 month ago

We have a callout in our Identity Verification page and at the very bottom of the version 5 migration guide, but it is not obvious, we will work to make this limitation clearer.

temcewen commented 1 month ago

@nan-li we have had identity verification turned on for months now... We are only setting the external ids through the backend SDK, not the frontend. There must have been an internal change that prevents even subscriptions from being created if identity verification is required. Is this true?

I just tested and turning identity verification off through the dashboard does cause the issue to go away. If we don't have identity verification enabled, how can we prevent bad actors from opting to receive the notifications of other users?

nan-li commented 1 month ago

Devices where the app was installed prior to 5/10/2024 are still able to receive notifications.

we have had identity verification turned on for months now... We are only setting the external ids through the backend SDK, not the frontend. There must have been an internal change that prevents even subscriptions from being created if identity verification is required. Is this true?

@temcewen you only saw this new issue on iOS only, not Android? How have you been setting the external ID through the backend? By calling Create User with an external ID?

temcewen commented 1 month ago

@nan-li We don't have an Android app out yet; however, from our debugging, I think it maybe is a problem with Android as well? Not positive about that.

We have been setting the external Id through the backend by calling UpdatePlayer with our external Id. We never called Create User from the backend at all.

MustafaYusef commented 1 month ago

I have the same issue , the new user can’t subscribe to onesignel
Subscription id return empty string on android and null on ios

temcewen commented 1 month ago

After more testing, it seems like there's either some documentation problems with OneSignal, or that there's internal bugs with OneSignal's API.

Here's a really disturbing behavior we found: OneSignal external ids are being reset on subsequent app opens after the app is fully closed. It looks like the new updates require that you call OneSignal.login() on every single app open. This must be an internal bug to OneSignal. As of now, we were setting external ids through the backend, so we don't set them on every app startup. I've debugged this process extensively, and I'm positive that we're doing things correctly.

If you want to see the bug for yourself, I would be happy to meet with you or anyone else on the OneSignal team over Zoom/Slack/Discord and I could share my screen and show exactly what's happening, and even debug it with you. You can find my LinkedIn and email in my bio @nan-li

temcewen commented 1 month ago

One more update:

I figured out something. The login method doesn't need to be called on every app open, it just needs to be called on the first. This was a change in how the APIs work because previously, it was possible to set the external Id from our backend through the .Net SDK and the external Id would be fixed for a subscription from that point on. What we've discovered is that it will be reset to empty on the next app open unless the "login" function was called locally from the device itself. In other words, the backend "UpdatePlayer" methods are now irrelevant. Login should be called from the device, it needs to be called only once, not on every app open.

Some clarification in the documentation would be great. This took us around 20-25 hours of debugging and work because the changes were made internally without any email, notice, or explanation. We had to manually discover how the new OneSignal API works ourselves.

jkasten2 commented 3 weeks ago

This was a change in how the APIs work because previously, it was possible to set the external Id from our backend through the .Net SDK and the external Id would be fixed for a subscription from that point on. What we've discovered is that it will be reset to empty on the next app open unless the "login" function was called locally from the device itself. In other words, the backend "UpdatePlayer" methods are now irrelevant.

Thanks for the details on here, this is a use-case we didn't think was common. We will look into improving this for those migrating in the future.

The login method doesn't need to be called on every app open, it just needs to be called on the first. ... Login should be called from the device, it needs to be called only once, not on every app open.

The SDK remembers which id you used with login(). So as you noted, you only need to call it once, but calling it with the same id should also be fine as well.