我是靠谱客的博主 苗条信封,最近开发中收集的这篇文章主要介绍iOS/Android 微信及浏览器中唤起本地APP,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

转自:http://blog.csdn.net/linshijun33/article/details/71429669

需求概述

分享应用活动链接已经成为手机应用一个非常重要的推广传播形式。为了提高转化率,就需要让用户不管是在微信或者是浏览器中,都能在点击链接后, 唤起本地的 app 后 , 跳转到指定页面 。

虽然这个功能从用户体验方面来说是自然而然的,但是由于 iOS/Android 平台差异性,在实现过程中还是有些问题。

  1. 未安装 app 时,如何做好引导页,引导用户下载后打开 app 后,是否可以打开之前唤醒前指定的页面或内容

  2. 如何绕过微信的  scheme  屏蔽,在微信中唤醒 app 中,并打开指定页面

  3. iOS 专用的  universal link ,Android 专用的  App Links  的集成要求,有哪些局限性。

现实情况

在实施过程中,还是有两个地方是没办法忽略的:

scheme 被微信屏蔽了

除非一些和微信有合作的 app 可以进入到白名单,其他的应用在微信内都没办法通过自定义 scheme 协议直接唤起 app,前端页面需要对唤起场景进行判断。

浏览器无法明确地判断本地是否已经安装 app

目前的取巧方案就是通过  setTimeOut  设置超时时间,在超时时间内唤起 app,然后获得成功失败回调,如果获得的是失败的回调,则说明本地没有安装 app,需要跳转到商店下载页面。

实现方案

踩坑方案

鉴于在打开 url scheme 的方法中,iOS9 和 iOS8/iOS7 区别很大,Android 不同厂商的是适配也不同,这里介绍的踩坑方案都是前人实践总结出来的。

两种打开方式:

一、 直接跳转:点击链接或者修改  window.location 。 
点击链接:

<a href="schemeUrl">唤醒你的APP</a>
  • 1

修改 window.location:

window.location.href = schemeUrl;
  • 1

这种情况,如果APP唤醒失败,或者APP未安装的话,很多时候都会跳到错误页,这很影响用户体验,而我们的要求可能是跳转到其他页面或者下载APP。

二、 iframe  跳转:在 body 上添加 iframe,设置 src 属性为跳转的 URL scheme

<a href="APP下载地址">下载或打开APP</a>
<script>
$('a').click(function() {
var ifr = document.createElement('iframe');
ifr.src = '自定义 URL scheme';
ifr.style.display = 'none';
document.body.appendChild(ifr);
setTimeout(function(){
document.body.removeChild(ifr);
}, 3000);
});
</script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

这一种方法不会引起页面内容可见的变化,不会导致浏览器历史记录的变化, 
实现过程是:点击 a 标签时,打开 自定义 scheme。若成功,就唤起 app,若失败,就到 href 属性,去到下载地址。

相应的,在 Android 客户端这边,需要在 manifest 文件里面配置 intent-filter,如下:

<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="自定义 URL scheme" />
</intent-filter>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

注意这里的  intent-filter  的这几个配置不能再和 action.MAIN 放在一起。如果是在同一个 activity 中配置,那么可以配置两个 intent-filter ,比如

<!-- 第一个filter -->
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<!-- 第二个filter -->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="mls" />
</intent-filter>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

理论上,在 Android 上这两种方式应该都是可以顺利实现的。但是 Android 的 chrome 内核从 chrome 25 以后就弃用了 iframe,不再支持通过 js 触发(非人为点击)或者通过设置  iframe src  地址来触发 scheme 跳转。所以,后一种方法在适配上存在比较多的问题。故一般选择前面一种做法,即 href 的点击或者 window.location 跳转。

使用第一种方案,setTimeOut 派上用场。

