深度链接 Deep Link

 

目的 

本文档用于帮助客户一步一步实施深度链接,不论是Android还是iOS系统,自定义的、或者更高 级的App Link / Universal Link。希望帮助客户实施用户召回这个方案上扫清障碍。

背景介绍 

2015年的Google I/O大会上推出的Universal App Campaigns距今已经有4年多了,客户伴随着 UAC1.0, 2.0, 2.5, 3.0的产品迭代,或多或少完成了自己获取新客户的需求,当下一个迫切的需求 就是如何召回老用户继续使用我的App。基于这样的业务需求,Google今年推出了App  Campaigns for Engagement这款产品来帮助广告主召回老用户。要想使用这款产品,有三个条 件是必不可少的: 

  1. 深度链接 
  2. 创建受众用户列表 
  3. 做好转化追踪 

其中深度链接是这三个条件当中相对来说比较复杂的一环,所以本文档会一步一步交给大家如何 正确实施适用于Google ACe的深度链接。 

概览 

文档会分别介绍Android和iOS基于Custom Scheme的深度链接和App Link / Universal Link的技术 方案,并且提供给开发者如何去验证你的深度连接是否工作。 

深度链接(Deep Link) 

什么是深度链接?通俗地讲,他是指移动端应用在处理特定URI的时候可以直接跳转到对应的内容 页或出发特定逻辑,而不仅仅是启动App。深度链接的好处是可以提高用户的打开转化率,便于 用户访问,提高用户体验,传播更方便,为营销提供了一种全新的工具。  目前处理深度链接主要有两种方式:Custom URI Schemes和App / Universal Links. 以下也会分别 介绍不同技术方案的实现方式和优缺点。 

自定义 URI Schemes 

在App / Universal Links出现以前,Android和iOS都采用的URI Schemes的方式来处理深度。使用 这种方式实现的有点是易于开发,可同时适用于Android和iOS系统。缺点是不安全,技术比较落 后,用户体验不是特别好。 

iOS Custom URI Scheme 

要想在iOS上实现自定义URI scheme,需要完成以下三个步骤: 

  1. 定义你的app的URL格式 
  2. 注册你的scheme 
  3. 在app内处理打开URL的业务逻辑 

如何定义URL 

URL一定要以scheme名称开头,既然是自定义URI scheme,按就要保证自己app的scheme是独 一无二的,不要跟同一设备里的其他app scheme重名,例如我们是做photo的开发者,可以定义 scheme为myphotoapp。 

注册URL Scheme 

注册你的URL scheme,以便让app知道哪些URL是可以被app直接打开的。在Xcode中打开 info.plist文件 

  1.  在Information Property List下添加URL types  
  2.  添加URL Schemes,例如:myphotoapp 
  3.  添加URL identifier,例如:com.example.myphotoapp 
  4.  添加Document Role, Viewer, 如图:

 

在应用内处理URL 

