Url scheme based link does not seem to work in Blazor MAUI - xamarin.ios

I am building an app with .NET MAUI and Blazor, that initially targets iOS, but should also support Android, in a next release.
I have, in my Info.plist file added an entry myapp in the CFBundleURLSchemes array. And I use this as a redirect uri from our web portal (open in app, with the href myapp://settings/profile).
What happens, is that iOS comes and asks confirmation if that link can be opened with my app. (see screenshot).
But it just opens the app to the page that was previously open. It does not navigate to the Blazor page that is registered with the #page "/settings/profile" directive.
Is this something that is not supported? Or do I have to add something around the routing, here?
Current logic
With the following code in AppDelegate (for iOS), I can intercept that call and access the requested Url from that scheme-link.
public override bool OpenUrl(UIApplication application, NSUrl url, NSDictionary options)
{
AuthenticationContinuationHelper.SetAuthenticationContinuationEventArgs(url);
if (url?.Scheme?.Equals(myScheme, StringComparison.InvariantCultureIgnoreCase) ?? false)
{
var pageUrl = url.ToString().Replace($"{myScheme}://", "");
PageSettings.RequestedUri = pageUrl; // This is the static class/var I want to leverage in BlazorWebView
return base.OpenUrl(application, new NSUrl( pageUrl), options);
}
return base.OpenUrl(application, url, options);
}
However, I don't seem to find out how I can enforce the BlazorWebView to navigate to the right uri.

As I know, there is no way to do this currently with MAUI Blazor.
Refer to the documentation maui-blazor documentation, the .NET MAUI Blazor hybrid project template isn't a Shell-based app.
If you want to route to #page "/settings/profile", you could describe some information about where to go in AppDelegate, then set some staic and launch a simple page (MAUI PAGE), get the value and show the Blazor page.
public override bool OpenUrl (UIApplication app, NSUrl url, string sourceApp, NSObject annotation){
if (url.BaseUrl.Host.Equals ("app.myapp.io")) {
UIViewController page = new TargetPage().CreateViewController();
}
return true;
}
Set the homepage to your needs
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:BlazorDemo"
x:Class="BlazorDemo.TargetPage"
BackgroundColor="{DynamicResource PageBackgroundColor}">
<BlazorWebView x:Name="blazorWebView" HostPage="wwwroot/profile.html">
<BlazorWebView.RootComponents>
<RootComponent Selector="#app" ComponentType="{x:Type local:Main}" />
</BlazorWebView.RootComponents>
</BlazorWebView>
</ContentPage>

Related

Integrate liferay 7.4 recaptcha with MVC Portlet and apache wicket

I have an old application uses wicket 1.4 and want to integrate the liferay reCAPTCHA ( liferay 7.4).
Is there any guide for that?
Or anyone might help ?
It worked for MVC portlet like the following but still cannot achieve same in wicket :
Use CAPTCHA or reCAPTCHA with custom portlet in Liferay MVC Portlet:
CAPTCHA is a “Completely Automated Public Turing test to tell Computers and Humans Apart”. It is used in the computer world to determine whether an end-user is human or non-human. Liferay provides the necessary API as well as tag library to implement CAPTCHA in your custom portlet. Also, you can integrate Google reCAPTCHA in your custom portlet.
Prerequisites
Java
Liferay portal 7/7.x
Use CAPTCHA in custom portlet
Assuming you’ve already created a Liferay-workspace project
Follow below steps to implement CAPTCHA in your custom portlet
Create MVC Portlet
Go to liferay workspace project → modules → new
Select other → Liferay → Liferay Module Project and Click on Next
Enter project name
Select “Project Template Name” as “mvc-portlet” and Click on “Next”
Enter Package name and Click on “Finish”
The necessary file structure for MVC module will get created as below :
2) Now we add below code in view.jsp
<%# include file="/init.jsp" %>
<%# taglib uri="http://liferay.com/tld/util" prefix="liferay-util" %>
<%# taglib uri="http://liferay.com/tld/captcha" prefix="liferay-captcha" %>
<%# page import="com.liferay.portal.kernel.captcha.CaptchaTextException"%>
<portlet:actionURL name="basicFormDataWithCaptcha" var="basicFormDataWithCaptchaAActionURL" />
<portlet:resourceURL id="captcha" var="captchaResourceURL"/>
<liferay-ui:error exception="<%= CaptchaTextException.class %>" message="captcha-verification-failed" />
<aui:form method="post" name="basicForm" action="<%= basicFormDataWithCaptchaAActionURL %>">
<aui:input name="firstName" >
<aui:validator name="alpha"/>
</aui:input>
<aui:input name="lastName" >
<aui:validator name="alpha"/>
</aui:input>
<liferay-captcha:captcha url="<%= captchaResourceURL %>"/>
<aui:button type="submit" value="Submit"></aui:button>
</aui:form>
3) Create Action method in CustomCaptchaPortlet
package ...;
import ...;
#Component(
...
)
public class CustomCaptchaPortlet extends MVCPortlet {
private Log log = LogFactoryUtil.getLog(this.getClass().getName());
#ProcessAction(name = "basicFormDataWithCaptcha")
public void basicFormDataWithCaptcha(ActionRequest actionRequest, ActionResponse actionResponse)
throws IOException, PortletException {
String firstName = ParamUtil.getString(actionRequest,"firstName");
String lastName=ParamUtil.getString(actionRequest,"lastName");
log.info("First Name : " + firstName);
log.info("Last Name : " + lastName);
try{
CaptchaUtil.check(actionRequest);
log.info("CAPTCHA verification successful.");
}catch(Exception exception) {
if(exception instanceof CaptchaTextException) {
SessionErrors.add(actionRequest, exception.getClass(), exception);
log.error("CAPTCHA verification failed.");
}
}
}
#Override
public void serveResource(ResourceRequest resourceRequest, ResourceResponse resourceResponse)
throws IOException, PortletException {
try {
CaptchaUtil.serveImage(resourceRequest, resourceResponse);
}catch(Exception exception) {
log.error(exception.getMessage(), exception);
}
}
protected boolean isCheckMethodOnProcessAction() {
return _CHECK_METHOD_ON_PROCESS_ACTION;
}
private static final boolean _CHECK_METHOD_ON_PROCESS_ACTION = false;}
Output with CAPTCHA
Use Google reCAPTCHA in custom portlet
To integrate Google reCAPTCHA in Liferay please follow below steps
1) Get Site key & Secret key from Google reCAPTCHA
Go to www.google.com/recaptcha in your web browser
Click on “Admin console” button (Located at top-right corner)
Fill up your details in the form and then click on “Submit”
4- You will get “Site key & Secret key” as below image. This you will require while configuring Google reCAPTCHA with Liferay
2) Enable Google reCAPTCHA in your Liferay
Login as admin user
Navigate to Control Panel → System Setting → SECURITY → Security Tools → CAPTCHA
Go to CAPTCHA Engine and change it to reCAPTCHA
Enter “reCAPTCHA public key” and “reCAPTCHA private key”
You need to enter the values you got from Google reCAPTCHA site in previse step , “reCAPTCHA public key” field, and “secret key” in “reCAPTCHA private key” field
Click on ‘Save’
To test Google reCAPTCHA is properly configured or not. Logout from Liferay and go to Create Account page. You can see a default Liferay CAPTCHA is replaced with the new Google reCAPTCHA
3) Use Google reCAPTCHA in your Custom Portlet
Once you configure reCAPTCHA from control panel below, code will render google reCAPTCHA
<liferay-captcha:captcha url="<%= captchaResourceURL %>"/>
If we configure reCAPTCHA from Liferay control panel, Output of above ‘custom-captcha-portlet’ will look like below
As you see it works for MVC portlet but I have some code written in apache wicket which I did not find a way to achieve same and wondering if there is a way to integrate Liferay reCAPTCHA with wicket somehow ?

