Ionic:iframe中的外部链接在webview中打开(嵌入youtube播放器)

时间:2016-04-15 11:32:02

标签: iframe ionic-framework youtube-iframe-api

在我的离子(v1.2.4)应用程序中,有一个嵌入式youtube播放器,其中有一个链接"在youtube上观看"。如果用户点击此链接,则会在cordova的网络视图中打开youtube网站。它破坏了我的应用程序的当前状态。我想在系统的网络浏览器(应用程序浏览器插件中的cordova)中打开该链接。

与任何iframe中的任何链接相同(vimeo,soundcloud ...)

此链接无法在iframe外部使用JS进行修改,因为跨域安全问题。因此,我无法将目标属性从_blank更新为_system

显示对话框onbeforeunload实际上不是一个选项,因为它看起来很难看:)

是否有可能避免将页面加载到同一webview或系统的Web浏览器中? 使用iframe sandbox属性打破链接不是一种选择,因为它会完全打破youtube播放器。

谢谢和欢呼

ps:我问了这个问题here,但无法获得任何有用的信息

3 个答案:

答案 0 :(得分:3)

感谢thepio提供allow-intentallow-navigation的提示。我第一次真正深入研究cordova-whitelist-plugin。最后我通过在config.xml

中设置正确的allow属性来修复我在android上的问题
<!-- Allow links to web pages to open in a browser -->
<allow-intent href="http://*/*" />
<allow-intent href="https://*/*" />

对于Android没有allow-navigation。完美的白标解决方案。无法在iOS上找到如何执行此操作,因为iOS需要allow-navigation属性才能加载iframe内容。

要以肮脏的方式解决我在iOS上的问题,我将其添加到我的config.xml:

<platform name="ios">
  <allow-navigation href="https://w.soundcloud.com/player/*"/>
  <allow-navigation href="https://www.youtube.com/embed/*"/>
  <allow-navigation href="https://player.vimeo.com/video/*"/>
</platform>

现在只加载了iframe内容。幸运的是,iframe内的每个链接(在YouTube上观看,分享,比如vimeo ......)都指向另一个域/子域,因此它在iOS上被阻止。

如果有任何建议,如何为iOS创建白标解决方案,我很满意。

由于

答案 1 :(得分:1)

好的,这是一种硬核解决方案,应该重新编写/编码。此解决方案使用cordova挂钩,并在从a-tag中单击时,将http或https协议的 ALL 链接打开到本机Web浏览器。例如<a href="https://www.youtube.com/embed">。这不仅会影响iframe,还会影响所有链接。

请注意,因为这可能会影响您应用中的某些不需要的链接

我正在运行

  • Cordova 6.1.1
  • Cordova-ios 4.1.1
  • Cordova-android 5.1.1

首先,您需要在hooks / after_platform_add文件夹中创建一个钩子。只有在您使用ionic platform add <platform>cordova platform add <platform>时才会运行此挂钩。如果您没有名为after_platform_add的文件夹,只需创建一个。然后创建一个文件“01_ios_external_links_hook.js”。

另请阅读Cordova hooks文档:

https://cordova.apache.org/docs/en/latest/guide/appdev/hooks/

有几种方法可以定义钩子并为它们创建文件夹似乎已被弃用,因此您应该使用config.xml来附加钩子。

https://cordova.apache.org/docs/en/latest/guide/appdev/hooks/index.html#via-hooks-directory-deprecated

您可以调用您的文件,如果您正在使用文件夹,请记住添加文件的访问权限。通常在终端:

chmod +x project/hooks/after_platform_add/01_ios_external_links_hook.js.

请注意,此修复程序仅适用于iOS设备,因为在Android上,您可以通过设置<allow-intent href="http://*/*" />和设置<access origin="*" />来解决此问题。但是在最新的Cordova-ios和白名单插件上,您需要设置<allow-navigation href="*.youtube.com" />或类似内容以允许在iOS上加载iframe的内容。这将导致您描述的情况是iframe中的外部网址将在网页视图中打开。

但回到解决方案。这是我在01_ios_external_links.js文件中的代码:

#!/usr/bin/env node

var fs = require('fs');
var replace = require('replace');

if (fs.existsSync('platforms/ios/CordovaLib/Classes/Private/Plugins/CDVUIWebViewEngine/CDVUIWebViewDelegate.m')) {

  console.log('platforms/ios/CordovaLib/Classes/Private/Plugins/CDVUIWebViewEngine/CDVUIWebViewDelegate.m - FOUND: fixing');

  replace({
    regex: /.*BOOL shouldLoad = YES;*./g,
    replacement: 'BOOL shouldLoad = YES; NSURL * requesturl = [request URL]; NSString * url = [[request URL]absoluteString]; NSString * documenturl = [[request mainDocumentURL]absoluteString]; if ((navigationType == UIWebViewNavigationTypeLinkClicked && ([[requesturl scheme] isEqualToString:@"http"] || [[requesturl scheme] isEqualToString:@"https"])) || (([url isEqualToString:documenturl]) && ([[requesturl scheme] isEqualToString:@"http"] || [[requesturl scheme] isEqualToString:@"https"]))) { [[UIApplication sharedApplication] openURL:requesturl]; return NO;}',
    paths: ['platforms/ios/CordovaLib/Classes/Private/Plugins/CDVUIWebViewEngine/CDVUIWebViewDelegate.m'],
    recursive: true,
    silent: true,
  });

} else {
  console.log('platforms/ios/CordovaLib/Classes/Private/Plugins/CDVUIWebViewEngine/CDVUIWebViewDelegate.m  - NOT FOUND');
}

请注意,这是一项有风险的操作,但我当时没有办法解决这个问题。上面的代码搜索在给定的路径中是否有一个名为CDVUIWebViewDelegate.m的文件,然后尝试在那里找到一段代码并用另一段代码替换它。但简而言之,上面的代码将在CDVUIWebViewDelegate中修改iOS的平台特定代码,并在此文件中添加以下类型的if语句:

NSURL * requesturl = [request URL];
NSString * url = [[request URL]absoluteString]; // URL that was requested
NSString * documenturl = [[request mainDocumentURL]absoluteString]; // Main document URL

if ((navigationType == UIWebViewNavigationTypeLinkClicked && ([[requesturl scheme] isEqualToString:@"http"] || [[requesturl scheme] isEqualToString:@"https"])) || (([url isEqualToString:documenturl]) && ([[requesturl scheme] isEqualToString:@"http"] || [[requesturl scheme] isEqualToString:@"https"]))) {
    [[UIApplication sharedApplication] openURL:requesturl]; // forward to application router
    return NO;
}

考虑到我不是一个客观的编码器,这对我自己也是新的,我做了这个解决方案,因为我没有找到任何其他解决方案来解决我的问题。上述if语句可以而且应该根据您的需要进行修改。我只在开发环境中使用了此代码,并且需要进一步调查并改进此方法,然后再将其应用到生产环境中。

请记住,您需要删除并添加平台才能生效。这仅在添加如上所述的平台时发生。

但就是这样。现在,您的iOS应用程序将打开本机浏览器中的所有URL。希望这有助于您找到(更好?)解决此问题的正确方向。

答案 2 :(得分:0)

我也面临同样的问题,并且能够使用以下代码解决。

$('iframe#youtube').get(0).contentWindow.open = function (url) {
    cordova.InAppBrowser.open(url, "_system");
};

此代码仅适用于iOS。