PWA:强制 window.open 打开浏览器而不是 PWA

PWA: force window.open to open browser instead of PWA

我已经构建了一个带有 angular 前端的 ASP.NET 核心应用程序。 angular 应用程序具有 @angular/pwa 节点包设置,因此它是一个渐进式网络应用程序,可以安装在 android/windows 上,其行为类似于本机应用程序。

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

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

弹出窗口的 url 路由到 ASP.NET 核心端点,我在其中进行了 return Challenge() 调用,returns 特定外部提供商的登录页面(微软、Google、脸书、推特)。

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

问题

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

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

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

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

我尝试过的事情

  1. 修改ngsw-config.json

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

  2. target='_system'

    打开window

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

  3. target='_blank'

    打开window

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

  4. target='_blank'打开window,不用baseUrl,只用绝对路径

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

  5. 使用 ngsw-bypass

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

但所有技巧似乎都表现相同,仍然在 PWA 中打开 window。

我最终创建了一个子域来托管我的外部登录端点(ExternalLoginExternalLoginCallbackAddExternalLoginAddExternalLoginCallback):

[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 中的嵌入式浏览器中打开 link,而当 运行 来自浏览器时 window.open 仍会在新浏览器 window 中打开 link(不在您的 PWA 中)。在这两种情况下,我仍然能够访问开启器以发送消息 (window.opener.postMessage)。