Using Trusted Web Activity to link multiple websites with native application

I've managed to link my native application to a website and launch the same on a button click. As the website is trusted, the URL bar is not visible. In the launched website there is a button which then further redirects to another website. I've created a digital asset link for both and have added the JSON file in <websitename>/.well-known/<json-file>.
Both the websites have also been referenced in strings.xml under
asset_statements. However, on launching the first website and then redirecting to the second website from the first, the second website launches as a regular custom chrome tab with the URL bar visible.
Is it possible to hide both the URL's? If so, how?
To enable multi-domain, you need to check 3 things
Each origin has a .well-known/assetlinks.json file
The android asset_statements contains all origins
Tell the Trusted Web Activity about additional origins when launching.
It seems you have the first two points covered, but not the last one.
Using the support library LauncherActivity:
If using the LauncherActivity that comes with the library, you can provide additional origins by updating the AndroidManifest:
Add a list of additional origins to res/values/strings.xml:
<string-array name="additional_trusted_origins">
<item>https://www.google.com</item>
</string-array>
Update AndroidManifest.xml:
<activity android:name="com.google.androidbrowserhelper.trusted.LauncherActivity"
android:label="#string/app_name">
<meta-data
android:name="android.support.customtabs.trusted.ADDITIONAL_TRUSTED_ORIGINS"
android:resource="#array/additional_trusted_origins" />
...
</activity>
Using a custom LauncherActivity
If using your own LauncherActivity, launching with additional origins can implemented like this:
public void launcherWithMultipleOrigins(View view) {
List<String> origins = Arrays.asList(
"https://checkout.example.com/"
);
TrustedWebActivityIntentBuilder builder = new TrustedWebActivityIntentBuilder(LAUNCH_URI)
.setAdditionalTrustedOrigins(origins);
new TwaLauncher(this).launch(builder, null, null);
}
Resources:
Article with more details here: https://developers.google.com/web/android/trusted-web-activity/multi-origin
Sample multi-origin implementation: https://github.com/GoogleChrome/android-browser-helper/tree/master/demos/twa-multi-domain

