PWA:强制 window.open 打开浏览器而不是 PWA [英] PWA: force window.open to open browser instead of PWA

查看:38
本文介绍了PWA:强制 window.open 打开浏览器而不是 PWA的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经构建了一个带有角度前端的 ASP.NET Core 应用程序.angular 应用程序具有 @angular/pwa 节点包设置,因此它是一个渐进式 Web 应用程序,可以像原生应用程序一样安装在 android/windows 上.

I have built an ASP.NET Core application with an angular frontend. The angular app has the @angular/pwa node package setup, so it's a progressive web app that can be installed on android/windows behaving like a native app.

我已经使用 Microsoft.AspNetCore.Identity 设置了外部登录(Microsoft、Google、Facebook、Twitter).从我的 angular 应用程序中,我打开了一个指向外部登录页面的弹出窗口:

I have setup external logins (Microsoft, Google, Facebook, Twitter) with Microsoft.AspNetCore.Identity. From my angular app I'm opening a popup to an external login page:

  this.authWindow = window.open(`${this.baseUrl}/web/v2/Account/${this.action}/${medium}/${this.platform}`, null, 'width=600,height=400');

弹出窗口的 url 路由到我有 return Challenge() 调用的 ASP.NET Core 端点,它返回特定外部提供程序(Microsoft、Google、Facebook、推特).

The url for the popup routes to an ASP.NET Core endpoint where I have the return Challenge() call, which returns the login page for the specific external provider (Microsoft, Google, Facebook, Twitter).

在 Windows 上的 Chrome 中,您单击触发 window.open() 的按钮以打开带有外部登录页面的窗口.成功登录后,您将被重定向到回调页面,这是一个 razor 页面,它向包含 angular 应用程序的主窗口发送消息.正在处理消息,正在关闭弹出窗口.

In Chrome on Windows, you click a button which triggers the window.open() in order to open a window with the external login page. On successfull login you're being redirected to the callback page, which is a razor page which sends a message to the main window containing the angular app. The message is being handled and the popup is being closed.

当我在 Chrome for Android 上使用该网站时,我可以将 PWA 安装为应用程序,这会在我的 android 主页上添加一个图标.当我打开 PWA 并单击按钮打开弹出窗口时,弹出窗口是在我的 PWA 的弹出窗口中打开的,所以没问题.

When I use the website on Chrome for Android, I can install the PWA as app, which adds an icon on my android homepage. When I open the PWA and click the button to open the popup, the popup is being opened in a popup window for my PWA, so no problem there.

当我在 android 上打开 Chrome 并访问网站时,安装了 PWA 时,window.open() 调用不会打开 Chrome 浏览器的弹出窗口,而是尝试打开Progressive Web App 的弹出窗口.既然如此,PWA 内部的弹出窗口就无法通知 Chrome 中的网站登录成功了(废话...).

When I open Chrome on android and visit the website, while the PWA is installed, the window.open() call does not open a popup window for the Chrome browser, but instead tries to open the popup window for the Progressive Web App. Since this is the case, the popup window inside the PWA cannot notify the website in Chrome about the successful login (duh...).

但是当未安装 PWA 时,window.open() 工作正常并在 Chrome 本身中打开弹出窗口.

But when the PWA is not installed, the window.open() works fine and opens the popup in Chrome itself.

所以底线是,PWA 安装在 android 上.我希望能够在 Chrome 中从我的网站调用 window.open(),并让它在 Chrome 浏览器而不是 PWA 中打开弹出窗口.

So the bottom line is, the PWA is installed on android. And I want to be able to call window.open() from my website inside Chrome, and have it open the popup in Chrome browser instead of the PWA.

  1. 修改 ngsw-config.json

  1. Modify ngsw-config.json

