转载注明出处:点击打开链接

无论 iOS 还是 Android 都不约而同地支持 URI Scheme(扫盲帖)来作为页面与客户端的通讯协议。这里的 URI Scheme 前缀不是一般的 http://,而是由客户端开发者定义的,一般在写程序的时候就会设置的了。然后剩下的部分就像普通的 URL 地址一样,需要大家来约定 URI Scheme 具体如何,例如参数是什么等等,好比网易新闻客户端的是以 newsapp:// 为前缀:

[html] view plaincopy

  1. <ahref="newsapp://">打开网易新闻客户端</a>

如此便可以从网页打开客户端了。这只是最简单的 Scheme 部分,除此之外,应该还有更多的参数,一般要约定好,让网页开发者和客户端开发者两者之间可以相互调用。

这种情况,当然是假设用户已经安装了客户端,进而才会自动打开。那么,问题就来了,没有安装怎么办?以及最关键的一点——如何判断客户端是否已经安装呢?如果没有安装的话,我们可以提示提示用户去下载(跳到相应的下载页面)这个比较简单;但是,如何判断客户端是否已经安装呢?遗憾的是,浏览器并没有一个方法可以告诉你哪个客户端安装了,哪个没有安装!因此,如果按照上述 a 链接直接跳转而用户又没有安装客户端的话,浏览者看到的是一张空白的页面,——用户体验很差哦~于是我们一般采用“障眼法”,也就是把“隐藏”的 iframe 派上场,用 iframe.src 指向 URI Scheme 地址就可以了,既可以尝试打开客户端,又可以停留在当前页面上。

不过,我们也可以不停留也页面上——因为我们总是鼓励使用客户端的,所以这时候可跳转到下载客户端的页面。这是在没有安装的情况下的做法。如果客户端已经安装了,那就可以不跳转。

具体逻辑如下:

[html] view plaincopy

  1. <iframeclass="openApp hide"src="about:blank"></iframe>
  2. <script>
  3. function openClient(el, downloadUrl){
  4. var iframe=arguments.callee.iframe;
  5. if(!iframe){
  6. iframe=document.querySelector('.openApp')
  7. arguments.callee.iframe=iframe;
  8. }
  9. var startTime= +new Date();
  10. iframe.src=el.getAttribute('data-scheme');
  11. // 如果已知安装的了,则无须跳转下载页
  12. setTimeout(function() { // 如果不能打开客户端,跳到下载页面
  13. if (Date.now() - startTime <500) // 通过判断触发的时间与执行settimeout的时间差值是否小于设置的定时时间加上一个浮动值(一般设为100)。
  14. window.location.href=downloadUrl;
  15. }, 400);
  16. }
  17. openClient=openClient.delegate(null, 'http://g.3gtv.net');
  18. </script>