How Can I have IIS properly serve .webmanifest files on my web site?

The Favicon Generator assembles a package for webmasters to use in order to have icons available for many different devices. The page comes with a file called site.manifest which is linked to via the following tag in the web page's document <head>:
<link rel="manifest" href="site.webmanifest">
According to Mozilla: "The web app manifest provides information about an application (such as name, author, icon, and description) in a JSON text file. The purpose of the manifest is to install web applications to the homescreen of a device, providing users with quicker access and a richer experience."
Unfortunately if you are using Microsoft's Internet Information Services (IIS), you'll get a 404.3 error if you try and access the site.webmanifest file.
The exact error message is as follows: "The page you are requesting cannot be served because of the extension configuration. If the page is a script, add a handler. If the file should be downloaded, add a MIME map."
How can I properly serve site.webmanifest files in IIS?
By default, IIS does not serve any files that does not have a MIME map associated with it in its (IIS) core settings.
To address this challenge, you will need to map the .webmanifest file extension to its appropriate MIME type.
To accomplish this, open IIS and follow the steps below;
On the left hand side, select either your web site or the entire server in the "Connections" menu.
If you select the server, your MIME mapping will apply to every web site on the server.
If you select a web site, it will only apply to a single web site.
Next, select "MIME Types" from the IIS menu:
Once there, click "add..." from the right hand menu.
In the dialog box that opens specify .webmanifest in the file name extension box application/manifest+json in the MIME type box.
Click "OK".
Congratulations; you've just defined the MIME type for .webmanifest on IIS.
For Azure I added this as the web.config
<?xml version="1.0"?>
<configuration>
<system.webServer>
<staticContent>
<mimeMap fileExtension=".json" mimeType="application/json" />
<mimeMap fileExtension=".webmanifest" mimeType="application/manifest+json" />
</staticContent>
</system.webServer>
</configuration>
For those using ASP.NET Core (I am using 2.1) you can configure the MIME types that can be served in the application Startup.cs file as per the static files docs:
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
FileExtensionContentTypeProvider provider = new FileExtensionContentTypeProvider();
provider.Mappings[".webmanifest"] = "application/manifest+json";
app.UseStaticFiles(new StaticFileOptions()
{
ContentTypeProvider = provider
});
app.UseMvc();
}
Easier solution is to rename your manifest file to site.webmanifest.json and link as
<link rel="manifest" href="site.webmanifest.json">
IIS should already have a MIME Type for .json files
This is also helpful if deploying to Azure where its not so easy to change the IIS settings.
Adding to #Ben's answer: if you have a SPA you should put StaticFileOptions code into the UseSpaStaticFiles() call:
FileExtensionContentTypeProvider provider = new FileExtensionContentTypeProvider();
provider.Mappings[".webmanifest"] = "application/manifest+json";
app.UseSpaStaticFiles(new StaticFileOptions()
{
ContentTypeProvider = provider
});
I found that the IIS server had ".json" listed in the Request Filtering feature saying it was not allowed.
Removing that allowed the file to be served.

