programing

아이폰의 웹 페이지에서 앱이 설치되어 있는지 확인하는 방법

newsource 2023. 7. 19. 21:24

아이폰의 웹 페이지에서 앱이 설치되어 있는지 확인하는 방법

iPhone에 애플리케이션이 설치되어 있지 않은 경우 iPhone을 App Store로 리디렉션하는 웹 페이지를 만들고 싶지만, iPhone에 애플리케이션이 설치되어 있는 경우에는 애플리케이션을 엽니다.

iPhone 응용 프로그램에 사용자 지정 URL을 이미 구현했으므로 응용 프로그램에 대한 다음과 같은 URL을 가지고 있습니다.

myapp://

그리고 이 URL이 올바르지 않으면 앱스토어로 페이지를 리디렉션하기를 원합니다.이것이 가능합니까?

전화기에 앱을 설치하지 않고 사파리에 myapp:// URL을 적으면 오류 메시지만 나타납니다.

자바스크립트로 추악한 해킹이 존재하더라도, 저는 정말 알고 싶습니다.

브라우저에서 앱이 설치되어 있는지 확인할 수 없는 것으로 알고 있습니다.

그러나 전화기를 앱으로 리디렉션하고 아무 일도 없으면 다음과 같이 지정된 페이지로 전화기를 리디렉션할 수 있습니다.

setTimeout(function () { window.location = "https://itunes.apple.com/appdir"; }, 25);
window.location = "appname://";

코드의 두 번째 행이 결과를 제공하면 첫 번째 행은 실행되지 않습니다.

유사한 질문:

승인된 답변을 추가하기 위해 앱을 실행한 후 브라우저로 돌아가는 사용자를 처리하기 위해 추가 코드를 추가해야 하는 경우가 있습니다. 이 코드는 사용자가 실행할 때마다 setTimeout 기능이 실행됩니다.그래서 저는 다음과 같은 일을 합니다.

var now = new Date().valueOf();
setTimeout(function () {
    if (new Date().valueOf() - now > 100) return;
    window.location = "https://itunes.apple.com/appdir";
}, 25);
window.location = "appname://";

그런 식으로 코드 실행에 동결이 발생한 경우(즉, 앱 전환) 실행되지 않습니다.

iOS Safari에는 웹 페이지에 "스마트" 배너를 추가할 수 있는 기능이 있습니다. 배너가 설치되어 있는 경우 앱 또는 앱 스토어에 연결됩니다.

다음을 추가하여 이 작업을 수행합니다.meta페이지에 태그를 붙입니다.앱이 로드될 때 특별한 작업을 수행하도록 하려면 상세 앱 URL을 지정할 수도 있습니다.

자세한 내용은 Apple의 스마트 앱 배너를 통한홍보 페이지에 있습니다.

이 메커니즘은 쉽고 표준화된 배너를 제공하는 장점이 있습니다.단점은 모양이나 위치를 제어할 수 없다는 것입니다.또한 Safari가 아닌 브라우저에서 페이지를 볼 경우 모든 베팅이 해제됩니다.

2017년 현재 앱이 설치된 것을 감지할 수 있는 신뢰할 수 있는 방법이 없는 것으로 보이며, 리디렉션 트릭이 모든 곳에서 작동하지는 않을 것입니다.

저처럼 이메일에서 직접 딥 링크(일반적으로)를 해야 하는 사람들은 다음 사항에 주목할 필요가 있습니다.

  • 링크가 Gmail에서 필터링되므로 appScheme://로 이메일을 보내면 제대로 작동하지 않습니다.

  • appScheme://로 자동 리디렉션이 Chrome에 의해 차단됩니다.Chrome은 리디렉션이 사용자 상호 작용과 동기화되어야 한다고 생각합니다(예: 클릭).

  • 이제 appScheme:// 없이도 딥 링크가 가능하며, 더 낫지만 현대적인 플랫폼과 추가 설정이 필요합니다.안드로이드 iOS


다른 사람들이 이미 이에 대해 깊이 생각했다는 점에 주목할 필요가 있습니다.Slack이 "매직 링크" 기능을 구현하는 방법을 살펴보면 다음과 같은 것을 알 수 있습니다.

  • 일반 HTTP 링크로 이메일을 보냅니다(Gmail로 OK).
  • 웹 페이지에는 appScheme://(Chrome과 함께 사용 가능)에 연결되는 큰 버튼이 있습니다.

