【问题标题】:Link to Safari "Add to Home Screen" from inside app?从应用程序内部链接到 Safari“添加到主屏幕”?
【发布时间】:2015-01-20 09:48:13
【问题描述】:

我的应用有一个自定义 URL 方案,可以使用深度链接直接从 URL 跳转到某些内容。我很想在最近的 Facebook 群组应用程序中复制这种行为,它允许用户点击应用程序中的“添加到主屏幕”按钮,这会将他们带到 Safari 中定制设计的localhost 页面,允许他们点击 Safari 的“分享”和“添加到主屏幕”按钮,然后会在他们的主屏幕上添加一个图标,当点击该图标时,会将他们带入“群组”应用程序以及相关的特定群组。

我的问题是,如果我将我的自定义 URL 方案深层链接发送到 Safari,在用户可以点击添加到主屏幕之前,它会跟随该链接并最终回到我的应用程序中。我需要向 Safari 发送一些实际上不会跟随深层链接的内容,但如果用户将其添加到他们的主屏幕,它仍然会链接到它,我不知道该怎么做。

Facebook Groups 在 Safari 地址栏中生成的链接看起来像这样,他们是否可能将 JavaScript 直接嵌入到 URL 中?:

data:text/html;charset=UTF-8;base64, <tens of thousands of characters in an alpha-numeric string>

知道那是什么,以及我可以如何做类似的事情吗?

