InvokeScriptAsync not launching script - webview

I have an UWP app and I'm trying to get a script invoked from a WebView. The NavigationCompleted event raises and my javascript is included (I think) in the page but the script isn't executed.
Here's my C# code
public sealed partial class MainPage : Page
{
readonly WebView _webView = new WebView();
public MainPage()
{
this.InitializeComponent();
Facebook.Navigate(new Uri("http://www.facebook.com/"));
_webView.NavigationCompleted += WebView_OnNavigationCompleted;
_webView.ScriptNotify += WebView_OnScriptNotify;
}
private async void WebView_OnNavigationCompleted(WebView sender, WebViewNavigationCompletedEventArgs args)
{
await _webView.InvokeScriptAsync("eval", new[]
{
"alert('HEY');" +
"window.external.notify('%%' + location.href);"
});
}
private void WebView_OnScriptNotify(object sender, NotifyEventArgs e)
{
var url = e.Value;
}
}
Also, I added http://www.facebook.com and https://www.facebook.com to my package manifest Content Uris list (include with all WinRT access).
I can't get the alert popping, same for the notify.
Thanks

As noted in the WebView docs, alert doesn't work in a WebView control.
For Script Notify to work you need to add the page to the app manifest as well:
To enable an external web page to fire the ScriptNotify event when calling window.external.notify, you must include the page's Uniform Resource Identifier (URI) in the ApplicationContentUriRules section of the app manifest.
And:
The URIs in this list must use HTTPS
So, try navigating to the https site instead.
Worst case, you can use a web allowed object in order to communicate back to your app as that can be injected in all cases.

Related

How to inject controller into WebApp

I am building a library that is supposed to add features into an aspnetcore WebApp.
My goal is to add Controllers written in the library to respond to requests on specific routes on the WebApp itself.
The first thing I've done is to write an extension method as such:
public static IApplicationBuilder UseCustomLibrary(this IApplicationBuilder app)
{
if (app == null)
{
throw new ArgumentNullException(nameof(app));
}
//Here I want to hookup the routes to respond using my controller
}
Given that piece of code, I can now run app.UseCustomLibrary() from Program.cs.
Now, hooking up the actual controller to respond turns out to be not an easy task.
Things I've tried:
Using Custom Middleware:
public class MyCustomMiddleware
{
private readonly RequestDelegate _next;
public MyCustomMiddleware(RequestDelegate next)
{
_next = next ?? throw new ArgumentNullException(nameof(next));
}
public async Task Invoke(HttpContext context)
{
if (context.Request.Path.Value.Contains("expectedpath"))
{
//Manually handle the request.
}
await _next(context);
}
}
Even though that kind of works, that doesn't really hookup the controller. Instead I can handle the request manually. I dislike that because I now have to rewrite the controller into some kind of handler. That forces to abandon the nice controller structure of automatically determining the route using area/controller/action pattern. So this is currently my plan B.
Using Custom IApplictionFeatureProviders:
internal class MyCustomFeatureProvider : IApplicationFeatureProvider<ControllerFeature>
{
public void PopulateFeature(IEnumerable<ApplicationPart> parts, ControllerFeature feature)
{
if (!feature.Controllers.Contains(typeof(CustomController).GetTypeInfo()))
{
feature.Controllers.Add(typeof(CustomController).GetTypeInfo());
}
}
}
Then I would slightly modify the extension method to be call that provider as such:
public static IApplicationBuilder UseCustomLibrary(this IApplicationBuilder app)
{
app.Services.AddMvc().PartManager.FeatureProviders.Add(new MyCustomFeatureProvider());
return builder;
}
I was trying to copy what Microsoft.Identity library does in how it adds the "AccountController". Unfortunately that also doesn't work. The controller actions are never called for some reason.
I have also tried using that in conjunction with the middleware, by replacing the invoke method of the middleware with the following:
public async Task Invoke(HttpContext context)
{
context.Features.Set<IApplicationFeatureProvider<ControllerFeature>>(new MyCustomFeatureProvider());
await _next(context);
}
Again, that simply does nothing and the controller actions are never called.
I've also tried calling app.MapControllerRoute from my extension method, but it doesn't work as well for a reason that I cannot understand. It seems the controller is not even registered so it is never called.
I am willing to provide more details. I know there must be a way to do that, since it is used all the time in Microsoft.Identity and Microsoft.AspNetCore.Authentication to respond to authentication callbacks from IdPs for example. So there must be a way to do what I want.