@알리스테어는 이 답변에서 때때로 사용자들이 앱을 연 후 브라우저로 돌아갈 것이라고 지적했습니다.그 답변에 대한 논평자는 iOS 버전에 따라 사용된 시간 값을 변경해야 한다고 지적했습니다.

팀에서 이 문제를 해결해야 할 때 초기 시간 초과 및 브라우저 복귀 여부를 알려주는 시간 값을 조정해야 하며 모든 사용자와 장치에 대해 작동하지 않는 경우가 종종 있었습니다.

임의의 시간 차이 임계값을 사용하여 브라우저로 돌아왔는지 여부를 확인하는 대신 "페이지 숨기기" 및 "페이지 표시" 이벤트를 탐지하는 것이 적절했습니다.

저는 무슨 일이 일어나고 있는지 진단하는 것을 돕기 위해 다음과 같은 웹 페이지를 개발했습니다.주로 콘솔 로깅, 경고 또는 Web Inspector, jsfiddle.net 등과 같은 기술을 사용하는 것이 모두 이 워크플로우에서 단점을 가지고 있었기 때문에 이벤트가 전개될 때 HTML 진단을 추가합니다.JavaScript는 시간 임계값을 사용하는 대신 "페이지 숨기기" 및 "페이지 표시" 이벤트 수를 계산하여 이벤트가 발생했는지 여부를 확인합니다.그리고 가장 강력한 전략은 (다른 사람이 보고하고 제안한 25, 50 또는 100이 아닌) 초기 타임아웃을 1000으로 사용하는 것이었습니다.

이는 로컬 서버에서 제공될 수 있습니다.python -m SimpleHTTPServeriOS Safari에서 볼 수 있습니다.

게임을 실행하려면 "설치된 앱 열기" 또는 "설치되지 않은 앱" 링크를 누릅니다.이러한 링크를 통해 각각 지도 앱 또는 앱 스토어가 열립니다.그런 다음 Safari로 돌아가 이벤트의 순서와 시간을 확인할 수 있습니다.

