iOS USES the schema protocol to invoke APP and APP to open APP

  • 2020-05-10 22:57:15
  • OfStack

In iOS, you need to set up an app to use the schema protocol, which is natively supported by iOS. In addition, since the iOS system can't use its own browser kernel, all browsers support it, which is different from android. android can do its own kernel, but iOS can't.

Two ways to open APP in a browser are provided in iOS: Smart App Banner and the schema protocol.

Smart App Banner

That is, through an meta tag, put the information of app on the tag and the behavior after opening, such as: app-id and so on. The code is like:

<meta name="apple-itunes-app" content="app-id=myAppStoreID, affiliate-data=myAffiliateData, app-argument=myURL">

Specific can see development documentation: https: / / developer apple. com/library/ios/documentation AppleApplications/Reference SafariWebContent/PromotingAppswithAppBanners/PromotingAppswithAppBanners html
Today, Smart APP Banner is not our protagonist, we are talking about schema

Open iOS APP using schema URL

schema is similar to the custom url protocol. We can open our own application through the custom protocol, as follows:


myapplink://
# For example, facebook the
fb://
# itunes the
itms-apps://
# Text messages are similar
sms://

If you want to open an app, the easiest way is through a link, as we wrote in html:

<a href="myapplink://"> Open my app</a>

When the user clicks on the link, the corresponding app can be opened.

Bind the click event

However, in practice, we are more likely to bind events, such as making a elastic layer, instead of using the a label, so we can solve it in two ways: location.href and iframe.

The iframe approach is commonly used in development, but it also has some problems:

1. We don't have a good way to tell if app is turned on
2. It will cause changes in history
3. Because of the change of history, there will be some problems with some webview. For example, let me check and open 1 page
4. If the page is leaked to the android system, the page will not open, etc
5. If the setting is not successful without app, safari of ios will pop up a dialog box by itself: unable to open the url or other prompts

So the question now is: how do you know that iframe has opened some app, which solves iframe and opens the app callback.

  USES iframe to open app on the iOS system

You might have thought of the iframe onload incident, but sadly, it didn't work! So we found a timer (setTimeout), by a timer, if over a period of time (such as 500 ms), when you click the button (record time1), page doesn't cut away (after tuning up app page process will be interrupted), process interruption, the timer will interrupt, this time should not trigger timer, if the failure, then timer will trigger, we judge if the page has not been cut in 1 time, will think tuning up the failure.

In addition, make a difference by timer2 when timer is triggered (the time after the cut should be longer than the actual timing of 500ms of timer) :


function openIos(url, callback) {
    if (!url) {
        return;
    }
    var node = document.createElement('iframe');
    node.style.display = 'none';
    var body = document.body;
    var timer;
    var clear = function(evt, isTimeout) {
       (typeof callback==='function') &&  callback(isTimeout);
        if (!node) {
            return;
        }
        node.onload = null;
        body.removeChild(node);
        node = null;     };
    var hide = function(e){
        clearTimeout(timer);
        clear(e, false);
    };
    node.onload = clear;
    node.src = url;
    body.appendChild(node);
    var now = +new Date();
    // If the event fails, then 1 Seconds is set to empty
    timer = setTimeout(function(){
        var newTime = +new Date();
          if(now-newTime>600){
            // Because it's gone, it takes time to cut it back
            // so timer Even if it does, the time difference between the two should follow 500ms There is a big discrepancy
            // But that's not the case!
            clear(null, false);
          }else{
            clear(null, true);
          }
    }, 500);
}

Looks like the method is very reliable, but the reality is always so cruel!

Different browsers app (including webview) have their own resident time in the background, that is, if a browser is in the background after being cut, resident 10s, then we set the timer 5s expired is useless, and 5s's timer, the user to wait for 5s empty! Interaction doesn't let you do that!

Finally, we came up with the pageshow and pagehide events. That is, if the browser is cut to app to be opened, the pagehide event of the browser should be triggered, while returning to the browser from app will trigger the pageshow method.

However, code testing found that in uc and chrome, the pagehide and pageshow methods would not be triggered, as they are in safari.

Conclusion:

1. Call schema URL with iframe
2. Use a timer to determine if the setting is successful in a period of time
3. Use pageshow and pagehide to assist the timer to make more detailed judgments
4. If there is an alert in the timer, it may not be ejected. This 1 point is surprising! The following dom actually executes 5, but alert does not pop up, which may have something to do with the implementation of alert
6. I used two timers in the experiment, because after cutting back to the browser, sometimes timeout triggers before pagehide and pageshow
7. It is also unreliable to calculate the actual execution time difference of timer

Finally, the code for the study is attached, which is a reliable method, although there are still 1 definite failure (the 3rd party browsers pagehide and pageshow do not trigger) :


<p><button id="btn"> Click me! Click me! alert Will not pop up </button></p>
<p><button id="btn2"> Click me! Click me! alert2 , although there are alert and info . info Execute, but alert Don't pop up </button></p>
<p><button id="btninfo"> Click me! Click me! info can </button></p> $(function(){   var $info = $('#info');   function info(msg){
    var p = $('<p>'+msg+'</p>');
    $info.append(p);
  }   $('#btn').on('click', function(){
    openIos('baiduboxapp://', function(t){
      if(t){
        alert('timeout or no baidu APP');
      }else{
        alert('invoke success');
      }
    });
  });
  $('#btn2').on('click', function(){
    openIos('baiduboxapp://', function(t){
      if(t){
        info('timeout or no baidu APP2');
        alert('timeout or no baidu APP2');
      }else{
        info('invoke success2');
        alert('invoke success2');
      }
    });
  });
  $('#btninfo').on('click', function(){
    openIos('baiduboxapp://', function(t){
      if(t){
        info('timeout or no baidu APP');
      }else{
        info('invoke success');
      }
    });
  }); }); function openIos(url, callback) {
    if (!url) {
        return;
    }
    var node = document.createElement('iframe');
    node.style.display = 'none';
    var body = document.body;
    var timer;
    var clear = function(evt, isTimeout) {
       (typeof callback==='function') &&  callback(isTimeout);
        window.removeEventListener('pagehide', hide, true);
        window.removeEventListener('pageshow', hide, true);
        if (!node) {
            return;
        }         node.onload = null;
        body.removeChild(node);
        node = null;     };
    var hide = function(e){
        clearTimeout(timer);
        clear(e, false);
    };
    window.addEventListener('pagehide', hide, true);
    window.addEventListener('pageshow', hide, true);
    node.onload = clear;
    node.src = url;
    body.appendChild(node);
    var now = +new Date();
    // If the event fails, then 1 Seconds is set to empty
    timer = setTimeout(function(){
        timer = setTimeout(function(){
          var newTime = +new Date();
          if(now-newTime>1300){
            clear(null, false);
          }else{
            clear(null, true);
          }         }, 1200);
    }, 60);
}


Related articles: