一、URL Scheme介绍


1、什么是 URL Scheme?URL Scheme的作用

  1. 对于AndroidScheme是一种页面内跳转协议,是一种非常好的实现机制,通过定义自己的scheme协议,可以非常方便跳转app中的各个页面;通过scheme协议,服务器可以定制化告诉App跳转那个页面,可以通过通知栏消息定制化跳转页面,可以通过H5页面跳转页面等。

对于iOS,我们都知道苹果手机中的APP都有一个沙盒,APP就是一个信息孤岛,相互是不可以进行通信的,但是苹果还是给出了一个可以在app之间跳转的方法:URL Scheme。iOS的APP可以注册自己的URL Scheme,URL Scheme是为方便app之间互相调用而设计的,我们可以通过系统的OpenURL来打开该app,并可以传递一些参数。

URL Scheme必须能唯一标识一个APP,如果你设置的URL Scheme与别的APP的URL Scheme冲突时,你的APP不一定会被启动起来。因为当你的APP在安装的时候,系统里面已经注册了你的URL Scheme。一般情况下,是会调用先安装的app,但是iOS的系统app的URL Scheme肯定是最高的,所以我们定义URL Scheme的时候,尽量避开系统app已经定义过的URL Scheme。

简单的说,URL Scheme就是一个可以让app相互之间可以跳转的协议。每个app的URL Scheme都是不一样的,如果存在一样的URL Scheme,那么系统就会响应先安装那个app的URL Scheme,因为后安装的app的URL Scheme被覆盖掉了,是不能被调用的。

2、URL Scheme应用场景:

客户端应用可以向操作系统注册一个 URL scheme,该 scheme 用于从浏览器或其他应用中启动本应用。通过指定的 URL 字段,可以让应用在被调起后直接打开某些特定页面,比如商品详情页、活动详情页等等。也可以执行某些指定动作,如完成支付等。也可以在应用内通过 html 页来直接调用显示 app 内的某个页面。综上URL Scheme使用场景大致分以下几种:

(1)服务器下发跳转路径,客户端根据服务器下发跳转路径跳转相应的页面

(2)H5页面点击锚点,根据锚点具体跳转路径APP端跳转具体的页面

(3)APP端收到服务器端下发的PUSH通知栏消息,根据消息的点击跳转路径跳转相关页面

(4)APP根据URL跳转到另外一个APP指定页面

3、URL Scheme协议格式:

客户端自定义的 URL 作为从一个应用调用另一个的基础,遵循 RFC 1808 (Relative Uniform Resource Locators) 标准。这跟我们常见的网页内容 URL 格式一样。

一个普通的 URL 分为几个部分:scheme、host、relativePath、query。

比如:http://www.baidu.com/s?rsv_bp=1&rsv_spt=1&wd=NSurl&inputT=2709,这个URL中,scheme 为 http,host 为www.baidu.com,relativePath 为 /s,query 为 rsv_bp=1&rsv_spt=1&wd=NSurl&inputT=2709。

一个应用中使用的 URL 例子(该 URL 会调起车辆详情页):uumobile://mobile/carDetail?car_id=123456,其中 scheme 为 uumobile,host 为mobile,relativePath 为 /carDetail,query 为 car_id=123456。

  1. 行为(应用的某个功能页面)
  2. |
  3. scheme://[path][?query]
  4. | |
  5. 应用标识 功能需要的参数
  6. |

二、安卓平台设置

1、设置UrlSchemes