$('a').click(function() {
location.href = '自定义 URL scheme';
t = Date.now();
setTimeout(function(){
if (Date.now() - t < 1200) {
location.href = 'Android 下载地址';
}
}, 1000);
return false;
}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

理想过程是这样:浏览器尝试打开 URL scheme,在 1 秒计时后,检查当前时间,如果实际时间已过 1200 毫秒,说明唤起 app 成功(唤起 app 会让浏览器的定时器变慢);如果没超过 1200 毫秒,很可能是没有安装应用,就跳到下载地址。

但是这么做也是有问题的,因为 Android 系统是多任务系统,setTimeOut基本就没那么精准,不能起到理想效果。换一种方式, setInterval ,如果设置比较小的运行间隔(<30ms),在浏览器或者 webview 中,应用切换到后台,setInterval 会被很明显的延迟执行,比如设置一个运行间隔 20ms,总计运行 100 次的定时器,如果页面一直处于前台,则 100 次跑完,总耗时与 100x20=2000ms 不会有太大差异,但页面在后台运行时,此时间会明显超过 2000ms。可以利用这一点来实现是否成功打开 app 检测及回调。

function openApp(openUrl, appUrl, action, callback) {
// 检查 app 是否打开
function checkOpen(cb){
var _clickTime = +(new Date());
function check(elsTime) {
if ( elsTime > 3000 || document.hidden || document.webkitHidden) {
cb(1);
} else {
cb(0);
}
}
// 启动间隔 20ms 运行的定时器,并检测累计消耗时间是否超过 3000ms,超过则结束
var _count = 0, intHandle;
intHandle = setInterval(function(){
_count++;
var elsTime = +(new Date()) - _clickTime;
if (_count>=100 || elsTime > 3000 ) {
clearInterval(intHandle);
check(elsTime);
}
}, 20);
}
// 在 iframe 中打开 app
var ifr = document.createElement('iframe');
ifr.src = openUrl;
ifr.style.display = 'none';
if (callback) {
checkOpen(function(opened){
callback && callback(opened);
});
}
document.body.appendChild(ifr);
setTimeout(function() {
document.body.removeChild(ifr);
}, 2000);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38

iOS9 上 iframe 也不可用

在 iOS 9 上,iframe 方案变得不可用。在打开自定义 URL scheme 时,会弹出对话框,询问是否用 xx 应用来打开。往往用户还没来得及点击打开,定时器又触发了,导致跳到 App Store。 
可以在尝试打开URL scheme 后,再加一个页面跳转,这样对话框会被覆盖,再刷新页面,就能无需确认唤起 app:

$('a').click(function() {
location.href = '自定义 URL scheme';
location.href = '下载页';
location.reload();
}
  • 1
  • 2
  • 3
  • 4
  • 5

APP已安装这是没问题的,但如果APP未安装,跳 App Store 的请求会失败。 这时可以使用两个定时器:

$('a').click(function() {
location.href = '自定义 URL scheme';
setTimeout(function() {
location.href = '下载页';
}, 250);
setTimeout(function() {
location.reload();
}, 1000);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

这里的链接指的是深度链接 (deep learning) ,这是一种能够方便地通过传统的 http 链接来启动 app 或网站。通过唯一的网址,就可以链接一个特定的视图到你的 app 里面不需要特别的 scheme。

使用要求: 
这里写图片描述
使用步骤:

  1. 添加域名到  Capabilities  
    首先, 你必须在 Xcode 的 capabilities 里 添加你的 APP 域名, 必须用 applinks: 前置它:还添加一些你可能拥有的子域和扩展(www.domain.com, news.domain.com 等等)。这将使你的 APP 从你的域名请求一个特殊的 JSON 文件 apple-app-site-association。当你第一次启动 APP,它会从 https://domain.com/apple-app-site-association 下载这个文件。 
    这里写图片描述

  2. 构建  apple-app-site-association  文件 
    该文件必须存在且为了安全原因可使用 SSL 通过 GET 请求访问到。你可以打开一个文本编辑器然后写一个这样的简单 JSON 格式: 
    这里写图片描述
    根据 paths 键设定一个允许的路径列表(你希望APP 作出反应的路径), 设置 * 号则只是打开 app 而已。 
    TEBEJCSf9DF 这一串是具有团队标示的 bundle id。 
    文件构建成功后,上传这个文件到你的域名根目录。

  3. 在 app 里处理通用链接 
    为了在 app 里支持通用链接, 需要在 AppDelegate 里实现  [application(_:continueUserActivity:restorationHandler:)]  。 尽管这种方法可以用于许多不同的目的(比如 [Handoff]和 [搜索 API]), 我们将只关注如何处理接收到的通用链接。 
    为了确保 app 可以翻译 URL 成实际的内容, 需要做下面几步:

    • 使用 [NSURLComponents]简单解析 webpageURL 到 host(如domain。com), 路径组成同理(如 [“/”]、”path”、”to”以及”thezoo”)。

    • 确保能识别 host。

    • 尝试将 pathComponents 匹配到 APP 的已知内容里。

    • 验证该内容实际上可以被呈现并呈现内容给用户。

Android 手机上,打开链接通常会跳出选择框选择用什么浏览器打开,而使用 app links,当点击了链接,安卓系统会检查是否有一个 app 可以处理 url(比如 twitter.com),然后跟核对哪个app(s)可以处理该域名的链接,直接在应用内处理,这样我们就能避免弹框影响用户。

和 iOS 一样,Android 的深度链接也需要相关的域名来配合,有以下的条件: 
这里写图片描述

想要让你的 app 处理链接,需要在 manifest 文件中使用 intent filter 声明 app 需要处理的 uri 模式。下面的例子,声明了一个  intent filter  能够处理 http://www.android.com 和 https://www.android.com:

<activity …>
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="http" />
<data android:scheme="https" />
<data android:host="www.android.com" />
</intent-filter>
</activity>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

配置  autoVerify 来触发系统自动校验。

如何验证成功?这就需要网站所有者必须声明和app的联系。网站所有者通过持有一个名为  assetlinks.json  的 Digital Asset Links JSON 文件来声明与一个 app 的联系,它在 domain 的well-known 位置:https://domain[:optional_port]/.well-known/assetlinks.json。 
注意:系统通过加密的 HTTPS 协议来验证 json 文件,所以不管 intent filter 中是否声明了 https,请确保 json 文件能够通过 HTTPS 连接来获取。 
Digital Asset Links JSON 文件声明了与此网站关联的 app,下面的示例 assetlinks.json 文件允许包名为 com.example 的app打开链接:

[{
"relation": ["delegate_permission/common.handle_all_urls"],
"target": {
"namespace": "android_app",
"package_name": "com.example",
"sha256_cert_fingerprints":
["14:6D:E9:83:C5:73:06:50:D8:EE:B9:95:2F:34:FC:64:16:A0:83:42:E6:1D:BE:A8:8A:04:96:B2:3F:CF:44:E5"]
}
}]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

sha256 可以通过 keytool 来获取。

预想可操作方案

  1. 链接页面里面有两个按钮:直接打开和下载。直接打开的话,判断本地是否存在 app 后直接启动 app,下载的话去到下载页面。前端需要设计两个页面(分享的页面,下载的页面)。

  2. 使用<a> 标签的方式,来启动客户端。

  3. 区分渠道,判断浏览器内核区分是 Android 还是 iOS,在 Android 6.0 以上,可使用 app links,在 iOS9.0 以上,可使用 universal link.但是这两个都需要提供应用网站域名来绑定。其他系统版本通过自定义 scheme 来截取。

  4. 补充下 Android 的调用流程: 
    这里写图片描述
    由于好多初始化工作都在 SplashActivity 里面做了,所以开启的流程也是从上到下一步一步开页面,数据也需要传递过去。遇到需要登录的时候,先跳登录页,再跳详情页,把登录页从栈中清掉,返回时,就能从详情页 DetailActivity 回到 MainActivity 了


最后

以上就是苗条信封为你收集整理的iOS/Android 微信及浏览器中唤起本地APP的全部内容,希望文章能够帮你解决iOS/Android 微信及浏览器中唤起本地APP所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(38)

评论列表共有 0 条评论

立即
投稿
返回
顶部