当以上都组做完之后,就可以在应用内开发处理URL的业务逻辑了。在iOS里是使用 application(_:open:options:)方法来实现的。实例代码如下:  

 1 func​ ​application(​_​ application: UIApplication,
 2                   ​open​ url: URL,
 3                   options: [UIApplicationOpenURLOptionsKey : ​Any​] = [:] )​ -> ​Bool​ {
 4      ​// Determine who sent the URL.
 5      ​let​ sendingAppID = options[.sourceApplication]
 6      ​print​(​"source application = \(sendingAppID ?? "​Unknown​")"​)
 7      ​// Process the URL.
 8      ​guard​ ​let​ components = ​NSURLComponents​(url: url, resolvingAgainstBaseURL: ​true​), 
 9         ​let​ albumPath = components.path,         ​
10         let​ params = components.queryItems ​else​ {             
11             ​print​(​"Invalid URL or album path missing"​)             
12return​ ​false     
13     }         ​
14     if​ ​let​ photoIndex = params.first(​where​: { $​0​.name == ​"index"​ })?.value {
15         ​print​(​"albumPath = \(albumPath)"​)         ​
16         print​(​"photoIndex = \(photoIndex)"​)         
17return​ ​true     
18     } ​else​ {        
19     ​    print​(​"Photo index missing"​)         ​
20         return​ ​false     
21 22 }   

  

Android Custom URI Scheme 

Android系统的深度链接需要完成以下步骤: 

  1.  在manifest中添加intent filter 
  2.  解析intent filter内容 
  3.  测试深度链接 

在manifest中添加Intent Filters 

要想开发一个可以打开你的应用的连接,需要在manifest文件中添加包含elements和attribute的 值到intent filter里: 

<action>:​ 请使用ACTION_VIEW intent action,这样才能让Google Search搜索到。 

<category>:​ 请包含BROWSABLE和DEFAULT category, 这样才能让你的app被浏览器访问到。 

<date>:​ data tag里必须包含​android:scheme  例如一个深度链接的URI是: ​example://gizmos​,那么intent filter应该是这样的 

 1 <activity     ​
 2     android:name​=​"com.example.android.GizmosActivity"     ​
 3     android:label​=​"@string/title_gizmos"​ ​>
 4     <intent-filter​ ​android:label​=​"@string/filter_view_example_gizmos"​>         
 5         ​<action​ ​android:name​=​"android.intent.action.VIEW"​ ​/>         ​
 6         <category​ ​android:name​=​"android.intent.category.DEFAULT"​ ​/>         ​
 7         <category​ ​android:name​=​"android.intent.category.BROWSABLE"​ ​/>         
 8         ​<!-- Accepts URIs that begin with "example://gizmos” -->         
 9         ​<data​ ​android:scheme​=​"example"               ​
10             android:host​=​"gizmos"​ ​/>     ​
11     </intent-filter>  
12 </activity> 

 解析Intent Filter内容 

通过调用getData()和getAction()可以获取Intent的Data和Action。请参考以下Java代码示例: 

1 @Override  
2 public​ ​void​ onCreate(​Bundle​ savedInstanceState) {
3     ​super​.onCreate(savedInstanceState);
4     setContentView(R.layout.main);
5        
6     ​Intent​ intent = getIntent();     ​
7     String​ action = intent.getAction();     ​
8     Uri​ data = intent.getData();  
9

 测试深度链接 

可以使用​Android Debug Bridge​和Activity Manager工具来测试深度链接是否可以实现正确的 app操作。可以在设备或者模拟器上运行adb命令,示例如下:  

1 $ adb shell am start        
2  -W -a android.intent.action.VIEW         
3 -d <URI> <PACKAGE>  

 更多信息请参考 官方文档 

Custom Scheme 测试工具 

1. 安装app并打开至少一次。 

2. 用手机浏览器打开​https://appdevdeeplink.firebaseapp.com/ 

3. 输入你的Custom Scheme URL,点击​“Generate Deep Link” 

4. 点击生成的蓝色按钮。如果深度链接配置正确,将可以打开你的app。  

 

 

 

App / Universal Links 

随着技术的演进,2015年的时候,Android和iOS分别发布新的技术来支持深度链接,Android阵 营是App Links,iOS阵营是Universal Links,才使得开发深度链接更加便捷、安全和高效。就应 用开发的安全性和面向未来的兼容性而言,我们强烈推荐采用App / Universal Links的方式开发深 度链接。 

iOS

实现iOS通用链接(深度链接)需要有一个域名,并且网站是支持HTTPS协议。打开深度链接时,  iOS 会检查该设备已安装的应用是否在这一域中被否注册了,如果已注册,App 将立即启动,无 需加载网页。否则,网页 URL (可以简单重定向到 App Store)将在 Safari 浏览器中加载。   

配置​iOS深度链接需要完成以下3个步骤: 

  1.  创建apple-app-site-association文件,其中包含app可以处理URL,内容为JSON格式。 
  2.  将apple-app-site-association上传至你的服务器,将文件放在根目录或 .well-known子目 录下。 
  3.  准备好你的app。   

创建并上传Association File 

每个包含不同内容的域名需要一个单独的​apple-app-site-association​ 文件,没有后缀名。iOS版本 9.3.1以上的,未压缩的​apple-app-site-association​ 文件大小不能超过128kb。  在​apple-app-site-association​ 文件中,你需要指定使用深度链接的路径(path)。以下示例展示了3条 路径均要被处理为深度链接的情况: 

 1  2     "applinks": {        
 3         "apps": [],        
 4         "details": [            
 5  6                 "appID": "9JA89QQLNQ.com.apple.wwdc" 7                 "paths": [ "/wwdc/news/", "/videos/wwdc/2015/*" 8             },            
 9 10                 "appID": "ABCD1234.com.apple.wwdc"11                 "paths": [ "*"12 13 14     }  
15 }

 因为系统会按path数组的顺序评估,因而需要将高优先级的path放在前面。有多种指定path的方法: 

  1.  用*来代替所有网页 
  2.  指定一个特定的URL, 比如加上 ​/wwdc/news/ 
  3.  除了可以用*之外,还可以用?来匹配单一字符   

创建完​ ​apple-app-site-association​文件之后,需要将它上传至服务器根目录或者​ ​.well-known​ 目录 下。这个文件需要可以直接通过HTTPS访问而不经过任何跳转。  

准备App来测试深度链接 

当一个用户点击深度链接的时候,就会进入app了。iOS会触发app来发送NSUserActivity请求来 获取此app打开的方法。在你的app里使用深度链接,你需要完成下列步骤: 

  1.  Entitlement文件包含你的域名信息,将此文件加入到app support中。 
  2.  为app指定收到NSUserActivity请求时的响应处理。   

首先打开工程配置中的Associated Domains,并添加支持的域名,前缀是applinks:,例如 applinks:www.mywebsite.com​.   

 

 

 指定好域名之后,你需要采用UIApplicationDelegate方法( application:continueUserActivity:restorationHandler:​)使得你的app可以收到和处理请求。  当用户点击深度链接之后,会收到​NSUserActivity​ ​类型为​activityType​,​值为 NSUserActivityTypeBrowsingWeb​的请求。参考代码如下 

 1 @UIApplicationMain  
 2 class AppDelegate: UIResponder, UIApplicationDelegate {         
 3 
 4     var window: UIWindow?     
 5     func application(_ application: UIApplication, continue userActivity: NSUserActivity,                      
 6         restorationHandler: @escaping ([Any]?) -> Void) -> Bool {             
 7     if userActivity.activityType == NSUserActivityTypeBrowsingWeb {             
 8         let webpageURL = userActivity.webpageURL             
 9         print("点击的链接是:\(webpageURL)")                 
10         
11         //......         
12 13     return true     
14 }

 

 更多信息请参考官方文档

iOS 深度链接测试 

1. 打开 ​https://search.developer.apple.com/appsearch-validation-tool/ 

2. 输入你的深度链接URL,并点击搜索按钮 

3. 查看你的报告结果 (以https://maps.google.com为例)  

 

Android  

注:

url scheme =对应android帮助文档中deeplink和深层链接

app links = 对应android帮助文档中applinks 和 应用连接

应用链接是一种深层链接,它们基于已验证属于您网站的网站网址。因此,点击某个此 类链接会立即打开您的应用(如已安装),并且弹出选择应用程序的对话框。自定义scheme的 深度链接是一种 intent 过滤器,可让用户直接进入 Android 应用中的特定 Activity。点击此类链 接可能会打开一个应用程序选择对话框,该对话框可以让用户从多个能够处理给定网址的应用 (包括您的应用)中选择一个。

例如,图 显示的是在用户点击地图链接后打开的对话框,该对 话框会询问用户是在 Google 地图中还是 Chrome 中打开此链接 

 

 

 

 

 

以下列表介绍了App Link与自定义URI Scheme的关系:

 

 

Android系统的深度链接需要完成以下步骤:

  1.  在manifest中添加intent filter
  2.  解析intent filter内容
  3.  声明网站与应用
  4.  测试深度链接

当app收到网页链接访问请求时,安卓系统会优先用用户偏好的app打开此链接。若无此偏好设置 ,则会用唯一可以使用的app打开,最后才会让用户从对话框列表中自己选择。

Manifest文件的配置和Intent Handler定义了app和网页之间的链接和活动内容。

在manifest中添加Intent Filters

下面的XML代码展示了如何添Iintent Filter来实现深度链接,由此可以实现打开URI “http://www.example.com/gizmos”。 

 1 <activity
 2     android:name="com.example.android.GizmosActivity"
 3     android:label="@string/title_gizmos" >
 4     <intent-filter android:label="@string/filter_view_http_gizmos">
 5         <action android:name="android.intent.action.VIEW" />
 6         <category android:name="android.intent.category.DEFAULT" />
 7         <category android:name="android.intent.category.BROWSABLE" />
 8         <!-- Accepts URIs that begin with "http://www.example.com/gizmos” -->
 9         <data android:scheme="http"
10             android:host="www.example.com"
11             android:pathPrefix="/gizmos" />
12         <!-- note that the leading "/" is required for pathPrefix-->
13     </intent-filter>
14 </activity>

 解析Intent Filter内容

通过调用getData()和getAction()可以获取Intent的Data和Action。请参考以下Java代码示例:

1 @Override
2 public void onCreate(Bundle savedInstanceState) {
3     super.onCreate(savedInstanceState);
4     setContentView(R.layout.main);
5     
6     Intent intent = getIntent();
7     String action = intent.getAction();
8     Uri data = intent.getData();
9 }

 声明网站与应用

Android 应用链接是一种特殊类型的深层链接,可让您的网站网址直接在您的 Android 应 用中打开相应内容(无需用户选择应用)。

要向应用添加 Android 应用链接,请定义使用 HTTP 网址打开应用内容的 intent 过滤器 (如解析Intent Filter中所述),并验证您是否为相关应用和网站网址的所有者。如果系 统成功验证您是网址所有者,则会自动将这些网址 intent 路由到您的应用。

要验证您对应用和网站的所有权,您需要执行以下步骤:

  •  在清单中请求自动验证应用链接。这样即可向 Android 系统说明其应该验证您的 应用是否属于 intent 过滤器中使用的网址网域。
  •  通过在以下位置托管 Digital Asset Links JSON 文件,声明您的网站和 intent 过滤 器之间的关系:https://domain.name/.well-known/assetlinks.json

请求应用链接验证

要为您的应用启用链接处理验证,请在应用清单内的网址 intent 过滤器中设置 android:autoVerify="true",所选的过滤器可以是具有 android.intent.action.VIEW intent 操作 并属于 android.intent.category.BROWSABLE intent 类别的任意过滤器,如以下清单代码段 所示:

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

 如果您的任一 intent 过滤器中存在 android:autoVerify="true",则在搭载 Android 6.0 及更 高版本的设备上安装您的应用会导致系统尝试验证与应用的任何 intent 过滤器中的网址 相关联的所有主机。验证涉及以下方面:

  1.  系统会检查所有包含以下各项的 intent 过滤器:
    1.   
      • 操作:android.intent.action.VIEW 
      • 类别:android.intent.category.BROWSABLE 和 android.intent.category.DEFAULT 
      • 网络协议:http 或 https
  2.  对于在上述 intent 过滤器中找到的每个唯一主机名,Android 会在相应网站上查询 位于 https://hostname/.well-known/assetlinks.json 的 Digital Asset Links 文件。

仅当系统为清单中的所有主机找到匹配的 Digital Asset Links 文件后,才会将您的应用确 立为处理指定网址模式的默认处理程序。

支持多个主机的应用链接

系统必须能够对照每个相应网域上托管的 Digital Asset Links 文件验证应用网址 intent 过 滤器的 元素中指定的每个主机。如果任何验证失败了,应用便无法通过验证,因 此不能成为应用 intent 过滤器中定义的任何网址模式的默认处理程序。然后,系统会默 认采用标准行为来解析相应 intent。

例如,如果在 https://www.example.com/.well-known/assetlinks.json 或 https://www.example.net/.well-known/assetlinks.json 未找到 assetlinks.json 文件,则具有以 下 intent 过滤器的应用无法通过验证: 

 1     <application>
 2 
 3       <activity android:name=”MainActivity”>
 4         <intent-filter android:autoVerify="true">
 5           <action android:name="android.intent.action.VIEW" />
 6           <category android:name="android.intent.category.DEFAULT" />
 7           <category android:name="android.intent.category.BROWSABLE" />
 8           <data android:scheme="http" android:host="www.example.com" />
 9           <data android:scheme="https" />
10         </intent-filter>
11       </activity>
12       <activity android:name=”SecondActivity”>
13         <intent-filter>
14           <action android:name="android.intent.action.VIEW" />
15           <category android:name="android.intent.category.DEFAULT" />
16           <category android:name="android.intent.category.BROWSABLE" />
17           <data android:scheme="https" android:host="www.example.net" />
18         </intent-filter>
19       </activity>
20 
21     </application>
22     

 请注意,同一 intent 过滤器中的所有 元素会合并在一起以涵盖合并后属性的所有 变体。例如,上面的第一个 intent 过滤器包含一个仅声明 HTTPS 协议的 元素。但 是,该元素与其他 元素组合在一起,所以此 intent 过滤器支持 http://www.example.com 和 https://www.example.com。因此,如果您想要定义 URI 协议和 网域的特定组合,则必须创建单独的 intent 过滤器。 

支持多个子网域的应用链接

Digital Asset Links 协议将 intent 过滤器中的子网域视为唯一的独立主机。因此,如果您的 intent 过滤器列出多个包含不同子网域的主机,您必须在每个网域上分别发布一个有效的 assetlinks.json。例如,以下 Intent 过滤器包含 www.example.com 和 mobile.example.com 作为接受的 intent 网址主机。因此,必须在 https://www.example.com/.well-known/assetlinks.json 和 https://mobile.example.com/.well-known/assetlinks.json 上发布有效的 assetlinks.json。

 1     <application>
 2       <activity android:name=”MainActivity”>
 3         <intent-filter android:autoVerify="true">
 4           <action android:name="android.intent.action.VIEW" />
 5           <category android:name="android.intent.category.DEFAULT" />
 6           <category android:name="android.intent.category.BROWSABLE" />
 7           <data android:scheme="https" android:host="www.example.com" />
 8           <data android:scheme="https" android:host="mobile.example.com" />
 9         </intent-filter>
10       </activity>
11     </application>
12     

 或者,如果您使用通配符(例如 *.example.com)声明主机名,则必须在根主机名 (example.com) 上发布 assetlinks.json 文件。例如,只要将 assetlinks.json 文件发布到 https://example.com/.well- known/assetlinks.json,具有以下 intent 过滤器的应用就会通过针对 example.com 的任何子域名(如 foo.example.com)的验证:

 1 <application>
 2       <activity android:name=”MainActivity”>
 3         <intent-filter android:autoVerify="true">
 4           <action android:name="android.intent.action.VIEW" />
 5           <category android:name="android.intent.category.DEFAULT" />
 6           <category android:name="android.intent.category.BROWSABLE" />
 7           <data android:scheme="https" android:host="*.example.com" />
 8         </intent-filter>
 9       </activity>
10     </application>

 您必须在网站上发布 Digital Asset Links JSON 文件,以指示与网站相关联的 Android 应用并验证应用的网址 intent。JSON 文件使用下列字段标识关联的应用:

声明网站关联性

package_name:在应用的 build.gradle 文件中声明的应用 ID
sha256_cert_fingerprints:应用的签名证书的 SHA256 指纹。您可以利用 Java 密钥工具,通过以下命令生成该指纹:

$ keytool -list -v -keystore my-release-key.keystore

 此字段支持多个指纹,这些指纹可用于支持不同版本的应用,例如调试版 build 和正式版 build。

 

以下 assetlinks.json 示例文件可为 com.example Android 应用授予链接打开权限:

1  [{
2       "relation": ["delegate_permission/common.handle_all_urls"],
3       "target": {
4         "namespace": "android_app",
5         "package_name": "com.example",
6         "sha256_cert_fingerprints":
7         ["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"]
8       }
9     }]

 将网站与应用关联

需要将网站在assetlinks.json文件中声明与应用的关联性。一下文件展示了如何声明 example.com与app1的关联性。 https://www.example.com/.well-known/assetlinks.json

1 [{
2       "relation": ["delegate_permission/common.handle_all_urls"],
3       "target": {
4         "namespace": "android_app",
5         "package_name": "com.example",
6         "sha256_cert_fingerprints":
7         ["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"]
8       }
9     }]

 发布JSON验证文件

您必须在以下位置发布 JSON 验证文件: https://domain.name/.well-known/assetlinks.json

请确保以下几点:

  • 使用内容类型 application/json 发布 assetlinks.json 文件。 
  • 无论应用的 intent 过滤器是否将数据协议声明为 HTTPS,都必须可通过 HTTPS 连 接访问 assetlinks.json 文件。 
  • assetlinks.json 文件必须可直接访问,没有任何重定向(无 301 或 302 重定向), 并且漫游器可访问(您的 robots.txt 必须允许抓取 /.well-known/assetlinks.json)。 
  • 如果您的应用链接支持多个主机网域,则必须在每个网域上分别发布 assetlinks.json 文件。 
  • 请勿发布清单文件中的开发/测试网址无法供公众访问的应用(例如,任何只可通 过 VPN 访问的应用)。

Android 应用链接测试

可以使用Android Debug Bridge和Activity Manager工具来测试深度链接是否可以实现正确的 app操作。可以在设备或者模拟器上运行adb命令,示例如下:

1 adb shell am start -a android.intent.action.VIEW \
2         -c android.intent.category.BROWSABLE \
3         -d "http://domain.name:optional_port"

 更多信息请参考官网文档

posted @ 2020-08-12 16:16  酉乐  阅读(4652)  评论(0编辑  收藏  举报