(참고: 이 기능은 Safari에서만 사용할 수 있습니다.다른 브라우저(예: Chrome)의 경우 페이지 숨기기/표시 등가 이벤트에 대한 핸들러를 설치해야 합니다.

업데이트: @Mikko가 코멘트에서 지적했듯이, 우리가 사용하고 있는 페이지 표시/페이지 숨기기 이벤트는 iOS8에서 더 이상 지원되지 않습니다.

<html>
<head>
</head>

<body>
<a href="maps://" onclick="clickHandler()">Open an installed app</a>
<br/><br/>
<a href="xmapsx://" onclick="clickHandler()">App not installed</a>
<br/>

<script>
    var hideShowCount = 0 ;
    window.addEventListener("pagehide", function() {
        hideShowCount++;
        showEventTime('pagehide');
    });

    window.addEventListener("pageshow", function() {
        hideShowCount++;
        showEventTime('pageshow');
    });

    function clickHandler(){
        var hideShowCountAtClick = hideShowCount;
        showEventTime('click');
        setTimeout(function () {
                      showEventTime('timeout function ' + (hideShowCount-hideShowCountAtClick) + ' hide/show events');
                      if (hideShowCount == hideShowCountAtClick){
                              // app is not installed, go to App Store
                           window.location = 'http://itunes.apple.com/app';
                      }
                   }, 1000);
    }

    function currentTime()
    {
        return Date.now()/1000;
    }

    function showEventTime(event){
        var time = currentTime() ;
        document.body.appendChild(document.createElement('br'));
        document.body.appendChild(document.createTextNode(time + ' ' + event));
    }
</script>
</body>

</html>

이 플러그인을 통해 문제를 해결할 수 있습니다.missemisa 및 Alastair 등에서 설명한 것과 동일한 접근 방식을 기반으로 하지만 대신 숨겨진 iframe을 사용합니다.

https://github.com/hampusohlsson/browser-deeplink

저는 이런 일을 해야 했고, 결국 다음과 같은 해결책을 얻었습니다.

두 개의 단추가 있는 페이지를 열 특정 웹 사이트 URL이 있습니다.

  1. 1번 버튼은 웹사이트로 이동합니다.

  2. 2번 버튼은 애플리케이션(iPhone/Android 폰/태블릿)으로 이동합니다.앱이 설치되지 않은 경우(예: 다른 URL 또는 앱 스토어) 여기서 기본 위치로 되돌릴 수 있습니다.

  3. 사용자의 선택을 기억하는 쿠키

     <head>
         <title>Mobile Router Example </title>
    
    
         <script type="text/javascript">
             function set_cookie(name,value)
             {
                // JavaScript code to write a cookie
             }
             function read_cookie(name) {
                // JavaScript code to read a cookie
             }
    
             function goToApp(appLocation) {
                 setTimeout(function() {
                     window.location = appLocation;
                         // This is a fallback if the app is not installed.
                         // It could direct to an app store or a website
                         // telling user how to get the app
                 }, 25);
                 window.location = "custom-uri://AppShouldListenForThis";
             }
    
             function goToWeb(webLocation) {
                 window.location = webLocation;
             }
    
             if (readCookie('appLinkIgnoreWeb') == 'true' ) {
                 goToWeb('http://somewebsite');
    
             }
             else if (readCookie('appLinkIgnoreApp') == 'true') {
                 goToApp('http://fallbackLocation');
             }
    
         </script>
     </head>
    
     <body>
         <div class="iphone_table_padding">
         <table border="0" cellspacing="0" cellpadding="0" style="width:100%;">
             <tr>
                 <td class="iphone_table_leftRight">&nbsp;</td>
                 <td>
                     <!-- Intro -->
                     <span class="iphone_copy_intro">Check out our new app or go to website</span>
                 </td>
                 <td class="iphone_table_leftRight">&nbsp;</td>
             </tr>
             <tr>
                 <td class="iphone_table_leftRight">&nbsp;</td>
                 <td>
                     <div class="iphone_btn_padding">
    
                         <!-- Get iPhone app button -->
                         <table border="0" cellspacing="0" cellpadding="0" class="iphone_btn" onclick="set_cookie('appLinkIgnoreApp',document.getElementById('chkDontShow').checked);goToApp('http://getappfallback')">
                             <tr>
                                 <td class="iphone_btn_on_left">&nbsp;</td>
                                 <td class="iphone_btn_on_mid">
                                     <span class="iphone_copy_btn">
                                         Get The Mobile Applications
                                     </span>
                                 </td>
                                 <td class="iphone_btn_on_right">&nbsp;</td>
                             </tr>
                         </table>
    
                     </div>
                 </td>
                 <td class="iphone_table_leftRight">&nbsp;</td>
             </tr>
             <tr>
                 <td class="iphone_table_leftRight">&nbsp;</td>
                 <td>
                     <div class="iphone_btn_padding">
    
                         <table border="0" cellspacing="0" cellpadding="0" class="iphone_btn"  onclick="set_cookie('appLinkIgnoreWeb',document.getElementById('chkDontShow').checked);goToWeb('http://www.website.com')">
                             <tr>
                                 <td class="iphone_btn_left">&nbsp;</td>
                                 <td class="iphone_btn_mid">
                                     <span class="iphone_copy_btn">
                                         Visit Website.com
                                     </span>
                                 </td>
                                 <td class="iphone_btn_right">&nbsp;</td>
                             </tr>
                         </table>
    
                     </div>
                 </td>
                 <td class="iphone_table_leftRight">&nbsp;</td>
             </tr>
             <tr>
                 <td class="iphone_table_leftRight">&nbsp;</td>
                 <td>
                     <div class="iphone_chk_padding">
    
                         <!-- Check box -->
                         <table border="0" cellspacing="0" cellpadding="0">
                             <tr>
                                 <td><input type="checkbox" id="chkDontShow" /></td>
                                 <td>
                                     <span class="iphone_copy_chk">
                                         <label for="chkDontShow">&nbsp;Don&rsquo;t show this screen again.</label>
                                     </span>
                                 </td>
                             </tr>
                         </table>
    
                     </div>
                 </td>
                 <td class="iphone_table_leftRight">&nbsp;</td>
             </tr>
         </table>
    
         </div>
    
     </body>
    
     </html>
    

몇 가지 답변을 종합한 후, 저는 다음과 같은 코드를 생각해냈습니다.저를 놀라게 한 것은 PC(크롬 및 파이어폭스)나 안드로이드 크롬에서 타이머가 동결되지 않는다는 것입니다. 트리거는 백그라운드에서 작동했고 가시성 검사는 유일하게 신뢰할 수 있는 정보였습니다.

var timestamp        = new Date().getTime();
var timerDelay       = 5000;
var processingBuffer = 2000;

var redirect = function(url) {
  //window.location = url;
  log('ts: ' + timestamp + '; redirecting to: ' + url);
}

var isPageHidden = function() {
    var browserSpecificProps = {hidden:1, mozHidden:1, msHidden:1, webkitHidden:1};
    for (var p in browserSpecificProps) {
        if(typeof document[p] !== "undefined"){
          return document[p];
      }
    }
    return false; // Actually inconclusive, assuming not
}
var elapsedMoreTimeThanTimerSet = function(){
  var elapsed = new Date().getTime() - timestamp;
  log('elapsed: ' + elapsed);
  return timerDelay + processingBuffer < elapsed;
}

var redirectToFallbackIfBrowserStillActive = function() {
  var elapsedMore = elapsedMoreTimeThanTimerSet();
  log('hidden:' + isPageHidden() + '; time: ' + elapsedMore);
  if (isPageHidden() || elapsedMore) {
    log('not redirecting');
  }else{
      redirect('appStoreUrl');
  }
}

var log = function(msg){
    document.getElementById('log').innerHTML += msg + "<br>";
}

setTimeout(redirectToFallbackIfBrowserStillActive, timerDelay);
redirect('nativeApp://');

JS 피들

iOS 10부터 14까지 테스트한 다음 답변은 여전히 작동합니다.그것은 이전의 답변을 기반으로 합니다.추가했습니다.window.close()리디렉션 또는 페이지 반환 후 브라우저에 남아 있던 빈 탭 창을 제거합니다.4가지 시나리오 중 2가지를 수정하면 3번째와 4번째는 다른 사람이 수정할 수 있습니다.

<script>
var now = new Date().valueOf();
setTimeout(function () {
  // time stamp comaprison prevents redirecting to app store a 2nd time
  if (new Date().valueOf() - now > 100) {
    window.close() ;  // scenario #4
    // old way - "return" - but this would just leave a blank page in users browser
    //return;  
  }
  if (isIOS == 1) {
    // still can't avoid the "invalid address" safari pops up
    // but at least we can explain it to users
    var msg = "'invalid address' = MyApp NOT DETECTED.\n\nREDIRECTING TO APP STORE" ;
  } else {
    var msg = "MyApp NOT DETECTED\n\nREDIRECTING TO APP STORE" ;
  }
  if (window.confirm(msg)) {
    window.location = "<?=$storeUrl?>";
    // scenario #2 - will leave a blank tab in browser
  } else {
    window.close() ;  // scenario #3
  }
}, 50);
window.location = "<?=$mobileUrl?>";  
// scenario #1 - this will leave a blank tab
</script>

저는 iOS15용 Safari 확장에서 동일한 것을 달성하기 위해 노력해 왔습니다.이전의 모든 전략 - "열기" 대화상자와 "잘못된 주소" 대화상자는 완전히 동일하고 차단되지 않으므로, 타이머 기반 솔루션은 페이지를 로드하는 데 걸리는 시간에 따라 일관성 없는 결과를 제공합니다.

해결 방법은 시스템 프롬프트의 모양을 모방한 모달 팝업 내에 앱스토어 리디렉션 메시지를 만들고, 시스템 프롬프트 뒤에 숨기고, 탭의 초점이 떨어지면 이벤트 수신기로 제거하는 것이었습니다.UX에는 두 가지 문제가 남아 있습니다.

  1. 잘못된 주소 프롬프트를 표시할 수 없습니다.우리가 할 수 있는 모든 것은 (유니버설 링크 경로로 가지 않는 경우) 나중에 우리만의 프롬프트로 설명하는 것입니다.
  2. 사용자가 "열기" 프롬프트에서 "취소"를 선택한 경우에도 리디렉션 프롬프트가 나타납니다.

다음 코드는 위의 답변과 모달 팝업 생성을 위한 이 SO 코드의 이점을 모두 제공합니다.

// Change the following vars to suit your needs
var my_app_name = "My App";
var my_app_id = "id1438151717"
var my_app_scheme = "myapp://do.this"

function toggleModal(isModal, inputs, elems, msg) {
  for (const input of inputs) input.disabled = isModal;
  modal.style.display = isModal ? "block" : "none";
  elems[0].textContent = isModal ? msg : "";
}

function myConfirm(msg) {
  const inputs = [...document.querySelectorAll("input, textarea, select")].filter(input => !input.disabled);
  const modal = document.getElementById("modal");
  const elems = modal.children[0].children;

  return new Promise((resolve) => {
    toggleModal(true, inputs, elems, msg);
    elems[3].onclick = () => resolve(true);
    elems[4].onclick = () => resolve(false);
  }).then(result => {
    toggleModal(false, inputs, elems, msg);
    return result;
  });
}

function redirectMessage() {
  var r = myConfirm("To download " + my_app_name + ", tap OK.");
  return r.then(ok => {
    if (ok) {
      console.log("Redirecting to the App Store...");
      window.location = "itms-apps://itunes.apple.com/app/" + my_app_id;
    } else {
      console.log("User cancelled redirect to the App Store");
    }
    return ok;
  });
}

function prepareListener() {
  document.addEventListener("visibilitychange", function() {
    const inputs = [...document.querySelectorAll("input, textarea, select")].filter(input => !input.disabled);
    const modal = document.getElementById("modal");
    const elems = modal.children[0].children;

    if (!document.hasFocus()) {
      console.log("User left tab. Closing modal popup")
      toggleModal(false, inputs, elems, "");
    }
  });
}

function onTap() {
  setTimeout(function() {
    // We can't avoid the "invalid address" Safari popup,
    // but at least we can explain it to users.
    // We will create a modal popup behind it, which the
    // event listener will close automatically if the app 
    // opens and we leave the tab

    redirectMessage()

  }, 50);
  window.location = my_app_scheme;
}

prepareListener()
#modal {
  display: none;
  position: fixed;
  z-index: 1;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  overflow: auto;
  background: rgb(0, 0, 0);
  background: rgba(0, 0, 0, 0.4);
  font-family: "ms sans serif", arial, sans-serif;
  font-size: medium;
  border-radius: 15px;
}