【问题讨论】:

    标签: ios objective-c facebook safari deep-linking


    【解决方案1】:

    如果您将这些字符粘贴到任何在线 base64 解码器中,您将获得以下信息:

    <!DOCTYPE HTML>
    <html>
    
    <head id="htmlHead">
        <meta name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1.0; user-scalable=no;" />
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <meta name="apple-mobile-web-app-capable" content="no" />
        <title>Promote Groups or Pages</title>
        <link rel="apple-touch-icon-precomposed" href="data:image/png;base64,
    </head>
    
    <body>
        <a id="redirect" href="fb-groups://group?id=1503507809911018&s=s"></a>
    </body>
    
    </html>
    <script type="text/javascript">
        function jump() {
            var e = document.getElementById('redirect');
            var ev = document.createEvent('MouseEvents');
            ev.initEvent('click', true, true, document.defaultView, 1, 0, 0, 0, 0, false, false, false, false, 0, null);
            e.dispatchEvent(ev);
            window.close();
        }
        if (("standalone" in window.navigator) && window.navigator.standalone) {
            document.body.style.backgroundColor = '#000000';
            jump();
        } else {
            var time = 1422371365;
            var timeout = new Date().getTime() / 1000;
            if (timeout > time + 4) {
                document.write('</head><body bgcolor="#fff"><div align="center"></div>');
                jump();
            } else {
                document.write(
                  ####
                              )}
        }
    </script>
    

    下面是####,而不是:

    <style>
        html,
        body,
        div,
        span,
        object,
        iframe,
        h1,
        h2,
        h3,
        h4,
        h5,
        h6 {
            margin: 0;
            padding: 0;
            border: 0;
            font-size: 100%;
            vertical-align: baseline;
            font-family: HelveticaNeue-Light, sans-serif;
            -webkit-touch-callout: none;
            -webkit-user-select: none;
            -khtml-user-select: none;
            -moz-user-select: none;
            -ms-user-select: none;
            user-select: none
        }
        a {
            color: inherit;
            text-decoration: none
        }
        #headerBox {
            width: 100%;
            height: 48px;
            border-bottom: .5px solid #979797;
            background-color: #F6F6F6;
            text-align: center
        }
        #popoverBox {
            position: absolute;
            bottom: 15px;
            width: 290px;
            height: 132px;
            -webkit-border-radius: 11px;
            border-radius: 11px;
            background-color: #2891F7;
            border: none;
            margin-left: -145px;
            left: 50%
        }
        #popoverBox:after {
            top: 100%;
            left: 50%;
            border: solid transparent;
            content: " ";
            height: 0;
            width: 0;
            position: absolute;
            pointer-events: none;
            border-color: rgba(40, 145, 247, 0);
            border-top-color: #2891F7;
            border-width: 13px;
            margin-left: -13px
        }
        .icon {
            margin-bottom: 5px
        }
        #groupIconContainer {
            margin-left: 40px;
            width: 60px;
            float: left;
            height: 100%
        }
        #groupIcon {
            height: 60px;
            width: 60px;
            -webkit-border-radius: 14px;
            border-radius: 14px;
            background-color: #FFF;
            margin-top: 25px
        }
        #addToHomeIconContainer {
            margin-right: 40px;
            width: 60px;
            float: right;
            height: 100%
        }
        #addToHomeIcon {
            margin-top: 25px
        }
        #arrow {
            margin: 0 auto;
            display: block;
            margin-top: 49px
        }
        #infoText {
            color: #141823;
            font-size: 18px;
            line-height: 28px;
            text-align: center;
            width: 280px;
            height: 160px;
            margin: auto;
            position: absolute;
            top: 0;
            left: 0;
            bottom: 0;
            right: 0
        }
        .iconLabelContainer {
            font-size: 12px;
            color: #FFF;
            line-height: 14px;
            width: 100px;
            height: 30px;
            margin-left: -20px;
            text-align: center
        }
        #groupCoverImage {
            box-sizing: border-box;
            -webkit-box-sizing: border-box;
            background-size: cover;
            background-position: center;
            background-image: url("data:image/png;base64,
            width: 52px;
            height: 52px;
            border-radius: 50%;
            position: relative;
            top: 4px;
            left: 4px;
            border: 0.5px solid rgba(0, 0, 0, 0.10);
        }
    </style>
    
    <body>
        <div id="headerBox"><span style="font-size:17px;color:#2891F7;line-height:20px;position:relative;top:13.5px"><a href="fb-groups://">Отмена</a></span>
        </div>
        <div id="infoText">Коснитесь кнопки
            <svg style="vertical-align:text-bottom" width="22px" height="30px" viewbox="0 0 44 60" version="1.1">
                <defs></defs>
                <g id="Final" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
                    <g id="Add-Group-to-Home-Screen" transform="translate(-299.000000, -459.000000)">
                        <g id="Tap-+-below-+-Share-Icon" transform="translate(231.000000, 458.000000)">
                            <g id="share-icon" transform="translate(60.000000, 0.000000)">
                                <path d="M20.4,12 L30,2.4 L39.6,12" id="Shape" stroke="#3F75FF" stroke-width="2"></path>
                                <path d="M30,39.0000013 L30,2.7996" id="Shape" stroke="#3F75FF" stroke-width="2"></path>
                                <rect id="Rectangle-path" x="0" y="0" width="60" height="60"></rect>
                                <path d="M20.2682927,20 L9,20 L9,60 L51,60 L51,20 L39.7317073,20" id="Shape" stroke="#3F75FF" stroke-width="2"></path>
                            </g>
                        </g>
                    </g>
                </g>
            </svg> ниже,
            <br>Затем коснитесь &ldquo;Добавить на основной экран&rdquo;</div>
        <div id="popoverBox">
            <div id="groupIconContainer">
                <div id="groupIcon" class="icon">
                    <div id="groupCoverImage"></div>
                </div>
                <div class="iconLabelContainer">Promote Groups or Pages</div>
                <!-- Replace with dynamic name -->
            </div>
            <div id="addToHomeIconContainer">
                <svg id="addToHomeIcon" width="60px" height="60px" viewbox="0 0 120 120" version="1.1">
                    <defs></defs>
                    <g id="Add-Group-to-Home-Screen-Spec" transform="translate(-410.000000, -802.000000)">
                        <g id="Add-to-Home-Screen" transform="translate(367.000000, 802.000000)">
                            <g id="Add-to-Home-Screen-Icon" transform="translate(43.000000, 0.000000)">
                                <rect id="Rectangle-6" fill="#FFFFFF" x="0" y="0" width="120" height="120" rx="28"></rect>
                                <rect id="Rectangle-6" fill="#686870" x="25" y="25" width="70" height="70" rx="15"></rect>
                                <path d="M58,58 L58,46.991617 C58,45.8978404 58.8954305,45 60,45 C61.1122704,45 62,45.8916773 62,46.991617 L62,58 L73.008383,58 C74.1021596,58 75,58.8954305 75,60 C75,61.1122704 74.1083227,62 73.008383,62 L62,62 L62,73.008383 C62,74.1021596 61.1045695,75 60,75 C58.8877296,75 58,74.1083227 58,73.008383 L58,62 L46.991617,62 C45.8978404,62 45,61.1045695 45,60 C45,58.8877296 45.8916773,58 46.991617,58 L58,58 Z" id="Rectangle-8" fill="#FFFFFF"></path>
                            </g>
                        </g>
                    </g>
                </svg>
                <div class="iconLabelContainer">Добавить на
                    <br>основной экран</div>
            </div>
            <svg id="arrow" width="12px" height="20px" viewbox="0 0 24 40" version="1.1">
                <defs></defs>
                <g id="Explorations" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
                    <g id="Add-Group-to-Home-Screen" transform="translate(-307.000000, -847.000000)" stroke-linecap="round" stroke="#FFFFFF" stroke-width="5">
                        <g id="Group" sketch:type="MSLayerGroup" transform="translate(30.000000, 752.000000)">
                            <path d="M297,132 L280,115 L297,98" id="Path-35" transform="translate(288.500000, 115.000000) rotate(-180.000000) translate(-288.500000, -115.000000) "></path>
                        </g>
                    </g>
                </g>
            </svg>
        </div>
        <div id="popoverNub"></div>');
    

    所以我相信他们的实现如下:

    1) 应用程序中嵌入了一个 Web 服务器(类似于RoutingHTTPServer)。它在某个端口(例如 5555)上运行,并配置为返回包含以下内容的页面:

    <HTML><script>window.location.href=[data:text/html;charset=UTF-8;base64, tens of thousands of characters in an alpha-numeric string]</script></HTML>
    

    语法错误,但想法是用 base64 编码数据替换当前 URL (http://localhost:5555)。

    2) 当您在应用程序中点击 add to home page 时,它会在 Safari 中打开链接 http://localhost:5555,应用程序内的网络服务器会响应网页,其中包含一个将 URL 替换为 base64 编码数据的脚本(此数据包含生成脚本的当前时间)

    3)从base64编码数据的内容可以看出有两个检查:

    a)如果应用程序不是在 Safari 中运行,而是独立运行

    b)如果脚本生成后已经过了一段时间

    如果这些陈述中的任何一个为真,您将被重定向到使用深层链接的应用程序。 如果两者都为 false,则会显示提示用户添加主屏幕链接的页面(这就是我用#### 替换的页面)。

    当链接添加到主屏幕时,所有这些脚本和网页都会作为 base64 编码数据嵌入到该链接中。

    【讨论】:

    • 这似乎是绝对正确的——非常感谢你深入研究这个!
    • 这是如何在后台工作的?例如,当您在 Safari 中点击链接并打开网页时,应用程序不再运行在前台,那么应用程序如何在后台处理 HTTP 请求?
    猜你喜欢
    • 2011-12-28
    • 1970-01-01
    • 2011-04-17
    • 1970-01-01
    • 1970-01-01
    • 2013-02-14
    • 2018-05-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多