{...,导航网址":[/",!//.",!//__",!//__/",!/web/v2/Account/connect//",!/web/v2/Account/add//**"]}

{ ..., "navigationUrls": [ "/", "!//.", "!//__", "!//__/", "!/web/v2/Account/connect//", "!/web/v2/Account/add//**" ] }

使用 target='_system'

this.authWindow = window.open(${this.baseUrl}/web/v2/Account/${this.action}/${medium}/${this.platform},'_system', 'width=600,height=400');

this.authWindow = window.open(${this.baseUrl}/web/v2/Account/${this.action}/${medium}/${this.platform}, '_system', 'width=600,height=400');

使用 target='_blank'

this.authWindow = window.open(${this.baseUrl}/web/v2/Account/${this.action}/${medium}/${this.platform},'_blank', 'width=600,height=400');

this.authWindow = window.open(${this.baseUrl}/web/v2/Account/${this.action}/${medium}/${this.platform}, '_blank', 'width=600,height=400');

target='_blank' 打开窗口,没有 baseUrl,只有一个绝对路径.

Open the window with target='_blank' and without baseUrl, just an absolute path.

this.authWindow = window.open(/web/v2/Account/${this.action}/${medium}/${this.platform}, '_blank', 'width=600,高度=400');

this.authWindow = window.open(/web/v2/Account/${this.action}/${medium}/${this.platform}, '_blank', 'width=600,height=400');

使用 ngsw-bypass

Use ngsw-bypass

this.authWindow = window.open(/web/v2/Account/${this.action}/${medium}/${this.platform}?ngsw-bypass=true,'_blank', 'width=600,height=400');

this.authWindow = window.open(/web/v2/Account/${this.action}/${medium}/${this.platform}?ngsw-bypass=true, '_blank', 'width=600,height=400');

但所有的技巧似乎都表现得一样,仍然在 PWA 中打开窗口.

But all tricks seem to behave the same and still open the window in the PWA.

推荐答案

我最终创建了一个子域来托管我的外部登录端点(ExternalLogin、ExternalLoginCallback、AddExternalLogin、AddExternalLoginCallback):

I ended up creating a subdomain hosting my endpoints for external login (ExternalLogin, ExternalLoginCallback, AddExternalLogin, AddExternalLoginCallback):

[Controller]
[Route("web/v2/[controller]")]
public class AccountController : Controller
{
    private IAccountService accountService;
    public AccountController(IAccountService accountService)
    {
        this.accountService = accountService;
    }

    ...

    // GET: web/Account/providers
    [AllowAnonymous]
    [HttpGet("providers", Name = "web-v2-account-external-providers")]
    public async Task<ActionResult<IEnumerable<string>>> Providers()
    {
        var result = await accountService.GetProviders();
        return Ok(result);
    }

    // GET: web/Account/connect/{provider}
    [AllowAnonymous]
    [HttpGet("connect/{medium}/{provider}", Name = "web-v2-account-external-connect-challenge")]
#if RELEASE
    [Host("external.mintplayer.com")]
#endif
    public async Task<ActionResult> ExternalLogin([FromRoute]string medium, [FromRoute]string provider)
    {
        var redirectUrl = Url.RouteUrl("web-v2-account-external-connect-callback", new { medium, provider });
        var properties = await accountService.ConfigureExternalAuthenticationProperties(provider, redirectUrl);
        return Challenge(properties, provider);
    }

    // GET: web/Account/connect/{provider}/callback
    [HttpGet("connect/{medium}/{provider}/callback", Name = "web-v2-account-external-connect-callback")]
#if RELEASE
    [Host("external.mintplayer.com")]
#endif
    public async Task<ActionResult> ExternalLoginCallback([FromRoute]string medium, [FromRoute]string provider)
    {
        try
        {
            var login_result = await accountService.PerfromExternalLogin();
            if (login_result.Status)
            {
                var model = new LoginResultVM
                {
                    Status = true,
                    Medium = medium,
                    Platform = login_result.Platform
                };
                return View(model);
            }
            else
            {
                var model = new LoginResultVM
                {
                    Status = false,
                    Medium = medium,
                    Platform = login_result.Platform,

                    Error = login_result.Error,
                    ErrorDescription = login_result.ErrorDescription
                };
                return View(model);
            }
        }
        catch (OtherAccountException otherAccountEx)
        {
            var model = new LoginResultVM
            {
                Status = false,
                Medium = medium,
                Platform = provider,

                Error = "Could not login",
                ErrorDescription = otherAccountEx.Message
            };
            return View(model);
        }
        catch (Exception ex)
        {
            var model = new LoginResultVM
            {
                Status = false,
                Medium = medium,
                Platform = provider,

                Error = "Could not login",
                ErrorDescription = "There was an error with your social login"
            };
            return View(model);
        }
    }

    // GET: web/Account/logins
    [Authorize]
    [HttpGet("logins", Name = "web-v2-account-external-logins")]
    public async Task<ActionResult<IEnumerable<string>>> GetExternalLogins()
    {
        var logins = await accountService.GetExternalLogins(User);
        return Ok(logins.Select(l => l.ProviderDisplayName));
    }

    // GET: web/Account/add/{provider}
    [Authorize]
    [HttpGet("add/{medium}/{provider}", Name = "web-v2-account-external-add-challenge")]
#if RELEASE
    [Host("external.mintplayer.com")]
#endif
    public async Task<ActionResult> AddExternalLogin([FromRoute]string medium, [FromRoute]string provider)
    {
        var redirectUrl = Url.RouteUrl("web-v2-account-external-add-callback", new { medium, provider });
        var properties = await accountService.ConfigureExternalAuthenticationProperties(provider, redirectUrl);
        return Challenge(properties, provider);
    }

    // GET: web/Account/add/{provider}/callback
    [Authorize]
    [HttpGet("add/{medium}/{provider}/callback", Name = "web-v2-account-external-add-callback")]
#if RELEASE
    [Host("external.mintplayer.com")]
#endif
    public async Task<ActionResult> AddExternalLoginCallback([FromRoute]string medium, [FromRoute]string provider)
    {
        try
        {
            await accountService.AddExternalLogin(User);
            var model = new LoginResultVM
            {
                Status = true,
                Medium = medium,
                Platform = provider
            };
            return View(model);
        }
        catch (Exception)
        {
            var model = new LoginResultVM
            {
                Status = false,
                Medium = medium,
                Platform = provider,

                Error = "Could not login",
                ErrorDescription = "There was an error with your social login"
            };
            return View(model);
        }
    }
}

在 PWA 中运行时,window.open 仍会在您的 PWA 内的嵌入式浏览器中打开链接,当从浏览器 window.open 运行时,仍将在新的浏览器窗口中打开链接(而不是在您的 PWA 中)).在这两种情况下,我仍然可以访问 opener 来发送消息 (window.opener.postMessage).

When running in the PWA, the window.open will still open the link inside an embedded browser within your PWA, and when running from the browser window.open will still open the link in a new browser window (not in your PWA). In both cases I'm still able to access the opener to send messages (window.opener.postMessage).

这篇关于PWA:强制 window.open 打开浏览器而不是 PWA的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