#modal>div {
  position: relative;
  padding: 10px;
  width: 320px;
  height: 60px;
  margin: 0 auto;
  top: 50%;
  margin-top: -45px;
  background: white;
  border: 2px outset;
  border-radius: 15px;
}

#cancel_button {
  position: fixed;
  right: 50%;
  margin-right: -95px;
  bottom: 50%;
  margin-bottom: -32px;
  padding: 0;
  border: none;
  background: none;
  color: rgb(0, 122, 255);
  font-size: medium;
  font-weight: normal;
}

#ok_button {
  position: fixed;
  right: 50%;
  margin-right: -140px;
  bottom: 50%;
  margin-bottom: -32px;
  padding: 0;
  border: none;
  background: none;
  color: rgb(0, 122, 255);
  font-size: medium;
  font-weight: semi-bold;
}
<div id="modal">
  <div>
    <div></div><br><br>
    <button id="ok_button">OK</button>
    <button id="cancel_button">Cancel</button>
  </div>
</div>

<p><a href="#" onclick="onTap();"> Tap here to open app </a></p>

날짜 솔루션이 다른 솔루션보다 훨씬 좋습니다.저는 그렇게 시간을 50시간으로 늘려야 했습니다.

다음은 트위터의 예입니다.

// On click of your event handler...
var twMessage = "Your Message to share";
var now = new Date().valueOf();
setTimeout(function () {
   if (new Date().valueOf() - now > 100) 
       return;
   var twitterUrl = "https://twitter.com/share?text=" + twMessage;
   window.open(twitterUrl, '_blank');
}, 50);
window.location = "twitter://post?message=" + twMessage;

모바일 iOS Safari의 유일한 문제는 앱이 장치에 설치되어 있지 않은 경우이므로 새 URL이 열리면 자동으로 해제되는 알림이 Safari에 표시됩니다.어쨌든, 그것은 현재로서는 좋은 해결책입니다!

저는 이 답변들을 모두 읽지는 않았지만, 당신은 iframe을 사용하여 "내 앱://whating"에 소스를 추가하고 있을 수 있습니다.

그런 다음 페이지의 설정된 간격이 404인지 아닌지 정기적으로 확인합니다.

Ajax 전화를 사용할 수도 있습니다.404 응답이 있으면 앱이 설치되지 않습니다.

언급URL : https://stackoverflow.com/questions/13044805/how-can-i-check-if-an-app-is-installed-from-a-web-page-on-an-iphone