How to make runtime changes to a Vaadin component after loading

How can I change a Vaadin h1 element dynamically using a timer after the page is navigated to from another Vaadin page?
navigate
start.addClickListener(e->{
ActorCallsHandler.ach.startGame();
UI.getCurrent().navigate(Playboard.class);
});
class
public class Playboard extends VerticalLayout
{
private H1 timer;
public Playboard() throws ExecutionException, InterruptedException{
generateGUI();
}
private void generateGUI(){
//h1 element that should alter using a timer after page load
H1 timer = new H1();
}
}
For this to work, you need to use either the Push or Polling functionality of Vaadin so that changes can be sent to the client at any time instead of only in the response to a request that is triggered by some user action.
I would recommend that you check out the documentation for the Push feature at https://vaadin.com/docs/v13/flow/advanced/tutorial-push-configuration.html.

Vaadin 7 and browser url update

My Vaadin 7 application doesn't react on browser url changing. For example I entering from keyboard a new url parameters and pressing Enter key and after that nothing is changing.
Application only reacts on F5 or page refresh button.
How to also make Vaadin 7 application to respond to Enter key after url update ?
UPDATED
I'm using Vaadin com.vaadin.navigator.Navigator object.
For example I have an url: http://example.com/#!products/30970
When I change the url in browser address bar (for example to http://example.com/#!products/34894) and press enter key I would like to change information at my page in order to show info about product with id 34894 instead of product with a previous id 30970.
Vaadin Navigator and UriFragmentChangedListener
Right now I'm using Vaadin Navigator in order to define views:
Navigator navigator = new Navigator(this, viewDisplay);
navigator.addView("products", ProductView.class);
First time in web browser I'm successfully able to access this view with product id parameter for example by the following url:
http://example.com/#!products/30970
ProductView is constructed first time and in its public void enter(ViewChangeListener.ViewChangeEvent event) method I'm able to get uri parameters.
But after that when I change product id in web browser address bar in this url to another one(for example to 30971 in order to display information for another product):
http://example.com/#!products/30971
and press Enter key the view is not refreshed and doesn't react on these changes..
As suggested in the comments I have added UriFragmentChangedListener listener and now at least able to handle URL fragment changes(after Enter key presing).
Now, my logic have to react on these changes and I'm looking for a correct way how it should be implemented in Vaadin 7.
So, If I understood correctly - in additional to Navigator logic I also have to use this listener and inside of this listener logic I have to get a reference on appropriate view(navigator.getCurrentView() ?) object and invoke some method on this object in order to change internal view state without full view rebuild ? If I'm correct - is there some standard mechanism in Vaadin in order to simplify this job ?
i can not think of another way than pass the UriFragmentChangeEvent manually to your View. I guess the Vaadin API can not do it automatic.
public class MyUI extends UI{
#Override
protected void init(final VaadinRequest request) {
/*
* UriFragmentChangedListener
* when URL+Parameter manuell eingegeben werden
*/
getPage().addUriFragmentChangedListener(new UriFragmentChangedListener() {
#Override
public void uriFragmentChanged(UriFragmentChangedEvent event) {
View currentView = getNavigator().getCurrentView();
if(currentView != null){
if(currentView instanceof UriFragmentChangedListener){
((UriFragmentChangedListener)currentView).uriFragmentChanged(event); //custom method
}
}
}
});
}
}
To make this work add UriFragmentChangedListener to your ProductView:
public class ProductView extends CustomComponent implements View, UriFragmentChangedListener {
}
take a look at the Parameters in the ViewChangeEvent of your ProductView
By using this url structure "http://example.com/#!products/30970", you can read the product id as following:
#Override
public void enter(ViewChangeEvent event) {
String productId = event.getParameters();
}

initially load a page with the BrowserField and then have links clicked in that open up in the BB browser instead of the BrowserField?

I want to initially load a page (stored html page) with the BrowserField and then have links clicked in that open up in the BB browser instead of the BrowserField?
My current code is as following,
BrowserFieldConfig.setProperty(BrowserFieldConfig.CONTROLLER, new BrowserFieldController()
{
public InputConnection handleResourceRequest(BrowserFieldRequest request) throws Exception {
return (InputConnection)Connector.open(request.getURL());
}
public void handleNavigationRequest(BrowserFieldRequest request) throws Exception
{
BrowserSession b = Browser.getDefaultSession();
b.displayPage(request.getURL());
}
});
And I want to load the html page stored in resources in browserfield and then open the links from the page in BB Browser which I'm doing using
browserfield.requestContent("local:///test.html");
But application tries to open the html file in browser, which is not desirable.
Please suggest me a workaround,
Thanks,
Aniket
This should be quite easy to achieve.
Firstly you will need to use the BrowserField object instead.
Extend the browser field's javascript engine, by using BrowserField.extendScriptEngine(String name, Scriptable scriptable)
Within the Scriptable you will open the native browser.
In the html, make the buttons execute the extended javascript function you created.
The handleNavigationRequest(BrowserFieldRequest request) method is called each time the browserfield requests content.
Add a count inside the method.
Increment the count by 1 each time the method is called.
If the count is greater then 0, it means the Browserfield has already loaded the first time. Subsequent calls to the method should then open a browser session instead of requesting content inside the Browserfield.
public void handleNavigationRequest(BrowserFieldRequest request) throws Exception
{
if(click<1){
// request for content inside Browserfield
}
else {
BrowserSession b = Browser.getDefaultSession();
b.displayPage(request.getURL());
}
click++;
}

Implementing a WAP site using ASP.NET-MVC

We plan on implementing a WAP site using ASP.NET-MVC.
Has anyone any experiance of this? Are there any Gotchas?
We will also be implementing a "standard" web site for browsers. Would it be possible to have a single set of Models and Controllers, and just have seperate views for each site?
It is possible to have for the most part a single set of models and controllers.
The way to do it will be via implementing the following Theming/Templating engine.
[Theming Support][1]
I piggy backed my solution on top of a Theming/Templating engine.
The major deviation from the article source is in the Global.asax.cs file where you need to add the following lines of code:
protected void Application_BeginRequest(Object Sender, EventArgs e)
{
SetTheme();
}
//this will set the responses Content Type to xhtml and is necessary as C# sends the WML response header
protected void Application_PreSendRequestHeaders(Object Sender, EventArgs e)
{
if (this.Context.Items["themeName"].ToString() == "xhtml")
{
this.Context.Response.ContentType = "application/vnd.wap.xhtml+xml";
}
}
private void SetTheme()
{
//set the content type for the ViewEngine to utilize.
HttpContext context = this.Context;
MobileCapabilities currentCapabilities = (MobileCapabilities)context.Request.Browser;
String prefMime = currentCapabilities.PreferredRenderingMime;
string accept = context.Request.ServerVariables["HTTP_ACCEPT"];
context.Items.Remove("theme");
context.Items.Remove("themeName");
if (accept.Contains("application/vnd.wap.xhtml+xml"))
{
context.Items.Add("themeName", "xhtml");
}
else if (prefMime == "text/vnd.wap.wml")
{
context.Items.Add("themeName", "WAP");
}
if (!context.Items.Contains("themeName"))
{
context.Items.Add("themeName", "Default");
}
}
I know I had to make a couple of code changes to make it MVC 1 compatible, but I can't remember the exact changes.
The other major problem I had was debugging the output. For this I used firefox with an extension ([User Agent Switcher][2]) that I've changed to add Accept Types to it.
For WAP2/XHTML1.2 the Accept Types are: text/html,application/vnd.wap.xhtml+xml,application/xhtml+xml,application/xml;q=0.9,/;q=0.8
Obviously you need your masterpage and content pages to adhere to WML or XHTML1.2
[1]: http://frugalcoder.us/post/2008/11/13/ASPNet-MVC-Theming.aspx Theming Support
[2]: http://chrispederick.com/work/user-agent-switcher/ User Agent Switcher

Resources