打开项目的manifest.json文件,切换到“代码视图”
(1)5+App项目:在manifest.json文件的”plus”->”distribute”->”google”下添加schemes节点数据如下:

  1. "plus": {
  2.  "distribute": {
  3. "google": {
  4. "schemes": [
  5. "test"
  6. ],
  7. //...
  8. },
  9. //...
  10. },

(2)uni-app项目:把上面的schemes节点数据放到manifest.json的”app-plus”->”distribute”->”android”节点下
(3)值域说明:
为字符串数组,每个字符串为一个urlscheme,使用小写字母(不要使用特殊字符、中文),可设置多个。比如设置为test,那么其他App呼起你的app的scheme协议就是test://。
保存后提交App云端打包生效。

2、浏览器中通过href启动应用

安装应用后,我们可以在html页面中,通过href直接调用应用:

  1. <a href="test://abc">test:<a>

3、uni-app中处理urlscheme启动传递的参数

在App.vue的onShow里可以直接获取

  1. onShow: function() {
  2. var args= plus.runtime.arguments;
  3. if(args){
  4. // 处理args参数,如直达到某新页面等
  5. }
  6. }

4、5+ APP中处理urlscheme启动传递的参数

在其它应用中通过href调用Url Scheme传递过来的值,可以通过plus.runtime.arguments获取,其值为完整的urlscheme字符串,如上面href的值启动应用后获取的plus.runtime.arguments值为“test://abc”。代码示例如下:

  1. document.addEventListener('plusready',function(){
  2. checkArguments();
  3. },false);
  4. // 判断启动方式
  5. function checkArguments(){
  6. console.log("plus.runtime.launcher: "+plus.runtime.launcher);
  7. var args= plus.runtime.arguments;
  8. if(args){
  9. // 处理args参数,如直达到某新页面等
  10. }
  11. }
  12. // 处理从后台恢复
  13. document.addEventListener('newintent',function(){
  14. console.log("addEventListener: newintent");
  15. checkArguments();
  16. },false);

三、iOS平台设置

1、设置UrlSchemes

(1)可视化界面配置:打开项目的manifest.json文件,在“App常用其它设置”页面“iOS设置”下的UrlSchemes中配置scheme字段:
H5唤起app,跳转指定页面 - 图1
注意:多个scheme使用’,’分割

2、代码视图配置:打开项目的manifest.json文件,切换到“代码视图”

(1)5+App项目:在manifest.json文件的”plus”->”distribute”->”apple”节点下添加urltypes数据
(2)uni-app项目:在manifest.json的”app-plus”->”distribute”->”ios”节点下添加urltypes数据
urltypes节点数据如下:

  1. "plus": {
  2. "distribute": {
  3. "apple": {
  4. "urltypes": [
  5. {
  6. "urlidentifier":"com.xxx.test",
  7. "urlschemes": [
  8. "test"
  9. ]
  10. }
  11. ],
  12. //...
  13. },
  14. //...
  15. },
  16. //...
  17. },
  18. //...

值域说明:urlidentifier为标识,可自定义,格式为反向域名格式;
urlschemes为要指定的scheme值,字符串数组,使用小写字母,可设置多个。 比如设置为test,那么其他App呼起你的app的scheme协议就是test://。

3、uni-app中处理urlscheme启动传递的参数

在App.vue 中onLaunch 里获取

  1. onLaunch: function() {
  2. plus.globalEvent.addEventListener('newintent', (e)=>{
  3. var args= plus.runtime.arguments;
  4. if(args){
  5. // 处理args参数,如直达到某新页面等
  6. }
  7. });
  8. }

在App.vue的onShow里获取

  1. onShow: function() {
  2. setTimeout(function(){
  3. var args= plus.runtime.arguments;
  4. if(args){
  5. // 处理args参数,如直达到某新页面等
  6. }
  7. },10);
  8. }

h5页面

  1. <html lang="en">
  2. <head>
  3. <meta charset="UTF-8">
  4. <meta name="format-detection" content="telephone=no,email=no,date=no,address=no">
  5. <meta name="apple-mobile-web-app-status-bar-style" content="black">
  6. <meta name="apple-mobile-web-app-capable" content="yes" /><!-- home screen app 全屏 -->
  7. <meta name="apple-mobile-web-app-status-bar-style" content="black" /><!-- 状态栏 -->
  8. <meta http-equiv="Access-Control-Allow-Origin" content="*">
  9. <meta name="keywords" content="红叉">
  10. <link rel="icon" href="#" type="image/x-icon"/>
  11. <title>红叉</title>
  12. <script>
  13. ;(function(win, lib) {
  14. var doc = win.document;
  15. var docEl = doc.documentElement;
  16. var metaEl = doc.querySelector('meta[name="viewport"]');
  17. var flexibleEl = doc.querySelector('meta[name="flexible"]');
  18. var dpr = 0;
  19. var scale = 0;
  20. var tid;
  21. var flexible = lib.flexible || (lib.flexible = {});
  22. if (metaEl) {
  23. console.warn('将根据已有的meta标签来设置缩放比例');
  24. var match = metaEl.getAttribute('content').match(/initial\-scale=([\d\.]+)/);
  25. if (match) {
  26. scale = parseFloat(match[1]);
  27. dpr = parseInt(1 / scale);
  28. }
  29. } else if (flexibleEl) {
  30. var content = flexibleEl.getAttribute('content');
  31. if (content) {
  32. var initialDpr = content.match(/initial\-dpr=([\d\.]+)/);
  33. var maximumDpr = content.match(/maximum\-dpr=([\d\.]+)/);
  34. if (initialDpr) {
  35. dpr = parseFloat(initialDpr[1]);
  36. scale = parseFloat((1 / dpr).toFixed(2));
  37. }
  38. if (maximumDpr) {
  39. dpr = parseFloat(maximumDpr[1]);
  40. scale = parseFloat((1 / dpr).toFixed(2));
  41. }
  42. }
  43. }
  44. if (!dpr && !scale) {
  45. var isAndroid = win.navigator.appVersion.match(/android/gi);
  46. var isIPhone = win.navigator.appVersion.match(/iphone/gi);
  47. var devicePixelRatio = win.devicePixelRatio;
  48. if (isIPhone) {
  49. // iOS下,对于2和3的屏,用2倍的方案,其余的用1倍方案
  50. if (devicePixelRatio >= 3 && (!dpr || dpr >= 3)) {
  51. dpr = 3;
  52. } else if (devicePixelRatio >= 2 && (!dpr || dpr >= 2)){
  53. dpr = 2;
  54. } else {
  55. dpr = 1;
  56. }
  57. } else {
  58. // 其他设备下,仍旧使用1倍的方案
  59. dpr = 1;
  60. }
  61. scale = 1 / dpr;
  62. }
  63. docEl.setAttribute('data-dpr', dpr);
  64. if (!metaEl) {
  65. metaEl = doc.createElement('meta');
  66. metaEl.setAttribute('name', 'viewport');
  67. metaEl.setAttribute('content', 'initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no');
  68. if (docEl.firstElementChild) {
  69. docEl.firstElementChild.appendChild(metaEl);
  70. } else {
  71. var wrap = doc.createElement('div');
  72. wrap.appendChild(metaEl);
  73. doc.write(wrap.innerHTML);
  74. }
  75. }
  76. function refreshRem(){
  77. var width = docEl.getBoundingClientRect().width;
  78. if (width / dpr > 540) {
  79. width = 540 * dpr;
  80. }
  81. var rem = width / 10;
  82. docEl.style.fontSize = rem + 'px';
  83. flexible.rem = win.rem = rem;
  84. }
  85. win.addEventListener('resize', function() {
  86. clearTimeout(tid);
  87. tid = setTimeout(refreshRem, 300);
  88. }, false);
  89. win.addEventListener('pageshow', function(e) {
  90. if (e.persisted) {
  91. clearTimeout(tid);
  92. tid = setTimeout(refreshRem, 300);
  93. }
  94. }, false);
  95. if (doc.readyState === 'complete') {
  96. doc.body.style.fontSize = 12 * dpr + 'px';
  97. } else {
  98. doc.addEventListener('DOMContentLoaded', function(e) {
  99. doc.body.style.fontSize = 12 * dpr + 'px';
  100. }, false);
  101. }
  102. refreshRem();
  103. flexible.dpr = win.dpr = dpr;
  104. flexible.refreshRem = refreshRem;
  105. flexible.rem2px = function(d) {
  106. var val = parseFloat(d) * this.rem;
  107. if (typeof d === 'string' && d.match(/rem$/)) {
  108. val += 'px';
  109. }
  110. return val;
  111. }
  112. flexible.px2rem = function(d) {
  113. var val = parseFloat(d) / this.rem;
  114. if (typeof d === 'string' && d.match(/px$/)) {
  115. val += 'rem';
  116. }
  117. return val;
  118. }
  119. })(window, window['lib'] || (window['lib'] = {}));
  120. </script>
  121. <script>
  122. // 初始化方法
  123. window.onload = function(){
  124. var dom = document.getElementById("xpopup");
  125. var page = document.getElementById("body");
  126. var ua = window.navigator.userAgent.toLowerCase();
  127. if(ua.match(/MicroMessenger/i) == 'micromessenger'){
  128. dom.style.display="black";
  129. page.style.overflow="hidden";
  130. return true; //是微信
  131. }else{
  132. dom.style.display="none";
  133. return false; //不是微信
  134. }
  135. }
  136. //解决ios下 双击放大问题!
  137. var lastTouchEnd = 0;
  138. document.documentElement.addEventListener('touchend', function (event) {
  139. var now = Date.now();
  140. if (now - lastTouchEnd <= 300) {
  141. event.preventDefault();
  142. }
  143. lastTouchEnd = now;
  144. }, false);
  145. //判断打开的浏览器是不是微信浏览器
  146. function isWeiXin(){
  147. var ua = window.navigator.userAgent.toLowerCase();
  148. if(ua.match(/MicroMessenger/i) == 'micromessenger'){
  149. return true; //是微信
  150. }else{
  151. return false; //不是微信
  152. }
  153. }
  154. //点击下载方法
  155. function xclick(){
  156. let u = navigator.userAgent;
  157. if (/(iPhone|iPad|iPod|iOS)/i.test(u)) {
  158. window.location = "t7heo9://";
  159. // window.location.href = "https://apps.apple.com/cn/app/%E7%BA%A2%E5%8F%89/id1581706539";
  160. setTimeout(function(){
  161. window.location.href = "https://apps.apple.com/cn/app/%E7%BA%A2%E5%8F%89/id1581706539";
  162. },200);
  163. }else{
  164. window.location = "t7heo9://pay";
  165. setTimeout(function(){
  166. window.location.href = "https://sizex-app.oss-cn-hangzhou.aliyuncs.com/92066ce78abb4d0ab9a5f29a78c005ab/dev-install/1212.apk?uuid=612f6858d3775";
  167. },200);
  168. }
  169. }
  170. </script>
  171. </head>
  172. <body id='body' style="overflow-x:hidden">
  173. <div id="hc">
  174. <!-- 微信浏览器弹窗 -->
  175. <div class="images ximg" id="xpopup">
  176. <img class="w80" src="https://sizex-app.oss-accelerate.aliyuncs.com/92066ce78abb4d0ab9a5f29a78c005ab/base/landing-popup.png">
  177. </div>
  178. <!-- 顶部标题 -->
  179. <div class="image" onclick="xclick()">
  180. <img src="https://sizex-app.oss-accelerate.aliyuncs.com/92066ce78abb4d0ab9a5f29a78c005ab/base/landing-header.png">
  181. </div>
  182. <!-- 下载app领福利 -->
  183. <div class="image" onclick="xclick()">
  184. <img src="https://sizex-app.oss-accelerate.aliyuncs.com/92066ce78abb4d0ab9a5f29a78c005ab/base/landing-content.png">
  185. </div>
  186. <!-- 商品列表 -->
  187. <div class="image" onclick="xclick()">
  188. <img src="https://sizex-app.oss-accelerate.aliyuncs.com/92066ce78abb4d0ab9a5f29a78c005ab/base/landing-product.png">
  189. </div>
  190. <!-- 底部小程序二维码 -->
  191. <div class="image">
  192. <img src="https://sizex-app.oss-accelerate.aliyuncs.com/92066ce78abb4d0ab9a5f29a78c005ab/base/landing-bottom.png">
  193. </div>
  194. </div>
  195. </body>
  196. <style>
  197. * {
  198. padding: 0;
  199. margin: 0;
  200. }
  201. .image{
  202. width: 100%;
  203. }
  204. .images{
  205. height: 100%;
  206. position: absolute;
  207. width: 100%;
  208. z-index: 10;
  209. top: 0px;
  210. background-color: rgba(0,0,0,0.7);
  211. }
  212. .image img{width: 100%;}
  213. .w80{
  214. position: absolute;
  215. width: 80%;
  216. top:30px;
  217. right: 30px;
  218. z-index: 10;
  219. }
  220. .ximg{
  221. position: absolute;
  222. width: 100%;
  223. z-index: 10;
  224. top: 0px;
  225. }
  226. </style>
  227. </html>