firebase / firebase-ios-sdk

Firebase SDK for Apple App Development
https://firebase.google.com
Apache License 2.0
5.52k stars 1.44k forks source link

FR: Add property to InAppMessagingAction to indicate if primary action button #6380

Open willbattel opened 3 years ago

willbattel commented 3 years ago

Feature proposal

The InAppMessagingCardDisplay has two action buttons, primaryActionButton and secondaryActionButton. We're trying to configure a new campaign that uses Cards with these two buttons. However, we have to set the behavior of the buttons at runtime. We cannot simply drop URLs into the Firebase Console because the actions are dependent on the current app state, i.e., the action would be related to the currently viewed content when the message was triggered. For example: if we wanted to recommend a related product to what the user is currently viewing, then we would need to insert the deep link to that recommended product into the message programatically at runtime- we couldn't do that in the Firebase Console, because there will be different recommended products depending on the currently displayed content.

We configured a new message campaign in the Firebase Console that has a Card with two buttons, both of which are set to dismissal behavior. At runtime, we're trying to use the InAppMessagingDisplayDelegate function messageClicked(_:with:) to determine which button was pressed. If and only if it was the primary button, then we will perform some action. The problem is that there is not currently a good way to determine which button was pressed. The only two properties on the InAppMessagingAction class are actionText and actionURL. The former is subject to localization and shouldn't be used as an identifier, and the latter is always nil for the reason described in the previous paragraph. How are we supposed to ID which button was pressed so we can act accordingly?

fiam

My API proposal is to add a boolean property isPrimaryAction to InAppMessagingAction to be used to confidently determine how to respond in the messageClicked(_:with:) delegate function.

Also, I'm getting some mixed impressions reading the docs. On one hand, it seems like there may be a way to create messages programatically at runtime where we can directly set the button URLs, but on the other hand there is no example code demonstrating this that I could find. This would be the ideal solution, even more so than the route we are trying to go with the delegate. Being able to set the URLs on the message at runtime before it is displayed would be best, but I'm having a hard time determining if this is possible.

Overall, perhaps because it is in Beta, the FIAM docs seem a bit lacking. At the moment FIAM seems to really only be setup for static campaigns, and less so for campaigns that are responsive to the application state. Please let me know if I'm missing something.

willbattel commented 3 years ago

Can someone on the FIAM team let me know if I'm thinking about this correctly or if I've misunderstood something? I find it hard to believe that FIAM cannot be used with URLs inserted at runtime- preventing usage in all use cases that can't use static URLs (which I'd imagine to be the majority of use cases).

christibbs commented 3 years ago

@willbattel Hey, this is Chris from the FIAM team. Just to get my head wrapped around your use case-- are you mostly showing in-app messages on app foregrounding, or ones that are triggered by custom analytics events?

willbattel commented 3 years ago

@willbattel Hey, this is Chris from the FIAM team. Just to get my head wrapped around your use case-- are you mostly showing in-app messages on app foregrounding, or ones that are triggered by custom analytics events?

Currently it's mostly triggered by custom analytics events while the app is in use, rather than upon the app becoming active.

On a different tangent, another quick question:

Is the only different between:

Analytics.logEvent("event_name") (no custom parameters)

and

InAppMessaging.inAppMessaging().triggerEvent("event_name")

that Firebase Analytics won't record the latter?

willbattel commented 3 years ago

Let me also provide a more clear use case example. Let's say the app session flows like the following series:

  1. App launches, session start
  2. User navigates to product page
  3. User purchases product
  4. After completed purchase, trigger FIAM message to suggest another product using a recommendation ML model.
  5. User is taken to other product or dismisses message.

We would need to insert the URL for the FIAM message at runtime, because the product we want to take them to is dependent on the product they just purchased.

Putting in the FIAM action URL in the Firebase Console would only work if the campaign revolved around a single product. If the campaign is contextual, as it is in our case, then I don't think we can use FIAM unless we could enter the URLs at runtime.

christibbs commented 3 years ago

Is the only different between:

Analytics.logEvent("event_name") (no custom parameters)

and

InAppMessaging.inAppMessaging().triggerEvent("event_name")

that Firebase Analytics won't record the latter?

Yes, that's the only difference. The in-app message display behavior will be the same.

christibbs commented 3 years ago

Let me also provide a more clear use case example. Let's say the app session flows like the following series:

  1. App launches, session start
  2. User navigates to product page
  3. User purchases product
  4. After completed purchase, trigger FIAM message to suggest another product using a recommendation ML model.
  5. User is taken to other product or dismisses message.

We would need to insert the URL for the FIAM message at runtime, because the product we want to take them to is dependent on the product they just purchased.

Putting in the FIAM action URL in the Firebase Console would only work if the campaign revolved around a single product If the campaign is contextual, as it is in our case, then I don't think we can use FIAM unless we could enter the URLs at runtime.

OK. That clears things up for me. You're right that you've reached the limits of our API with this case. We have the messageClicked(_:with:) callback for developers that want to handle clicks themselves, but as you mentioned there's no way to tell which button was clicked if you can't rely on the button text.

Adding isPrimaryAction would solve your use case, but I wonder if adding an identifier to an action would be a better API. I'll talk to the team about this.

willbattel commented 3 years ago

Adding isPrimaryAction would solve your use case, but I wonder if adding an identifier to an action would be a better API. I'll talk to the team about this.

I agree. I only suggested the boolean for its simplicity- but having a canonical identifier would be more versatile. Thanks for looking into it!

willbattel commented 3 years ago

@christibbs because of #6405 it would probably be best if we could set the actionURL programmatically. The ability to set the URL at runtime would solve both issues, I believe.

I think the most straightforward API would be a new delegate function, something like prepare(for inAppMessage: InAppMessagingDisplayMessage) for example. Such a function would allow the app to configure message properties, such as the actions, before it is displayed to the user. We could then use the messageID property from the inAppMessage.campaignInfo parameter to optionally prepare the message. This is just an idea, let me know what you think.

christibbs commented 3 years ago

Hmm, I like the idea of prepare(for inAppMessage: InAppMessagingDisplayMessage), it has recognizability from prepare(for:sender:) and it unlocks a lot of other potential use cases (different background color for light mode/dark mode for example).

We would have to change all of the properties on message objects to be readwrite, but I don't immediately see anything risky in that. Will run this by the group. Any changes to public API require approval from the larger Firebase team.

christibbs commented 3 years ago

@willbattel We are going to address this by allowing templated messages in the in-app messaging console. It'll work something like a format string-- you'll add a template parameter for action URL in the console and then supply the action URL in your app's code.

The reasoning for this is we don't want a lot of divergence from what's on the console and what's appearing on users' phones/tablets. I'll keep this open until it's implemented, though it will take a bit longer than adding a prepare method would have.

willbattel commented 3 years ago

@christibbs that should do the trick, thanks for looking into it!