Remove canonical link from Sharepoint site

We have a main public site, abcd.com, which is using SharePoint Office 365 and another replica SharePoint site using this format - abcd-public.sharepoint.com.
For some reason,
<link rel="canonical" href="http://abcd-public.sharepoint.com:80/Pages/Home.aspx" />
shows up on every page our main public website (abcd.com). The path above changes depending on the page the user is on.
If I understand this correctly, this could be one of the reason why our site does not show up on google search result at all. If possible, we would like to reverse the behavior so the SharePoint version of the site has the canonical url = abcd.com.
or
Is there a way to completely remove the canonical url from the main website (abcd.com)? Or is there some sort of a setting that could help our site to show on google search result?
I had the same problem and the only solution that I found is create a webpart to put in the masterpage and in the prerender event of the webpart put this lines of code:
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
HttpContext.Current.Items["CanonicalURLWithParameters"] = "http://example.com/customurl";
}
Sergio

Why isn't the constructor of my WPF page control being called?

I am trying to create a Windows Store app for Desktop/tablet and Phone with a Universal App in Visual Studio 2013 Express. I am having some difficulty understanding what is happening in WPF, as my prior Windows 8 development experience has been with HTML/JS apps.
I ask VS to create a New Project->Visual C#->Store Apps->Universal Apps->Blank App. I open MainPage.xaml.cs and put a breakpoint on the first line in the constructor function, which happens to be this.InitializeComponent(). I hit F5, the app compiles and I am switched to the familiar full-screen Modern app view, but none of my breakpoints are ever hit.
I add a TextBlock to MainPage.xaml just so that there's something in there, but still no breakpoints are hit. What am I missing? Below is (some) the code the is generated by Visual Studio. I am probably missing something very fundamental about how WPF apps work and are structured, but all my google-fu has come to naught.
MainPage.xaml:
<Page
x:Class="SoloCoach.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:SoloCoach"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid>
</Grid>
</Page>
MainPage.xaml.cs:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234238
namespace SoloCoach
{
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
this.NavigationCacheMode = NavigationCacheMode.Required;
}
/// <summary>
/// Invoked when this page is about to be displayed in a Frame.
/// </summary>
/// <param name="e">Event data that describes how this page was reached.
/// This parameter is typically used to configure the page.</param>
protected override void OnNavigatedTo(NavigationEventArgs e)
{
// TODO: Prepare page for display here.
// TODO: If your application contains multiple pages, ensure that you are
// handling the hardware Back button by registering for the
// Windows.Phone.UI.Input.HardwareButtons.BackPressed event.
// If you are using the NavigationHelper provided by some templates,
// this event is handled for you.
}
}
}
When you create a Universal App it creates both a Windows 8.1 and a Windows Phone 8.1 app. The code you're showing is the default page constructor for the Phone version so you're probably in the wrong project which is not the Windows Modern App that you're running.

Resources