稍有点不足的就是,iOS 上面,如果没安装客户端,那么这段自定义的 URL Scheme(如 newsapp://) 就被视为"无效的链接“,弹对话框出来!(貌似 腾讯视频可以解决该问题哦,点击这里看页面——无奈的就是代码经过混淆的,不易察觉) 更新代码后,没有发现这个问题了。如果还是会这样的话,可以尝试用 script tag 发起请求,看能不能规避这个弹出框。

最后我们遇到一个下载页面的问题,由于微信内部浏览器限制的原因,不允许下载 apk 文件或者访问 app store,除非腾讯旗下的“应用宝”才可以。我们对腾讯这一封闭的做法十分不齿,却又无可奈何。于是只能默默地“归化”应用宝。好了,用就用呗——本来跳到下载页面是没有问题的。但令人觉得蛋疼的是,应用宝页面居然自己又会调起客户端(如果安装过的话)!这样势必就是“二次打开”客户端!要规避这个问题,一、不直接跳掉应用宝下载页面;二、改 UI,提供两个按钮,一是打开客户端的,另外一个是下载。

后记,还是兼容性问题:

  • 发现三星 note3 系统浏览器竟然不能 iframe 调起!
  • QQ 浏览器杯具了,竟然对 URI Scheme 一点都不支持!如下图所示,对此,优酷的做法是干脆把 打开客户端 的按钮隐藏掉。
[html] view plaincopy

  1. <%@tagpageEncoding="UTF-8"import="com.ajaxjs.bigfoot.*"%>
  2. <%@ attributename="download_url"required="true"description="应用的下载页面,for Android used"%>
  3. <%@ attributename="app_store_id"required="true"description="苹果商店的之 id,当前为 iphone 版,有 ipad 版吗?"%>
  4. <%@ attributename="URI_Scheme_iOS"required="true"description="iOS 的 URI_Scheme"%>
  5. <%@ attributename="URI_Scheme_Android"required="true"description="安卓的 URI_Scheme"%>
  6. <!-- 按钮 单击事件 -->
  7. <!-- <a class="openBtn">打开客户端</a> -->
  8. <iframeid="ifr"style="display: none;border:0;"src="javascript:void(0)"></iframe>
  9. <script>
  10. ;(function(window, doc){
  11. /**
  12. * 读取 search 和 hash 的参数
  13. */
  14. function localParam(search, hash){
  15. search=search|| window.location.search;
  16. hash=hash|| window.location.hash;
  17. var fn=function(str, reg){
  18. if(str){
  19. var data= {};
  20. str.replace(reg,function( $0, $1, $2, $3 ){
  21. data[ $1 ] = $3;
  22. });
  23. return data;
  24. }
  25. }
  26. return {
  27. search: fn(search,  new RegExp( "([^?=&]+)(=([^&]*))?", "g" ))||{},
  28. hash:   fn(hash,    new RegExp( "([^#=&]+)(=([^&]*))?", "g" ))||{}
  29. };
  30. }
  31. // 应用注册的URI Scheme
  32. // 当发现没有安装应用的时候,跳转到 WAP 的下载页面
  33. window.scrollTo(0,1);
  34. var params=localParam(),
  35. isIDevice= (/iphone|ipod/gi).test(navigator.platform),
  36. isIDeviceIpad= (/ipad/gi).test(navigator.platform),
  37. isAndroid= (/Android/gi).test(navigator.userAgent),
  38. isWeixin= (/MicroMessenger/ig).test(navigator.userAgent),
  39. isappinstalled=params.search['isappinstalled'],
  40. appinstall=params.search['appinstall'],
  41. wxLink='weixinfallback.html',
  42. iDownload='itms-apps://itunes.apple.com/cn/app/<%=app_store_id%>?mt=8',
  43. openAppLink=params.hash['url'] || params.search['url'],
  44. iframe=document.getElementById('ifr');
  45. if( (isIDevice || isIDeviceIpad) && !isAndroid){
  46. //          openAppLink=openAppLink|| 'smcyuetv://';
  47. openAppLink=openAppLink|| '<%=URI_Scheme_iOS%>';
  48. }else if(isAndroid){
  49. //          openAppLink=openAppLink|| 'yuetv://';
  50. openAppLink=openAppLink|| '<%=URI_Scheme_Android%>';
  51. }
  52. if(isappinstalled!==undefined){
  53. wxLink += '?isappinstalled='+isappinstalled+'&openurl='+openAppLink;
  54. }else if(appinstall!==undefined){
  55. wxLink += '?appinstall='+appinstall+'&openurl='+openAppLink;
  56. }else{
  57. wxLink += '?openurl='+openAppLink;
  58. }
  59. if(isIDeviceIpad){
  60. //iDownload='itms-apps://itunes.apple.com/cn/app/id425349261?mt=8';
  61. }
  62. function download(){
  63. // if(isAndroid){
  64. // window.location='http://3g.163.com/m/android/software/2vbrks.html';
  65. // }else{
  66. window.location='<%=download_url%>';
  67. // }
  68. }
  69. /*
  70. * iOS点击打开:
  71. 1.如果是微信就去引导图页面
  72. 2.如果不是微信就走安装就打开不安装就去app store
  73. 3.如果微信用户按引导图从浏览器打开就能走通第2条
  74. android点击打开:
  75. 1.如果是微信就在打开的时候同时跳转到有图的引导页
  76. 2.如果不是微信就同时跳转到公公共下载页
  77. 3.如果微信用户按引导图从浏览器打开就能走通第2条
  78. */
  79. function open(){
  80. if(isWeixin){
  81. window.location=wxLink;
  82. }else if((isIDevice || isIDeviceIpad) && !isAndroid){
  83. window.location=openAppLink;
  84. setTimeout(function(){
  85. window.location=iDownload;
  86. }, 50);
  87. }else{
  88. iframe.src=openAppLink;
  89. download();
  90. }
  91. }
  92. document.querySelector(".openBtn").addEventListener("click", open, false);
  93. // 自动打开
  94. var autoopen=params.search['autoopen'] || params.hash['autoopen'];
  95. autoopen== 1 && open();
  96. })(window,document);
  97. </script>

其实,只要是在页面,就应该可以通过 URI Scheme 调用客户端。那么,在 WebApp / Hyper App 也能如是作法吧!

另外,我这里只是着重讨论的网页的部分。调用客户端还是比较简单的,如果需要调用客户端里面的某个一个模块呢?客户端可不想网页那样,天生就是有 URL 定位,传个地址或参数就可以了。这里涉及的客户端原生程序的部分比较多,就是说,如果直接跳到某个模块里面去,——这涉及到客户端模块是否已经合理解耦了,以及所依赖的上下文参数等等诸多问题,——需要和客户端开发者好好商量才行。

参考:

  • 《在mobile safari中巧妙实现检测应用安装就打开,否则进App Store下载》
  • http://yansong.me/2013/10/24/open-native-app-in-browser.html
  • Intent scheme URL attack

网页调用 iOS/Android 客户端相关推荐

  1. 除草机(Grasscutter) ios/Android客户端配置教程

    本文章仅为Grasscutter的ios/Android客户端配置教程,不提供任何服务器,如果你按图中的数据连上了,纯属瞎猫碰到死耗子. 对应的客户端配置教程在:从零开始,一镜到底,纯净系统搭建除草机 ...

  2. 携程 android4.3,携程发布3.0版iOS和Android客户端

    腾讯科技讯 3月26日,携程旅行网正式发布了全新的无线旅行服务平台-携程无线3.0版iOS/ Android客户端,改版后的客户端是以 "旅行工具书"的形式呈现,其中最特别的是能实 ...

  3. 微软云平台媒体服务实践系列 2- 使用动态封装为iOS, Android , Windows 等多平台提供视频点播(VoD)方案...

    文章微软云平台媒体服务实践系列 1- 使用静态封装为iOS, Android 设备实现点播(VoD)方案  介绍了如何针对少数iOS, Android 客户端的场景,出于节约成本的目的使用媒体服务的静 ...

  4. FFmpeg音视频开发实战5 iOS/Android/windows/Linux -陈超-专题视频课程

    FFmpeg音视频开发实战5 iOS/Android/windows/Linux -159618人已学习 课程介绍          咨询QQ: 347181469. 本课程适合中,从事音视频,网络通 ...

  5. 微软云平台媒体服务实践系列 1- 使用静态封装为iOS, Android 设备实现点播(VoD)方案...

    微软的云平台媒体服务为流媒体服务提供了多种选择,在使用流媒体服务为企业做流媒体方案时,首先需要确认要流媒体接收目标,如针对广大iOS, Android移动设备,由于它们都支持HLS 格式的流媒体,基于 ...

  6. 基于OpenAPI Specification自动生成Android客户端代码

    OpenAPI Specification(OAS) 无论你从事前端开发还是后端开发,或多或少都听说过Swagger. Swagger Specification 是一种 API Specificat ...

  7. js怎么调用ios的方法(原网址:https://www.jianshu.com/p/ce5e8c2f6d2e或者https://tech.youzan.com/jsbridge/)

    网页(js)与oc(iOS)之间的方法调用及传值 清都 关注 2017.07.27 15:36* 字数 363 阅读 110评论 0喜欢 0 最后更新时间:2017-07-27 调用的对象bsg只是一 ...

  8. android iOS App客户端如何实现在线支付

    *android iOS App客户端如何实现在线支付**Q~~1⑨9⑦O*⑦46 阔别已久,小课堂再次开课,今天将和大家分享在开通各个支付渠道之前,你可能想要了解的一些信息. 对支付领域一无所知,对 ...

  9. java制作安卓客户端_制作网页的Android客户端(一)

    当发现一个有趣的新闻网站(AnimeNews)没有android客户端时,打算做一个学习和自用. 0.简单的需求分析 1.能看新闻 2.能查单词 3.单词表 1.建立新闻的抽象类 需要的属性有: 新闻 ...

最新文章

  1. android 更新 18个月,MIUI迎接史上最大更新:18个月内绝不卡顿,友商羡慕!
  2. 手把手教你如何扩展GridView之自带CheckBox
  3. wifi管理系统_KJ725(A)精确人员定位管理系统实现对井下人员和车辆的精确定位
  4. 详解让人闹心的C++语句 cout<<“Hello“<<endl;
  5. 云计算,从“资源时代”迈入“功能时代”
  6. SpringMVC的请求-获得请求参数-获得集合类型参数2
  7. 赞!图像生成PyTorch库火了,涵盖18+ SOTA GAN实现
  8. 001机器学习深度学习简介
  9. SQL实战之找出所有员工当前薪水salary情况
  10. 打开usb计算机连接怎么办,iqoo3怎么打开usb调试?iqoo3开启usb调试连接电脑的方法...
  11. 实现网页页面跳转的几种方法(meta标签、js实现、php实现)
  12. 一文带你了解微信/支付宝支付的相关概念
  13. 四川计算机专业高职高考,四川职高计算机专业分数线
  14. 远程实时调试手机上的web页面
  15. Belief System
  16. [LOJ6515]贪玩蓝月
  17. 关闭各种广告弹窗……
  18. javascript的基础-1
  19. 华为首个芯片工厂封顶!
  20. MATLAB利用仿射变换实现图像的缩放,旋转,剪切,平移操作

热门文章

  1. 复合材料力学_桥桂琼编_西工大版
  2. 从ACL 2022 Onsite经历看NLP热点
  3. ​定了,北京时间 9 月 16 日凌晨 1 点见。
  4. abp 部署到ubuntu_centos和ubuntu系列总结 - 白色的番茄
  5. 3682. 宇恒棋 (华师月赛)
  6. 人工智能实战2019第七次作业(OpenPAI) 16721088 焦宇恒
  7. 报表软件选型时应该知道的
  8. 达梦数据库LENGTH_IN_CHAR(对象的长度是否以字符为单位)总结
  9. 数学建模-火箭发射问题
  10. 解决Windows环境下PHP连接MySQL很慢的问题