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 205 forks source link

[Bug]: Invalid `token` format for device type SMS #915

Closed ramithks closed 4 days ago

ramithks commented 5 days ago

What happened?

I have logged in using OneSignal.login and then called addSms and addEmail. I can see these pieces of information in the OneSignal Dashboard as different channels (i.e., Push, SMS, and Email). My question is: why are they being created as different channels (or why are they appearing in different rows)?

Additionally, when I called the Signal.Notifications.requestPermission(true) method, I received the following error message: "Invalid token format for device type SMS." In the OneSignal dashboard, it also indicates "permission not granted."

My PushNotificationsController:

import 'package:justpoll/global_index.dart';
import 'package:onesignal_flutter/onesignal_flutter.dart';

/// Controller class for handling push notifications.
class PushNotificationsController extends GetxController {
  bool requireConsent = false;

  final appId = dotenv.env['ONE_SIGNAL_APPID'].toString();

  var isPushEnabled = false.obs;

  @override
  void onInit() {
    super.onInit();
    initPlatformState();
  }

  /// Initializes the platform state for push notifications.
  Future<void> initPlatformState() async {
    OneSignal.Debug.setLogLevel(OSLogLevel.verbose);
    OneSignal.Debug.setAlertLevel(OSLogLevel.none);

    OneSignal.consentRequired(requireConsent);
    OneSignal.initialize(appId);
    OneSignal.Notifications.clearAll();

    OneSignal.User.pushSubscription.addObserver((state) {
      isPushEnabled.value = OneSignal.User.pushSubscription.optedIn!;
    });
  }

  Future<void> promptForPushNotifications() async {
    await OneSignal.Notifications.requestPermission(true);
  }

  /// Logs in the user and adds their phone number and email for push notifications.
  Future<void> login({
    required String userId,
    required String phoneNumber,
    required String email,
  }) async {
    try {
      await OneSignal.login(userId);
      await OneSignal.User.addSms("+$phoneNumber");
      await OneSignal.User.addEmail(email);
    } catch (e) {
      rethrow;
    }
  }

  /// Handles the logout process for push notifications.
  Future<void> handleLogout() async {
    await OneSignal.logout();
  }

  /// Handles the opt-in process for push notifications.
  Future<void> handleOptIn() async {
    await OneSignal.User.pushSubscription.optIn();
  }

  /// Handles the opt-out process for push notifications.
  Future<void> handleOptOut() async {
    await OneSignal.User.pushSubscription.optOut();
  }

  /// Toggles the push notifications on or off based on the current state.
  void togglePushNotifications() {
    if (isPushEnabled.value) {
      handleOptOut();
    } else {
      handleOptIn();
    }
  }
}

### Steps to reproduce?

