How can I add App Tracking Transparency (ATT) to maui app on IOS?
I added this code to MainPage.xaml
protected override void OnAppearing()
{
base.OnAppearing();
// Prompt the user for tracking authorization
ATTrackingManager.RequestTrackingAuthorization(async (status) =>
{
string message = "";
// Handle the user's authorization status here
switch (status)
{
case ATTrackingManagerAuthorizationStatus.Authorized:
message = "Authorized";
await Application.Current.MainPage.DisplayAlert("Authorization Status", message, "OK");
break;
case ATTrackingManagerAuthorizationStatus.Denied:
message = "Denied";
await Application.Current.MainPage.DisplayAlert("Authorization Status", message, "OK");
break;
case ATTrackingManagerAuthorizationStatus.Restricted:
message = "Restricted";
await Application.Current.MainPage.DisplayAlert("Authorization Status", message, "OK");
break;
case ATTrackingManagerAuthorizationStatus.NotDetermined:
message = "NotDetermined";
await Application.Current.MainPage.DisplayAlert("Authorization Status", message, "OK");
break;
}
});
}
and this code to info.plist
<key>NSUserTrackingUsageDescription</key>
<string>This app uses data to deliver personalized advertising.</string>
and it still doesn't work. I don't get any error. but the message is not displayed.
Edit: I expected to get message like this
https://support.apple.com/en-in/HT212025
According to this issue which is about Xamarin App Tracking Transparency Dialog does not appear since iOS 15, you can try to put the code into the /Platforms/iOS/AppDelegates.cs. Such as:
public override void OnActivated(UIApplication application)
{
base.OnActivated(application);
ATTrackingManager.RequestTrackingAuthorization(async (status) =>
{
string message = "";
// Handle the user's authorization status here
switch (status)
{
case ATTrackingManagerAuthorizationStatus.Authorized:
message = "Authorized";
break;
case ATTrackingManagerAuthorizationStatus.Denied:
message = "Denied";
break;
case ATTrackingManagerAuthorizationStatus.Restricted:
message = "Restricted";
break;
case ATTrackingManagerAuthorizationStatus.NotDetermined:
message = "NotDetermined";
break;
}
});
}
I have tested this in my project, and the alert about requesting permission will show up.
Related
So I have a .NET 5 web api with a custom error handler middle ware that looks like this:
public class ErrorHandlerMiddleware
{
private readonly RequestDelegate _next;
public ErrorHandlerMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context)
{
try
{
await _next(context);
}
catch (Exception error)
{
var response = context.Response;
response.ContentType = "application/json";
var responseModel = new Response<string>() { Succeeded = false, Message = error?.Message };
switch (error)
{
case ConflictException:
response.StatusCode = (int)HttpStatusCode.Conflict;
break;
case ApiException:
// custom application error
response.StatusCode = (int)HttpStatusCode.BadRequest;
break;
case ValidationException e:
response.StatusCode = (int)HttpStatusCode.BadRequest;
responseModel.Errors = e.Errors;
break;
case KeyNotFoundException:
response.StatusCode = (int)HttpStatusCode.NotFound;
break;
default:
// unhandled error
response.StatusCode = (int)HttpStatusCode.InternalServerError;
break;
}
var result = JsonSerializer.Serialize(responseModel);
await response.WriteAsync(result);
}
}
}
It works fine across the board, save for when I have a model binding error. When I hit an endpoint with an invalid model (e.g. send an int for a datetime) this middleware doesn't get hit. I know this is happening because of the built in behavior of ApiController, but I can't for the life of me figure out how to bypass it.
I confirmed my app registration is the first item in my Configure method in Startup
I tried suppressing model state like so, but my endpoint just throws a 500 before hitting my middleware instead.
services.AddControllers()
.ConfigureApiBehaviorOptions(options =>
{
// ...
options.SuppressModelStateInvalidFilter = true;
// ...
}
I've seen a ton of articles and responses addressing this with attribute filters, but that is not something I want to implement as it would split my logic between different areas of my app.
I am trying to follow this article from Microsoft Docs in order to migrate our version 3 code to version 4.
However, I am not sure how to rewrite the Luis dialog. What has to be done?
I have added the below code in onturnasync, not sure how to rewrite the AfterFAQ resume method now.
Kindly help me rewrite these existing Luis methods:
//The LUIS dialog service call the back the method if the conversation is part of Greeting intent
[LuisIntent("Greetings")]
public async Task Greetings(IDialogContext context, IAwaitable<IMessageActivity> activity, LuisResult result)
{
needMoreInformation = false;
qnaInvalidMessageCount = 0;
var messageToForward = await activity;
string[] supportList = { "HELP", "FEEDBACK", "SUPPORT", "ESCALATE", "AGENT" };
string qnaAnswer;
if (messageToForward.Text == null || supportList.Any(x => x == messageToForward.Text.ToUpper()))
{
await context.PostAsync("Please reach out to ...");
context.Wait(MessageReceived);
}
else if (GreetingColl.TryGetValue(messageToForward.Text.Trim().ToLower(), out qnaAnswer))
{
await context.PostAsync(qnaAnswer);
context.Wait(MessageReceived);
}
else
{
await context.Forward(new QnAGreetingsDialog(), AfterFAQDialog, messageToForward, CancellationToken.None);
}
}
modified code:
public async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default(CancellationToken))
{
if (turnContext.Activity.Type == ActivityTypes.Message)
{
...
var luisResults = await botServices.LuisServices[LuisKey].RecognizeAsync(turnContext, cancellationToken);
var topScoringIntent = luisResults?.GetTopScoringIntent();
var topIntent = topScoringIntent.Value.intent;
// Continue the current dialog
var dialogResult = await dc.ContinueDialogAsync();
// if no one has responded,
if (!dc.Context.Responded)
{
// examine results from active dialog
switch (dialogResult.Status)
{
case DialogTurnStatus.Empty:
switch (topIntent)
{
case NoneIntent:
case GreetingsIntent:
await dc.BeginDialogAsync(nameof(QnAGreetingsDialog));
break;
case CredentialsIntent:
case ContactusIntent:
await LuisVar.Feedback(turnContext);
break;
case FeedbackIntent:
await LuisVar.Feedback(turnContext);
break;
default:
// No intent identified, provide some help to the user
await dc.Context.SendActivityAsync("I didn't understand what you just said to me.");
break;
}
break;
case DialogTurnStatus.Waiting:
// The active dialog is waiting for a response from the user, so do nothing.
break;
case DialogTurnStatus.Complete:
await dc.EndDialogAsync();
break;
default:
await dc.CancelAllDialogsAsync();
break;
}
}
}
}
if your question is regarding Bot Framework core v4, PFB steps to fetch intents:
first you need to inject LUIS services in services with key in bot framework.
Fetch recognizer result object using below code
var luisResults = await services.LuisServices[LuisKey].RecognizeAsync(turnContext, default(CancellationToken));
LUIS key is key used while injection of LUIS service.
this is how you can fetch intents using RecognizerResult object.
luisResults.GetTopIntent(luisThresholdScore).intent;
Has something changed with Cortana in the last few days?
I have buttons on an adaptive card which now do nothing. I have remote debugged and hit all breakpoints as expected but when tapping on a button nothing happens. It is as though the buttons are disabled somehow.
Everything works fine in the emulator.
My Bot code simply shows buttons in an adaptive card which then post their DataJson value which is received by the MessageReceivedAsync method.
I have been refining how this all works as I found that Cortana has a limit of 5 actions on one card. I did a bit of a work around in this and make each button appear on a card.
Therefore, I have been thinking that in my refining, I have done something to make these buttons no longer work.
However, I have now put my code back to how it was days ago which definitely did work in Cortana and it now does not work.
My question therefore is, has anything changed in the Cortana side to stop this?
Thanks!
I modified the echodemo to put up a simple adaptive card and it worked as documented: "Thanks for Clicking! SomeType is SomeData". (I am logging a ticket to update documentation to v1.0.3 of adaptive cards).
public async Task ClickHandleAsync(IDialogContext context, IAwaitable<IMessageActivity> argument)
{
var message = await argument;
try
{
string someValue = "unknown";
if (message.Value != null)
{
// Got an Action Submit
dynamic value = message.Value;
string s = value.ToString();
Trace.WriteLine(s);
someValue = value.SomeType;
}
else
Trace.TraceInformation("There is no value");
//string data = message.ChannelData.ToString();
//Trace.WriteLine(data);
//Trace.TraceInformation("stringify message");
//string json = new JavaScriptSerializer().Serialize(message);
//Trace.WriteLine(json);
await context.PostAsync("Thanks for the click! SomeType is " + someValue);
context.Wait(MessageReceivedAsync);
}
catch (Exception e)
{
Trace.TraceInformation(e.ToString());
}
}
public async Task MessageReceivedAsync(IDialogContext context, IAwaitable<IMessageActivity> argument)
{
var message = await argument;
if (message.Text == "show card")
{
var response = context.MakeMessage();
if (response.Attachments == null)
response.Attachments = new List<Attachment>();
AdaptiveCard card = new AdaptiveCard();
card.Body.Add(new AdaptiveTextBlock()
{
Text = "This is a test",
Weight = AdaptiveTextWeight.Bolder,
Size = AdaptiveTextSize.Medium
});
card.Actions.Add(new AdaptiveSubmitAction()
{
Title = "Click Me",
Id = "12345678",
DataJson = "{ \"SomeType\": \"SomeData\" }"
});
Attachment attachment = new Attachment()
{
ContentType = AdaptiveCard.ContentType,
Content = card,
Name = "MyCard"
};
response.Attachments.Add(attachment);
await context.PostAsync(response);
context.Wait(ClickHandleAsync);
}
I am using DirectLine API to send message to the bot, I need the service URL of the Published Bot to perform a post request for the load test as mentioned in the steps here https://blog.botframework.com/2017/06/19/Load-Testing-A-Bot/
This is the code, can anyone point where I am going wrong
private static async Task<Chat> TalkToTheBot(string Message)
{
Chat objChat = null;
// Connect to the DirectLine service
try
{
DirectLineClient client = new DirectLineClient(directLineSecret);
Conversation conversation = await client.Conversations.StartConversationAsync();
string watermark = null;
Activity reply = new Activity
{
From = new ChannelAccount("User1", "User Name"),
Text = "Hello",
Type = ActivityTypes.Message,
};
//await client.Conversations.PostActivityAsync(conversation.ConversationId, reply.CreateReply(text: Message, locale: "en-US"), CancellationToken.None);
await client.Conversations.PostActivityAsync(conversation.ConversationId,reply , CancellationToken.None);
// Get the response as a Chat object
objChat = await ReadBotMessagesAsync(client, conversation.ConversationId, watermark);
}
catch (Exception e)
{
throw;
}
// Return the response as a Chat object
return objChat;
}
private static async Task<Chat> ReadBotMessagesAsync(DirectLineClient client, string conversationId, string watermark)
{
// Create an Instance of the Chat object
Chat objChat = new Chat();
// We want to keep waiting until a message is received
bool messageReceived = false;
while (!messageReceived)
{
// Get any messages related to the conversation since the last watermark
ActivitySet messages = await client.Conversations.GetActivitiesAsync(conversationId, watermark, CancellationToken.None);
// Set the watermark to the message received
watermark = messages?.Watermark;
// Get all the messages
var messagesFromBotText = from message in messages.Activities
where message.From.Id == botId
select message;
// Loop through each message
foreach (var message in messagesFromBotText)
{
// We have Text
if (message.Text != null)
{
// Set the text response
// to the message text
objChat.ChatResponse
+= " "
+ message.Text.Replace("\n\n", "<br />");
}
}
// Mark messageReceived so we can break
// out of the loop
messageReceived = true;
}
// Set watermark on the Chat object that will be
// returned
objChat.watermark = watermark;
// Return a response as a Chat object
return objChat;
}
Per the article,
The serviceUrl property here is critical to note, and needs to be set
to the endpoint of your message sink/client.
and:
In order to test your bot, you’ll need to create a custom UI/message
sink to send and receive messages to your bot. This message sink will
effectively act like a channel and accept HTTP POST messages with
JSON-serialized bot framework activities.
Which basically means that you will have to build a "message client" and the url of that client is the one that you will have to provide in the serviceUrl of your request.
I am having a issue accesing a text box in a view controller .cs file
async partial void loginUser(UIButton sender)
{
// Show the progressBar as the MainActivity is being loade
Console.WriteLine("Entered email : " + txtEmail.Text);
// Create user object from entered email
mCurrentUser = mJsonHandler.DeserialiseUser(txtEmail.Text);
try
{
Console.WriteLine("Starting network check");
// Calls email check to see if a registered email address has been entered
if (EmailCheck(txtEmail.Text) == true)
{
await CheckPassword();
}
else
{
UIAlertView alert = new UIAlertView()
{
Title = "Login Alert",
Message = "Incorrect email or password entered"
};
alert.AddButton("OK");
alert.Show();
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine("An error has occured: '{0}'", ex);
}
It is within this funciton that it complains it cannot access a text box which is on a aynsc method
public Task CheckPassword()
{
return Task.Run(() =>
{
// Creates instance of password hash to compare plain text and encrypted passwords.
PasswordHash hash = new PasswordHash();
// Checks password with registered user password to confirm access to account.
if (hash.ValidatePassword(txtPassword.Text ,mCurrentUser.password)==true)
{
Console.WriteLine("Password correct");
UIAlertView alert = new UIAlertView()
{
Title = "Login Alert",
Message = "Password Correct Loggin In"
};
alert.AddButton("OK");
alert.Show();
//insert intent call to successful login here.
}
else
{
UIAlertView alert = new UIAlertView()
{
Title = "Login Alert",
Message = "Incorrect email or password entered"
};
alert.AddButton("OK");
alert.Show();
}
Console.WriteLine("Finished check password");
});
}
Its this line the error occurs:
txtPassword.Text
The error is as follows:
UIKit.UIKitThreadAccessException: UIKit Consistency error: you are
calling a UIKit method that can only be invoked from the UI thread.
Also my Password Correct does not show even though if it is a correct password.
Do i have to run the UI Alerts on a seperate thread?
Any UIKit methods must be called from the UI thread (or Main thread, Main queue, etc.). This ensures consistency in the UI. Xamarin adds a check to all UIKit methods in debug mode and throws that exception if you try to use a background thread to change the UI.
The solution is simple: only modify the UI from the UI thread. That essentially means if you're using a class with "UI" in front it, you should probably do it from the UI thread. (That's a rule of thumb and there are other times to be on the UI thread).
How do I get my code on this mythical UI thread? I'm glad you asked. In iOS, you have a few options:
When in a subclass of NSObject, InvokeOnMainThread will do the trick.
From anywhere, CoreFoundation.DispatchQueue.MainQueue.DispatchAsync will always work.
Both of those methods just accept an Action, which can be a lambda or a method.
So in your code, if we add an InvokeOnMainThread (because I think this is in your UIViewController subclass)...
public Task CheckPassword()
{
return Task.Run(() =>
{
// Creates instance of password hash to compare plain text and encrypted passwords.
PasswordHash hash = new PasswordHash();
// Checks password with registered user password to confirm access to account.
InvokeOnMainThread(() => {
if (hash.ValidatePassword(txtPassword.Text ,mCurrentUser.password)==true)
{
Console.WriteLine("Password correct");
UIAlertView alert = new UIAlertView()
{
Title = "Login Alert",
Message = "Password Correct Loggin In"
};
alert.AddButton("OK");
alert.Show();
//insert intent call to successful login here.
}
else
{
UIAlertView alert = new UIAlertView()
{
Title = "Login Alert",
Message = "Incorrect email or password entered"
};
alert.AddButton("OK");
alert.Show();
}
});
Console.WriteLine("Finished check password");
});
}
Maybe this helps someone. So I will add what solve my issue, that was the same of rogue.
Follow the code that avoid this error of consistency in xamarin forms when used in iOS
await Task.Run(async () =>
{
await Device.InvokeOnMainThreadAsync(async () =>
{
await MaterialDialog.Instance.SnackbarAsync(message: "Bla bla bla",
msDuration: MaterialSnackbar.DurationShort).ConfigureAwait(false);
}).ConfigureAwait(false);
}).ConfigureAwait(false);