META
Интеграции
Embedded Frames

Embedded Frames

Общие замечания

Важно! Чтобы встроенное приложение поддерживало Cookies, они должны при установке иметь свойства secure=true и SameSite=None

Изменения на стороне Меты

На странице META размещаем такой код

<script type="meta/js" id="token" internal>
function main(env, vm, OAuthService) {
  // генерируем токен авторизации
  vm.accessToken = OAuthService.getAccessToken(env.userId, ['userinfo.profile']);
}
</script>
 
<!--
baseUrl - посадочная
accessToken - токен авторизации, доступен в amp.garpun.com так как он переведен на общую авторизацию account.garpun.com
minAbsHeightDiff - минимальное изменение высоты на которое сработает ресайз iframe. Будет зависеть от вашего случая
handleUrls - набор правил переадресации, чтобы например при клите со списка алгоритмов внутри iframe мы могли открыть алгоритм не внутри iframe, а как url меты, т.е. карточку алгоритма в meta приложении 
-->
<elem id="garpunUrl" name="me-iframe"  order="0"
  attrs='{
     "baseUrl":"https://amp.garpun.com/interface/clients/algorithms/?adHandsClientId=${env.objectId}",
     "accessToken":"${pvm.data.token.vm.accessToken}",
     "minAbsHeightDiff": 90,
     "handleUrls": [
      {"regexp": "add-algorithm\\?algorithmId=(\\d+)", "goTo": "/card?e=182&o=$1&a=${env.applicationId}"}
     ]
     }'
></elem>

Изменение на стороне встраиваемого сайта

Встраивание многостраничных сайтов (на примере amp.garpun.com)

Пример на основе интеграции старого Garpun в новое META-приложение

В Garpun мы разместили код

<script type="text/javascript">
  function inIframe() {
    try {
  return window.self !== window.top;
    } catch (e) {
  return true;
    }
  }
  document.addEventListener("DOMContentLoaded", function () {
    if (inIframe()) {
  // Это мы использовали чтобы убрать ненужные кнопки
  document.body.classList.add("garpunEmbedded");
    }
    document.body.classList.remove("garpunLoading");
  });
 
  // 
  (metaframewatcher = window.metaframewatcher || []).push({
    height_classes: ['t_window', 'cover', 'stickyWrap', 'mainBox']
  });
 
  if (inIframe()) {
    // Это не относится к задаче встраивания напрямую, но наверняка будет полезно для GTM для отключения виджетов поддержки и пр
    window['IS_EMBED_MODE'] = true;
 
    // Размещаем загрузки интеграционного скрипта
    (function() {
  var lt = document.createElement('script');
  lt.type ='text/javascript';
  lt.src = 'https://app.garpun.com/_b/meta-element/iframe/content-watcher.js';
  var sc = document.getElementsByTagName('script')[0];
  if ( sc ) sc.parentNode.insertBefore(lt, sc);
  else document.documentElement.firstChild.appendChild(lt);
    })();
  }
</script>

Встраивание одностраничных сайтов

Одностраничные сайты (в нашем случае таких много на NextJS) загружают внешний скрипт content-watcher.js только при загрузке приложения, из-за чего он не может полноценно работать, т.к.страницы динамически переключаются и их DOM перестраивается. Соответственно, не работает биндинг на события элементов для отслеживания изменения их размеров

Чтобы это обойти, был создан компонент MetaFrame:

'use client'
import 'antd/dist/reset.css';
import {useEffect} from "react";
import { useResizeDetector } from 'react-resize-detector';
 
const MetaFrame = ({children}: {children: React.ReactNode}) => {
    const { width, height, ref } = useResizeDetector();
    useEffect(() => {
        if (window.parent) {
            window.parent.postMessage({type: 'icwHeight', height: height}, '*');
        }
    }, [height])
    useEffect(() => {
        //Первичный запуск
        if (window.parent) {
            window.parent.postMessage({'type': 'icwHandshake', 'url': window.location.href}, '*');
        }
    }, []);
    return (
      <div ref={ref}>
          {children}
      </div>
    )
}
export default MetaFrame;

В него необходимо обернуть область контента. В моем случае он размещается сразу внутри body:

<body>
    <MetaFrame>
        {children}
    </MetaFrame>
</body>