问题
We're building a Gmail Add-On however we wish to show a different card on depending on some business logic when the add-on's onTriggerFunction
is called. This works fine for the first time the function runs when an email opens.
We have the conditional logic, but Gmail appears to cache the result of the initial call returning the first card. Going to another email and back to original, the onTriggerFunction
is not called again, so the conditional logic is not run to change the initial card rendered.
Is there anyway to get the onTriggerFunction to run every time an email is opened, not just once the first time the email is opened?
Here's an example add-on with a trigger function that returns a single card displaying the current time:
Code.js
function buildAddOn(e) {
var card = CardService.newCardBuilder();
card.setHeader(CardService.newCardHeader().setTitle(new Date().toLocaleTimeString()));
return [card.build()];
}
appsscript.json
{
"timeZone": "GMT",
"dependencies": {
},
"oauthScopes": ["https://www.googleapis.com/auth/gmail.addons.execute"],
"gmail": {
"name": "Minimal example",
"logoUrl": "https://www.gstatic.com/images/icons/material/system/2x/bookmark_black_24dp.png",
"contextualTriggers": [{
"unconditional": {
},
"onTriggerFunction": "buildAddOn"
}],
"primaryColor": "#4285F4",
"secondaryColor": "#4285F4",
"openLinkUrlPrefixes": ["https://mail.google.com/"],
"version": "TRUSTED_TESTER_V2"
}
}
When navigating to older conversations a spinner is displayed followed by the current time. However, when navigating back to previously displayed conversations the old value of the time is displayed instantly, suggesting some caching is taking place:
Actions inside the add-on, or other activity in our app can affect what should be displayed when re-opening a previously displayed conversation. This means that redisplaying an old copy of the card results in unexpected behaviour for the user.
回答1:
Unfortunately there is no way at the moment (July 2019) to force the trigger to run every time the email is opened. You can use ActionResponseBuilder.setStateChanged(true)
as a response to a button click to instruct Gmail to clear the cache, but it can't be sent along with a normal card response.
回答2:
There are a couple ways you can reload the UI of a card. Both of them have to happen in an ActionResponse.
The first is if you want to reload the current card as the result of some state change caused by a user action:
function buildCounterCard() {
const card = CardService.newCardBuilder().setName('Counter');
const count = CountApi.get(); // Or however you get this data
const countWidget = CardService.newKeyValue().setTopLabel('Current Count').setContent(`${count}`);
const incrementAction = CardService.newAction().setFunctionName('handleIncrement');
const incrementButton = CardService.newTextButton().setText('Increment').setOnClickAction(incrementAction);
const section = CardService.newCardSection().addWidget(countWidget).addWidget(incrementButton);
card.addSection(section);
return card.build();
}
function handleIncrement() {
const actionResponse = CardService.newActionResponseBuilder();
CountApi.update(); // Or however you update the data
const nav = CardService.newNavigation().updateCard(buildCounterCard());
actionResponse.setNavigation(nav);
return actionResponse.build();
}
The only other way I've found so far is to update the previous card in the Navigation stack. Imagine the following scenario:
- User fills out a form and clicks "Save"
- Script posts the data to the API and on success pushes a "Success" card on to the stack.
- User sees the "Success" card with a message letting them know the data was saved and a button to go "Back" or "Home".
The action handler for that button could look something like this:
function handleBackClick(event) {
const actionResponse = CardService.newActionResponseBuilder();
clearPreviousCardState() // Otherwise the user sees the same data they filled out previously when they go back to the form
const nav = CardService.newNavigation()
.popCard()
.updateCard(buildPreviousCard(event))
.popToRoot();
actionResponse.setNavigation(nav);
return actionResponse.build();
}
For whatever reason this works, but updating multiple cards by chaining navigation steps along with updateCard()
does not.
Seems like these are the only options right now. I find it pretty crazy that there's a Linear Optimization Service, but not a way to reload the UI. A commenter mentioned ActionResponseBuilder.setStateChanged(true)
, which sounds like what we want based on the documentation, but in my experience, it does absolutely nothing.
来源:https://stackoverflow.com/questions/50511085/gmail-add-ons-ontriggerfunction-only-ran-once-per-email-even-if-opening-the-emai