Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
212 views
in Technique[技术] by (71.8m points)

ios - Link to Safari "Add to Home Screen" from inside app?

My app has a custom URL scheme and can use deep linking to jump straight from a URL to some content. I'd love to replicate the behaviour in the recent Facebook Groups app, which allows the user to hit an "Add to Home Screen" button in the app, which takes them out to a custom-designed localhost page in Safari, allowing them to tap Safari's Share and Add to Home Screen buttons, which will then add an icon to their home screen which, when tapped, takes them into the Groups app, and to the specific group in question.

My problem is that if I send my custom URL scheme deep link to Safari, before the user could tap Add to Home Screen, it'll follow that link and just end up right back in my app. I need to send something to Safari which won't actually follow the deep link, but will still link to it if the user adds it to their home screen, and I have no idea how to do that.

Facebook Groups' generated links in the Safari address bar look something like this, have they perhaps embedded JavaScript directly into the URL?:

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

Any idea what that is, and how I might do something similar?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

If you paste these characters into any online base64 decoder, you'll get the following:

<!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>

Instead of #### there is the following:

<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>');

So I believe their implementation is as follows:

1) There is a web server embedded in the application (something like RoutingHTTPServer). It's running on some port like 5555 and configured to return a page with contents like:

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

The syntax is wrong, but the idea is to replace the current URL (http://localhost:5555) with that base64 encoded data.

2) When you tap add to home page in the app, it opens the link http://localhost:5555 in the Safari, the web server inside the app responds with the web page, containing a script that replaces the URL with base64 encoded data (this data contains the current time, when the script was generated)

3)From the contents of the base64 encoded data you can see that there are two checks:

a)if the app is running not in Safari, but standalone

b)if some time has passed since the script was generated

If any of these statements is true, you are redirected into the app using deep link. If both of them are false, the page prompting user to add link to home screen is shown (that's what I replaced with ####).

When the link is added to home screen, all these scripts and web pages are embedded into that link as base64 encoded data.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...