```Markdown
1. Call the login method and pass the necessary information (this step is working fine).
2. Call the promptForPushNotifications method.

Note: Refer to the PushNotificationsController for all the methods mentioned here.

What did you expect to happen?

No errors should be displayed when requesting permission, and the push notifications permission should be granted.

OneSignal Flutter SDK version

^5.2.1

Which platform(s) are affected?

Relevant log output

D/OneSignal(31754): [bucket:8, retries:0, operation:{"name":"update-subscription","appId":"7cd6bc1e-40e9-4f5f-a1d9-0770ddb80f43","onesignalId":"8205b714-b936-422e-9d27-1d1709ccda6d","subscriptionId":"f2336340-123e-4e54-b22a-84197f48d0a8","type":"PUSH","enabled":true,"address":"<PUSH_TOKEN>","status":"SUBSCRIBED","id":"d20a5443-8351-4ac3-abdd-82b2ca7e60c7"}
D/OneSignal(31754): ]
D/OneSignal(31754): [OpRepo] SubscriptionOperationExecutor(operations: [{"name":"update-subscription","appId":"7cd6bc1e-40e9-4f5f-a1d9-0770ddb80f43","onesignalId":"8205b714-b936-422e-9d27-1d1709ccda6d","subscriptionId":"f2336340-123e-4e54-b22a-84197f48d0a8","type":"PUSH","enabled":true,"address":"<PUSH_TOKEN>","status":"SUBSCRIBED","id":"d20a5443-8351-4ac3-abdd-82b2ca7e60c7"}])
D/OneSignal(31754): [DefaultDispatcher-worker-3] HttpClient: Request Sent = PATCH https://api.onesignal.com/apps/7cd6bc1e-40e9-4f5f-a1d9-0770ddb80f43/subscriptions/f2336340-123e-4e54-b22a-84197f48d0a8 - Body: {"subscription":{"type":"AndroidPush","token":"<PUSH_TOKEN>","enabled":true,"notification_types":1,"sdk":"050115","device_model":"sdk_gphone64_arm64","device_os":"14","rooted":false,"net_type":0,"carrier":"T-Mobile","app_version":"6"}} - Headers: Accept=[application/vnd.onesignal.v1+json], Content-Type=[application/json; charset=UTF-8], OneSignal-Install-Id=[638dfa67-3966-4da7-9db9-c7b878324ff0], OneSignal-Subscription-Id=[f2336340-123e-4e54-b22a-84197f48d0a8], SDK-Version=[onesignal/android/050115], SDK-Wrapper=[onesignal/flutter/050201]

D/TrafficStats(31754): tagSocket(125) with statsTag=0x2710, statsUid=-1
D/OneSignal(31754): [DefaultDispatcher-worker-3] HttpClient: Got Response = PATCH https://api.onesignal.com/apps/7cd6bc1e-40e9-4f5f-a1d9-0770ddb80f43/subscriptions/f2336340-123e-4e54-b22a-84197f48d0a8 - FAILED STATUS: 400
W/OneSignal(31754): [DefaultDispatcher-worker-3] HttpClient: Got Response = PATCH - STATUS: 400 - Body: {"errors":[{"title":"Invalid `token` format for device type SMS"}]}
D/OneSignal(31754): [OpRepo] OperationRepo: execute response = FAIL_NORETRY
E/OneSignal(31754): Operation execution failed without retry: [{"name":"update-subscription","appId":"7cd6bc1e-40e9-4f5f-a1d9-0770ddb80f43","onesignalId":"8205b714-b936-422e-9d27-1d1709ccda6d","subscriptionId":"f2336340-123e-4e54-b22a-84197f48d0a8","type":"PUSH","enabled":true,"address":"<PUSH_TOKEN>","status":"SUBSCRIBED","id":"d20a5443-8351-4ac3-abdd-82b2ca7e60c7"}]
D/OneSignal(31754): [OpRepo] retryAfterSeconds: null
D/OneSignal(31754): [OpRepo] processQueueForever:ops:
D/OneSignal(31754): null

Code of Conduct

ramithks commented 4 days ago

Issue Summary

I had logged in using OneSignal.login and then called addSms and addEmail. I could see these pieces of information in the OneSignal Dashboard as different channels (i.e., Push, SMS, and Email). However, they were appearing in different rows, which was unexpected.

Additionally, when I called the OneSignal.Notifications.requestPermission(true) method, I received the following error message: "Invalid token format for device type SMS." In the OneSignal dashboard, it also indicated "permission not granted."

Solution

I resolved this issue by taking the following steps:

  1. Switched to a newer device (in my case, it was a new emulator). Alternatively, you can clear the device cache or restart the phone. This leads me to believe that the token might be stored in the device cache, causing the issue.
  2. Called the login() method after addSms() and addEmail().

This approach worked for me, and I am now closing this issue.

nan-li commented 4 days ago

Hi @ramithks thank you for reporting this. This looks like a bug in the SDK. The correct order is to call login then add email and SMS to ensure the email and SMS are applied to the correct external ID.

To workaround the current bug, you can delay adding email and SMS until later.

ramithks commented 4 days ago

Hi @ramithks thank you for reporting this. This looks like a bug in the SDK. The correct order is to call login then add email and SMS to ensure the email and SMS are applied to the correct external ID.

Hey @nan-li,

For me, it's the opposite. I was initially using the approach you mentioned, but since it wasn't working, I'm now calling the login method after adding the SMS and email.

I believe there might be an issue with the SDK (perhaps we are attaching the wrong token while sending a patch/post request).

Additionally, I have a question: Typically, in most apps, users first click on "ask," then the prompt appears. If they allow notifications, we can enable them later in the settings. If they disallow notifications, we can re-enable them in the settings.

However, we are confused about which method to use for different scenarios. There are so many observables, Booleans, permissions, and more. The example provided includes all the methods and just calls them.

Is there a proper example or blog post supporting this? I've been working on this for a week but still haven't figured it out, and even ChatGPT, Claude AI, and Gemini are confused too. Any help would be much appreciated.

nan-li commented 4 days ago

Hi @ramithks the initial approach is correct, but when the email and SMS are added at the same time as login, the SDK interpreted some server responses incorrectly. We are actively fixing this now.

You are asking about prompting and managing notifications permissions, correct? We have a mobile SDK reference here. Can you explain more what you mean by "If they allow notifications, we can enable them later in the settings. If they disallow notifications, we can re-enable them in the settings."?

ramithks commented 4 days ago

Hi @ramithks the initial approach is correct, but when the email and SMS are added at the same time as login, the SDK interpreted some server responses incorrectly. We are actively fixing this now.

You are asking about prompting and managing notifications permissions, correct? We have a mobile SDK reference here. Can you explain more what you mean by "If they allow notifications, we can enable them later in the settings. If they disallow notifications, we can re-enable them in the settings."?

What I meant is that we will allow notifications at the beginning (from the system prompt). Later, users should be able to disable them in the app’s settings (if allowed). Conversely, if notifications are disallowed initially, we need to enable them later, right?

Regarding the mobile SDK reference, it's very much confusing. There is no practical guidance. If you provide me with sample projects or any blog posts that would be helpful. 🚀